A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
tap-bridge.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 University of Washington
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include "tap-bridge.h"
8
9#include "tap-encode-decode.h"
10
11#include "ns3/abort.h"
12#include "ns3/boolean.h"
13#include "ns3/channel.h"
14#include "ns3/enum.h"
15#include "ns3/ethernet-header.h"
16#include "ns3/fd-reader.h"
17#include "ns3/ipv4.h"
18#include "ns3/llc-snap-header.h"
19#include "ns3/log.h"
20#include "ns3/node.h"
21#include "ns3/packet.h"
22#include "ns3/realtime-simulator-impl.h"
23#include "ns3/simulator.h"
24#include "ns3/string.h"
25#include "ns3/uinteger.h"
26
27#include <cerrno>
28#include <cstdlib>
29#include <limits>
30#include <net/if.h>
31#include <sys/ioctl.h>
32#include <sys/socket.h>
33#include <sys/stat.h>
34#include <sys/un.h>
35#include <sys/wait.h>
36#include <unistd.h>
37
38namespace ns3
39{
40
41NS_LOG_COMPONENT_DEFINE("TapBridge");
42
43FdReader::Data
45{
46 NS_LOG_FUNCTION(this);
47
48 uint32_t bufferSize = 65536;
49 auto buf = (uint8_t*)std::malloc(bufferSize);
50 NS_ABORT_MSG_IF(buf == nullptr, "malloc() failed");
51
52 NS_LOG_LOGIC("Calling read on tap device fd " << m_fd);
53 ssize_t len = read(m_fd, buf, bufferSize);
54 if (len <= 0)
55 {
56 NS_LOG_INFO("TapBridgeFdReader::DoRead(): done");
57 std::free(buf);
58 buf = nullptr;
59 len = 0;
60 }
61
62 return FdReader::Data(buf, len);
63}
64
65#define TAP_MAGIC 95549
66
68
69TypeId
71{
72 static TypeId tid =
73 TypeId("ns3::TapBridge")
75 .SetGroupName("TapBridge")
76 .AddConstructor<TapBridge>()
77 .AddAttribute("Mtu",
78 "The MAC-level Maximum Transmission Unit",
82 .AddAttribute("DeviceName",
83 "The name of the tap device to create.",
84 StringValue(""),
87 .AddAttribute("Gateway",
88 "The IP address of the default gateway to assign to the host machine, "
89 "when in ConfigureLocal mode.",
90 Ipv4AddressValue("255.255.255.255"),
94 .AddAttribute(
95 "IpAddress",
96 "The IP address to assign to the tap device, when in ConfigureLocal mode. "
97 "This address will override the discovered IP address of the simulated device.",
98 Ipv4AddressValue("255.255.255.255"),
101 .AddAttribute(
102 "MacAddress",
103 "The MAC address to assign to the tap device, when in ConfigureLocal mode. "
104 "This address will override the discovered MAC address of the simulated device.",
105 Mac48AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")),
108 .AddAttribute(
109 "Netmask",
110 "The network mask to assign to the tap device, when in ConfigureLocal mode. "
111 "This address will override the discovered MAC address of the simulated device.",
112 Ipv4MaskValue("255.255.255.255"),
115 .AddAttribute("Start",
116 "The simulation time at which to spin up the tap device read thread.",
117 TimeValue(Seconds(0.)),
120 .AddAttribute("Stop",
121 "The simulation time at which to tear down the tap device read thread.",
122 TimeValue(Seconds(0.)),
125 .AddAttribute("Mode",
126 "The operating and configuration mode to use.",
130 "ConfigureLocal",
131 USE_LOCAL,
132 "UseLocal",
134 "UseBridge"))
135 .AddAttribute("Verbose",
136 "Enable verbose output from tap-creator child process",
137 BooleanValue(false),
140 return tid;
141}
142
144 : m_node(nullptr),
145 m_ifIndex(0),
146 m_sock(-1),
147 m_startEvent(),
148 m_stopEvent(),
149 m_fdReader(nullptr),
150 m_ns3AddressRewritten(false)
151{
152 NS_LOG_FUNCTION(this);
153 m_packetBuffer = new uint8_t[65536];
155}
156
158{
159 NS_LOG_FUNCTION(this);
160
162
163 delete[] m_packetBuffer;
164 m_packetBuffer = nullptr;
165
166 m_bridgedDevice = nullptr;
167}
168
169void
175
176void
178{
179 NS_LOG_FUNCTION(this << tStart);
180
181 //
182 // Cancel any pending start event and schedule a new one at some relative time in the future.
183 //
186}
187
188void
190{
191 NS_LOG_FUNCTION(this << tStop);
192 //
193 // Cancel any pending stop event and schedule a new one at some relative time in the future.
194 //
197}
198
199void
201{
202 NS_LOG_FUNCTION(this);
203
204 NS_ABORT_MSG_IF(m_sock != -1, "TapBridge::StartTapDevice(): Tap is already started");
205
206 //
207 // A similar story exists for the node ID. We can't just naively do a
208 // GetNode ()->GetId () since GetNode is going to give us a Ptr<Node> which
209 // is reference counted. We need to stash away the node ID for use in the
210 // read thread.
211 //
212 m_nodeId = GetNode()->GetId();
213
214 //
215 // Spin up the tap bridge and start receiving packets.
216 //
217 NS_LOG_LOGIC("Creating tap device");
218
219 //
220 // Call out to a separate process running as suid root in order to get the
221 // tap device allocated and set up. We do this to avoid having the entire
222 // simulation running as root. If this method returns, we'll have a socket
223 // waiting for us in m_sock that we can use to talk to the newly created
224 // tap device.
225 //
226 CreateTap();
227
228 // Declare the link up
229 NotifyLinkUp();
230
231 //
232 // Now spin up a read thread to read packets from the tap device.
233 //
234 NS_ABORT_MSG_IF(m_fdReader, "TapBridge::StartTapDevice(): Receive thread is already running");
235 NS_LOG_LOGIC("Spinning up read thread");
236
239}
240
241void
243{
244 NS_LOG_FUNCTION(this);
245
246 if (m_fdReader)
247 {
248 m_fdReader->Stop();
249 m_fdReader = nullptr;
250 }
251
252 if (m_sock != -1)
253 {
254 close(m_sock);
255 m_sock = -1;
256 }
257}
258
259void
261{
262 NS_LOG_FUNCTION(this);
263
264 //
265 // The TapBridge has three distinct operating modes. At this point, the
266 // differences revolve around who is responsible for creating and configuring
267 // the underlying network tap that we use. In ConfigureLocal mode, the
268 // TapBridge has the responsibility for creating and configuring the TAP.
269 //
270 // In UseBridge or UseLocal modes, the user will provide us a configuration
271 // and we have to adapt to it. For example, in UseLocal mode, the user will
272 // be configuring a tap device outside the scope of the ns-3 simulation and
273 // will be expecting us to work with it. The user will do something like:
274 //
275 // sudo ip tuntap add mode tap tap0
276 // sudo ip address add 10.1.1.1/24 dev tap0
277 // sudo ip link set dev tap0 address 00:00:00:00:00:01 up
278 //
279 // The user will then set the "Mode" Attribute of the TapBridge to "UseLocal"
280 // and the "DeviceName" Attribute to "tap0" in this case.
281 //
282 // In ConfigureLocal mode, the user is asking the TapBridge to do the
283 // configuration and create a TAP with the provided "DeviceName" with which
284 // the user can later do what she wants. We need to extract values for the
285 // MAC address, IP address, net mask, etc, from the simulation itself and
286 // use them to initialize corresponding values on the created tap device.
287 //
288 // In UseBridge mode, the user is asking us to use an existing tap device
289 // has been included in an OS bridge. She is asking us to take the simulated
290 // net device and logically add it to the existing bridge. We expect that
291 // the user has done something like:
292 //
293 // sudo ip link add mybridge type bridge
294 // sudo ip tuntap add mode tap mytap
295 // sudo ip link set dev mytap address 00:00:00:00:00:01 up
296 // sudo ip link set dev mytap master mybridge
297 // sudo ip link set dev ... master mybridge
298 // sudo ip address add 10.1.1.1/24 dev mybridge
299 // sudo ip link set dev mybridge up
300 //
301 // The bottom line at this point is that we want to either create or use a
302 // tap device on the host based on the verb part "Use" or "Configure" of the
303 // operating mode. Unfortunately for us you have to have root privileges to
304 // do either. Instead of running the entire simulation as root, we decided
305 // to make a small program who's whole reason for being is to run as suid
306 // root and do what it takes to create the tap. We're just going to pass
307 // off the configuration information to that program and let it deal with
308 // the situation.
309 //
310 // We're going to fork and exec that program soon, but first we need to have
311 // a socket to talk to it with. So we create a local interprocess (Unix)
312 // socket for that purpose.
313 //
314 int sock = socket(PF_UNIX, SOCK_DGRAM, 0);
316 sock == -1,
317 "TapBridge::CreateTap(): Unix socket creation error, errno = " << std::strerror(errno));
318
319 //
320 // Bind to that socket and let the kernel allocate an endpoint
321 //
322 struct sockaddr_un un;
323 memset(&un, 0, sizeof(un));
324 un.sun_family = AF_UNIX;
325 int status = bind(sock, (struct sockaddr*)&un, sizeof(sa_family_t));
326 NS_ABORT_MSG_IF(status == -1,
327 "TapBridge::CreateTap(): Could not bind(): errno = " << std::strerror(errno));
328 NS_LOG_INFO("Created Unix socket");
329 NS_LOG_INFO("sun_family = " << un.sun_family);
330 NS_LOG_INFO("sun_path = " << un.sun_path);
331
332 //
333 // We have a socket here, but we want to get it there -- to the program we're
334 // going to exec. What we'll do is to do a getsockname and then encode the
335 // resulting address information as a string, and then send the string to the
336 // program as an argument. So we need to get the sock name.
337 //
338 socklen_t len = sizeof(un);
339 status = getsockname(sock, (struct sockaddr*)&un, &len);
341 status == -1,
342 "TapBridge::CreateTap(): Could not getsockname(): errno = " << std::strerror(errno));
343
344 //
345 // Now encode that socket name (family and path) as a string of hex digits
346 //
347 std::string path = TapBufferToString((uint8_t*)&un, len);
348 NS_LOG_INFO("Encoded Unix socket as \"" << path << "\"");
349
350 //
351 // Tom Goff reports the possibility of a deadlock when trying to acquire the
352 // python GIL here. He says that this might be due to trying to access Python
353 // objects after fork() without calling PyOS_AfterFork() to properly reset
354 // Python state (including the GIL). Originally these next three lines were
355 // done after the fork, but were moved here to work around the deadlock.
356 //
358 Ptr<Node> n = nd->GetNode();
359 Ptr<Ipv4> ipv4 = n->GetObject<Ipv4>();
360
361 //
362 // Fork and exec the process to create our socket. If we're us (the parent)
363 // we wait for the child (the creator) to complete and read the socket it
364 // created and passed back using the ancillary data mechanism.
365 //
366 pid_t pid = ::fork();
367 if (pid == 0)
368 {
369 NS_LOG_DEBUG("Child process");
370
371 //
372 // build a command line argument from the encoded endpoint string that
373 // the socket creation process will use to figure out how to respond to
374 // the (now) parent process. We're going to have to give this program
375 // quite a bit of information.
376 //
377 // -d<device-name> The name of the tap device we want to create;
378 // -i<IP-address> The IP address to assign to the new tap device;
379 // -m<MAC-address> The MAC-48 address to assign to the new tap device;
380 // -n<network-mask> The network mask to assign to the new tap device;
381 // -o<operating mode> The operating mode of the bridge (1=ConfigureLocal, 2=UseLocal,
382 // 3=UseBridge) -p<path> the path to the unix socket described above.
383 //
384 // Example tap-creator -dnewdev -g1.2.3.2 -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -o1
385 // -pblah
386 //
387 // We want to get as much of this stuff automagically as possible.
388 //
389 // For CONFIGURE_LOCAL mode only:
390 // <IP-address> is the IP address we are going to set in the newly
391 // created Tap device on the Linux host. At the point in the simulation
392 // where devices are coming up, we should have all of our IP addresses
393 // assigned. That means that we can find the IP address to assign to
394 // the new Tap device from the IP address associated with the bridged
395 // net device.
396 //
397
398 bool wantIp = (m_mode == CONFIGURE_LOCAL);
399
400 if (wantIp && (!ipv4) && m_tapIp.IsBroadcast() && m_tapNetmask == Ipv4Mask::GetOnes())
401 {
402 NS_FATAL_ERROR("TapBridge::CreateTap(): Tap device IP configuration requested but "
403 "neither IP address nor IP netmask is provided");
404 }
405
406 // Some stub values to make tap-creator happy
407 Ipv4Address ipv4Address("255.255.255.255");
408 Ipv4Mask ipv4Mask("255.255.255.255");
409
410 if (ipv4)
411 {
412 uint32_t index = ipv4->GetInterfaceForDevice(nd);
413 if (ipv4->GetNAddresses(index) > 1)
414 {
416 "Underlying bridged NetDevice has multiple IP addresses; using first one.");
417 }
418 ipv4Address = ipv4->GetAddress(index, 0).GetLocal();
419
420 //
421 // The net mask is sitting right there next to the ipv4 address.
422 //
423 ipv4Mask = ipv4->GetAddress(index, 0).GetMask();
424 }
425
426 //
427 // The MAC address should also already be assigned and waiting for us in
428 // the bridged net device.
429 //
430 Address address = nd->GetAddress();
431 Mac48Address mac48Address = Mac48Address::ConvertFrom(address);
432
433 //
434 // The device-name is something we may want the system to make up in
435 // every case. We also rely on it being configured via an Attribute
436 // through the helper. By default, it is set to the empty string
437 // which tells the system to make up a device name such as "tap123".
438 //
439 std::ostringstream ossDeviceName;
440 ossDeviceName << "-d" << m_tapDeviceName;
441
442 //
443 // For flexibility, we do allow a client to override any of the values
444 // above via attributes, so only use our found values if the Attribute
445 // is not equal to its default value (empty string or broadcast address).
446 //
447 std::ostringstream ossIp;
448 if (m_tapIp.IsBroadcast())
449 {
450 ossIp << "-i" << ipv4Address;
451 }
452 else
453 {
454 ossIp << "-i" << m_tapIp;
455 }
456
457 std::ostringstream ossMac;
458 if (m_tapMac.IsBroadcast())
459 {
460 ossMac << "-m" << mac48Address;
461 }
462 else
463 {
464 ossMac << "-m" << m_tapMac;
465 }
466
467 std::ostringstream ossNetmask;
469 {
470 ossNetmask << "-n" << ipv4Mask;
471 }
472 else
473 {
474 ossNetmask << "-n" << m_tapNetmask;
475 }
476
477 std::ostringstream ossMode;
478 ossMode << "-o";
479 if (m_mode == CONFIGURE_LOCAL)
480 {
481 ossMode << "1";
482 }
483 else if (m_mode == USE_LOCAL)
484 {
485 ossMode << "2";
486 }
487 else
488 {
489 ossMode << "3";
490 }
491
492 std::ostringstream ossVerbose;
493 if (m_verbose)
494 {
495 ossVerbose << "-v";
496 }
497
498 std::ostringstream ossPath;
499 ossPath << "-p" << path;
500
501 NS_LOG_DEBUG("Executing: " << TAP_CREATOR << " " << ossDeviceName.str() << " "
502 << ossIp.str() << " " << ossMac.str() << " " << ossNetmask.str()
503 << " " << ossMode.str() << " " << ossPath.str() << " "
504 << ossVerbose.str());
505
506 //
507 // Execute the socket creation process image.
508 //
509 status = ::execlp(TAP_CREATOR,
510 TAP_CREATOR, // argv[0] (filename)
511 ossDeviceName.str().c_str(), // argv[1] (-d<device name>)
512 ossIp.str().c_str(), // argv[2] (-i<IP address>)
513 ossMac.str().c_str(), // argv[3] (-m<MAC address>)
514 ossNetmask.str().c_str(), // argv[4] (-n<net mask>)
515 ossMode.str().c_str(), // argv[5] (-o<operating mode>)
516 ossPath.str().c_str(), // argv[6] (-p<path>)
517 ossVerbose.str().c_str(), // argv[7] (-v)
518 (char*)nullptr);
519
520 //
521 // If the execlp successfully completes, it never returns. If it returns it failed or the
522 // OS is broken. In either case, we bail.
523 //
524 NS_FATAL_ERROR("TapBridge::CreateTap(): Back from execlp(), status = "
525 << status << " errno = " << ::strerror(errno));
526 }
527 else
528 {
529 NS_LOG_DEBUG("Parent process");
530 //
531 // We're the process running the emu net device. We need to wait for the
532 // socket creator process to finish its job.
533 //
534 int st;
535 pid_t waited = waitpid(pid, &st, 0);
537 waited == -1,
538 "TapBridge::CreateTap(): waitpid() fails, errno = " << std::strerror(errno));
539 NS_ASSERT_MSG(pid == waited, "TapBridge::CreateTap(): pid mismatch");
540
541 //
542 // Check to see if the socket creator exited normally and then take a
543 // look at the exit code. If it bailed, so should we. If it didn't
544 // even exit normally, we bail too.
545 //
546 if (WIFEXITED(st))
547 {
548 int exitStatus = WEXITSTATUS(st);
549 NS_ABORT_MSG_IF(exitStatus != 0,
550 "TapBridge::CreateTap(): socket creator exited normally with status "
551 << exitStatus);
552 }
553 else if (WIFSIGNALED(st))
554 {
555 NS_FATAL_ERROR("TapBridge::CreateTap(): socket creator exited with signal "
556 << WTERMSIG(st));
557 }
558 else
559 {
560 NS_FATAL_ERROR("TapBridge::CreateTap(): socket creator exited abnormally");
561 }
562
563 //
564 // At this point, the socket creator has run successfully and should
565 // have created our tap device, initialized it with the information we
566 // passed and sent it back to the socket address we provided. A socket
567 // (fd) we can use to talk to this tap device should be waiting on the
568 // Unix socket we set up to receive information back from the creator
569 // program. We've got to do a bunch of grunt work to get at it, though.
570 //
571 // The struct iovec below is part of a scatter-gather list. It describes a
572 // buffer. In this case, it describes a buffer (an integer) that will
573 // get the data that comes back from the socket creator process. It will
574 // be a magic number that we use as a consistency/sanity check.
575 //
576 struct iovec iov;
577 uint32_t magic;
578 iov.iov_base = &magic;
579 iov.iov_len = sizeof(magic);
580
581 //
582 // The CMSG macros you'll see below are used to create and access control
583 // messages (which is another name for ancillary data). The ancillary
584 // data is made up of pairs of struct cmsghdr structures and associated
585 // data arrays.
586 //
587 // First, we're going to allocate a buffer on the stack to receive our
588 // data array (that contains the socket). Sometimes you'll see this called
589 // an "ancillary element" but the msghdr uses the control message termimology
590 // so we call it "control."
591 //
592 constexpr size_t msg_size = sizeof(int);
593 char control[CMSG_SPACE(msg_size)];
594
595 //
596 // There is a msghdr that is used to minimize the number of parameters
597 // passed to recvmsg (which we will use to receive our ancillary data).
598 // This structure uses terminology corresponding to control messages, so
599 // you'll see msg_control, which is the pointer to the ancillary data and
600 // controllen which is the size of the ancillary data array.
601 //
602 // So, initialize the message header that describes the ancillary/control
603 // data we expect to receive and point it to buffer.
604 //
605 struct msghdr msg;
606 msg.msg_name = nullptr;
607 msg.msg_namelen = 0;
608 msg.msg_iov = &iov;
609 msg.msg_iovlen = 1;
610 msg.msg_control = control;
611 msg.msg_controllen = sizeof(control);
612 msg.msg_flags = 0;
613
614 //
615 // Now we can actually receive the interesting bits from the tap
616 // creator process. Lots of pain to get four bytes.
617 //
618 ssize_t bytesRead = recvmsg(sock, &msg, 0);
619 NS_ABORT_MSG_IF(bytesRead != sizeof(int),
620 "TapBridge::CreateTap(): Wrong byte count from socket creator");
621
622 //
623 // There may be a number of message headers/ancillary data arrays coming in.
624 // Let's look for the one with a type SCM_RIGHTS which indicates it's the
625 // one we're interested in.
626 //
627 struct cmsghdr* cmsg;
628 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg))
629 {
630 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
631 {
632 //
633 // This is the type of message we want. Check to see if the magic
634 // number is correct and then pull out the socket we care about if
635 // it matches
636 //
637 if (magic == TAP_MAGIC)
638 {
639 NS_LOG_INFO("Got SCM_RIGHTS with correct magic " << magic);
640 int* rawSocket = (int*)CMSG_DATA(cmsg);
641 NS_LOG_INFO("Got the socket from the socket creator = " << *rawSocket);
642 m_sock = *rawSocket;
643 break;
644 }
645 else
646 {
647 NS_LOG_INFO("Got SCM_RIGHTS, but with bad magic " << magic);
648 }
649 }
650 }
651 if (cmsg == nullptr)
652 {
653 NS_FATAL_ERROR("Did not get the raw socket from the socket creator");
654 }
655
656 if (m_mode == USE_BRIDGE)
657 {
658 //
659 // Set the ns-3 device's mac address to the overlying container's
660 // mac address
661 //
662 struct ifreq s;
663 memset(&s, 0, sizeof(struct ifreq));
664 strncpy(s.ifr_name, m_tapDeviceName.c_str(), IFNAMSIZ - 1);
665
666 NS_LOG_INFO("Trying to get MacAddr of " << m_tapDeviceName);
667 int ioctlResult = ioctl(sock, SIOCGIFHWADDR, &s);
668 if (ioctlResult == 0)
669 {
670 Mac48Address learnedMac;
671 learnedMac.CopyFrom((uint8_t*)s.ifr_hwaddr.sa_data);
672 NS_LOG_INFO("Learned Tap device MacAddr is "
673 << learnedMac << ": setting ns-3 device to use this address");
674 m_bridgedDevice->SetAddress(learnedMac);
676 }
677
679 {
680 NS_LOG_INFO("Cannot get MacAddr of Tap device: "
682 << " while in USE_LOCAL/USE_BRIDGE mode: " << std::strerror(errno));
683 NS_LOG_INFO("Underlying ns-3 device will continue to use default address, what can "
684 "lead to connectivity errors");
685 }
686 }
687 }
688
689 close(sock);
690}
691
692void
693TapBridge::ReadCallback(uint8_t* buf, ssize_t len)
694{
695 NS_LOG_FUNCTION(this << buf << len);
696
697 NS_ASSERT_MSG(buf != nullptr, "invalid buf argument");
698 NS_ASSERT_MSG(len > 0, "invalid len argument");
699
700 //
701 // It's important to remember that we're in a completely different thread
702 // than the simulator is running in. We need to synchronize with that
703 // other thread to get the packet up into ns-3. What we will need to do
704 // is to schedule a method to deal with the packet using the multithreaded
705 // simulator we are most certainly running. However, I just said it -- we
706 // are talking about two threads here, so it is very, very dangerous to do
707 // any kind of reference counting on a shared object. Just don't do it.
708 // So what we're going to do is pass the buffer allocated on the heap
709 // into the ns-3 context thread where it will create the packet.
710 //
711
712 NS_LOG_INFO("TapBridge::ReadCallback(): Received packet on node " << m_nodeId);
713 NS_LOG_INFO("TapBridge::ReadCallback(): Scheduling handler");
715 Seconds(0),
717}
718
719void
720TapBridge::ForwardToBridgedDevice(uint8_t* buf, ssize_t len)
721{
722 NS_LOG_FUNCTION(this << buf << len);
723
724 //
725 // There are three operating modes for the TapBridge
726 //
727 // CONFIGURE_LOCAL means that ns-3 will create and configure a tap device
728 // and we are expected to use it. The tap device and the ns-3 net device
729 // will have the same MAC address by definition. Thus Send and SendFrom
730 // are equivalent in this case. We use Send to allow all ns-3 devices to
731 // participate in this mode.
732 //
733 // USE_LOCAL mode tells us that we have got to USE a pre-created tap device
734 // that will have a different MAC address from the ns-3 net device. We
735 // also enforce the requirement that there will only be one MAC address
736 // bridged on the Linux side so we can use Send (instead of SendFrom) in
737 // the linux to ns-3 direction. Again, all ns-3 devices can participate
738 // in this mode.
739 //
740 // USE_BRIDGE mode tells us that we are logically extending a Linux bridge
741 // on which lies our tap device. In this case there may be many linux
742 // net devices on the other side of the bridge and so we must use SendFrom
743 // to preserve the possibly many source addresses. Thus, ns-3 devices
744 // must support SendFrom in order to be considered for USE_BRIDGE mode.
745 //
746
747 //
748 // First, create a packet out of the byte buffer we received and free that
749 // buffer.
750 //
751 Ptr<Packet> packet = Create<Packet>(reinterpret_cast<const uint8_t*>(buf), len);
752 std::free(buf);
753 buf = nullptr;
754
755 //
756 // Make sure the packet we received is reasonable enough for the rest of the
757 // system to handle and get it ready to be injected directly into an ns-3
758 // device. What should come back is a packet with the Ethernet header
759 // (and possibly an LLC header as well) stripped off.
760 //
761 Address src;
762 Address dst;
763 uint16_t type;
764
765 NS_LOG_LOGIC("Received packet from tap device");
766
767 Ptr<Packet> p = Filter(packet, &src, &dst, &type);
768 if (!p)
769 {
771 "TapBridge::ForwardToBridgedDevice: Discarding packet as unfit for ns-3 consumption");
772 return;
773 }
774
775 NS_LOG_LOGIC("Pkt source is " << src);
776 NS_LOG_LOGIC("Pkt destination is " << dst);
777 NS_LOG_LOGIC("Pkt LengthType is " << type);
778 if (m_mode == USE_LOCAL)
779 {
780 //
781 // Packets we are going to forward should not be from a broadcast src
782 //
784 "TapBridge::ForwardToBridgedDevice: Source addr is broadcast");
786 {
787 //
788 // Set the ns-3 device's mac address to the overlying container's
789 // mac address
790 //
791 Mac48Address learnedMac = Mac48Address::ConvertFrom(src);
792 NS_LOG_LOGIC("Learned MacAddr is " << learnedMac
793 << ": setting ns-3 device to use this address");
794 m_bridgedDevice->SetAddress(Mac48Address::ConvertFrom(learnedMac));
796 }
797 //
798 // If we are operating in USE_LOCAL mode, we may be attached to an ns-3
799 // device that does not support bridging (SupportsSendFrom returns false).
800 // But, since the mac addresses are now aligned, we can call Send()
801 //
802 NS_LOG_LOGIC("Forwarding packet to ns-3 device via Send()");
803 m_bridgedDevice->Send(packet, dst, type);
804 return;
805 }
806
807 //
808 // If we are operating in USE_BRIDGE mode, we have the
809 // situation described below:
810 //
811 // Other Device <-bridge-> Tap Device <-bridge-> ns3 device
812 // Mac Addr A Mac Addr B Mac Addr C
813 //
814 // In Linux, "Other Device" and "Tap Device" are bridged together. By this
815 // we mean that a user has sone something in Linux like:
816 //
817 // ip link add mybridge type bridge
818 // ip link set dev other-device master mybridge
819 // ip link set dev tap-device master mybridge
820 //
821 // In USE_BRIDGE mode, we want to logically extend this Linux behavior to the
822 // simulated ns3 device and make it appear as if it is connected to the Linux
823 // subnet. As you may expect, this means that we need to act like a real
824 // Linux bridge and take all packets that come from "Tap Device" and ask
825 // "ns3 Device" to send them down its directly connected network. Just like
826 // in a normal everyday bridge we need to call SendFrom in order to preserve
827 // the original packet's from address.
828 //
829 // If we are operating in CONFIGURE_LOCAL mode, we simply simply take all packets
830 // that come from "Tap Device" and ask "ns3 Device" to send them down its
831 // directly connected network. A normal bridge would need to call SendFrom
832 // in order to preserve the original from address, but in CONFIGURE_LOCAL mode
833 // the tap device and the ns-3 device have the same MAC address by definition so
834 // we can call Send.
835 //
836 NS_LOG_LOGIC("Forwarding packet");
837
838 if (m_mode == USE_BRIDGE)
839 {
840 m_bridgedDevice->SendFrom(packet, src, dst, type);
841 }
842 else
843 {
845 "TapBridge::ForwardToBridgedDevice(): Internal error");
846 m_bridgedDevice->Send(packet, dst, type);
847 }
848}
849
851TapBridge::Filter(Ptr<Packet> p, Address* src, Address* dst, uint16_t* type)
852{
853 NS_LOG_FUNCTION(this << p);
855
856 //
857 // We have a candidate packet for injection into ns-3. We expect that since
858 // it came over a socket that provides Ethernet packets, it should be big
859 // enough to hold an EthernetHeader. If it can't, we signify the packet
860 // should be filtered out by returning 0.
861 //
862 pktSize = p->GetSize();
863 EthernetHeader header(false);
864 if (pktSize < header.GetSerializedSize())
865 {
866 return nullptr;
867 }
868
869 uint32_t headerSize = p->PeekHeader(header);
870 p->RemoveAtStart(headerSize);
871
872 NS_LOG_LOGIC("Pkt source is " << header.GetSource());
873 NS_LOG_LOGIC("Pkt destination is " << header.GetDestination());
874 NS_LOG_LOGIC("Pkt LengthType is " << header.GetLengthType());
875
876 //
877 // If the length/type is less than 1500, it corresponds to a length
878 // interpretation packet. In this case, it is an 802.3 packet and
879 // will also have an 802.2 LLC header. If greater than 1500, we
880 // find the protocol number (Ethernet type) directly.
881 //
882 if (header.GetLengthType() <= 1500)
883 {
884 *src = header.GetSource();
885 *dst = header.GetDestination();
886
887 pktSize = p->GetSize();
888 LlcSnapHeader llc;
889 if (pktSize < llc.GetSerializedSize())
890 {
891 return nullptr;
892 }
893
894 p->RemoveHeader(llc);
895 *type = llc.GetType();
896 }
897 else
898 {
899 *src = header.GetSource();
900 *dst = header.GetDestination();
901 *type = header.GetLengthType();
902 }
903
904 //
905 // What we give back is a packet without the Ethernet header (nor the
906 // possible llc/snap header) on it. We think it is ready to send on
907 // out the bridged net device.
908 //
909 return p;
910}
911
918
919void
921{
922 NS_LOG_FUNCTION(this << bridgedDevice);
923
924 NS_ASSERT_MSG(m_node, "TapBridge::SetBridgedDevice: Bridge not installed in a node");
925 NS_ASSERT_MSG(bridgedDevice != this, "TapBridge::SetBridgedDevice: Cannot bridge to self");
926 NS_ASSERT_MSG(!m_bridgedDevice, "TapBridge::SetBridgedDevice: Already bridged");
927
928 if (!Mac48Address::IsMatchingType(bridgedDevice->GetAddress()))
929 {
930 NS_FATAL_ERROR("TapBridge::SetBridgedDevice: Device does not support eui 48 addresses: "
931 "cannot be added to bridge.");
932 }
933
934 if (m_mode == USE_BRIDGE && !bridgedDevice->SupportsSendFrom())
935 {
936 NS_FATAL_ERROR("TapBridge::SetBridgedDevice: Device does not support SendFrom: cannot be "
937 "added to bridge.");
938 }
939
940 //
941 // We need to disconnect the bridged device from the internet stack on our
942 // node to ensure that only one stack responds to packets inbound over the
943 // bridged device. That one stack lives outside ns-3 so we just blatantly
944 // steal the device callbacks.
945 //
946 // N.B This can be undone if someone does a RegisterProtocolHandler later
947 // on this node.
948 //
949 bridgedDevice->SetReceiveCallback(MakeCallback(&TapBridge::DiscardFromBridgedDevice, this));
950 bridgedDevice->SetPromiscReceiveCallback(
952 m_bridgedDevice = bridgedDevice;
953}
954
955bool
957 Ptr<const Packet> packet,
958 uint16_t protocol,
959 const Address& src)
960{
961 NS_LOG_FUNCTION(this << device << packet << protocol << src);
962 NS_LOG_LOGIC("Discarding packet stolen from bridged device " << device);
963 return true;
964}
965
966bool
968 Ptr<const Packet> packet,
969 uint16_t protocol,
970 const Address& src,
971 const Address& dst,
972 PacketType packetType)
973{
974 NS_LOG_FUNCTION(this << device << packet << protocol << src << dst << packetType);
976 "TapBridge::SetBridgedDevice: Received packet from unexpected device");
977 NS_LOG_DEBUG("Packet UID is " << packet->GetUid());
978
979 //
980 // There are three operating modes for the TapBridge
981 //
982 // CONFIGURE_LOCAL means that ns-3 will create and configure a tap device
983 // and we are expected to use it. The tap device and the ns-3 net device
984 // will have the same MAC address by definition.
985 //
986 // USE_LOCAL mode tells us that we have got to USE a pre-created tap device
987 // that will have a different MAC address from the ns-3 net device. In this
988 // case we will be spoofing the MAC address of a received packet to match
989 // the single allowed address on the Linux side.
990 //
991 // USE_BRIDGE mode tells us that we are logically extending a Linux bridge
992 // on which lies our tap device.
993 //
994
995 if (m_mode == CONFIGURE_LOCAL && packetType == PACKET_OTHERHOST)
996 {
997 //
998 // We hooked the promiscuous mode protocol handler so we could get the
999 // destination address of the actual packet. This means we will be
1000 // getting PACKET_OTHERHOST packets (not broadcast, not multicast, not
1001 // unicast to the ns-3 net device, but to some other address). In
1002 // CONFIGURE_LOCAL mode we are not interested in these packets since they
1003 // don't refer to the single MAC address shared by the ns-3 device and
1004 // the TAP device. If, however, we are in USE_LOCAL or USE_BRIDGE mode,
1005 // we want to act like a bridge and forward these PACKET_OTHERHOST
1006 // packets.
1007 //
1008 return true;
1009 }
1010
1013
1014 Ptr<Packet> p = packet->Copy();
1015 EthernetHeader header = EthernetHeader(false);
1016 header.SetSource(from);
1017 header.SetDestination(to);
1018
1019 header.SetLengthType(protocol);
1020 p->AddHeader(header);
1021
1022 NS_LOG_LOGIC("Writing packet to Linux host");
1023 NS_LOG_LOGIC("Pkt source is " << header.GetSource());
1024 NS_LOG_LOGIC("Pkt destination is " << header.GetDestination());
1025 NS_LOG_LOGIC("Pkt LengthType is " << header.GetLengthType());
1026 NS_LOG_LOGIC("Pkt size is " << p->GetSize());
1027
1028 NS_ASSERT_MSG(p->GetSize() <= 65536,
1029 "TapBridge::ReceiveFromBridgedDevice: Packet too big " << p->GetSize());
1030 p->CopyData(m_packetBuffer, p->GetSize());
1031
1032 uint32_t bytesWritten = write(m_sock, m_packetBuffer, p->GetSize());
1033 NS_ABORT_MSG_IF(bytesWritten != p->GetSize(),
1034 "TapBridge::ReceiveFromBridgedDevice(): Write error.");
1035
1036 NS_LOG_LOGIC("End of receive packet handling on node " << m_node->GetId());
1037 return true;
1038}
1039
1040void
1042{
1043 NS_LOG_FUNCTION(this << index);
1044 m_ifIndex = index;
1045}
1046
1049{
1050 NS_LOG_FUNCTION(this);
1051 return m_ifIndex;
1052}
1053
1056{
1057 NS_LOG_FUNCTION(this);
1058 return nullptr;
1059}
1060
1061void
1063{
1064 NS_LOG_FUNCTION(this << address);
1066}
1067
1068Address
1070{
1071 NS_LOG_FUNCTION(this);
1072 return m_address;
1073}
1074
1075void
1077{
1078 NS_LOG_FUNCTION(this << mode);
1079 m_mode = mode;
1080}
1081
1084{
1085 NS_LOG_FUNCTION(this);
1086 return m_mode;
1087}
1088
1089bool
1090TapBridge::SetMtu(const uint16_t mtu)
1091{
1092 NS_LOG_FUNCTION(this << mtu);
1093 m_mtu = mtu;
1094 return true;
1095}
1096
1097uint16_t
1099{
1100 NS_LOG_FUNCTION(this);
1101 return m_mtu;
1102}
1103
1104void
1106{
1107 NS_LOG_FUNCTION(this);
1108 if (!m_linkUp)
1109 {
1110 m_linkUp = true;
1112 }
1113}
1114
1115bool
1117{
1118 NS_LOG_FUNCTION(this);
1119 return m_linkUp;
1120}
1121
1122void
1128
1129bool
1131{
1132 NS_LOG_FUNCTION(this);
1133 return true;
1134}
1135
1136Address
1138{
1139 NS_LOG_FUNCTION(this);
1141}
1142
1143bool
1145{
1146 NS_LOG_FUNCTION(this);
1147 return true;
1148}
1149
1150Address
1152{
1153 NS_LOG_FUNCTION(this << multicastGroup);
1154 Mac48Address multicast = Mac48Address::GetMulticast(multicastGroup);
1155 return multicast;
1156}
1157
1158bool
1160{
1161 NS_LOG_FUNCTION(this);
1162 return false;
1163}
1164
1165bool
1167{
1168 NS_LOG_FUNCTION(this);
1169 //
1170 // Returning false from IsBridge in a device called TapBridge may seem odd
1171 // at first glance, but this test is for a device that bridges ns-3 devices
1172 // together. The Tap bridge doesn't do that -- it bridges an ns-3 device to
1173 // a Linux device. This is a completely different story.
1174 //
1175 return false;
1176}
1177
1178bool
1179TapBridge::Send(Ptr<Packet> packet, const Address& dst, uint16_t protocol)
1180{
1181 NS_LOG_FUNCTION(this << packet << dst << protocol);
1182 NS_FATAL_ERROR("TapBridge::Send: You may not call Send on a TapBridge directly");
1183 return false;
1184}
1185
1186bool
1187TapBridge::SendFrom(Ptr<Packet> packet, const Address& src, const Address& dst, uint16_t protocol)
1188{
1189 NS_LOG_FUNCTION(this << packet << src << dst << protocol);
1190 NS_FATAL_ERROR("TapBridge::Send: You may not call SendFrom on a TapBridge directly");
1191 return false;
1192}
1193
1196{
1197 NS_LOG_FUNCTION(this);
1198 return m_node;
1199}
1200
1201void
1203{
1204 NS_LOG_FUNCTION(this);
1205 m_node = node;
1206}
1207
1208bool
1210{
1211 NS_LOG_FUNCTION(this);
1212 return true;
1213}
1214
1215void
1221
1222void
1228
1229bool
1231{
1232 NS_LOG_FUNCTION(this);
1233 return true;
1234}
1235
1236Address
1238{
1239 NS_LOG_FUNCTION(this << addr);
1240 return Mac48Address::GetMulticast(addr);
1241}
1242
1243} // namespace ns3
a polymophic address class
Definition address.h:90
AttributeValue implementation for Boolean.
Definition boolean.h:26
Callback template class.
Definition callback.h:422
Hold variables of type enum.
Definition enum.h:52
Packet header for Ethernet.
uint16_t GetLengthType() const
uint32_t GetSerializedSize() const override
void SetDestination(Mac48Address destination)
Mac48Address GetDestination() const
void SetLengthType(uint16_t size)
void SetSource(Mac48Address source)
Mac48Address GetSource() const
int m_fd
The file descriptor to read from.
Definition fd-reader.h:124
Ipv4 addresses are stored in host order in this class.
bool IsBroadcast() const
AttributeValue implementation for Ipv4Address.
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition ipv4.h:69
a class to represent an Ipv4 address mask
static Ipv4Mask GetOnes()
AttributeValue implementation for Ipv4Mask.
Describes an IPv6 address.
Header for the LLC/SNAP encapsulation.
uint16_t GetType()
Return the Ethertype.
uint32_t GetSerializedSize() const override
an EUI-48 address
static Mac48Address GetMulticast(Ipv4Address address)
static bool IsMatchingType(const Address &address)
void CopyFrom(const uint8_t buffer[6])
static Mac48Address ConvertFrom(const Address &address)
static Mac48Address GetBroadcast()
bool IsBroadcast() const
AttributeValue implementation for Mac48Address.
Network layer to device interface.
Definition net-device.h:87
PacketType
Packet types are used as they are in Linux.
Definition net-device.h:289
@ PACKET_OTHERHOST
Packet addressed to someone else.
Definition net-device.h:296
uint32_t GetId() const
Definition node.cc:106
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
Smart pointer class similar to boost::intrusive_ptr.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:561
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:274
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Definition simulator.h:578
Hold variables of type string.
Definition string.h:45
FdReader::Data DoRead() override
The read implementation.
Definition tap-bridge.cc:44
A bridge to make it appear that a real host process is connected to an ns-3 net device.
Definition tap-bridge.h:98
void SetBridgedNetDevice(Ptr< NetDevice > bridgedDevice)
Set the ns-3 net device to bridge.
bool ReceiveFromBridgedDevice(Ptr< NetDevice > device, Ptr< const Packet > packet, uint16_t protocol, const Address &src, const Address &dst, PacketType packetType)
Receives a packet from a bridged Device.
void CreateTap()
Call out to a separate process running as suid root in order to get our tap device created.
void SetIfIndex(const uint32_t index) override
uint32_t m_nodeId
a copy of the node id so the read thread doesn't have to GetNode() in in order to find the node ID.
Definition tap-bridge.h:444
static TypeId GetTypeId()
Get the type ID.
Definition tap-bridge.cc:70
bool m_ns3AddressRewritten
Whether the MAC address of the underlying ns-3 device has already been rewritten is stored in this va...
Definition tap-bridge.h:432
void AddLinkChangeCallback(Callback< void > callback) override
uint8_t * m_packetBuffer
A 64K buffer to hold packet data while it is being sent.
Definition tap-bridge.h:437
bool m_linkUp
Flag indicating whether or not the link is up.
Definition tap-bridge.h:451
Address GetAddress() const override
TracedCallback m_linkChangeCallbacks
Callbacks to fire if the link changes state (up or down).
Definition tap-bridge.h:463
void SetMode(TapBridge::Mode mode)
Set the operating mode of this device.
NetDevice::PromiscReceiveCallback m_promiscRxCallback
Callback used to hook the promiscuous packet receive callback of the TapBridge ns-3 net device.
Definition tap-bridge.h:330
~TapBridge() override
void SetReceiveCallback(NetDevice::ReceiveCallback cb) override
bool SendFrom(Ptr< Packet > packet, const Address &source, const Address &dest, uint16_t protocolNumber) override
int m_sock
The socket (actually interpreted as fd) to use to talk to the Tap device on the real internet host.
Definition tap-bridge.h:351
void StopTapDevice()
Tear down the device.
Address GetBroadcast() const override
uint32_t m_ifIndex
The ns-3 interface index of this TapBridge net device.
Definition tap-bridge.h:340
bool DiscardFromBridgedDevice(Ptr< NetDevice > device, Ptr< const Packet > packet, uint16_t protocol, const Address &src)
Receives a packet from a bridged Device.
bool NeedsArp() const override
void SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb) override
NetDevice::ReceiveCallback m_rxCallback
Callback used to hook the standard packet receive callback of the TapBridge ns-3 net device.
Definition tap-bridge.h:319
Mac48Address m_address
The (unused) MAC address of the TapBridge net device.
Definition tap-bridge.h:383
void Start(Time tStart)
Set a start time for the device.
bool SetMtu(const uint16_t mtu) override
bool IsLinkUp() const override
bool IsPointToPoint() const override
Return true if the net device is on a point-to-point link.
bool IsBridge() const override
Return true if the net device is acting as a bridge.
Ptr< TapBridgeFdReader > m_fdReader
Includes the ns-3 read thread used to do blocking reads on the fd corresponding to the host device.
Definition tap-bridge.h:369
uint16_t m_mtu
The common mtu to use for the net devices.
Definition tap-bridge.h:345
void ReadCallback(uint8_t *buf, ssize_t len)
Callback to process packets that are read.
Ipv4Address m_tapIp
The IP address to use as the device IP on the host.
Definition tap-bridge.h:409
Ipv4Mask m_tapNetmask
The network mask to assign to the device created on the host.
Definition tap-bridge.h:422
bool m_verbose
Flag indicating whether or not the link is up.
Definition tap-bridge.h:458
bool SupportsSendFrom() const override
void StartTapDevice()
Spin up the device.
Ptr< Packet > Filter(Ptr< Packet > packet, Address *src, Address *dst, uint16_t *type)
The host we are bridged to is in the evil real world.
Mode m_mode
The operating mode of the bridge.
Definition tap-bridge.h:375
Ptr< Node > m_node
Pointer to the (ghost) Node to which we are connected.
Definition tap-bridge.h:335
EventId m_stopEvent
The ID of the ns-3 event used to schedule the tear down of the underlying host Tap device and ns-3 re...
Definition tap-bridge.h:363
void ForwardToBridgedDevice(uint8_t *buf, ssize_t len)
Forward a packet received from the tap device to the bridged ns-3 device.
void Stop(Time tStop)
Set a stop time for the device.
void NotifyLinkUp()
Notifies that the link is up and ready.
Ptr< NetDevice > m_bridgedDevice
The ns-3 net device to which we are bridging.
Definition tap-bridge.h:427
bool IsBroadcast() const override
Mode
Enumeration of the operating modes supported in the class.
Definition tap-bridge.h:111
@ USE_BRIDGE
ns-3 uses a pre-created tap, and bridges to a bridging net device
Definition tap-bridge.h:115
@ USE_LOCAL
ns-3 uses a pre-created tap, without configuring it
Definition tap-bridge.h:114
@ CONFIGURE_LOCAL
ns-3 creates and configures tap device
Definition tap-bridge.h:113
void SetAddress(Address address) override
Set the address of this interface.
Ptr< Node > GetNode() const override
EventId m_startEvent
The ID of the ns-3 event used to schedule the start up of the underlying host Tap device and ns-3 rea...
Definition tap-bridge.h:357
bool IsMulticast() const override
Time m_tStart
Time to start spinning up the device.
Definition tap-bridge.h:388
Ipv4Address m_tapGateway
The IP address to use as the device default gateway on the host.
Definition tap-bridge.h:404
TapBridge::Mode GetMode()
Get the operating mode of this device.
Ptr< NetDevice > GetBridgedNetDevice()
Get the bridged net device.
Time m_tStop
Time to start tearing down the device.
Definition tap-bridge.h:393
void SetNode(Ptr< Node > node) override
std::string m_tapDeviceName
The name of the device to create on the host.
Definition tap-bridge.h:399
Address GetMulticast(Ipv4Address multicastGroup) const override
Make and return a MAC multicast address using the provided multicast group.
void DoDispose() override
Call out to a separate process running as suid root in order to get our tap device created.
uint16_t GetMtu() const override
bool Send(Ptr< Packet > packet, const Address &dest, uint16_t protocolNumber) override
Ptr< Channel > GetChannel() const override
uint32_t GetIfIndex() const override
Mac48Address m_tapMac
The MAC address to use as the hardware address on the host; only used in UseLocal mode.
Definition tap-bridge.h:417
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
AttributeValue implementation for Time.
Definition nstime.h:1432
void ConnectWithoutContext(const CallbackBase &callback)
Append a Callback to the chain (without a context).
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
@ OBSOLETE
Attribute or trace source is not used anymore; simulation fails.
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition enum.h:221
Ptr< const AttributeAccessor > MakeIpv4AddressAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeIpv4AddressChecker()
Ptr< const AttributeAccessor > MakeIpv4MaskAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeIpv4MaskChecker()
Ptr< const AttributeAccessor > MakeMac48AddressAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeMac48AddressChecker()
Ptr< const AttributeChecker > MakeStringChecker()
Definition string.cc:19
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition string.h:46
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1433
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1453
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
std::enable_if_t< std::is_member_pointer_v< MEM >, EventImpl * > MakeEvent(MEM mem_ptr, OBJ obj, Ts... args)
Make an EventImpl from class method members which take varying numbers of arguments.
Definition make-event.h:133
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition log.h:250
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1345
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition callback.h:684
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition enum.h:179
std::string TapBufferToString(uint8_t *buffer, uint32_t len)
Convert a byte buffer to a string containing a hex representation of the buffer.
A structure representing data read.
Definition fd-reader.h:80
#define TAP_MAGIC
uint32_t pktSize
packet size used for the simulation (in bytes)