wire needed values into tap-bridge Attribute system, but figure out as many as possible in the default case
authorCraig Dowell <craigdo@ee.washington.edu>
Thu, 29 Jan 2009 11:53:12 -0800
changeset 4167 7e444dc749ee
parent 4166 eaba645ea35c
child 4168 3d8f0d101f79
wire needed values into tap-bridge Attribute system, but figure out as many as possible in the default case
examples/csma-tap-bridge.cc
src/devices/tap-bridge/tap-bridge.cc
src/devices/tap-bridge/tap-bridge.h
src/helper/tap-bridge-helper.cc
src/helper/tap-bridge-helper.h
--- a/examples/csma-tap-bridge.cc	Tue Jan 27 22:00:29 2009 -0800
+++ b/examples/csma-tap-bridge.cc	Thu Jan 29 11:53:12 2009 -0800
@@ -20,6 +20,7 @@
 //  | external |                           | external |  
 //  |  Linux   |                           |  Linux   |  
 //  |   Host   |                           |   Host   |  
+//  |  "left"  |                           | "right"  |  
 //  +----------+                           +----------+
 //       |           n0             n3           |
 //       |       +--------+     +--------+       |
@@ -91,34 +92,59 @@
   internet.Install (nodes);
 
   //
-  // Add the tap bridges to nodes zero and one to enable external Linux 
-  // processes to talk to the CSMA devices.
+  // We've got the "hardware" in place.  Now add IP addresses.
   //
-  TapBridgeHelper bridge;
-  NetDeviceContainer bridgeDevices;
-  bridgeDevices.Add (bridge.Install (nodes.Get (0), devices.Get (0)));
-  bridgeDevices.Add (bridge.Install (nodes.Get (3), devices.Get (3)));
+  NS_LOG_INFO ("Assign IP Addresses.");
+  Ipv4AddressHelper ipv4;
+  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+  Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
 
   //
-  // We've got the "hardware" in place.  Now add IP addresses.  We mjust not
-  // add IP addresses to the devices that we bridged using the TapBridgeHelper
-  // above.  The IP addresses are added to the bridge itself and are propagated
-  // to the tap device on the host.  We do need to add IP addresses to the CSMA
-  // devices that are attached to the nodes that are entirely contained within
-  // the simulation (not connected to any other external host).
+  // The Tap bridge is going to use the address information we just created
+  // when it makes a Tap device on the Linux host.  This actually happens
+  // when the simulation is started, so there is no dependence on ordering
+  // of the IP and MAC address assignment in the initialization phase of
+  // the simulation.
+  //
+  // The Tap bridge will suck the MAC address out of the bridged device, and 
+  // the IP address and net mask out of the Ipv4Interface which is associated 
+  // with the bridged device.  It will use these found values unless we 
+  // configure Attribute to provide alternate values.  There are two 
+  // configuration Attributes we always need to pay some attention to.
+  //
+  // The "Gateway" Attribute is the IP address of the default gateway that 
+  // will be set on the newly created Tap devices on the Linux hosts.  We
+  // can't derive this address, so it must be set.  Following standard 
+  // practice in helpers, this Attribute is a construction parameter for
+  // the Helper.  Here, we pick the interface corresponding to the 
+  // CSMA device on node one as the default gateway.  You can change this
+  // at a later time by setting the "Gateway" Attribute in the helper.
+  //
+  TapBridgeHelper bridge (interfaces.GetAddress (1));
+
   //
