src/devices/tap-bridge/tap-bridge.cc
changeset 4289 2f5b0ec50102
parent 4286 2cabb9cfae98
child 4290 af8a40d5c2cb
--- 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