diff --git a/src/devices/tap-bridge/tap-bridge.cc b/src/devices/tap-bridge/tap-bridge.cc index 1d0f3d844..8e6a2e5c4 100644 --- a/src/devices/tap-bridge/tap-bridge.cc +++ b/src/devices/tap-bridge/tap-bridge.cc @@ -80,22 +80,22 @@ TapBridge::GetTypeId (void) MakeStringAccessor (&TapBridge::m_tapDeviceName), MakeStringChecker ()) .AddAttribute ("Gateway", - "The IP address of the default gateway to assign to the tap device.", + "The IP address of the default gateway to assign to the host machine, when in ConfigureLocal mode.", Ipv4AddressValue ("255.255.255.255"), MakeIpv4AddressAccessor (&TapBridge::m_tapGateway), MakeIpv4AddressChecker ()) .AddAttribute ("IpAddress", - "The IP address to assign to the tap device.", + "The IP address to assign to the tap device, when in ConfigureLocal mode.", Ipv4AddressValue ("255.255.255.255"), MakeIpv4AddressAccessor (&TapBridge::m_tapIp), MakeIpv4AddressChecker ()) .AddAttribute ("MacAddress", - "The MAC address to assign to the tap device.", + "The MAC address to assign to the tap device, when in ConfigureLocal mode.", Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")), MakeMac48AddressAccessor (&TapBridge::m_tapMac), MakeMac48AddressChecker ()) .AddAttribute ("Netmask", - "The network mask to assign to the tap device.", + "The network mask to assign to the tap device, when in ConfigureLocal mode.", Ipv4MaskValue ("255.255.255.255"), MakeIpv4MaskAccessor (&TapBridge::m_tapNetmask), MakeIpv4MaskChecker ()) @@ -110,11 +110,12 @@ TapBridge::GetTypeId (void) MakeTimeAccessor (&TapBridge::m_tStop), MakeTimeChecker ()) .AddAttribute ("Mode", - "The operating and configuration mode (LocalDevice or BridgedDevice) to use.", - EnumValue (LOCAL_DEVICE), + "The operating and configuration mode to use.", + EnumValue (USE_LOCAL), MakeEnumAccessor (&TapBridge::SetMode), - MakeEnumChecker (LOCAL_DEVICE, "LocalDevice", - BRIDGED_DEVICE, "BridgedDevice")) + MakeEnumChecker (CONFIGURE_LOCAL, "ConfigureLocal", + USE_LOCAL, "UseLocal", + USE_BRIDGE, "UseBridge")) ; return tid; } @@ -126,7 +127,8 @@ TapBridge::TapBridge () m_sock (-1), m_startEvent (), m_stopEvent (), - m_readThread (0) + m_readThread (0), + m_learnedMac (Mac48Address ("ff:ff:ff:ff:ff:ff")) { NS_LOG_FUNCTION_NOARGS (); Start (m_tStart); @@ -222,20 +224,20 @@ TapBridge::CreateTap (void) // // The TapBridge has two distinct operating modes. The difference revolves // around who is responsible for creating and configuring the underlying - // network tap that we use. In LocalDevice mode, the TapBridge has the + // network tap that we use. In ConfigureLocal mode, the TapBridge has the // responsibility for creating and configuring the TAP. // - // In BridgedDevice mode, the user will provide us a configuration and we have + // In UseBridge mode, the user will provide us a configuration and we have // to adapt to it. For example, the user will do something like: // // sudo tunctl -t tap0 // sudo ifconfig tap0 hw ether 00:00:00:00:00:01 // sudo ifconfig tap0 10.1.1.1 netmask 255.255.255.0 up // - // set the "Mode" Attribute to "BridgedDevice" and the "DeviceName" Attribute + // set the "Mode" Attribute to "UseBridge" and the "DeviceName" Attribute // to "tap0" in this case. // - // In LocalDevice mode, we will do the configuration and create a TAP with + // In ConfigureLocal mode, we will do the configuration and create a TAP with // the provided "DeviceName" with which the user can later do what she wants. // // We want to either create or use a tap device on the host. Unfortunately for @@ -296,7 +298,7 @@ TapBridge::CreateTap (void) // -i The IP address to assign to the new tap device; // -m The MAC-48 address to assign to the new tap device; // -n The network mask to assign to the new tap device; - // -o The operating mode of the bridge (1=LocalDevice, 2=BridgedDevice) + // -o The operating mode of the bridge (1=ConfigureLocal, 2=UseLocal, 3=UseBridge) // -p the path to the unix socket described above. // // Example tap-creator -dnewdev -g1.2.3.2 -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -o1 -pblah @@ -381,14 +383,18 @@ TapBridge::CreateTap (void) std::ostringstream ossMode; ossMode << "-o"; - if (m_mode == LOCAL_DEVICE) + if (m_mode == CONFIGURE_LOCAL) { ossMode << "1"; } - else + else if (m_mode == USE_LOCAL) { ossMode << "2"; } + else + { + ossMode << "3"; + } std::ostringstream ossPath; ossPath << "-p" << path; @@ -590,11 +596,12 @@ TapBridge::ReadThread (void) uint32_t bufferSize = 65536; uint8_t *buf = (uint8_t *)malloc (bufferSize); NS_ABORT_MSG_IF (buf == 0, "TapBridge::ReadThread(): malloc packet buffer failed"); - NS_LOG_LOGIC ("Calling read on tap device socket fd"); + NS_LOG_LOGIC ("Calling read on tap device socket fd " << m_sock); len = read (m_sock, buf, bufferSize); if (len == -1) { + NS_LOG_INFO ("TapBridge::ReadThread(): Returning"); free (buf); buf = 0; return; @@ -603,13 +610,13 @@ TapBridge::ReadThread (void) NS_LOG_INFO ("TapBridge::ReadThread(): Received packet"); NS_LOG_INFO ("TapBridge::ReadThread(): Scheduling handler"); DynamicCast (Simulator::GetImplementation ())->ScheduleRealtimeNow ( - MakeEvent (&TapBridge::ForwardToBridgedDevice, this, buf, len)); + MakeEvent (&TapBridge::ForwardToSimDevice, this, buf, len)); buf = 0; } } void -TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) +TapBridge::ForwardToSimDevice (uint8_t *buf, uint32_t len) { NS_LOG_FUNCTION (buf << len); @@ -641,10 +648,22 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) NS_LOG_LOGIC ("Pkt source is " << src); NS_LOG_LOGIC ("Pkt destination is " << dst); NS_LOG_LOGIC ("Pkt LengthType is " << type); + if (m_mode == USE_LOCAL) + { + // Should not be a broadcast src + NS_ASSERT_MSG (Mac48Address::ConvertFrom (src) != Mac48Address ("ff:ff:ff:ff:ff:ff"), "TapBridge::ForwardToSimDevice: Source addr is broadcast"); + m_learnedMac = Mac48Address::ConvertFrom (src); + NS_LOG_LOGIC ("Learned MacAddr is " << m_learnedMac); + // If we are operating in USE_LOCAL mode, we may be attached to an ns-3 + // bridging or non-bridging NetDevice. We use the generic Send() method. + NS_LOG_LOGIC ("Forwarding packet"); + m_bridgedDevice->Send (packet, dst, type); + return; + } // - // If we are operating in BRIDGED_DEVICE mode, we have the situation described - // below: + // If we are operating in USE_BRIDGE mode, we have the + // situation described below: // // Other Device <--> Tap Device <--> ns3 device // Mac Addr A Mac Addr B Mac Addr C @@ -657,14 +676,14 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) // (modulo learning behavior) sent out to "Other Device." This makes it // appear as if both devices are on a single subnet. // - // In BRIDGED_DEVICE mode, we want to logically extend this Linux behavior + // In USE_BRIDGE mode, we want to logically extend this Linux behavior // to the ns3 device and make it appear as if it is connected to the Linux // subnet. As you may expect, this means that we need to act like a real // bridge and do what is described above. The code here will do the // equivalent of a SendFrom on "ns3 Device" of the bits received on // "Tap Device" // - // If we are operating in LOCAL_DEVICE mode, we simply simply take all packets + // If we are operating in CONFIGURE_LOCAL mode, we simply simply take all packets // that come from "Tap Device" and ask "ns3 Device" to send them down its // directly connected network. To to this, we just need to remove the // Ethernet header (which was done for us by the Filter () method), and then @@ -677,16 +696,15 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) // what to do if the bridged device does not support SendFrom, which will be // the case for Wifi STA nodes. // - NS_LOG_LOGIC ("Forwarding packet"); - if (m_bridgedDevice->SupportsSendFrom ()) + if (m_mode == USE_BRIDGE) { m_bridgedDevice->SendFrom (packet, src, dst, type); } else { - NS_FATAL_ERROR ("TapBridge::ForwardToBridgedDevice(): Bridged device does not support SendFrom"); + m_bridgedDevice->Send (packet, dst, type); } } @@ -698,7 +716,7 @@ TapBridge::Filter (Ptr p, Address *src, Address *dst, uint16_t *type) // // We have a candidate packet for injection into ns-3. We expect that since - // it came over a socket that provides Ethernet packets, it sould be big + // it came over a socket that provides Ethernet packets, it should be big // enough to hold an EthernetHeader. If it can't, we signify the packet // should be filtered out by returning 0. // @@ -772,7 +790,7 @@ TapBridge::SetBridgedNetDevice (Ptr bridgedDevice) NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support eui 48 addresses: cannot be added to bridge."); } - if (!bridgedDevice->SupportsSendFrom ()) + if (m_mode == USE_BRIDGE && !bridgedDevice->SupportsSendFrom ()) { NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support SendFrom: cannot be added to bridge."); } @@ -781,12 +799,12 @@ TapBridge::SetBridgedNetDevice (Ptr bridgedDevice) // Tell the bridged device to forward its received packets here. We use the // promiscuous mode hook to get both the source and destination addresses. // - m_node->RegisterProtocolHandler (MakeCallback (&TapBridge::ReceiveFromBridgedDevice, this), 0, bridgedDevice, true); + m_node->RegisterProtocolHandler (MakeCallback (&TapBridge::ReceiveFromSimDevice, this), 0, bridgedDevice, true); m_bridgedDevice = bridgedDevice; } void -TapBridge::ReceiveFromBridgedDevice ( +TapBridge::ReceiveFromSimDevice ( Ptr device, Ptr packet, uint16_t protocol, @@ -799,11 +817,33 @@ TapBridge::ReceiveFromBridgedDevice ( NS_LOG_DEBUG ("Packet UID is " << packet->GetUid ()); + if (m_mode == CONFIGURE_LOCAL && packetType == PACKET_OTHERHOST) + { + // We hooked the promiscuous mode protocol handler so we could get the + // destination address of the actual packet. This means we will be + // getting PACKET_OTHERHOST packets (not broadcast, not multicast, not + // unicast to the ns-3 net device, but to some other address). In + // CONFIGURE_LOCAL mode we are not interested in these packets since they + // don't refer to the single MAC address shared by the ns-3 device and + // the TAP device. If, however, we are in USE_LOCAL or USE_BRIDGE mode, + // we want to act like a bridge and forward these + // PACKET_OTHERHOST packets. + return; + } + Mac48Address from = Mac48Address::ConvertFrom (src); - Mac48Address to = Mac48Address::ConvertFrom (dst); + Mac48Address to; + if (m_mode == USE_LOCAL) + { + to = Mac48Address::ConvertFrom (m_learnedMac); + } + else + { + to = Mac48Address::ConvertFrom (dst); + } // - // If we are operating in BRIDGED_DEVICE mode, we have the situation described + // If we are operating in USE_BRIDGE mode, we have the situation described // below: // // Other Device <--> Tap Device <--> ns3 device @@ -817,14 +857,14 @@ TapBridge::ReceiveFromBridgedDevice ( // (modulo learning behavior) sent out to "Other Device." This makes it // appear as if both devices are on a single subnet. // - // In BRIDGED_DEVICE mode, we want to logically extend this Linux behavior + // In USE_BRIDGE mode, we want to logically extend this Linux behavior // to the ns3 device and make it appear as if it is connected to the Linux // subnet. As you may expect, this means that we need to act like a real // bridge and do what is described above. The code here will do the // equivalent of a SendFrom on the "Tap Device" of the bits received on the // ns-3 device. // - // If we are operating in LOCAL_DEVICE mode, we simply simply take all packets + // If we are operating in CONFIGURE_LOCAL mode, we simply simply take all packets // that would normally be received by the device and forward them to the TAP // device as if the ns-3 net device was never there. To to this, we just need // to reconstruct an Ethernet header and add the original source and @@ -835,19 +875,6 @@ TapBridge::ReceiveFromBridgedDevice ( // even though they seem quite different at first glance. // - if (m_mode == LOCAL_DEVICE && packetType == PACKET_OTHERHOST) - { - // We hooked the promiscuous mode protocol handler so we could get the - // destination address of the actual packet. This means we will be - // getting PACKET_OTHERHOST packets (not broadcast, not multicast, not - // unicast to the ns-3 net device, but to some other address). In - // LOCAL_DEVICE mode we are not interested in these packets since they - // don't refer to the single MAC address shared by the ns-3 device and - // the TAP device. If, however, we are in BRIDGED_DEVICE mode, we want - // to act like a bridge and forward these PACKET_OTHERHOST packets. - return; - } - // // We have received a packet from the ns-3 net device that has been associated // with this bridge. We want to take these bits and send them off to the @@ -873,7 +900,7 @@ TapBridge::ReceiveFromBridgedDevice ( NS_LOG_LOGIC ("Pkt size is " << p->GetSize ()); uint32_t bytesWritten = write (m_sock, p->PeekData (), p->GetSize ()); - NS_ABORT_MSG_IF (bytesWritten != p->GetSize (), "TapBridge::ReceiveFromBridgedDevice(): Write error."); + NS_ABORT_MSG_IF (bytesWritten != p->GetSize (), "TapBridge::ReceiveFromSimDevice(): Write error."); } void diff --git a/src/devices/tap-bridge/tap-bridge.h b/src/devices/tap-bridge/tap-bridge.h index 1b399cad0..8b5fae7e1 100644 --- a/src/devices/tap-bridge/tap-bridge.h +++ b/src/devices/tap-bridge/tap-bridge.h @@ -105,8 +105,9 @@ public: */ enum Mode { ILLEGAL, /**< mode not set */ - LOCAL_DEVICE, /**< ns-3 creates and configures TAP device */ - BRIDGED_DEVICE, /**< user creates and configures TAP */ + CONFIGURE_LOCAL, /**< ns-3 creates and configures tap device */ + USE_LOCAL, /**< ns-3 uses a pre-created tap, without configuring it */ + USE_BRIDGE, /**< ns-3 uses a pre-created tap, and bridges to a bridging net device */ }; TapBridge (); @@ -209,7 +210,7 @@ protected: */ virtual void DoDispose (void); - void ReceiveFromBridgedDevice (Ptr device, Ptr packet, uint16_t protocol, + void ReceiveFromSimDevice (Ptr device, Ptr packet, uint16_t protocol, Address const &src, Address const &dst, PacketType packetType); private: @@ -264,7 +265,7 @@ private: * received from the host. * \param buf The length of the buffer. */ - void ForwardToBridgedDevice (uint8_t *buf, uint32_t len); + void ForwardToSimDevice (uint8_t *buf, uint32_t len); /** * \internal @@ -426,18 +427,11 @@ private: /** * \internal * - * The MAC address to use as the hardware address on the host. This can - * come from one of two places depending on the operating mode. - * - * If the TapBridge is in LocalDevice mode, this value comes from the MAC + * The MAC address to use as the hardware address on the host; only used + * in UseLocal mode. This value comes from the MAC * address assigned to the bridged ns-3 net device and matches the MAC * address of the underlying network TAP which we configured to have the * same value. - * - * If the TapBridge is in BridgedDevice mode, this value is learned from - * from the packets received by the underlying netowrk TAP. This is - * because we did not configure the TAP, but have got to spoof packets - * destined for there. */ Mac48Address m_tapMac; @@ -454,6 +448,17 @@ private: * The ns-3 net device to which we are bridging. */ Ptr m_bridgedDevice; + /** + * \internal + * + * The MAC address of the local tap device is stored in this variable. + * When in UseLocal mode, this address is added back to the destination + * Mac address for frames destined to the tap device. It is learned from + * the first frame sent from the host to the TapBridge device. In the + * other modes of this device, this value is unused. + */ + Mac48Address m_learnedMac; + }; } // namespace ns3 diff --git a/src/devices/tap-bridge/tap-creator.cc b/src/devices/tap-bridge/tap-creator.cc index 7c82de7e6..54ffe0b51 100644 --- a/src/devices/tap-bridge/tap-creator.cc +++ b/src/devices/tap-bridge/tap-creator.cc @@ -39,7 +39,7 @@ #define TAP_MAGIC 95549 -static int gVerbose = 0; // Set to true to turn on logging messages. +static int gVerbose = 1; // Set to true to turn on logging messages. #define LOG(msg) \ if (gVerbose) \ @@ -295,13 +295,15 @@ CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, con LOG ("Allocated TAP device " << tapDeviceName); // - // Operating mode "2" corresponds to BRIDGED_DEVICE mode. This means that + // Operating mode "2" corresponds to USE_LOCAL and "3" to USE_BRIDGE mode. + // This means that // we expect that the user will have named, created and configured a network // tap that we are just going to use. So don't mess up his hard work by // changing anything, just return the tap fd. // - if (strcmp (mode, "2") == 0) + if (strcmp (mode, "2") == 0 || strcmp (mode, "3") == 0) { + LOG ("Returning precreated tap "); return tap; } diff --git a/src/devices/tap-bridge/wscript b/src/devices/tap-bridge/wscript index 0939c1a98..81db5e4ba 100644 --- a/src/devices/tap-bridge/wscript +++ b/src/devices/tap-bridge/wscript @@ -27,6 +27,7 @@ def build(bld): module.source.extend([ 'tap-bridge.cc', 'tap-encode-decode.cc', + 'tap-creator.cc', ]) headers.source.extend([ 'tap-bridge.h', diff --git a/src/helper/tap-bridge-helper.cc b/src/helper/tap-bridge-helper.cc index 70c638eb0..2087df5bd 100644 --- a/src/helper/tap-bridge-helper.cc +++ b/src/helper/tap-bridge-helper.cc @@ -18,6 +18,7 @@ #include "ns3/log.h" #include "ns3/node.h" +#include "ns3/enum.h" #include "ns3/tap-bridge.h" #include "ns3/names.h" #include "tap-bridge-helper.h" @@ -26,11 +27,18 @@ NS_LOG_COMPONENT_DEFINE ("TapBridgeHelper"); namespace ns3 { +TapBridgeHelper::TapBridgeHelper () +{ + NS_LOG_FUNCTION_NOARGS (); + m_deviceFactory.SetTypeId ("ns3::TapBridge"); +} + TapBridgeHelper::TapBridgeHelper (Ipv4Address gateway) { NS_LOG_FUNCTION_NOARGS (); m_deviceFactory.SetTypeId ("ns3::TapBridge"); SetAttribute ("Gateway", Ipv4AddressValue (gateway)); + SetAttribute ("Mode", EnumValue(TapBridge::CONFIGURE_LOCAL)); } void @@ -41,6 +49,14 @@ TapBridgeHelper::SetAttribute (std::string n1, const AttributeValue &v1) } +Ptr +TapBridgeHelper::Install (Ptr node, Ptr nd, const AttributeValue &v1) +{ + NS_LOG_FUNCTION (node << nd << &v1); + m_deviceFactory.Set ("DeviceName", v1); + return Install (node, nd); +} + Ptr TapBridgeHelper::Install (Ptr node, Ptr nd) { diff --git a/src/helper/tap-bridge-helper.h b/src/helper/tap-bridge-helper.h index 6e6a7a238..0ac7460a7 100644 --- a/src/helper/tap-bridge-helper.h +++ b/src/helper/tap-bridge-helper.h @@ -21,6 +21,7 @@ #include "net-device-container.h" #include "ns3/object-factory.h" +#include "ns3/tap-bridge.h" #include namespace ns3 { @@ -31,12 +32,14 @@ class AttributeValue; class TapBridgeHelper { public: + TapBridgeHelper (); TapBridgeHelper (Ipv4Address gateway); void SetAttribute (std::string n1, const AttributeValue &v1); Ptr Install (Ptr node, Ptr nd); Ptr Install (std::string nodeName, Ptr nd); Ptr Install (Ptr node, std::string ndName); Ptr Install (std::string nodeName, std::string ndName); + Ptr Install (Ptr node, Ptr nd, const AttributeValue &v1); private: ObjectFactory m_deviceFactory; };