-  NS_LOG_INFO ("Assign IP Addresses.");
-  NetDeviceContainer ndc;
-  ndc.Add (bridgeDevices.Get (0));
-  ndc.Add (devices.Get (1));
-  ndc.Add (devices.Get (2));
-  ndc.Add (bridgeDevices.Get (0));
-          
-  Ipv4AddressHelper ipv4;
-  ipv4.SetBase ("10.1.1.0", "255.255.255.0");
-  Ipv4InterfaceContainer interfaces = ipv4.Assign (ndc);
+  // The "DeviceName" is the name of the Tap device that will be created on
+  // the Linux host.  If we leave this Attribute set to the default value,
+  // the Linux system will create on of the name /dev/tapx where x will be 
+  // a number from 0 to 255.  In a simulation where you have some number of
+  // Tap devices, it is convenient to assign a name.  Referring back to the 
+  // topology illustration, we assign the name "left" to the tap device on
+  // the host to the left of the diagram, and "right" to the host on the right.
+  //
+  // Create a tap-bridge on node zero, create a Tap device called "left" on the
+  // Linux host and bridge that Linux device to the CSMA device on node zero.
+  //
+  bridge.SetAttribute ("DeviceName", StringValue ("left"));
+  bridge.Install (nodes.Get (0), devices.Get (0));
 
-#if 1
+  //
+  // Create a tap-bridge on node three, create a Tap device called "right" on the
+  // Linux host and bridge that Linux device to the CSMA device on node three.
+  //
+  bridge.SetAttribute ("DeviceName", StringValue ("right"));
+  bridge.Install (nodes.Get (3), devices.Get (3));
+
+#if 0
   //
   // Testing only -- send a packet from an internal node to an external node
   //
--- a/src/devices/tap-bridge/tap-bridge.cc	Tue Jan 27 22:00:29 2009 -0800
+++ b/src/devices/tap-bridge/tap-bridge.cc	Thu Jan 29 11:53:12 2009 -0800
@@ -27,6 +27,7 @@
 #include "ns3/log.h"
 #include "ns3/boolean.h"
 #include "ns3/string.h"
+#include "ns3/ipv4.h"
 #include "ns3/simulator.h"
 #include "ns3/realtime-simulator-impl.h"
 #include "ns3/system-thread.h"
@@ -64,26 +65,26 @@
                    StringValue (""),
                    MakeStringAccessor (&TapBridge::m_tapDeviceName),
                    MakeStringChecker ())
