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"),
93 .AddAttribute(
94 "IpAddress",
95 "The IP address to assign to the tap device, when in ConfigureLocal mode. "
96 "This address will override the discovered IP address of the simulated device.",
97 Ipv4AddressValue("255.255.255.255"),
100 .AddAttribute(
101 "MacAddress",
102 "The MAC address to assign to the tap device, when in ConfigureLocal mode. "
103 "This address will override the discovered MAC address of the simulated device.",
104 Mac48AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")),
107 .AddAttribute(
108 "Netmask",
109 "The network mask to assign to the tap device, when in ConfigureLocal mode. "
110 "This address will override the discovered MAC address of the simulated device.",
111 Ipv4MaskValue("255.255.255.255"),
114 .AddAttribute("Start",
115 "The simulation time at which to spin up the tap device read thread.",
116 TimeValue(Seconds(0.)),
119 .AddAttribute("Stop",
120 "The simulation time at which to tear down the tap device read thread.",
121 TimeValue(Seconds(0.)),
124 .AddAttribute("Mode",
125 "The operating and configuration mode to use.",
129 "ConfigureLocal",
130 USE_LOCAL,
131 "UseLocal",
133 "UseBridge"))
134 .AddAttribute("Verbose",
135 "Enable verbose output from tap-creator child process",
136 BooleanValue(false),
139 return tid;
140}
141
143 : m_node(nullptr),
144 m_ifIndex(0),
145 m_sock(-1),
146 m_startEvent(),
147 m_stopEvent(),
148 m_fdReader(nullptr),
149 m_ns3AddressRewritten(false)
150{
151 NS_LOG_FUNCTION(this);
152 m_packetBuffer = new uint8_t[65536];
154}
155
157{
158 NS_LOG_FUNCTION(this);
159
161
162 delete[] m_packetBuffer;
163 m_packetBuffer = nullptr;
164
165 m_bridgedDevice = nullptr;
166}
167
168void
174
175void
177{
178 NS_LOG_FUNCTION(this << tStart);
179
180 //
181 // Cancel any pending start event and schedule a new one at some relative time in the future.
182 //
185}
186
187void
189{
190 NS_LOG_FUNCTION(this << tStop);
191 //
192 // Cancel any pending stop event and schedule a new one at some relative time in the future.
193 //
196}
197
198void
200{
201 NS_LOG_FUNCTION(this);
202
203 NS_ABORT_MSG_IF(m_sock != -1, "TapBridge::StartTapDevice(): Tap is already started");
204
205 //
206 // A similar story exists for the node ID. We can't just naively do a
207 // GetNode ()->GetId () since GetNode is going to give us a Ptr<Node> which
208 // is reference counted. We need to stash away the node ID for use in the
209 // read thread.
210 //
211 m_nodeId = GetNode()->GetId();
212
213 //
214 // Spin up the tap bridge and start receiving packets.
215 //
216 NS_LOG_LOGIC("Creating tap device");
217
218 //
219 // Call out to a separate process running as suid root in order to get the
220 // tap device allocated and set up. We do this to avoid having the entire
221 // simulation running as root. If this method returns, we'll have a socket
222 // waiting for us in m_sock that we can use to talk to the newly created
223 // tap device.
224 //
225 CreateTap();
226
227 // Declare the link up
228 NotifyLinkUp();
229
230 //
231 // Now spin up a read thread to read packets from the tap device.
232 //
233 NS_ABORT_MSG_IF(m_fdReader, "TapBridge::StartTapDevice(): Receive thread is already running");
234 NS_LOG_LOGIC("Spinning up read thread");
235
238}
239
240void
242{
243 NS_LOG_FUNCTION(this);
244
245 if (m_fdReader)
246 {
247 m_fdReader->Stop();
248 m_fdReader = nullptr;
249 }
250
251 if (m_sock != -1)
252 {
253 close(m_sock);
254 m_sock = -1;
255 }
256}
257
258void
260{
261 NS_LOG_FUNCTION(this);
262
263 //
264 // The TapBridge has three distinct operating modes. At this point, the
265 // differences revolve around who is responsible for creating and configuring
266 // the underlying network tap that we use. In ConfigureLocal mode, the
267 // TapBridge has the responsibility for creating and configuring the TAP.
268 //
269 // In UseBridge or UseLocal modes, the user will provide us a configuration
270 // and we have to adapt to it. For example, in UseLocal mode, the user will
271 // be configuring a tap device outside the scope of the ns-3 simulation and
272 // will be expecting us to work with it. The user will do something like:
273 //
274 // sudo ip tuntap add mode tap tap0
275 // sudo ip address add 10.1.1.1/24 dev tap0
276 // sudo ip link set dev tap0 address 00:00:00:00:00:01 up
277 //
278 // The user will then set the "Mode" Attribute of the TapBridge to "UseLocal"
279 // and the "DeviceName" Attribute to "tap0" in this case.
280 //
281 // In ConfigureLocal mode, the user is asking the TapBridge to do the
282 // configuration and create a TAP with the provided "DeviceName" with which
283 // the user can later do what she wants. We need to extract values for the
284 // MAC address, IP address, net mask, etc, from the simulation itself and
285 // use them to initialize corresponding values on the created tap device.
286 //
287 // In UseBridge mode, the user is asking us to use an existing tap device
288 // has been included in an OS bridge. She is asking us to take the simulated
289 // net device and logically add it to the existing bridge. We expect that
290 // the user has done something like:
291 //
292 // sudo ip link add mybridge type bridge
293 // sudo ip tuntap add mode tap mytap
294 // sudo ip link set dev mytap address 00:00:00:00:00:01 up
295 // sudo ip link set dev mytap master mybridge
296 // sudo ip link set dev ... master mybridge
297 // sudo ip address add 10.1.1.1/24 dev mybridge
298 // sudo ip link set dev mybridge up
299 //
300 // The bottom line at this point is that we want to either create or use a
301 // tap device on the host based on the verb part "Use" or "Configure" of the
302 // operating mode. Unfortunately for us you have to have root privileges to
303 // do either. Instead of running the entire simulation as root, we decided
304 // to make a small program who's whole reason for being is to run as suid
305 // root and do what it takes to create the tap. We're just going to pass
306 // off the configuration information to that program and let it deal with
307 // the situation.
308 //
309 // We're going to fork and exec that program soon, but first we need to have
310 // a socket to talk to it with. So we create a local interprocess (Unix)
311 // socket for that purpose.
312 //
313 int sock = socket(PF_UNIX, SOCK_DGRAM, 0);
315 sock == -1,
316 "TapBridge::CreateTap(): Unix socket creation error, errno = " << std::strerror(errno));
317
318 //
319 // Bind to that socket and let the kernel allocate an endpoint
320 //
321 struct sockaddr_un un;
322 memset(&un, 0, sizeof(un));
323 un.sun_family = AF_UNIX;
324 int status = bind(sock, (struct sockaddr*)&un, sizeof(sa_family_t));
325 NS_ABORT_MSG_IF(status == -1,
326 "TapBridge::CreateTap(): Could not bind(): errno = " << std::strerror(errno));
327 NS_LOG_INFO("Created Unix socket");
328 NS_LOG_INFO("sun_family = " << un.sun_family);
329 NS_LOG_INFO("sun_path = " << un.sun_path);
330
331 //
332 // We have a socket here, but we want to get it there -- to the program we're
333 // going to exec. What we'll do is to do a getsockname and then encode the
334 // resulting address information as a string, and then send the string to the
335 // program as an argument. So we need to get the sock name.
336 //
337 socklen_t len = sizeof(un);
338 status = getsockname(sock, (struct sockaddr*)&un, &len);
340 status == -1,
341 "TapBridge::CreateTap(): Could not getsockname(): errno = " << std::strerror(errno));
342
343 //
344 // Now encode that socket name (family and path) as a string of hex digits
345 //
346 std::string path = TapBufferToString((uint8_t*)&un, len);
347 NS_LOG_INFO("Encoded Unix socket as \"" << path << "\"");
348
349 //
350 // Tom Goff reports the possibility of a deadlock when trying to acquire the
351 // python GIL here. He says that this might be due to trying to access Python
352 // objects after fork() without calling PyOS_AfterFork() to properly reset
353 // Python state (including the GIL). Originally these next three lines were
354 // done after the fork, but were moved here to work around the deadlock.
355 //
357 Ptr<Node> n = nd->GetNode();
358 Ptr<Ipv4> ipv4 = n->GetObject<Ipv4>();
359
360 //
361 // Fork and exec the process to create our socket. If we're us (the parent)
362 // we wait for the child (the creator) to complete and read the socket it
363 // created and passed back using the ancillary data mechanism.
364 //
365 pid_t pid = ::fork();
366 if (pid == 0)
367 {
368 NS_LOG_DEBUG("Child process");
369
370 //
371 // build a command line argument from the encoded endpoint string that
372 // the socket creation process will use to figure out how to respond to
373 // the (now) parent process. We're going to have to give this program
374 // quite a bit of information.
375 //
376 // -d<device-name> The name of the tap device we want to create;
377 // -g<gateway-address> The IP address to use as the default gateway;
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 // The gateway-address is something we can't derive, so we rely on it
444 // being configured via an Attribute through the helper.
445 //
446 std::ostringstream ossGateway;
447 ossGateway << "-g" << m_tapGateway;
448
449 //
450 // For flexibility, we do allow a client to override any of the values
451 // above via attributes, so only use our found values if the Attribute
452 // is not equal to its default value (empty string or broadcast address).
453 //
454 std::ostringstream ossIp;
455 if (m_tapIp.IsBroadcast())
456 {
457 ossIp << "-i" << ipv4Address;
458 }
459 else
460 {
461 ossIp << "-i" << m_tapIp;
462 }
463
464 std::ostringstream ossMac;
465 if (m_tapMac.IsBroadcast())
466 {
467 ossMac << "-m" << mac48Address;
468 }
469 else
470 {
471 ossMac << "-m" << m_tapMac;
472 }
473
474 std::ostringstream ossNetmask;
476 {
477 ossNetmask << "-n" << ipv4Mask;
478 }
479 else
480 {
481 ossNetmask << "-n" << m_tapNetmask;
482 }
483
484 std::ostringstream ossMode;
485 ossMode << "-o";
486 if (m_mode == CONFIGURE_LOCAL)
487 {
488 ossMode << "1";
489 }
490 else if (m_mode == USE_LOCAL)
491 {
492 ossMode << "2";
493 }
494 else
495 {
496 ossMode << "3";
497 }
498
499 std::ostringstream ossVerbose;
500 if (m_verbose)
501 {
502 ossVerbose << "-v";
503 }
504
505 std::ostringstream ossPath;
506 ossPath << "-p" << path;
507
508 NS_LOG_DEBUG("Executing: " << TAP_CREATOR << " " << ossDeviceName.str() << " "
509 << ossGateway.str() << " " << ossIp.str() << " " << ossMac.str()
510 << " " << ossNetmask.str() << " " << ossMode.str() << " "
511 << ossPath.str() << " " << ossVerbose.str());
512
513 //
514 // Execute the socket creation process image.
515 //
516 status = ::execlp(TAP_CREATOR,
517 TAP_CREATOR, // argv[0] (filename)
518 ossDeviceName.str().c_str(), // argv[1] (-d<device name>)
519 ossGateway.str().c_str(), // argv[2] (-g<gateway>)
520 ossIp.str().c_str(), // argv[3] (-i<IP address>)
521 ossMac.str().c_str(), // argv[4] (-m<MAC address>)
522 ossNetmask.str().c_str(), // argv[5] (-n<net mask>)
523 ossMode.str().c_str(), // argv[6] (-o<operating mode>)
524 ossPath.str().c_str(), // argv[7] (-p<path>)
525 ossVerbose.str().c_str(), // argv[8] (-v)
526 (char*)nullptr);
527
528 //
529 // If the execlp successfully completes, it never returns. If it returns it failed or the
530 // OS is broken. In either case, we bail.
531 //
532 NS_FATAL_ERROR("TapBridge::CreateTap(): Back from execlp(), status = "
533 << status << " errno = " << ::strerror(errno));
534 }
535 else
536 {
537 NS_LOG_DEBUG("Parent process");
538 //
539 // We're the process running the emu net device. We need to wait for the
540 // socket creator process to finish its job.
541 //
542 int st;
543 pid_t waited = waitpid(pid, &st, 0);
545 waited == -1,
546 "TapBridge::CreateTap(): waitpid() fails, errno = " << std::strerror(errno));
547 NS_ASSERT_MSG(pid == waited, "TapBridge::CreateTap(): pid mismatch");
548
549 //
550 // Check to see if the socket creator exited normally and then take a
551 // look at the exit code. If it bailed, so should we. If it didn't
552 // even exit normally, we bail too.
553 //
554 if (WIFEXITED(st))
555 {
556 int exitStatus = WEXITSTATUS(st);
557 NS_ABORT_MSG_IF(exitStatus != 0,
558 "TapBridge::CreateTap(): socket creator exited normally with status "
559 << exitStatus);
560 }
561 else if (WIFSIGNALED(st))
562 {
563 NS_FATAL_ERROR("TapBridge::CreateTap(): socket creator exited with signal "
564 << WTERMSIG(st));
565 }
566 else
567 {
568 NS_FATAL_ERROR("TapBridge::CreateTap(): socket creator exited abnormally");
569 }
570
571 //
572 // At this point, the socket creator has run successfully and should
573 // have created our tap device, initialized it with the information we
574 // passed and sent it back to the socket address we provided. A socket
575 // (fd) we can use to talk to this tap device should be waiting on the
576 // Unix socket we set up to receive information back from the creator
577 // program. We've got to do a bunch of grunt work to get at it, though.
578 //
579 // The struct iovec below is part of a scatter-gather list. It describes a
580 // buffer. In this case, it describes a buffer (an integer) that will
581 // get the data that comes back from the socket creator process. It will
582 // be a magic number that we use as a consistency/sanity check.
583 //
584 struct iovec iov;
585 uint32_t magic;
586 iov.iov_base = &magic;
587 iov.iov_len = sizeof(magic);
588
589 //
590 // The CMSG macros you'll see below are used to create and access control
591 // messages (which is another name for ancillary data). The ancillary
592 // data is made up of pairs of struct cmsghdr structures and associated
593 // data arrays.
594 //
595 // First, we're going to allocate a buffer on the stack to receive our
596 // data array (that contains the socket). Sometimes you'll see this called
597 // an "ancillary element" but the msghdr uses the control message termimology
598 // so we call it "control."
599 //
600 constexpr size_t msg_size = sizeof(int);
601 char control[CMSG_SPACE(msg_size)];
602
603 //
604 // There is a msghdr that is used to minimize the number of parameters
605 // passed to recvmsg (which we will use to receive our ancillary data).
606 // This structure uses terminology corresponding to control messages, so
607 // you'll see msg_control, which is the pointer to the ancillary data and
608 // controllen which is the size of the ancillary data array.
609 //
610 // So, initialize the message header that describes the ancillary/control
611 // data we expect to receive and point it to buffer.
612 //
613 struct msghdr msg;
614 msg.msg_name = nullptr;
615 msg.msg_namelen = 0;
616 msg.msg_iov = &iov;
617 msg.msg_iovlen = 1;
618 msg.msg_control = control;
619 msg.msg_controllen = sizeof(control);
620 msg.msg_flags = 0;
621
622 //
623 // Now we can actually receive the interesting bits from the tap
624 // creator process. Lots of pain to get four bytes.
625 //
626 ssize_t bytesRead = recvmsg(sock, &msg, 0);
627 NS_ABORT_MSG_IF(bytesRead != sizeof(int),
628 "TapBridge::CreateTap(): Wrong byte count from socket creator");
629
630 //
631 // There may be a number of message headers/ancillary data arrays coming in.
632 // Let's look for the one with a type SCM_RIGHTS which indicates it's the
633 // one we're interested in.
634 //
635 struct cmsghdr* cmsg;
636 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg))
637 {
638 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
639 {
640 //
641 // This is the type of message we want. Check to see if the magic
642 // number is correct and then pull out the socket we care about if
643 // it matches
644 //
645 if (magic == TAP_MAGIC)
646 {
647 NS_LOG_INFO("Got SCM_RIGHTS with correct magic " << magic);
648 int* rawSocket = (int*)CMSG_DATA(cmsg);
649 NS_LOG_INFO("Got the socket from the socket creator = " << *rawSocket);
650 m_sock = *rawSocket;
651 break;
652 }
653 else
654 {
655 NS_LOG_INFO("Got SCM_RIGHTS, but with bad magic " << magic);
656 }
657 }
658 }
659 if (cmsg == nullptr)
660 {
661 NS_FATAL_ERROR("Did not get the raw socket from the socket creator");
662 }
663
664 if (m_mode == USE_BRIDGE)
665 {
666 //
667 // Set the ns-3 device's mac address to the overlying container's
668 // mac address
669 //
670 struct ifreq s;
671 memset(&s, 0, sizeof(struct ifreq));
672 strncpy(s.ifr_name, m_tapDeviceName.c_str(), IFNAMSIZ - 1);
673
674 NS_LOG_INFO("Trying to get MacAddr of " << m_tapDeviceName);
675 int ioctlResult = ioctl(sock, SIOCGIFHWADDR, &s);
676 if (ioctlResult == 0)
677 {
678 Mac48Address learnedMac;
679 learnedMac.CopyFrom((uint8_t*)s.ifr_hwaddr.sa_data);
680 NS_LOG_INFO("Learned Tap device MacAddr is "
681 << learnedMac << ": setting ns-3 device to use this address");
682 m_bridgedDevice->SetAddress(learnedMac);
684 }
685
687 {
688 NS_LOG_INFO("Cannot get MacAddr of Tap device: "
690 << " while in USE_LOCAL/USE_BRIDGE mode: " << std::strerror(errno));
691 NS_LOG_INFO("Underlying ns-3 device will continue to use default address, what can "
692 "lead to connectivity errors");
693 }
694 }
695 }
696
697 close(sock);
698}
699
700void
701TapBridge::ReadCallback(uint8_t* buf, ssize_t len)
702{
703 NS_LOG_FUNCTION(this << buf << len);
704
705 NS_ASSERT_MSG(buf != nullptr, "invalid buf argument");
706 NS_ASSERT_MSG(len > 0, "invalid len argument");
707
708 //
709 // It's important to remember that we're in a completely different thread
710 // than the simulator is running in. We need to synchronize with that
711 // other thread to get the packet up into ns-3. What we will need to do
712 // is to schedule a method to deal with the packet using the multithreaded
713 // simulator we are most certainly running. However, I just said it -- we
714 // are talking about two threads here, so it is very, very dangerous to do
715 // any kind of reference counting on a shared object. Just don't do it.
716 // So what we're going to do is pass the buffer allocated on the heap
717 // into the ns-3 context thread where it will create the packet.
718 //
719
720 NS_LOG_INFO("TapBridge::ReadCallback(): Received packet on node " << m_nodeId);
721 NS_LOG_INFO("TapBridge::ReadCallback(): Scheduling handler");
723 Seconds(0.0),
725}
726
727void
728TapBridge::ForwardToBridgedDevice(uint8_t* buf, ssize_t len)
729{
730 NS_LOG_FUNCTION(this << buf << len);
731
732 //
733 // There are three operating modes for the TapBridge
734 //
735 // CONFIGURE_LOCAL means that ns-3 will create and configure a tap device
736 // and we are expected to use it. The tap device and the ns-3 net device
737 // will have the same MAC address by definition. Thus Send and SendFrom
738 // are equivalent in this case. We use Send to allow all ns-3 devices to
739 // participate in this mode.
740 //
741 // USE_LOCAL mode tells us that we have got to USE a pre-created tap device
742 // that will have a different MAC address from the ns-3 net device. We
743 // also enforce the requirement that there will only be one MAC address
744 // bridged on the Linux side so we can use Send (instead of SendFrom) in
745 // the linux to ns-3 direction. Again, all ns-3 devices can participate
746 // in this mode.
747 //
748 // USE_BRIDGE mode tells us that we are logically extending a Linux bridge
749 // on which lies our tap device. In this case there may be many linux
750 // net devices on the other side of the bridge and so we must use SendFrom
751 // to preserve the possibly many source addresses. Thus, ns-3 devices
752 // must support SendFrom in order to be considered for USE_BRIDGE mode.
753 //
754
755 //
756 // First, create a packet out of the byte buffer we received and free that
757 // buffer.
758 //
759 Ptr<Packet> packet = Create<Packet>(reinterpret_cast<const uint8_t*>(buf), len);
760 std::free(buf);
761 buf = nullptr;
762
763 //
764 // Make sure the packet we received is reasonable enough for the rest of the
765 // system to handle and get it ready to be injected directly into an ns-3
766 // device. What should come back is a packet with the Ethernet header
767 // (and possibly an LLC header as well) stripped off.
768 //
769 Address src;
770 Address dst;
771 uint16_t type;
772
773 NS_LOG_LOGIC("Received packet from tap device");
774
775 Ptr<Packet> p = Filter(packet, &src, &dst, &type);
776 if (!p)
777 {
779 "TapBridge::ForwardToBridgedDevice: Discarding packet as unfit for ns-3 consumption");
780 return;
781 }
782
783 NS_LOG_LOGIC("Pkt source is " << src);
784 NS_LOG_LOGIC("Pkt destination is " << dst);
785 NS_LOG_LOGIC("Pkt LengthType is " << type);
786 if (m_mode == USE_LOCAL)
787 {
788 //
789 // Packets we are going to forward should not be from a broadcast src
790 //
792 "TapBridge::ForwardToBridgedDevice: Source addr is broadcast");
794 {
795 //
796 // Set the ns-3 device's mac address to the overlying container's
797 // mac address
798 //
799 Mac48Address learnedMac = Mac48Address::ConvertFrom(src);
800 NS_LOG_LOGIC("Learned MacAddr is " << learnedMac
801 << ": setting ns-3 device to use this address");
802 m_bridgedDevice->SetAddress(Mac48Address::ConvertFrom(learnedMac));
804 }
805 //
806 // If we are operating in USE_LOCAL mode, we may be attached to an ns-3
807 // device that does not support bridging (SupportsSendFrom returns false).
808 // But, since the mac addresses are now aligned, we can call Send()
809 //
810 NS_LOG_LOGIC("Forwarding packet to ns-3 device via Send()");
811 m_bridgedDevice->Send(packet, dst, type);
812 return;
813 }
814
815 //
816 // If we are operating in USE_BRIDGE mode, we have the
817 // situation described below:
818 //
819 // Other Device <-bridge-> Tap Device <-bridge-> ns3 device
820 // Mac Addr A Mac Addr B Mac Addr C
821 //
822 // In Linux, "Other Device" and "Tap Device" are bridged together. By this
823 // we mean that a user has sone something in Linux like:
824 //
825 // ip link add mybridge type bridge
826 // ip link set dev other-device master mybridge
827 // ip link set dev tap-device master mybridge
828 //
829 // In USE_BRIDGE mode, we want to logically extend this Linux behavior to the
830 // simulated ns3 device and make it appear as if it is connected to the Linux
831 // subnet. As you may expect, this means that we need to act like a real
832 // Linux bridge and take all packets that come from "Tap Device" and ask
833 // "ns3 Device" to send them down its directly connected network. Just like
834 // in a normal everyday bridge we need to call SendFrom in order to preserve
835 // the original packet's from address.
836 //
837 // If we are operating in CONFIGURE_LOCAL mode, we simply simply take all packets
838 // that come from "Tap Device" and ask "ns3 Device" to send them down its
839 // directly connected network. A normal bridge would need to call SendFrom
840 // in order to preserve the original from address, but in CONFIGURE_LOCAL mode
841 // the tap device and the ns-3 device have the same MAC address by definition so
842 // we can call Send.
843 //
844 NS_LOG_LOGIC("Forwarding packet");
845
846 if (m_mode == USE_BRIDGE)
847 {
848 m_bridgedDevice->SendFrom(packet, src, dst, type);
849 }
850 else
851 {
853 "TapBridge::ForwardToBridgedDevice(): Internal error");
854 m_bridgedDevice->Send(packet, dst, type);
855 }
856}
857
859TapBridge::Filter(Ptr<Packet> p, Address* src, Address* dst, uint16_t* type)
860{
861 NS_LOG_FUNCTION(this << p);
863
864 //
865 // We have a candidate packet for injection into ns-3. We expect that since
866 // it came over a socket that provides Ethernet packets, it should be big
867 // enough to hold an EthernetHeader. If it can't, we signify the packet
868 // should be filtered out by returning 0.
869 //
870 pktSize = p->GetSize();
871 EthernetHeader header(false);
872 if (pktSize < header.GetSerializedSize())
873 {
874 return nullptr;
875 }
876
877 uint32_t headerSize = p->PeekHeader(header);
878 p->RemoveAtStart(headerSize);
879
880 NS_LOG_LOGIC("Pkt source is " << header.GetSource());
881 NS_LOG_LOGIC("Pkt destination is " << header.GetDestination());
882 NS_LOG_LOGIC("Pkt LengthType is " << header.GetLengthType());
883
884 //
885 // If the length/type is less than 1500, it corresponds to a length
886 // interpretation packet. In this case, it is an 802.3 packet and
887 // will also have an 802.2 LLC header. If greater than 1500, we
888 // find the protocol number (Ethernet type) directly.
889 //
890 if (header.GetLengthType() <= 1500)
891 {
892 *src = header.GetSource();
893 *dst = header.GetDestination();
894
895 pktSize = p->GetSize();
896 LlcSnapHeader llc;
897 if (pktSize < llc.GetSerializedSize())
898 {
899 return nullptr;
900 }
901
902 p->RemoveHeader(llc);
903 *type = llc.GetType();
904 }
905 else
906 {
907 *src = header.GetSource();
908 *dst = header.GetDestination();
909 *type = header.GetLengthType();
910 }
911
912 //
913 // What we give back is a packet without the Ethernet header (nor the
914 // possible llc/snap header) on it. We think it is ready to send on
915 // out the bridged net device.
916 //
917 return p;
918}
919
926
927void
929{
930 NS_LOG_FUNCTION(this << bridgedDevice);
931
932 NS_ASSERT_MSG(m_node, "TapBridge::SetBridgedDevice: Bridge not installed in a node");
933 NS_ASSERT_MSG(bridgedDevice != this, "TapBridge::SetBridgedDevice: Cannot bridge to self");
934 NS_ASSERT_MSG(!m_bridgedDevice, "TapBridge::SetBridgedDevice: Already bridged");
935
936 if (!Mac48Address::IsMatchingType(bridgedDevice->GetAddress()))
937 {
938 NS_FATAL_ERROR("TapBridge::SetBridgedDevice: Device does not support eui 48 addresses: "
939 "cannot be added to bridge.");
940 }
941
942 if (m_mode == USE_BRIDGE && !bridgedDevice->SupportsSendFrom())
943 {
944 NS_FATAL_ERROR("TapBridge::SetBridgedDevice: Device does not support SendFrom: cannot be "
945 "added to bridge.");
946 }
947
948 //
949 // We need to disconnect the bridged device from the internet stack on our
950 // node to ensure that only one stack responds to packets inbound over the
951 // bridged device. That one stack lives outside ns-3 so we just blatantly
952 // steal the device callbacks.
953 //
954 // N.B This can be undone if someone does a RegisterProtocolHandler later
955 // on this node.
956 //
957 bridgedDevice->SetReceiveCallback(MakeCallback(&TapBridge::DiscardFromBridgedDevice, this));
958 bridgedDevice->SetPromiscReceiveCallback(
960 m_bridgedDevice = bridgedDevice;
961}
962
963bool
965 Ptr<const Packet> packet,
966 uint16_t protocol,
967 const Address& src)
968{
969 NS_LOG_FUNCTION(this << device << packet << protocol << src);
970 NS_LOG_LOGIC("Discarding packet stolen from bridged device " << device);
971 return true;
972}
973
974bool
976 Ptr<const Packet> packet,
977 uint16_t protocol,
978 const Address& src,
979 const Address& dst,
980 PacketType packetType)
981{
982 NS_LOG_FUNCTION(this << device << packet << protocol << src << dst << packetType);
984 "TapBridge::SetBridgedDevice: Received packet from unexpected device");
985 NS_LOG_DEBUG("Packet UID is " << packet->GetUid());
986
987 //
988 // There are three operating modes for the TapBridge
989 //
990 // CONFIGURE_LOCAL means that ns-3 will create and configure a tap device
991 // and we are expected to use it. The tap device and the ns-3 net device
992 // will have the same MAC address by definition.
993 //
994 // USE_LOCAL mode tells us that we have got to USE a pre-created tap device
995 // that will have a different MAC address from the ns-3 net device. In this
996 // case we will be spoofing the MAC address of a received packet to match
997 // the single allowed address on the Linux side.
998 //
999 // USE_BRIDGE mode tells us that we are logically extending a Linux bridge
1000 // on which lies our tap device.
1001 //
1002
1003 if (m_mode == CONFIGURE_LOCAL && packetType == PACKET_OTHERHOST)
1004 {
1005 //
1006 // We hooked the promiscuous mode protocol handler so we could get the
1007 // destination address of the actual packet. This means we will be
1008 // getting PACKET_OTHERHOST packets (not broadcast, not multicast, not
1009 // unicast to the ns-3 net device, but to some other address). In
1010 // CONFIGURE_LOCAL mode we are not interested in these packets since they
1011 // don't refer to the single MAC address shared by the ns-3 device and
1012 // the TAP device. If, however, we are in USE_LOCAL or USE_BRIDGE mode,
1013 // we want to act like a bridge and forward these PACKET_OTHERHOST
1014 // packets.
1015 //
1016 return true;
1017 }
1018
1021
1022 Ptr<Packet> p = packet->Copy();
1023 EthernetHeader header = EthernetHeader(false);
1024 header.SetSource(from);
1025 header.SetDestination(to);
1026
1027 header.SetLengthType(protocol);
1028 p->AddHeader(header);
1029
1030 NS_LOG_LOGIC("Writing packet to Linux host");
1031 NS_LOG_LOGIC("Pkt source is " << header.GetSource());
1032 NS_LOG_LOGIC("Pkt destination is " << header.GetDestination());
1033 NS_LOG_LOGIC("Pkt LengthType is " << header.GetLengthType());
1034 NS_LOG_LOGIC("Pkt size is " << p->GetSize());
1035
1036 NS_ASSERT_MSG(p->GetSize() <= 65536,
1037 "TapBridge::ReceiveFromBridgedDevice: Packet too big " << p->GetSize());
1038 p->CopyData(m_packetBuffer, p->GetSize());
1039
1040 uint32_t bytesWritten = write(m_sock, m_packetBuffer, p->GetSize());
1041 NS_ABORT_MSG_IF(bytesWritten != p->GetSize(),
1042 "TapBridge::ReceiveFromBridgedDevice(): Write error.");
1043
1044 NS_LOG_LOGIC("End of receive packet handling on node " << m_node->GetId());
1045 return true;
1046}
1047
1048void
1050{
1051 NS_LOG_FUNCTION(this << index);
1052 m_ifIndex = index;
1053}
1054
1057{
1058 NS_LOG_FUNCTION(this);
1059 return m_ifIndex;
1060}
1061
1064{
1065 NS_LOG_FUNCTION(this);
1066 return nullptr;
1067}
1068
1069void
1071{
1072 NS_LOG_FUNCTION(this << address);
1074}
1075
1076Address
1078{
1079 NS_LOG_FUNCTION(this);
1080 return m_address;
1081}
1082
1083void
1085{
1086 NS_LOG_FUNCTION(this << mode);
1087 m_mode = mode;
1088}
1089
1092{
1093 NS_LOG_FUNCTION(this);
1094 return m_mode;
1095}
1096
1097bool
1098TapBridge::SetMtu(const uint16_t mtu)
1099{
1100 NS_LOG_FUNCTION(this << mtu);
1101 m_mtu = mtu;
1102 return true;
1103}
1104
1105uint16_t
1107{
1108 NS_LOG_FUNCTION(this);
1109 return m_mtu;
1110}
1111
1112void
1114{
1115 NS_LOG_FUNCTION(this);
1116 if (!m_linkUp)
1117 {
1118 m_linkUp = true;
1120 }
1121}
1122
1123bool
1125{
1126 NS_LOG_FUNCTION(this);
1127 return m_linkUp;
1128}
1129
1130void
1136
1137bool
1139{
1140 NS_LOG_FUNCTION(this);
1141 return true;
1142}
1143
1144Address
1146{
1147 NS_LOG_FUNCTION(this);
1149}
1150
1151bool
1153{
1154 NS_LOG_FUNCTION(this);
1155 return true;
1156}
1157
1158Address
1160{
1161 NS_LOG_FUNCTION(this << multicastGroup);
1162 Mac48Address multicast = Mac48Address::GetMulticast(multicastGroup);
1163 return multicast;
1164}
1165
1166bool
1168{
1169 NS_LOG_FUNCTION(this);
1170 return false;
1171}
1172
1173bool
1175{
1176 NS_LOG_FUNCTION(this);
1177 //
1178 // Returning false from IsBridge in a device called TapBridge may seem odd
1179 // at first glance, but this test is for a device that bridges ns-3 devices
1180 // together. The Tap bridge doesn't do that -- it bridges an ns-3 device to
1181 // a Linux device. This is a completely different story.
1182 //
1183 return false;
1184}
1185
1186bool
1187TapBridge::Send(Ptr<Packet> packet, const Address& dst, uint16_t protocol)
1188{
1189 NS_LOG_FUNCTION(this << packet << dst << protocol);
1190 NS_FATAL_ERROR("TapBridge::Send: You may not call Send on a TapBridge directly");
1191 return false;
1192}
1193
1194bool
1195TapBridge::SendFrom(Ptr<Packet> packet, const Address& src, const Address& dst, uint16_t protocol)
1196{
1197 NS_LOG_FUNCTION(this << packet << src << dst << protocol);
1198 NS_FATAL_ERROR("TapBridge::Send: You may not call SendFrom on a TapBridge directly");
1199 return false;
1200}
1201
1204{
1205 NS_LOG_FUNCTION(this);
1206 return m_node;
1207}
1208
1209void
1211{
1212 NS_LOG_FUNCTION(this);
1213 m_node = node;
1214}
1215
1216bool
1218{
1219 NS_LOG_FUNCTION(this);
1220 return true;
1221}
1222
1223void
1229
1230void
1236
1237bool
1239{
1240 NS_LOG_FUNCTION(this);
1241 return true;
1242}
1243
1244Address
1246{
1247 NS_LOG_FUNCTION(this << addr);
1248 return Mac48Address::GetMulticast(addr);
1249}
1250
1251} // namespace ns3
a polymophic address class
Definition address.h:90
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
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition ipv4.h:69
a class to represent an Ipv4 address mask
static Ipv4Mask GetOnes()
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
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:560
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:577
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
void ConnectWithoutContext(const CallbackBase &callback)
Append a Callback to the chain (without a context).
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
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
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:1308
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition nstime.h:1396
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 AttributeAccessor > MakeUintegerAccessor(T1 a1)
Definition uinteger.h:35
Ptr< const AttributeAccessor > MakeMac48AddressAccessor(T1 a1)
Ptr< const AttributeChecker > MakeMac48AddressChecker()
Ptr< const AttributeAccessor > MakeIpv4AddressAccessor(T1 a1)
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
Ptr< const AttributeChecker > MakeIpv4AddressChecker()
Ptr< const AttributeAccessor > MakeIpv4MaskAccessor(T1 a1)
Ptr< const AttributeChecker > MakeIpv4MaskChecker()
Ptr< const AttributeChecker > MakeStringChecker()
Definition string.cc:19
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Definition string.h:46
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Definition boolean.h:70
std::string TapBufferToString(uint8_t *buffer, uint32_t len)
Convert a byte buffer to a string containing a hex representation of the buffer.
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Definition enum.h:221
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1416
A structure representing data read.
Definition fd-reader.h:80
#define TAP_MAGIC
uint32_t pktSize
packet size used for the simulation (in bytes)