12#include "ns3/boolean.h"
13#include "ns3/channel.h"
15#include "ns3/ethernet-header.h"
16#include "ns3/fd-reader.h"
18#include "ns3/llc-snap-header.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"
32#include <sys/socket.h>
49 auto buf = (uint8_t*)std::malloc(bufferSize);
53 ssize_t len = read(
m_fd, buf, bufferSize);
65#define TAP_MAGIC 95549
75 .SetGroupName(
"TapBridge")
78 "The MAC-level Maximum Transmission Unit",
82 .AddAttribute(
"DeviceName",
83 "The name of the tap device to create.",
87 .AddAttribute(
"Gateway",
88 "The IP address of the default gateway to assign to the host machine, "
89 "when in ConfigureLocal mode.",
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.",
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.",
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.",
114 .AddAttribute(
"Start",
115 "The simulation time at which to spin up the tap device read thread.",
119 .AddAttribute(
"Stop",
120 "The simulation time at which to tear down the tap device read thread.",
124 .AddAttribute(
"Mode",
125 "The operating and configuration mode to use.",
134 .AddAttribute(
"Verbose",
135 "Enable verbose output from tap-creator child process",
149 m_ns3AddressRewritten(false)
313 int sock = socket(PF_UNIX, SOCK_DGRAM, 0);
316 "TapBridge::CreateTap(): Unix socket creation error, errno = " << std::strerror(errno));
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));
326 "TapBridge::CreateTap(): Could not bind(): errno = " << std::strerror(errno));
337 socklen_t len =
sizeof(un);
338 status = getsockname(sock, (
struct sockaddr*)&un, &len);
341 "TapBridge::CreateTap(): Could not getsockname(): errno = " << std::strerror(errno));
347 NS_LOG_INFO(
"Encoded Unix socket as \"" << path <<
"\"");
365 pid_t pid = ::fork();
402 NS_FATAL_ERROR(
"TapBridge::CreateTap(): Tap device IP configuration requested but "
403 "neither IP address nor IP netmask is provided");
408 Ipv4Mask ipv4Mask(
"255.255.255.255");
412 uint32_t index = ipv4->GetInterfaceForDevice(nd);
413 if (ipv4->GetNAddresses(index) > 1)
416 "Underlying bridged NetDevice has multiple IP addresses; using first one.");
418 ipv4Address = ipv4->GetAddress(index, 0).GetLocal();
423 ipv4Mask = ipv4->GetAddress(index, 0).GetMask();
430 Address address = nd->GetAddress();
439 std::ostringstream ossDeviceName;
446 std::ostringstream ossGateway;
454 std::ostringstream ossIp;
457 ossIp <<
"-i" << ipv4Address;
464 std::ostringstream ossMac;
467 ossMac <<
"-m" << mac48Address;
474 std::ostringstream ossNetmask;
477 ossNetmask <<
"-n" << ipv4Mask;
484 std::ostringstream ossMode;
499 std::ostringstream ossVerbose;
505 std::ostringstream ossPath;
506 ossPath <<
"-p" << path;
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());
516 status = ::execlp(TAP_CREATOR,
518 ossDeviceName.str().c_str(),
519 ossGateway.str().c_str(),
521 ossMac.str().c_str(),
522 ossNetmask.str().c_str(),
523 ossMode.str().c_str(),
524 ossPath.str().c_str(),
525 ossVerbose.str().c_str(),
532 NS_FATAL_ERROR(
"TapBridge::CreateTap(): Back from execlp(), status = "
533 << status <<
" errno = " << ::strerror(errno));
543 pid_t waited = waitpid(pid, &st, 0);
546 "TapBridge::CreateTap(): waitpid() fails, errno = " << std::strerror(errno));
547 NS_ASSERT_MSG(pid == waited,
"TapBridge::CreateTap(): pid mismatch");
556 int exitStatus = WEXITSTATUS(st);
558 "TapBridge::CreateTap(): socket creator exited normally with status "
561 else if (WIFSIGNALED(st))
563 NS_FATAL_ERROR(
"TapBridge::CreateTap(): socket creator exited with signal "
568 NS_FATAL_ERROR(
"TapBridge::CreateTap(): socket creator exited abnormally");
586 iov.iov_base = &magic;
587 iov.iov_len =
sizeof(magic);
600 constexpr size_t msg_size =
sizeof(int);
601 char control[CMSG_SPACE(msg_size)];
614 msg.msg_name =
nullptr;
618 msg.msg_control = control;
619 msg.msg_controllen =
sizeof(control);
626 ssize_t bytesRead = recvmsg(sock, &msg, 0);
628 "TapBridge::CreateTap(): Wrong byte count from socket creator");
635 struct cmsghdr* cmsg;
636 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg !=
nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg))
638 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
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);
655 NS_LOG_INFO(
"Got SCM_RIGHTS, but with bad magic " << magic);
661 NS_FATAL_ERROR(
"Did not get the raw socket from the socket creator");
671 memset(&s, 0,
sizeof(
struct ifreq));
675 int ioctlResult = ioctl(sock, SIOCGIFHWADDR, &s);
676 if (ioctlResult == 0)
679 learnedMac.
CopyFrom((uint8_t*)s.ifr_hwaddr.sa_data);
681 << learnedMac <<
": setting ns-3 device to use this address");
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");
721 NS_LOG_INFO(
"TapBridge::ReadCallback(): Scheduling handler");
779 "TapBridge::ForwardToBridgedDevice: Discarding packet as unfit for ns-3 consumption");
792 "TapBridge::ForwardToBridgedDevice: Source addr is broadcast");
801 <<
": setting ns-3 device to use this address");
810 NS_LOG_LOGIC(
"Forwarding packet to ns-3 device via Send()");
853 "TapBridge::ForwardToBridgedDevice(): Internal error");
877 uint32_t headerSize = p->PeekHeader(header);
878 p->RemoveAtStart(headerSize);
902 p->RemoveHeader(llc);
933 NS_ASSERT_MSG(bridgedDevice !=
this,
"TapBridge::SetBridgedDevice: Cannot bridge to self");
938 NS_FATAL_ERROR(
"TapBridge::SetBridgedDevice: Device does not support eui 48 addresses: "
939 "cannot be added to bridge.");
944 NS_FATAL_ERROR(
"TapBridge::SetBridgedDevice: Device does not support SendFrom: cannot be "
958 bridgedDevice->SetPromiscReceiveCallback(
970 NS_LOG_LOGIC(
"Discarding packet stolen from bridged device " << device);
982 NS_LOG_FUNCTION(
this << device << packet << protocol << src << dst << packetType);
984 "TapBridge::SetBridgedDevice: Received packet from unexpected device");
1028 p->AddHeader(header);
1037 "TapBridge::ReceiveFromBridgedDevice: Packet too big " << p->GetSize());
1042 "TapBridge::ReceiveFromBridgedDevice(): Write error.");
1190 NS_FATAL_ERROR(
"TapBridge::Send: You may not call Send on a TapBridge directly");
1198 NS_FATAL_ERROR(
"TapBridge::Send: You may not call SendFrom on a TapBridge directly");
a polymophic address class
AttributeValue implementation for Boolean.
Hold variables of type enum.
int m_fd
The file descriptor to read from.
Ipv4 addresses are stored in host order in this class.
AttributeValue implementation for Ipv4Address.
Access to the IPv4 forwarding table, interfaces, and configuration.
a class to represent an Ipv4 address mask
static Ipv4Mask GetOnes()
AttributeValue implementation for Ipv4Mask.
Describes an IPv6 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()
AttributeValue implementation for Mac48Address.
Network layer to device interface.
PacketType
Packet types are used as they are in Linux.
@ PACKET_OTHERHOST
Packet addressed to someone else.
virtual void DoDispose()
Destructor implementation.
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.
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...
static void ScheduleWithContext(uint32_t context, const Time &delay, FUNC f, Ts &&... args)
Schedule an event with the given context.
Hold variables of type string.
FdReader::Data DoRead() override
The read implementation.
A bridge to make it appear that a real host process is connected to an ns-3 net device.
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.
static TypeId GetTypeId()
Get the type ID.
bool m_ns3AddressRewritten
Whether the MAC address of the underlying ns-3 device has already been rewritten is stored in this va...
void AddLinkChangeCallback(Callback< void > callback) override
uint8_t * m_packetBuffer
A 64K buffer to hold packet data while it is being sent.
bool m_linkUp
Flag indicating whether or not the link is up.
Address GetAddress() const override
TracedCallback m_linkChangeCallbacks
Callbacks to fire if the link changes state (up or down).
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.
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.
void StopTapDevice()
Tear down the device.
Address GetBroadcast() const override
uint32_t m_ifIndex
The ns-3 interface index of this TapBridge net device.
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.
Mac48Address m_address
The (unused) MAC address of the TapBridge net device.
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.
uint16_t m_mtu
The common mtu to use for the net devices.
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.
Ipv4Mask m_tapNetmask
The network mask to assign to the device created on the host.
bool m_verbose
Flag indicating whether or not the link is up.
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.
Ptr< Node > m_node
Pointer to the (ghost) Node to which we are connected.
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...
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.
bool IsBroadcast() const override
Mode
Enumeration of the operating modes supported in the class.
@ USE_BRIDGE
ns-3 uses a pre-created tap, and bridges to a bridging net device
@ USE_LOCAL
ns-3 uses a pre-created tap, without configuring it
@ CONFIGURE_LOCAL
ns-3 creates and configures tap device
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...
bool IsMulticast() const override
Time m_tStart
Time to start spinning up the device.
Ipv4Address m_tapGateway
The IP address to use as the device default gateway on the host.
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.
void SetNode(Ptr< Node > node) override
std::string m_tapDeviceName
The name of the device to create on the host.
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.
Simulation virtual time values and global simulation resolution.
AttributeValue implementation for Time.
void ConnectWithoutContext(const CallbackBase &callback)
Append a Callback to the chain (without a context).
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Hold an unsigned integer type.
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Ptr< const AttributeChecker > MakeBooleanChecker()
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakeEnumAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
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()
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Ptr< const AttributeChecker > MakeUintegerChecker()
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
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.
#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.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
#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.
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Time Seconds(double value)
Construct a Time in the indicated unit.
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...
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
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.
uint32_t pktSize
packet size used for the simulation (in bytes)