initial modifications to tap-bridge
authorcore@samcore1.nettech.boeing.com
Sat, 21 Mar 2009 15:40:49 -0700
changeset 4289 2f5b0ec50102
parent 4288 8a999429091b
child 4290 af8a40d5c2cb
initial modifications to tap-bridge
src/devices/tap-bridge/tap-bridge.cc
src/devices/tap-bridge/tap-bridge.h
src/devices/tap-bridge/tap-creator.cc
src/devices/tap-bridge/wscript
src/helper/tap-bridge-helper.cc
src/helper/tap-bridge-helper.h
--- a/src/devices/tap-bridge/tap-bridge.cc	Tue Mar 17 16:00:46 2009 -0700
+++ b/src/devices/tap-bridge/tap-bridge.cc	Sat Mar 21 15:40:49 2009 -0700
@@ -80,22 +80,22 @@
                    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 @@
                    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 @@
   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 @@
   // 
   // 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 @@
       // -i<IP-address> The IP address to assign to the new tap device;
       // -m<MAC-address> The MAC-48 address to assign to the new tap device;
       // -n<network-mask> The network mask to assign to the new tap device;
-      // -o<operating mode> The operating mode of the bridge (1=LocalDevice, 2=BridgedDevice)
+      // -o<operating mode> The operating mode of the bridge (1=ConfigureLocal, 2=UseLocal, 3=UseBridge)
       // -p<path> 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,13 +383,17 @@
 
       std::ostringstream ossMode;
       ossMode << "-o";
-      if (m_mode == LOCAL_DEVICE)
+      if (m_mode == CONFIGURE_LOCAL)
         {
           ossMode << "1";
         }
+      else if (m_mode == USE_LOCAL)
+        {
+          ossMode << "2";
+        }
       else
         {
-          ossMode << "2";
+          ossMode << "3";
         }
 
       std::ostringstream ossPath;
@@ -590,11 +596,12 @@
       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 @@
       NS_LOG_INFO ("TapBridge::ReadThread(): Received packet");
       NS_LOG_INFO ("TapBridge::ReadThread(): Scheduling handler");
       DynamicCast<RealtimeSimulatorImpl> (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 @@
   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 @@
   // (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 @@
   // 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 @@
 
   //
   // 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 @@
       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 @@
   // 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<NetDevice> device, 
   Ptr<const Packet> packet, 
   uint16_t protocol,
@@ -799,11 +817,33 @@
   
   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 @@
   // (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 @@
   // 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 @@
   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 
--- a/src/devices/tap-bridge/tap-bridge.h	Tue Mar 17 16:00:46 2009 -0700
+++ b/src/devices/tap-bridge/tap-bridge.h	Sat Mar 21 15:40:49 2009 -0700
@@ -105,8 +105,9 @@
    */
   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 @@
    */
   virtual void DoDispose (void);
 
-  void ReceiveFromBridgedDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
+  void ReceiveFromSimDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
                                  Address const &src, Address const &dst, PacketType packetType);
 private:
 
@@ -264,7 +265,7 @@
    *            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 @@
   /**
    * \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 @@
    * The ns-3 net device to which we are bridging.
    */
   Ptr<NetDevice> 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
--- a/src/devices/tap-bridge/tap-creator.cc	Tue Mar 17 16:00:46 2009 -0700
+++ b/src/devices/tap-bridge/tap-creator.cc	Sat Mar 21 15:40:49 2009 -0700
@@ -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 @@
   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;
     }
 
--- a/src/devices/tap-bridge/wscript	Tue Mar 17 16:00:46 2009 -0700
+++ b/src/devices/tap-bridge/wscript	Sat Mar 21 15:40:49 2009 -0700
@@ -27,6 +27,7 @@
         module.source.extend([
                 'tap-bridge.cc',
                 'tap-encode-decode.cc',
+                'tap-creator.cc',
                 ])
         headers.source.extend([
                 'tap-bridge.h',
--- a/src/helper/tap-bridge-helper.cc	Tue Mar 17 16:00:46 2009 -0700
+++ b/src/helper/tap-bridge-helper.cc	Sat Mar 21 15:40:49 2009 -0700
@@ -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 @@
 
 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 @@
 }
 
 
+Ptr<NetDevice>
+TapBridgeHelper::Install (Ptr<Node> node, Ptr<NetDevice> nd, const AttributeValue &v1)
+{
+  NS_LOG_FUNCTION (node << nd << &v1);
+  m_deviceFactory.Set ("DeviceName", v1);
+  return Install (node, nd);
+}
+
   Ptr<NetDevice>
 TapBridgeHelper::Install (Ptr<Node> node, Ptr<NetDevice> nd)
 {
--- a/src/helper/tap-bridge-helper.h	Tue Mar 17 16:00:46 2009 -0700
+++ b/src/helper/tap-bridge-helper.h	Sat Mar 21 15:40:49 2009 -0700
@@ -21,6 +21,7 @@
 
 #include "net-device-container.h"
 #include "ns3/object-factory.h"
+#include "ns3/tap-bridge.h"
 #include <string>
 
 namespace ns3 {
@@ -31,12 +32,14 @@
 class TapBridgeHelper
 {
 public:
+  TapBridgeHelper ();
   TapBridgeHelper (Ipv4Address gateway);
   void SetAttribute (std::string n1, const AttributeValue &v1);
   Ptr<NetDevice> Install (Ptr<Node> node, Ptr<NetDevice> nd);
   Ptr<NetDevice> Install (std::string nodeName, Ptr<NetDevice> nd);
   Ptr<NetDevice> Install (Ptr<Node> node, std::string ndName);
   Ptr<NetDevice> Install (std::string nodeName, std::string ndName);
+  Ptr<NetDevice> Install (Ptr<Node> node, Ptr<NetDevice> nd, const AttributeValue &v1);
 private:
   ObjectFactory m_deviceFactory;
 };