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