-    .AddAttribute ("TapGateway", 
+    .AddAttribute ("Gateway", 
                    "The IP address of the default gateway to assign to the tap device.",
-                   StringValue (""),
-                   MakeStringAccessor (&TapBridge::m_tapGateway),
-                   MakeStringChecker ())
-    .AddAttribute ("TapIp", 
+                   Ipv4AddressValue ("255.255.255.255"),
+                   MakeIpv4AddressAccessor (&TapBridge::m_tapGateway),
+                   MakeIpv4AddressChecker ())
+    .AddAttribute ("IpAddress", 
                    "The IP address to assign to the tap device.",
-                   StringValue (""),
-                   MakeStringAccessor (&TapBridge::m_tapIp),
-                   MakeStringChecker ())
-    .AddAttribute ("TapMac", 
+                   Ipv4AddressValue ("255.255.255.255"),
+                   MakeIpv4AddressAccessor (&TapBridge::m_tapIp),
+                   MakeIpv4AddressChecker ())
+    .AddAttribute ("MacAddress", 
                    "The MAC address to assign to the tap device.",
-                   StringValue (""),
-                   MakeStringAccessor (&TapBridge::m_tapMac),
-                   MakeStringChecker ())
-    .AddAttribute ("TapNetmask", 
+                   Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
+                   MakeMac48AddressAccessor (&TapBridge::m_tapMac),
+                   MakeMac48AddressChecker ())
+    .AddAttribute ("Netmask", 
                    "The network mask to assign to the tap device.",
-                   StringValue (""),
-                   MakeStringAccessor (&TapBridge::m_tapMac),
-                   MakeStringChecker ())
+                   Ipv4MaskValue ("255.255.255.255"),
+                   MakeIpv4MaskAccessor (&TapBridge::m_tapNetmask),
+                   MakeIpv4MaskChecker ())
     .AddAttribute ("Start", 
                    "The simulation time at which to spin up the tap device read thread.",
                    TimeValue (Seconds (0.)),
@@ -114,6 +115,7 @@
 TapBridge::~TapBridge()
 {
   NS_LOG_FUNCTION_NOARGS ();
+  m_bridgedDevice = 0;
 }
 
   void 
@@ -265,7 +267,7 @@
       // build a command line argument from the encoded endpoint string that 
       // the socket creation process will use to figure out how to respond to
       // the (now) parent process.  We're going to have to give this program
-      // quite a bit of information and we use program arguments to do so.
+      // quite a bit of information.
       //
       // -d<device-name> The name of the tap device we want to create;
       // -g<gateway-address> The IP address to use as the default gateway;
@@ -276,9 +278,81 @@
       //
       // Example tap-sock-creator -dnewdev -g1.2.3.2 -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -pblah
       //
+      // We want to get as much of this stuff automagically as possible.
+      //
+      // <IP-address> is the IP address we are going to set in the newly 
+      // created Tap device on the Linux host.  At the point in the simulation
+      // where devices are coming up, we should have all of our IP addresses
+      // assigned.  That means that we can find the IP address to assign to 
+      // the new Tap device from the IP address associated with the bridged
+      // net device.
+      //
+      Ptr<NetDevice> nd = GetBridgedNetDevice ();
+      Ptr<Node> n = nd->GetNode ();
+      Ptr<Ipv4> ipv4 = n->GetObject<Ipv4> ();
+      uint32_t index = ipv4->FindInterfaceForDevice (nd);
+      Ipv4Address ipv4Address = ipv4->GetAddress (index);
+
+      //
+      // The net mask is sitting right there next to the ipv4 address.
+      //
+      Ipv4Mask ipv4Mask = ipv4->GetNetworkMask (index);
+
+      //
+      // The MAC address should also already be assigned and waiting for us in
+      // the bridged net device.
+      //
+      Address address = nd->GetAddress ();
+      Mac48Address mac48Address = Mac48Address::ConvertFrom (address);
+
+      //
+      // The device-name is something we may want the system to make up in 
+      // every case.  We also rely on it being configured via an Attribute 
+      // through the helper.  By default, it is set to the empty string 
+      // which tells the system to make up a device name such as "tap123".
+      //
       std::ostringstream oss;
-      oss << "-d" << m_tapDeviceName << " -g" << m_tapGateway << " -i" << m_tapIp << " -m" << m_tapMac
-          << " -n" << m_tapNetmask << " -p" << path;
+      oss << "-d" << m_tapDeviceName;
+
+      //
+      // The gateway-address is something we can't derive, so we rely on it
+      // being configured via an Attribute through the helper.
+      //
+      oss << " -g" << m_tapGateway;
+
+      //
+      // For flexibility, we do allow a client to override any of the values
+      // above via attributes, so only use our found values if the Attribute
+      // is not equal to its default value (empty string or broadcast address). 
+      //
+      if (m_tapIp.IsBroadcast ())
+        {
+          oss << " -i" << ipv4Address;
+        }
+      else
+        {
+          oss << " -i" << m_tapIp;
+        }
+
+      if (m_tapMac.IsBroadcast ())
+        {
+          oss << " -m" << mac48Address;
+        }
+      else
+        {
+          oss << " -m" << m_tapMac;
+        }
+
+      if (m_tapNetmask.IsEqual (Ipv4Mask::GetOnes ()))
+        {
+          oss << " -n" << ipv4Mask;
+        }
+      else
+        {
+          oss << " -n" << m_tapNetmask;
+        }
+
+      oss << " -p" << path;
       NS_LOG_INFO ("creator arguments set to \"" << oss.str () << "\"");
 
       //
@@ -514,8 +588,15 @@
   m_bridgedDevice->SendFrom (packet, header.GetSource (), header.GetDestination (), 0x800);
 }
 
+Ptr<NetDevice>
+TapBridge::GetBridgedNetDevice (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_bridgedDevice;
+}
+
 void 
