A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
emu-net-device.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2008 University of Washington
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18 
19 #include "emu-net-device.h"
20 #include "emu-encode-decode.h"
21 
22 #include "ns3/log.h"
23 #include "ns3/queue.h"
24 #include "ns3/simulator.h"
25 #include "ns3/ethernet-header.h"
26 #include "ns3/ethernet-trailer.h"
27 #include "ns3/llc-snap-header.h"
28 #include "ns3/boolean.h"
29 #include "ns3/uinteger.h"
30 #include "ns3/pointer.h"
31 #include "ns3/string.h"
32 #include "ns3/trace-source-accessor.h"
33 #include "ns3/channel.h"
34 #include "ns3/system-thread.h"
35 #include "ns3/mac48-address.h"
36 #include "ns3/enum.h"
37 
38 #include <sys/wait.h>
39 #include <sys/stat.h>
40 #include <sys/socket.h>
41 #include <sys/un.h>
42 #include <sys/ioctl.h>
43 #include <net/ethernet.h>
44 #include <net/if.h>
45 #include <netinet/in.h>
46 #include <netpacket/packet.h>
47 #include <arpa/inet.h>
48 #include <cerrno>
49 #include <limits>
50 #include <cstdlib>
51 #include <ctime>
52 #include <unistd.h>
53 
54 NS_LOG_COMPONENT_DEFINE ("EmuNetDevice");
55 
56 namespace ns3 {
57 
58 NS_OBJECT_ENSURE_REGISTERED (EmuNetDevice)
59  ;
60 
61 #define EMU_MAGIC 65867
62 
63 TypeId
65 {
66  static TypeId tid = TypeId ("ns3::EmuNetDevice")
67  .SetParent<NetDevice> ()
68  .AddConstructor<EmuNetDevice> ()
69  .AddAttribute ("Mtu", "The MAC-level Maximum Transmission Unit",
70  UintegerValue (0), // arbitrary un-used value because no setter
71  MakeUintegerAccessor (&EmuNetDevice::GetMtu),
72  MakeUintegerChecker<uint16_t> ())
73  .AddAttribute ("Address",
74  "The ns-3 MAC address of this (virtual) device.",
75  Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
76  MakeMac48AddressAccessor (&EmuNetDevice::m_address),
77  MakeMac48AddressChecker ())
78  .AddAttribute ("DeviceName",
79  "The name of the underlying real device (e.g. eth1).",
80  StringValue ("eth1"),
81  MakeStringAccessor (&EmuNetDevice::m_deviceName),
82  MakeStringChecker ())
83  .AddAttribute ("Start",
84  "The simulation time at which to spin up the device thread.",
85  TimeValue (Seconds (0.)),
86  MakeTimeAccessor (&EmuNetDevice::m_tStart),
87  MakeTimeChecker ())
88  .AddAttribute ("Stop",
89  "The simulation time at which to tear down the device thread.",
90  TimeValue (Seconds (0.)),
91  MakeTimeAccessor (&EmuNetDevice::m_tStop),
92  MakeTimeChecker ())
93  .AddAttribute ("EncapsulationMode",
94  "The link-layer encapsulation type to use.",
95  EnumValue (DIX),
97  MakeEnumChecker (DIX, "Dix",
98  LLC, "Llc"))
99 
100  //
101  // Transmit queueing discipline for the device which includes its own set
102  // of trace hooks. Note that this is really going to run "on top of" the
103  // queueing discipline that will most likely be present in the devices of
104  // the underlying operating system.
105  //
106  .AddAttribute ("TxQueue",
107  "A queue to use as the transmit queue in the device.",
108  PointerValue (),
109  MakePointerAccessor (&EmuNetDevice::m_queue),
110  MakePointerChecker<Queue> ())
111 
112  .AddAttribute ("RxQueueSize", "Maximum size of the read queue. "
113  "This value limits number of packets that have been read "
114  "from the network into a memory buffer but have not yet "
115  "been processed by the simulator.",
116  UintegerValue (1000),
117  MakeUintegerAccessor (&EmuNetDevice::m_maxPendingReads),
118  MakeUintegerChecker<uint32_t> ())
119 
120  //
121  // Trace sources at the "top" of the net device, where packets transition
122  // to/from higher layers. These points do not really correspond to the
123  // MAC layer of the underlying operating system, but exist to provide
124  // a consitent tracing environment. These trace hooks should really be
125  // interpreted as the points at which a packet leaves the ns-3 environment
126  // destined for the underlying operating system or vice-versa.
127  //
128  .AddTraceSource ("MacTx",
129  "Trace source indicating a packet has arrived for transmission by this device",
131  .AddTraceSource ("MacTxDrop",
132  "Trace source indicating a packet has been dropped by the device before transmission",
134  .AddTraceSource ("MacPromiscRx",
135  "A packet has been received by this device, has been passed up from the physical layer "
136  "and is being forwarded up the local protocol stack. This is a promiscuous trace,",
138  .AddTraceSource ("MacRx",
139  "A packet has been received by this device, has been passed up from the physical layer "
140  "and is being forwarded up the local protocol stack. This is a non-promiscuous trace,",
142 #if 0
143  // Not currently implemented for this device
144  .AddTraceSource ("MacRxDrop",
145  "Trace source indicating a packet was dropped before being forwarded up the stack",
147 #endif
148  //
149  // In normal ns-3 net devices, these trace souces correspond to the "bottom"
150  // of the net device, where packets transition to/from the channel. In
151  // the case of the emu device, there is no physical layer access -- all we
152  // do is to send packets to another device that is really at a "real" MAC
153  // level. Since it could be misleading to call anything here PHY, we do not
154  // implement these trace sources.
155  //
156 #if 0
157  .AddTraceSource ("PhyTxBegin",
158  "Trace source indicating a packet has begun transmitting over the channel",
160  .AddTraceSource ("PhyTxEnd",
161  "Trace source indicating a packet has been completely transmitted over the channel",
163  .AddTraceSource ("PhyTxDrop",
164  "Trace source indicating a packet has been dropped by the device during transmission",
166  .AddTraceSource ("PhyRxBegin",
167  "Trace source indicating a packet has begun being received by the device",
169  .AddTraceSource ("PhyRxEnd",
170  "Trace source indicating a packet has been completely received by the device",
172  .AddTraceSource ("PhyRxDrop",
173  "Trace source indicating a packet has been dropped by the device during reception",
175 #endif
176  //
177  // Trace sources designed to simulate a packet sniffer facility (tcpdump).
178  //
179  .AddTraceSource ("Sniffer",
180  "Trace source simulating a non-promiscuous packet sniffer attached to the device",
182  .AddTraceSource ("PromiscSniffer",
183  "Trace source simulating a promiscuous packet sniffer attached to the device",
185  ;
186  return tid;
187 }
188 
190  :
191  m_startEvent (),
192  m_stopEvent (),
193  m_sock (-1),
194  m_readThread (0),
195  m_ifIndex (std::numeric_limits<uint32_t>::max ()), // absurdly large value
196  m_sll_ifindex (-1),
197  m_isBroadcast (true),
198  m_isMulticast (false),
199  m_pendingReadCount (0)
200 {
201  NS_LOG_FUNCTION (this);
202  m_packetBuffer = new uint8_t[65536];
203  Start (m_tStart);
204 }
205 
207 {
208  delete [] m_packetBuffer;
209  m_packetBuffer = 0;
210 }
211 
212 void
214 {
216  if (m_readThread != 0)
217  {
218  StopDevice ();
219  }
220  m_node = 0;
222 }
223 
224 void
226 {
227  NS_LOG_FUNCTION (mode);
228  m_encapMode = mode;
229  NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
230 }
231 
234 {
236  return m_encapMode;
237 }
238 
239 void
241 {
242  NS_LOG_FUNCTION (tStart);
243 
244  //
245  // Cancel any pending start event and schedule a new one at some relative time in the future.
246  //
249 }
250 
251 void
253 {
254  NS_LOG_FUNCTION (tStop);
255  //
256  // Cancel any pending stop event and schedule a new one at some relative time in the future.
257  //
260 }
261 
262 void
264 {
266 
267  //
268  // Spin up the emu net device and start receiving packets.
269  //
270  if (m_sock != -1)
271  {
272  NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Device is already started");
273  }
274 
275  //
276  // A similar story exists for the node ID. We can't just naively do a
277  // GetNode ()->GetId () since GetNode is going to give us a Ptr<Node> which
278  // is reference counted. We need to stash away the node ID for use in the
279  // read thread.
280  //
281  m_nodeId = GetNode ()->GetId ();
282 
283  NS_LOG_LOGIC ("Creating socket");
284 
285  //
286  // Call out to a separate process running as suid root in order to get a raw
287  // socket. We do this to avoid having the entire simulation running as root.
288  // If this method returns, we'll have a raw socket waiting for us in m_sock.
289  //
290  CreateSocket ();
291 
292  //
293  // Figure out which interface index corresponds to the device name in the corresponding attribute.
294  //
295  struct ifreq ifr;
296  bzero (&ifr, sizeof(ifr));
297  strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
298 
299  NS_LOG_LOGIC ("Getting interface index");
300  int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
301  if (rc == -1)
302  {
303  NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Can't get interface index");
304  }
305 
306  //
307  // Save the real interface index for later calls to sendto
308  //
309  m_sll_ifindex = ifr.ifr_ifindex;
310 
311  //
312  // Bind the socket to the interface we just found.
313  //
314  struct sockaddr_ll ll;
315  bzero (&ll, sizeof(ll));
316 
317  ll.sll_family = AF_PACKET;
318  ll.sll_ifindex = m_sll_ifindex;
319  ll.sll_protocol = htons (ETH_P_ALL);
320 
321  NS_LOG_LOGIC ("Binding socket to interface");
322 
323  rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
324  if (rc == -1)
325  {
326  NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Can't bind to specified interface");
327  }
328 
329  rc = ioctl (m_sock, SIOCGIFFLAGS, &ifr);
330  if (rc == -1)
331  {
332  NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Can't get interface flags");
333  }
334 
335  //
336  // This device only works if the underlying interface is up in promiscuous
337  // mode. We could have turned it on in the socket creator, but the situation
338  // is that we expect these devices to be used in conjunction with virtual
339  // machines with connected host-only (simulated) networks, or in a testbed.
340  // There is a lot of setup and configuration happening outside of this one
341  // issue, and we expect that configuration to include choosing a valid
342  // interface (e.g, "ath1"), ensuring that the device supports promiscuous
343  // mode, and placing it in promiscuous mode. We just make sure of the
344  // end result.
345  //
346  if ((ifr.ifr_flags & IFF_PROMISC) == 0)
347  {
348  NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): " << m_deviceName << " is not in promiscuous mode");
349  }
350  if ((ifr.ifr_flags & IFF_BROADCAST) != IFF_BROADCAST)
351  {
352  // We default m_isBroadcast to true but turn it off here if not
353  // supported, because in the common case, overlying IP code will
354  // assert during configuration time if this is false, before this
355  // method has a chance to set it during runtime
356  m_isBroadcast = false;
357  }
358  if ((ifr.ifr_flags & IFF_MULTICAST) == IFF_MULTICAST)
359  {
360  // This one is OK to enable at runtime
361  m_isMulticast = true;
362  }
363 
364  //
365  // Now spin up a read thread to read packets.
366  //
367  if (m_readThread != 0)
368  {
369  NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): Receive thread is already running");
370  }
371 
372  NS_LOG_LOGIC ("Spinning up read thread");
373 
374  m_readThread = Create<SystemThread> (MakeCallback (&EmuNetDevice::ReadThread, this));
375  m_readThread->Start ();
376 
377  NotifyLinkUp ();
378 }
379 
380 void
382 {
384  //
385  // We want to create a raw socket for our net device. Unfortunately for us
386  // you have to have root privileges to do that. Instead of running the
387  // entire simulation as root, we decided to make a small program who's whole
388  // reason for being is to run as suid root and create a raw socket. We're
389  // going to fork and exec that program soon, but we need to have a socket
390  // to talk to it with. So we create a local interprocess (Unix) socket
391  // for that purpose.
392  //
393  int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
394  if (sock == -1)
395  {
396  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Unix socket creation error, errno = " << std::strerror (errno));
397  }
398 
399  //
400  // Bind to that socket and let the kernel allocate an endpoint
401  //
402  struct sockaddr_un un;
403  memset (&un, 0, sizeof (un));
404  un.sun_family = AF_UNIX;
405  int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t));
406  if (status == -1)
407  {
408  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not bind(): errno = " << std::strerror (errno));
409  }
410 
411  NS_LOG_INFO ("Created Unix socket");
412  NS_LOG_INFO ("sun_family = " << un.sun_family);
413  NS_LOG_INFO ("sun_path = " << un.sun_path);
414 
415  //
416  // We have a socket here, but we want to get it there -- to the program we're
417  // going to exec. What we'll do is to do a getsockname and then encode the
418  // resulting address information as a string, and then send the string to the
419  // program as an argument. So we need to get the sock name.
420  //
421  socklen_t len = sizeof (un);
422  status = getsockname (sock, (struct sockaddr*)&un, &len);
423  if (status == -1)
424  {
425  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not getsockname(): errno = " << std::strerror (errno));
426  }
427 
428  //
429  // Now encode that socket name (family and path) as a string of hex digits
430  //
431  std::string path = EmuBufferToString ((uint8_t *)&un, len);
432  NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\"");
433  //
434  // Fork and exec the process to create our socket. If we're us (the parent)
435  // we wait for the child (the socket creator) to complete and read the
436  // socket it created using the ancillary data mechanism.
437  //
438  // Tom Goff reports the possiblility of a deadlock when trying to acquire the
439  // python GIL here. He says that this might be due to trying to access Python
440  // objects after fork() without calling PyOS_AfterFork() to properly reset
441  // Python state (including the GIL). There is no code to cause the problem
442  // here in emu, but this was visible in similar code in tap-bridge.
443  //
444  pid_t pid = ::fork ();
445  if (pid == 0)
446  {
447  NS_LOG_DEBUG ("Child process");
448 
449  //
450  // build a command line argument from the encoded endpoint string that
451  // the socket creation process will use to figure out how to respond to
452  // the (now) parent process.
453  //
454  std::ostringstream oss;
455  oss << "-p" << path;
456  NS_LOG_INFO ("Parameters set to \"" << oss.str () << "\"");
457 
458  //
459  // Execute the socket creation process image.
460  //
461  status = ::execlp (EMU_SOCK_CREATOR,
462  EMU_SOCK_CREATOR, // argv[0] (filename)
463  oss.str ().c_str (), // argv[1] (-p<path?
464  (char *)NULL);
465 
466  //
467  // If the execlp successfully completes, it never returns. If it returns it failed or the OS is
468  // broken. In either case, we bail.
469  //
470  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Back from execlp(), errno = " << std::strerror (errno));
471  }
472  else
473  {
474  NS_LOG_DEBUG ("Parent process");
475  //
476  // We're the process running the emu net device. We need to wait for the
477  // socket creator process to finish its job.
478  //
479  int st;
480  pid_t waited = waitpid (pid, &st, 0);
481  if (waited == -1)
482  {
483  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): waitpid() fails, errno = " << std::strerror (errno));
484  }
485  NS_ASSERT_MSG (pid == waited, "EmuNetDevice::CreateSocket(): pid mismatch");
486 
487  //
488  // Check to see if the socket creator exited normally and then take a
489  // look at the exit code. If it bailed, so should we. If it didn't
490  // even exit normally, we bail too.
491  //
492  if (WIFEXITED (st))
493  {
494  int exitStatus = WEXITSTATUS (st);
495  if (exitStatus != 0)
496  {
497  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited normally with status " << exitStatus);
498  }
499  }
500  else
501  {
502  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited abnormally");
503  }
504 
505  //
506  // At this point, the socket creator has run successfully and should
507  // have created our raw socket and sent it back to the socket address
508  // we provided. Our socket should be waiting on the Unix socket. We've
509  // got to do a bunch of grunto work to get at it, though.
510  //
511  // The struct iovec below is part of a scatter-gather list. It describes a
512  // buffer. In this case, it describes a buffer (an integer) that will
513  // get the data that comes back from the socket creator process. It will
514  // be a magic number that we use as a consistency/sanity check.
515  //
516  struct iovec iov;
517  uint32_t magic;
518  iov.iov_base = &magic;
519  iov.iov_len = sizeof(magic);
520 
521  //
522  // The CMSG macros you'll see below are used to create and access control
523  // messages (which is another name for ancillary data). The ancillary
524  // data is made up of pairs of struct cmsghdr structures and associated
525  // data arrays.
526  //
527  // First, we're going to allocate a buffer on the stack to receive our
528  // data array (that contains the socket). Sometimes you'll see this called
529  // an "ancillary element" but the msghdr uses the control message termimology
530  // so we call it "control."
531  //
532  size_t msg_size = sizeof(int);
533  char control[CMSG_SPACE (msg_size)];
534 
535  //
536  // There is a msghdr that is used to minimize the number of parameters
537  // passed to recvmsg (which we will use to receive our ancillary data).
538  // This structure uses terminology corresponding to control messages, so
539  // you'll see msg_control, which is the pointer to the ancillary data and
540  // controllen which is the size of the ancillary data array.
541  //
542  // So, initialize the message header that describes the ancillary/control
543  // data we expect to receive and point it to buffer.
544  //
545  struct msghdr msg;
546  msg.msg_name = 0;
547  msg.msg_namelen = 0;
548  msg.msg_iov = &iov;
549  msg.msg_iovlen = 1;
550  msg.msg_control = control;
551  msg.msg_controllen = sizeof (control);
552  msg.msg_flags = 0;
553 
554  //
555  // Now we can actually receive the interesting bits from the socket
556  // creator process.
557  //
558  ssize_t bytesRead = recvmsg (sock, &msg, 0);
559  if (bytesRead != sizeof(int))
560  {
561  NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Wrong byte count from socket creator");
562  }
563 
564  //
565  // There may be a number of message headers/ancillary data arrays coming in.
566  // Let's look for the one with a type SCM_RIGHTS which indicates it' the
567  // one we're interested in.
568  //
569  struct cmsghdr *cmsg;
570  for (cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR (&msg, cmsg))
571  {
572  if (cmsg->cmsg_level == SOL_SOCKET &&
573  cmsg->cmsg_type == SCM_RIGHTS)
574  {
575  //
576  // This is the type of message we want. Check to see if the magic
577  // number is correct and then pull out the socket we care about if
578  // it matches
579  //
580  if (magic == EMU_MAGIC)
581  {
582  NS_LOG_INFO ("Got SCM_RIGHTS with correct magic " << magic);
583  int *rawSocket = (int*)CMSG_DATA (cmsg);
584  NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
585  m_sock = *rawSocket;
586  return;
587  }
588  else
589  {
590  NS_LOG_INFO ("Got SCM_RIGHTS, but with bad magic " << magic);
591  }
592  }
593  }
594  NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
595  }
596 }
597 
598 void
600 {
602 
603  close (m_sock);
604  m_sock = -1;
605 
606  NS_ASSERT_MSG (m_readThread != 0, "EmuNetDevice::StopDevice(): Receive thread is not running");
607 
608  NS_LOG_LOGIC ("Joining read thread");
609  m_readThread->Join ();
610  m_readThread = 0;
611 }
612 
613 void
614 EmuNetDevice::ForwardUp (uint8_t *buf, uint32_t len)
615 {
616  NS_LOG_FUNCTION (buf << len);
617 
618  //
619  // Create a packet out of the buffer we received and free that buffer.
620  //
621  Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
622  std::free (buf);
623  buf = 0;
624 
625  {
627  //std::cerr << std::endl << "EmuNetDevice main thread: m_pendingReadCount is " << m_pendingReadCount << std::endl;
629  }
630 
631  //
632  // Trace sinks will expect complete packets, not packets without some of the
633  // headers.
634  //
635  Ptr<Packet> originalPacket = packet->Copy ();
636 
637  EthernetHeader header (false);
638 
639  //
640  // This device could be running in an environment where completely unexpected
641  // kinds of packets are flying around, so we need to harden things a bit and
642  // filter out packets we think are completely bogus, so we always check to see
643  // that the packet is long enough to contain the header we want to remove.
644  //
645  if (packet->GetSize () < header.GetSerializedSize ())
646  {
647  m_phyRxDropTrace (originalPacket);
648  return;
649  }
650 
651  packet->RemoveHeader (header);
652 
653  NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
654  NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
655 
656  uint16_t protocol;
657 
658  switch (m_encapMode)
659  {
660  case LLC:
661  //
662  // If the length/type is less than 1500, it corresponds to a length
663  // interpretation packet. In this case, it is an 802.3 packet and
664  // will also have an 802.2 LLC header. If greater than 1500, we
665  // find the protocol number (Ethernet type) directly.
666  //
667  if (header.GetLengthType () <= 1500)
668  {
669  LlcSnapHeader llc;
670  //
671  // Check to see that the packet is long enough to possibly contain the
672  // header we want to remove before just naively calling.
673  //
674  if (packet->GetSize () < llc.GetSerializedSize ())
675  {
676  m_phyRxDropTrace (originalPacket);
677  return;
678  }
679 
680  packet->RemoveHeader (llc);
681  protocol = llc.GetType ();
682  }
683  else
684  {
685  protocol = header.GetLengthType ();
686  }
687  break;
688 
689  case DIX:
690  protocol = header.GetLengthType ();
691  break;
692 
693  default:
694  NS_FATAL_ERROR ("invalid encapsulation mode");
695  protocol = 0; /* quiet compiler */
696  }
697 
698  PacketType packetType;
699 
700  if (header.GetDestination ().IsBroadcast ())
701  {
702  packetType = NS3_PACKET_BROADCAST;
703  }
704  else if (header.GetDestination ().IsGroup ())
705  {
706  packetType = NS3_PACKET_MULTICAST;
707  }
708  else if (header.GetDestination () == m_address)
709  {
710  packetType = NS3_PACKET_HOST;
711  }
712  else
713  {
714  packetType = NS3_PACKET_OTHERHOST;
715  }
716 
717  //
718  // For all kinds of packetType we receive, we hit the promiscuous sniffer
719  // hook and pass a copy up to the promiscuous callback. Pass a copy to
720  // make sure that nobody messes with our packet.
721  //
722  m_promiscSnifferTrace (originalPacket);
723 
724  if (!m_promiscRxCallback.IsNull ())
725  {
726  m_macPromiscRxTrace (originalPacket);
727  m_promiscRxCallback (this, packet, protocol, header.GetSource (), header.GetDestination (), packetType);
728  }
729 
730  //
731  // If this packet is not destined for some other host, it must be for us
732  // as either a broadcast, multicast or unicast. We need to hit the mac
733  // packet received trace hook and forward the packet up the stack.
734  //
735  if (packetType != NS3_PACKET_OTHERHOST)
736  {
737  m_snifferTrace (originalPacket);
738  m_macRxTrace (originalPacket);
739  m_rxCallback (this, packet, protocol, header.GetSource ());
740  }
741 }
742 
743 void
745 {
747 
748  // It's important to remember that we're in a completely different thread than the simulator is running in.
749  // We are talking about multiple threads here, so it is very, very dangerous to do any kind of reference couning
750  // on a shared object.
751  //
752 
753  int32_t len = -1;
754  struct sockaddr_ll addr;
755  socklen_t addrSize = sizeof (addr);
756 
757  for (;;)
758  {
759  //
760  // Too many pending reads at the same time leads to excessive memory allocations. This counter prevents it.
761  //
762  bool skip = false;
763 
764  {
766  //std::cerr << std::endl << "EmuNetDevice read thread: m_pendingReadCount is " << m_pendingReadCount << std::endl;
768  {
769  skip = true;
770  }
771  else
772  {
774  }
775  }
776 
777  if (skip)
778  {
779  struct timespec time = { 0, 100000000L }; // 100 ms
780  nanosleep (&time, NULL);
781  continue;
782  }
783 
784  //
785  // to avoid any issues with a shared reference counted packet, we allocate a buffer on the heap and pass that
786  // buffer into the ns-3 context thread where it will create the packet, copy the buffer and then free it.
787  //
788  uint32_t bufferSize = 65536;
789  uint8_t *buf = (uint8_t *)std::malloc (bufferSize);
790  if (buf == 0)
791  {
792  NS_FATAL_ERROR ("EmuNetDevice::ReadThread(): malloc packet buffer failed");
793  }
794 
795  NS_LOG_LOGIC ("Calling recvfrom");
796  len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr, &addrSize);
797 
798  if (len == -1)
799  {
800  std::free (buf);
801  buf = 0;
802  return;
803  }
804 
805  NS_LOG_INFO ("EmuNetDevice::EmuNetDevice(): Received packet on node " << m_nodeId);
806  NS_LOG_INFO ("EmuNetDevice::ReadThread(): Scheduling handler");
808  MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
809  buf = 0;
810  }
811 }
812 
813 bool
814 EmuNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
815 {
816  NS_LOG_FUNCTION (packet << dest << protocolNumber);
817  //
818  // The immediate questions here are how are we going to encapsulate packets and what do we use as the MAC source and
819  // destination (hardware) addresses?
820  //
821  // If we return false from EmuNetDevice::NeedsArp, the ArpIpv4Interface will pass the broadcast address as the
822  // hardware (Ethernet) destination by default. If we return true from EmuNetDevice::NeedsArp, then the hardware
823  // destination is actually meaningful, but we'll have an ns-3 ARP running on this device. There can also be an ARP
824  // running on the underlying OS so we have to be very careful, both about multiple ARPs and also about TCP, UDP, etc.
825  //
826  // We are operating in promiscuous mode on the receive side (all ns-3 net devices are required to implement the
827  // promiscuous callback in a meaningful way), so we have an option regarding the hardware addresses. We don't actually have
828  // to use the real hardware addresses and IP addresses of the underlying system. We can completely use MAC-spoofing to
829  // fake out the OS by using the ns-3 assigned MAC address (and also the ns-3 assigned IP addresses). Ns-3 starts its
830  // MAC address allocation using the OUI (vendor-code) 00:00:00 which is unassigned to any organization and is a globally
831  // administered address, so there shouldn't be any collisions with real hardware.
832  //
833  // So what we do is we return true from EmuNetDevice::NeedsArp which tells ns-3 to use its own ARP. We spoof the
834  // MAC address of the device and use promiscuous mode to receive traffic destined to that address.
835  //
836  return SendFrom (packet, m_address, dest, protocolNumber);
837 }
838 
839 bool
840 EmuNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &dest, uint16_t protocolNumber)
841 {
842  NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
843  NS_LOG_LOGIC ("packet =" << packet);
844  NS_LOG_LOGIC ("UID is " << packet->GetUid () << ")");
845 
846  if (IsLinkUp () == false)
847  {
848  m_macTxDropTrace (packet);
849  return false;
850  }
851 
852  Mac48Address destination = Mac48Address::ConvertFrom (dest);
854 
855  NS_LOG_LOGIC ("Transmit packet with UID " << packet->GetUid ());
856  NS_LOG_LOGIC ("Transmit packet from " << source);
857  NS_LOG_LOGIC ("Transmit packet to " << destination);
858 
859  EthernetHeader header (false);
860  header.SetSource (source);
861  header.SetDestination (destination);
862 
863  switch (m_encapMode)
864  {
865  case LLC:
866  {
867  LlcSnapHeader llc;
868  llc.SetType (protocolNumber);
869  packet->AddHeader (llc);
870 
871  header.SetLengthType (packet->GetSize ());
872  }
873  break;
874 
875  case DIX:
876  header.SetLengthType (protocolNumber);
877  break;
878 
879  default:
880  NS_FATAL_ERROR ("invalid encapsulation mode");
881  }
882 
883  packet->AddHeader (header);
884 
885  //
886  // there's not much meaning associated with the different layers in this
887  // device, so don't be surprised when they're all stacked together in
888  // essentially one place. We do this for trace consistency across devices.
889  //
890  m_macTxTrace (packet);
891 
892  //
893  // Enqueue and dequeue the packet to hit the queue tracing hooks.
894  //
895  m_queue->Enqueue (packet);
896  packet = m_queue->Dequeue ();
897  NS_ASSERT_MSG (packet, "EmuNetDevice::SendFrom(): packet zero from queue");
898 
899  m_promiscSnifferTrace (packet);
900  m_snifferTrace (packet);
901 
902  struct sockaddr_ll ll;
903  bzero (&ll, sizeof (ll));
904 
905  ll.sll_family = AF_PACKET;
906  ll.sll_ifindex = m_sll_ifindex;
907  ll.sll_protocol = htons (ETH_P_ALL);
908 
909  NS_LOG_LOGIC ("calling sendto");
910 
911  NS_ASSERT_MSG (packet->GetSize () <= 65536, "EmuNetDevice::SendFrom(): Packet too big " << packet->GetSize ());
912  packet->CopyData (m_packetBuffer, packet->GetSize ());
913 
914  int32_t rc = sendto (m_sock, m_packetBuffer, packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
915  NS_LOG_LOGIC ("sendto returns " << rc);
916 
917  return rc == -1 ? false : true;
918 }
919 
920 void
922 {
923  NS_LOG_FUNCTION (this << bps);
924  NS_FATAL_ERROR ("EmuNetDevice::SetDataRate(): Unable.");
925 }
926 
927 void
929 {
930  NS_LOG_FUNCTION (this << q);
931  m_queue = q;
932 }
933 
934 Ptr<Queue>
936 {
938  return m_queue;
939 }
940 
941 void
943 {
944  m_linkUp = true;
946 }
947 
948 void
949 EmuNetDevice::SetIfIndex (const uint32_t index)
950 {
951  m_ifIndex = index;
952 }
953 
954 uint32_t
956 {
957  return m_ifIndex;
958 }
959 
962 {
963  NS_FATAL_ERROR ("EmuNetDevice::GetChannel(): Unable.");
964  return 0;
965 }
966 
967 void
969 {
970  NS_LOG_FUNCTION (address);
972 }
973 
974 Address
976 {
978  return m_address;
979 }
980 
981 bool
982 EmuNetDevice::SetMtu (const uint16_t mtu)
983 {
984  NS_FATAL_ERROR ("EmuNetDevice::SetMtu(): Unable.");
985  return false;
986 }
987 
988 uint16_t
990 {
991  struct ifreq ifr;
992  bzero (&ifr, sizeof (ifr));
993  strcpy (ifr.ifr_name, m_deviceName.c_str ());
994 
995  int32_t fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_IP);
996 
997 
998  int32_t rc = ioctl (fd, SIOCGIFMTU, &ifr);
999  if (rc == -1)
1000  {
1001  NS_FATAL_ERROR ("EmuNetDevice::GetMtu(): Can't ioctl SIOCGIFMTU");
1002  }
1003 
1004  close (fd);
1005 
1006  return ifr.ifr_mtu;
1007 }
1008 
1009 bool
1011 {
1012  return m_linkUp;
1013 }
1014 
1015 void
1017 {
1019 }
1020 
1021 bool
1023 {
1024  return m_isBroadcast;
1025 }
1026 
1027 Address
1029 {
1030  return Mac48Address ("ff:ff:ff:ff:ff:ff");
1031 }
1032 
1033 bool
1035 {
1036  return m_isMulticast;
1037 }
1038 
1039 Address
1041 {
1042  NS_LOG_FUNCTION (multicastGroup);
1043 
1044  Mac48Address ad = Mac48Address::GetMulticast (multicastGroup);
1045 
1046  //
1047  // Implicit conversion (operator Address ()) is defined for Mac48Address, so
1048  // use it by just returning the EUI-48 address which is automagically converted
1049  // to an Address.
1050  //
1051  NS_LOG_LOGIC ("multicast address is " << ad);
1052 
1053  return ad;
1054 }
1055 
1056 Address
1058 {
1059  NS_LOG_FUNCTION (this << addr);
1060 
1062  NS_LOG_LOGIC ("MAC IPv6 multicast address is " << ad);
1063 
1064  return ad;
1065 }
1066 
1067 bool
1069 {
1070  return false;
1071 }
1072 
1073 bool
1075 {
1076  return false;
1077 }
1078 
1079 void
1081 {
1082  m_promiscRxCallback = cb;
1083 }
1084 
1085 bool
1087 {
1089  return true;
1090 }
1091 
1092 
1093 Ptr<Node>
1095 {
1096  return m_node;
1097 }
1098 
1099 void
1101 {
1102  m_node = node;
1103 }
1104 
1105 bool
1107 {
1108  return true;
1109 }
1110 
1111 void
1113 {
1114  m_rxCallback = cb;
1115 }
1116 
1117 } // namespace ns3
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:268
keep track of time values and allow control of global simulation resolution
Definition: nstime.h:81
void StopDevice(void)
Tear down the device.
virtual ~EmuNetDevice()
Destroy a EmuNetDevice.
TracedCallback< Ptr< const Packet > > m_macPromiscRxTrace
The trace source fired for packets successfully received by the device immediately before being forwa...
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:345
Ptr< const AttributeChecker > MakeEnumChecker(int v1, std::string n1, int v2, std::string n2, int v3, std::string n3, int v4, std::string n4, int v5, std::string n5, int v6, std::string n6, int v7, std::string n7, int v8, std::string n8, int v9, std::string n9, int v10, std::string n10, int v11, std::string n11, int v12, std::string n12, int v13, std::string n13, int v14, std::string n14, int v15, std::string n15, int v16, std::string n16, int v17, std::string n17, int v18, std::string n18, int v19, std::string n19, int v20, std::string n20, int v21, std::string n21, int v22, std::string n22)
Definition: enum.cc:178
SystemMutex m_pendingReadMutex
virtual bool NeedsArp(void) const
Ptr< Queue > m_queue
The Queue which this EmuNetDevice uses as a packet source.
TracedCallback< Ptr< const Packet > > m_promiscSnifferTrace
A trace source that emulates a promiscuous mode protocol sniffer connected to the device...
std::string EmuBufferToString(uint8_t *buffer, uint32_t len)
Convert a byte buffer to a string containing a hex representation of the buffer.
virtual void SetReceiveCallback(NetDevice::ReceiveCallback cb)
hold variables of type string
Definition: string.h:19
std::string m_deviceName
The unix/linux name of the underlying device (e.g., eth0)
virtual bool Send(Ptr< Packet > packet, const Address &dest, uint16_t protocolNumber)
uint8_t * m_packetBuffer
A 64K buffer to hold packet data while it is being sent.
virtual bool IsBroadcast(void) const
EncapsulationMode
Enumeration of the types of packets supported in the class.
uint64_t GetUid(void) const
A packet is allocated a new uid when it is created empty or with zero-filled payload.
Definition: packet.cc:393
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1014
virtual bool SupportsSendFrom(void) const
bool m_isBroadcast
Flag indicating whether or not the underlying net device supports broadcast.
NS_OBJECT_ENSURE_REGISTERED(NullMessageSimulatorImpl)
Ptr< Queue > GetQueue(void) const
Get a copy of the attached Queue.
void StartDevice(void)
Spin up the device.
TracedCallback< Ptr< const Packet > > m_snifferTrace
A trace source that emulates a non-promiscuous protocol sniffer connected to the device.
uint16_t GetLengthType(void) const
uint32_t GetSize(void) const
Definition: packet.h:650
bool IsBroadcast(void) const
virtual void SetNode(Ptr< Node > node)
TracedCallback< Ptr< const Packet > > m_phyTxDropTrace
The trace source fired when the phy layer drops a packet as it tries to transmit it.
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object's destructor, whichever comes first...
Definition: object.cc:336
#define NS_LOG_INFO(msg)
Definition: log.h:298
static void Cancel(const EventId &id)
Set the cancel bit on this event: the event's associated function will not be invoked when it expires...
Definition: simulator.cc:268
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
Definition: log.h:309
void SetType(uint16_t type)
static EventId Schedule(Time const &time, MEM mem_ptr, OBJ obj)
Schedule an event to expire at the relative time "time" is reached.
Definition: simulator.h:824
void ReadThread(void)
Loop to read and process packets.
TracedCallback< Ptr< const Packet > > m_macRxTrace
The trace source fired for packets successfully received by the device immediately before being forwa...
virtual void SetIfIndex(const uint32_t index)
NetDevice::PromiscReceiveCallback m_promiscRxCallback
The callback used to notify higher layers that a packet has been received in promiscuous mode...
TracedCallback< Ptr< const Packet > > m_phyTxBeginTrace
The trace source fired when a packet begins the transmission process on the medium.
TracedCallback< Ptr< const Packet > > m_macTxDropTrace
The trace source fired when packets coming into the "top" of the device at the L3/L2 transition are d...
void SetSource(Mac48Address source)
Ptr< Node > m_node
The Node to which this device is attached.
#define EMU_MAGIC
void Start(Time tStart)
Set a start time for the device.
static TypeId GetTypeId(void)
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
a polymophic address class
Definition: address.h:86
virtual uint32_t GetIfIndex(void) const
virtual Address GetAddress(void) const
Class for representing data rates.
Definition: data-rate.h:71
TracedCallback< Ptr< const Packet > > m_phyRxBeginTrace
The trace source fired when a packet begins the reception process from the medium.
bool m_linkUp
Flag indicating whether or not the link is up.
void SetQueue(Ptr< Queue > queue)
Attach a queue to the EmuNetDevice.
hold variables of type 'enum'
Definition: enum.h:37
static Mac48Address GetMulticast(Ipv4Address address)
hold objects of type ns3::Time
Definition: nstime.h:961
virtual uint16_t GetMtu(void) const
uint16_t GetType(void)
A class which provides a simple way to implement a Critical Section.
Definition: system-mutex.h:109
virtual Ptr< Node > GetNode(void) const
TracedCallback< Ptr< const Packet > > m_macRxDropTrace
The trace source fired for packets successfully received by the device but which are dropped before b...
Hold an unsigned integer type.
Definition: uinteger.h:46
virtual Ptr< Channel > GetChannel(void) const
Ptr< SystemThread > m_readThread
EmuNetDevice::EncapsulationMode GetEncapsulationMode(void) const
Get the encapsulation mode of this device.
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1238
EmuNetDevice()
Construct a EmuNetDevice.
void SetEncapsulationMode(EmuNetDevice::EncapsulationMode mode)
Set the encapsulation mode of this device.
void Stop(Time tStop)
Set a stop time for the device.
static void ScheduleWithContext(uint32_t context, Time const &time, MEM mem_ptr, OBJ obj)
Schedule an event with the given context.
Definition: simulator.h:904
NetDevice::ReceiveCallback m_rxCallback
The callback used to notify higher layers that a packet has been received.
#define NS_LOG_LOGIC(msg)
Definition: log.h:368
static Mac48Address ConvertFrom(const Address &address)
virtual void SetPromiscReceiveCallback(PromiscReceiveCallback cb)
Ptr< Packet > Copy(void) const
Definition: packet.cc:122
uint32_t m_ifIndex
The ns-3 interface index (in the sense of net device index) that has been assigned to this network de...
TracedCallback m_linkChangeCallbacks
Callbacks to fire if the link changes state (up or down).
TracedCallback< Ptr< const Packet > > m_phyTxEndTrace
The trace source fired when a packet ends the transmission process on the medium. ...
void ForwardUp(uint8_t *buf, uint32_t len)
Method to handle received packets.
virtual bool SendFrom(Ptr< Packet > packet, const Address &source, const Address &dest, uint16_t protocolNumber)
virtual bool IsPointToPoint(void) const
Is this a point to point link?
void NotifyLinkUp(void)
hold objects of type Ptr
Definition: pointer.h:33
bool IsGroup(void) const
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
bool m_isMulticast
Flag indicating whether or not the underlying net device supports multicast.
NS_LOG_COMPONENT_DEFINE("EmuNetDevice")
an EUI-48 address
Definition: mac48-address.h:41
Packet header for Ethernet.
virtual void SetAddress(Address address)
Set the address of this interface.
virtual bool IsLinkUp(void) const
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition: enum.h:118
802.2 LLC/SNAP Packet
void SetDataRate(DataRate bps)
Set the Data Rate used for transmission of packets.
TracedCallback< Ptr< const Packet > > m_phyRxEndTrace
The trace source fired when a packet begins the reception process from the medium.
uint32_t m_pendingReadCount
#define NS_ASSERT_MSG(condition, message)
Definition: assert.h:86
Mac48Address GetSource(void) const
Describes an IPv6 address.
Definition: ipv6-address.h:46
Mac48Address GetDestination(void) const
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:38
void ConnectWithoutContext(const CallbackBase &callback)
uint32_t GetId(void) const
Definition: node.cc:104
Time m_tStart
Time to start spinning up the device.
int32_t m_sll_ifindex
The Unix interface index that we got from the system and which corresponds to the interface (e...
TracedCallback< Ptr< const Packet > > m_macTxTrace
The trace source fired when packets come into the "top" of the device at the L3/L2 transition...
uint32_t m_maxPendingReads
Time m_tStop
Time to start tearing down the device.
Network layer to device interface.
Definition: net-device.h:75
hold objects of type ns3::Mac48Address
virtual uint32_t GetSerializedSize(void) const
#define NS_LOG_DEBUG(msg)
Definition: log.h:289
void CreateSocket(void)
Call out to a separate process running as suid root in order to get a raw socket. ...
virtual uint32_t GetSerializedSize(void) const
virtual Address GetMulticast(Ipv4Address multicastGroup) const
Make and return a MAC multicast address using the provided multicast group.
void SetLengthType(uint16_t size)
EventImpl * MakeEvent(void(*f)(void))
Definition: make-event.cc:8
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object's destructor, whichever comes first...
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:452
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:381
DIX II / Ethernet II packet.
virtual void AddLinkChangeCallback(Callback< void > callback)
tuple address
Definition: first.py:37
PacketType
Packet types are used as they are in Linux.
Definition: net-device.h:270
EncapsulationMode m_encapMode
The type of packet that should be created by the AddHeader function and that should be processed by t...
void SetDestination(Mac48Address destination)
virtual bool SetMtu(const uint16_t mtu)
a unique identifier for an interface.
Definition: type-id.h:49
virtual Address GetBroadcast(void) const
TypeId SetParent(TypeId tid)
Definition: type-id.cc:611
virtual bool IsMulticast(void) const
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:253
Header for the LLC/SNAP encapsulation.
virtual bool IsBridge(void) const
Is this a bridge?
Mac48Address m_address
The MAC address which has been assigned to this device.
TracedCallback< Ptr< const Packet > > m_phyRxDropTrace
The trace source fired when the phy layer drops a packet it has received.