-TapBridge::SetBridgedDevice (Ptr<NetDevice> bridgedDevice)
+TapBridge::SetBridgedNetDevice (Ptr<NetDevice> bridgedDevice)
 {
   NS_LOG_FUNCTION_NOARGS ();
 
--- a/src/devices/tap-bridge/tap-bridge.h	Tue Jan 27 22:00:29 2009 -0800
+++ b/src/devices/tap-bridge/tap-bridge.h	Thu Jan 29 11:53:12 2009 -0800
@@ -77,7 +77,12 @@
   TapBridge ();
   virtual ~TapBridge ();
 
-  /** \brief Set the device to bridge.
+  /** \brief Get the bridged net device.
+   * \returns the bridged net device.
+   */
+  Ptr<NetDevice> GetBridgedNetDevice (void);
+
+  /** \brief Set the ns-3 net device to bridge.
    *
    * This method tells the bridge which ns-3 net device it should use to connect
    * the simulation side of the bridge.  
@@ -85,7 +90,7 @@
    * \attention The ns-3 net device that is being set as the device must not 
    * have an IP address.  This address is a property of the host Linux device.
    */
-  void SetBridgedDevice (Ptr<NetDevice> bridgedDevice);
+  void SetBridgedNetDevice (Ptr<NetDevice> bridgedDevice);
 
   /**
    * Set a start time for the device.
@@ -189,10 +194,10 @@
   Time m_tStop;
 
   std::string m_tapDeviceName;
-  std::string m_tapGateway;
-  std::string m_tapIp;
-  std::string m_tapMac;
-  std::string m_tapNetmask;
+  Ipv4Address m_tapGateway;
+  Ipv4Address m_tapIp;
+  Mac48Address m_tapMac;
+  Ipv4Mask m_tapNetmask;
 
   Ptr<NetDevice> m_bridgedDevice;
 };
--- a/src/helper/tap-bridge-helper.cc	Tue Jan 27 22:00:29 2009 -0800
+++ b/src/helper/tap-bridge-helper.cc	Thu Jan 29 11:53:12 2009 -0800
@@ -25,14 +25,15 @@
 
 namespace ns3 {
 
-TapBridgeHelper::TapBridgeHelper ()
+TapBridgeHelper::TapBridgeHelper (Ipv4Address gateway)
 {
   NS_LOG_FUNCTION_NOARGS ();
   m_deviceFactory.SetTypeId ("ns3::TapBridge");
+  SetAttribute ("Gateway", Ipv4AddressValue (gateway));
 }
 
 void 
-TapBridgeHelper::SetDeviceAttribute (std::string n1, const AttributeValue &v1)
+TapBridgeHelper::SetAttribute (std::string n1, const AttributeValue &v1)
 {
   NS_LOG_FUNCTION (n1 << &v1);
   m_deviceFactory.Set (n1, v1);
@@ -46,7 +47,7 @@
 
   Ptr<TapBridge> bridge = m_deviceFactory.Create<TapBridge> ();
   node->AddDevice (bridge);
-  bridge->SetBridgedDevice (nd);
+  bridge->SetBridgedNetDevice (nd);
 
   return bridge;
 }
--- a/src/helper/tap-bridge-helper.h	Tue Jan 27 22:00:29 2009 -0800
+++ b/src/helper/tap-bridge-helper.h	Thu Jan 29 11:53:12 2009 -0800
@@ -31,8 +31,8 @@
 class TapBridgeHelper
 {
 public:
-  TapBridgeHelper ();
-  void SetDeviceAttribute (std::string n1, const AttributeValue &v1);
+  TapBridgeHelper (Ipv4Address gateway);
+  void SetAttribute (std::string n1, const AttributeValue &v1);
   Ptr<NetDevice> Install (Ptr<Node> node, Ptr<NetDevice> nd);
 private:
   ObjectFactory m_deviceFactory;