first cut at enabling OpenVZ scenario
authorCraig Dowell <craigdo@ee.washington.edu>
Fri, 13 Mar 2009 17:37:35 -0700
changeset 4285 2b197a6b4460
parent 4261 82be63aaf35a
child 4286 2cabb9cfae98
first cut at enabling OpenVZ scenario
src/devices/csma/csma-net-device.h
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/tap.h
--- a/src/devices/csma/csma-net-device.h	Wed Mar 11 11:16:25 2009 +0000
+++ b/src/devices/csma/csma-net-device.h	Fri Mar 13 17:37:35 2009 -0700
@@ -61,7 +61,6 @@
 
   /**
    * Enumeration of the types of packets supported in the class.
-   *
    */
   enum EncapsulationMode {
     ILLEGAL,     /**< Encapsulation mode not set */
--- a/src/devices/tap-bridge/tap-bridge.cc	Wed Mar 11 11:16:25 2009 +0000
+++ b/src/devices/tap-bridge/tap-bridge.cc	Fri Mar 13 17:37:35 2009 -0700
@@ -28,6 +28,7 @@
 #include "ns3/abort.h"
 #include "ns3/boolean.h"
 #include "ns3/string.h"
+#include "ns3/enum.h"
 #include "ns3/ipv4.h"
 #include "ns3/simulator.h"
 #include "ns3/realtime-simulator-impl.h"
@@ -48,10 +49,7 @@
 // if you are running in an environment where you have got to run as root,
 // such as ORBIT or CORE.
 //
-//   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
-//
+
 
 // #define NO_CREATOR
 
@@ -111,6 +109,12 @@
                    TimeValue (Seconds (0.)),
                    MakeTimeAccessor (&TapBridge::m_tStop),
                    MakeTimeChecker ())
+    .AddAttribute ("Mode", 
+                   "The operating and configuration mode (LocalDevice or BridgedDevice) to use.",
+                   EnumValue (LOCAL_DEVICE),
+                   MakeEnumAccessor (&TapBridge::SetMode),
+                   MakeEnumChecker (LOCAL_DEVICE, "LocalDevice",
+                                    BRIDGED_DEVICE, "BridgedDevice"))
     ;
   return tid;
 }
@@ -215,35 +219,27 @@
 {
   NS_LOG_FUNCTION_NOARGS ();
 
-#ifdef NO_CREATOR
-  //
-  // In come cases, can you say FreeBSD, the tap-creator just gets in the way.
-  // in this case, just define NO_CREATOR, manually set up your tap device and
-  // just open and use it.
+  // 
+  // 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
+  // responsibility for creating and configuring the TAP.
   //
-  //
-  // Creation and management of Tap devices is done via the tun device
-  //
-  m_sock = open ("/dev/net/tun", O_RDWR);
-  NS_ABORT_MSG_IF (m_sock == -1, "TapBridge::CreateTap(): could not open /dev/net/tun: " << strerror (errno));
-
+  // In BridgedDevice mode, the user will provide us a configuration and we have
+  // to adapt to it.  For example, the user will do something like:
   //
-  // Allocate a tap device, making sure that it will not send the tun_pi header.
-  // If we provide a null name to the ifr.ifr_name, we tell the kernel to pick
-  // a name for us (i.e., tapn where n = 0..255
+  //   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
   //
-  struct ifreq ifr;
-  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
-  strcpy (ifr.ifr_name, m_tapDeviceName.c_str ());
-  int status = ioctl (m_sock, TUNSETIFF, (void *) &ifr);
-  NS_ABORT_MSG_IF (status == -1, "TapBridge::CreateTap(): could not open device " << m_tapDeviceName << 
-                   ": " << strerror (errno));
-
-#else // use the tap-creator
-
+  // set the "Mode" Attribute to "BridgedDevice" and the "DeviceName" Attribute
+  // to "tap0" in this case.
   //
-  // We want to create a tap device on the host.  Unfortunately for us
-  // you have to have root privileges to do that.  Instead of running the 
+  // In LocalDevice 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
+  // us you have to have root privileges to do that.  Instead of running the 
   // entire simulation as root, we decided to make a small program who's whole
   // reason for being is to run as suid root and do what it takes to create the
   // tap.  We're going to fork and exec that program soon, but we need to have 
@@ -300,9 +296,10 @@
       // -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)
       // -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 -pblah
+      // Example tap-creator -dnewdev -g1.2.3.2 -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -o1 -pblah
       //
       // We want to get as much of this stuff automagically as possible.
       //
@@ -382,6 +379,17 @@
           ossNetmask << "-n" << m_tapNetmask;
         }
 
+      std::ostringstream ossMode;
+      ossMode << "-o";
+      if (m_mode == LOCAL_DEVICE)
+        {
+          ossMode << "1";
+        }
+      else
+        {
+          ossMode << "2";
+        }
+
       std::ostringstream ossPath;
       ossPath << "-p" << path;
       //
@@ -394,7 +402,8 @@
                         ossIp.str ().c_str (),                // argv[3] (-i<IP address>)
                         ossMac.str ().c_str (),               // argv[4] (-m<MAC address>)
                         ossNetmask.str ().c_str (),           // argv[5] (-n<net mask>)
-                        ossPath.str ().c_str (),              // argv[6] (-p<path>)
+                        ossMode.str ().c_str (),              // argv[6] (-o<operating mode>)
+                        ossPath.str ().c_str (),              // argv[7] (-p<path>)
                         (char *)NULL);
 
       //
@@ -521,7 +530,6 @@
 	}
       NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
     }
-#endif // use the tap-creator
 }
 
 std::string
@@ -634,6 +642,32 @@
   NS_LOG_LOGIC ("Pkt destination is " << dst);
   NS_LOG_LOGIC ("Pkt LengthType is " << type);
 
+  //
+  // If we are in BridgedDevice mode, the MAC addresses of the bridged device
+  // and the TAP device will be different.  If this is a unicast packet, we
+  // need to remember the source MAC address for the trip back the other way.
+  // Only remember the first such address and error out if we find another
+  // one since "that can't happen."  We use the variable m_tapMac for 
+  // remembering this (set by the Attribute "MacAddress") which allows a 
+  // user to override the remembered address.
+  //
+  Mac48Address mac48Source = Mac48Address::ConvertFrom (src);
+  if (m_mode == BRIDGED_DEVICE)
+    {
+      if (mac48Source.IsBroadcast () == false && mac48Source.IsMulticast () == false)
+        {
+          if (m_tapMac.IsBroadcast ())
+            {
+              m_tapMac = mac48Source;
+            }
+          else
+            {
+              NS_ABORT_MSG_UNLESS (mac48Source == m_tapMac, "TapBridge::ForwardToBridgedDevice(): "
+                                   "Multiple distinct source addresses appearing from network tap unexpectedly");
+            }
+        }
+    }
+
   NS_LOG_LOGIC ("Forwarding packet");
   m_bridgedDevice->Send (packet, dst, type);
 }
@@ -755,7 +789,13 @@
   // destination address of the actual packet.  This means we will be getting
   // PACKET_OTHERHOST packets (not broadcast, not multicast, not unicast to 
   // this device, but to some other address).  We don't want to forward those
-  // PACKET_OTHERHOST packets so just ignore them
+  // PACKET_OTHERHOST packets so just ignore them.
+  // 
+  // In the BRIDGED_DEVICE case, as far as the ns-3 device knows, there is no
+  // other device involved.  As far as other devices on the ns-3 side of things
+  // are concerned, there is no other device involved, so a PACKET_OTHERHOST
+  // here carries the same meaning as in any other device.  THey are packets
+  // we can safely ignore.
   //
   if (packetType == PACKET_OTHERHOST)
     {
@@ -775,7 +815,34 @@
 
   EthernetHeader header = EthernetHeader (false);
   header.SetSource (from);
-  header.SetDestination (to);
+
+  //
+  // We have to be careful here when we're running in BRIDGED_DEVICE mode.
+  // In this case, the user will have configured the network tap and it will 
+  // have its own MAC address that is distinct from the ns-3 device from which
+  // we just got the packet.  We learn what this address is when we receive
+  // packets from the tap.  All we have to do is to spoof the packet by
+  // substituting the learned address in here as the source address.  However,
+  // until we get that address we don't know what to do and so we just ignore 
+  // the packet.  N.B. This means that bridging will not start until the 
+  // network tap sends its first packet across the bridge.
+  //
+  if (m_mode == BRIDGED_DEVICE)
+    {
+      if (m_tapMac.IsBroadcast ())
+        {
+          return;
+        }
+      else
+        {
+          header.SetDestination (m_tapMac);
+        }
+    }
+  else
+    {
+      header.SetDestination (to);
+    }
+
   header.SetLengthType (protocol);
   p->AddHeader (header);
 
@@ -831,6 +898,20 @@
   return m_address;
 }
 
+  void 
+TapBridge::SetMode (enum Mode mode)
+{
+  NS_LOG_FUNCTION (mode);
+  m_mode = mode;
+}
+
+  TapBridge::Mode
+TapBridge::GetMode (void)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_mode;
+}
+  
 bool 
 TapBridge::SetMtu (const uint16_t mtu)
 {
--- a/src/devices/tap-bridge/tap-bridge.h	Wed Mar 11 11:16:25 2009 +0000
+++ b/src/devices/tap-bridge/tap-bridge.h	Fri Mar 13 17:37:35 2009 -0700
@@ -38,57 +38,77 @@
 class Node;
 
 /**
- * \ingroup devices
- * \defgroup tap-bridge TapBridge
+ * \ingroup tap-bridge
  * 
- * \brief A bridge to make it appear that a host is connected to an ns-3 net device.
- *
- * The Tap Bridge lives in a kind of a gray world somewhere between a Linux host and
- * an ns-3 bridge device.  From the Linux perspective, this code appears as the user
- * mode handler for a Tap net device.  That is, when the Linux host writes to the
- * /dev/tap device that we create for it, the write is redirected into the TapBridge
- * and from that perspective, becomes a read.  The TapBridge then redirects the data
- * written (by the Linux host) to the tap device on out the ns-3 net device to which
- * we are bridged.  When a packet comes in from the ns-3 world to the ns-3 net device
- * we are bridging, it appears via a callback from that net device.  Our job is to
- * take those bits and write them back to the host using the user mode handler for
- * /dev/tapx.  This write to the device will then appear to the Linux host as if a 
- * packet has arrived on its device.
+ * \brief A bridge to make it appear that a real host process is connected to 
+ * an ns-3 net device.
  *
- * The upshot is that the Tap Bridge appears to bridge a tap device on a Linux host 
- * in the "real world" to an ns-3 net device in the simulation.  In order to do this
- * we need a "ghost node" in the simulation to hold the bridged ns-3 net device and 
- * this Tap Bridge.  This node will not be able to actually do anything else in the 
- * simulation with respect to the Tap Bridge and its bridged net device.  This is 
- * because:
- *
- * - Bits sent to the Tap Bridge using its Send() method are completely ignored.  
- *   The Tap Bridge is not, itself, connected to any network.
- * - The bridged ns-3 net device is has had its receive callback disconnected from
- *   the ns-3 node and reconnected to the Tap Bridge.  All data received by a 
- *   bridged device will be sent to the Linux host and will not be received by the
- *   node.  You can send but you cannot ever receive.
+ * The Tap Bridge lives in a kind of a gray world somewhere between a
+ * Linux host and an ns-3 bridge device.  From the Linux perspective,
+ * this code appears as the user mode handler for a Tap net device.  That
+ * is, when the Linux host writes to a /dev/tap device (that is either
+ * manually or automatically created depending on basic operating mode 
+ * -- more on this later), the write is redirected into the TapBridge that
+ * lives in the ns-3 world; and from this perspective, becomes a read.
+ * In other words, a Linux process writes a packet to a tap device and
+ * this packet is redirected to an ns-3 process where it is received by
+ * the TapBridge as a result of a read operation there.  The TapBridge
+ * then sends the packet to the ns-3 net device to which it is bridged.
+ * In the other direction, a packet received by an ns-3 net device is
+ * bridged to the TapBridge (it appears via a callback from that net
+ * device.  The TapBridge then takes that packet and writes it back to
+ * the host using the Linux TAP mechanism.  This write to the device will
+ * then appear to the Linux host as if a packet has arrived on its
+ * device.
  * 
- * You will be able to perform typical ns-3 operations on the ghost node if you so
- * desire.  The internet stack, for example, must be there and functional on that
- * node in order to participate in IP address assignment and global routing.
- * However, interfaces talking any Tap Bridge or associated bridged net devices 
- * will not work completely.  If you understand exactly what you are doing, you 
- * can set up other interfaces and devices on the ghost node and use them; but we 
- * generally recommend that you treat this node as a ghost of the Linux host and 
- * leave it alone.
+ * The upshot is that the Tap Bridge appears to bridge a tap device on a
+ * Linux host in the "real world" to an ns-3 net device in the simulation
+ * and make is appear that a ns-3 net device is actually installed in the
+ * Linux host.  In order to do this on the ns-3 side, we need a "ghost
+ * node" in the simulation to hold the bridged ns-3 net device and the
+ * TapBridge.  This node should not actually do anything else in the
+ * simulation since its job is simply to make the net device appear in
+ * Linux.  This is not just arbitrary policy, it is because:
+ *
+ * - Bits sent to the Tap Bridge from higher layers in the ghost node (using
+ *   the TapBridge Send() method) are completely ignored.  The Tap Bridge is 
+ *   not, itself, connected to any network, neither in Linux nor in ns-3;
+ * - The bridged ns-3 net device is has had its receive callback disconnected
+ *   from the ns-3 node and reconnected to the Tap Bridge.  All data received 
+ *   by a bridged device will be sent to the Linux host and will not be 
+ *   received by the node.  From the perspective of the ghost node, you can 
+ *   send over this device but you cannot ever receive.
+ *
+ * Of course, if you understand all of the issues you can take control of
+ * your own destiny and do whatever you want -- we do not actively
+ * prevent you from using the ghost node for anything you decide.  You
+ * will be able to perform typical ns-3 operations on the ghost node if
+ * you so desire.  The internet stack, for example, must be there and
+ * functional on that node in order to participate in IP address
+ * assignment and global routing.  However, as mentioned above,
+ * interfaces talking any Tap Bridge or associated bridged net devices
+ * will not work completely.  If you understand exactly what you are
+ * doing, you can set up other interfaces and devices on the ghost node
+ * and use them; or take advantage of the operational send side of the
+ * bridged devices to create traffic generators.  We generally recommend
+ * that you treat this node as a ghost of the Linux host and leave it to
+ * itself, though.
  */
-
-/**
- * \ingroup tap-bridge
- * \brief A bridge to make it appear that a host is connected to an ns-3 net device.
- */
-
 class TapBridge : public NetDevice
 {
 public:
   static TypeId GetTypeId (void);
 
+  /**
+   * Enumeration of the operating modes supported in the class.
+   *
+   */
+  enum Mode {
+    ILLEGAL,         /**< mode not set */
+    LOCAL_DEVICE,   /**< ns-3 creates and configures TAP device */
+    BRIDGED_DEVICE, /**< user creates and configures TAP */  
+  };
+
   TapBridge ();
   virtual ~TapBridge ();
 
@@ -134,6 +154,20 @@
    */
   void Stop (Time tStop);
 
+  /**
+   * Set the operating mode of this device.
+   *
+   * \param mode The operating mode of this device.
+   */
+  void SetMode (TapBridge::Mode mode);
+
+  /**
+   * Get the operating mode of this device.
+   *
+   * \returns The operating mode of this device.
+   */
+  TapBridge::Mode  GetMode (void);
+
   //
   // The following methods are inherited from NetDevice base class and are
   // documented there.
@@ -338,13 +372,19 @@
 
   /**
    * \internal
+   *     
+   * The operating mode of the bridge.  Tells basically who creates and
+   * configures the underlying network tap.
+   */
+  Mode m_mode;
+
+  /**
+   * \internal
    *
    * The (unused) MAC address of the TapBridge net device.  Since the TapBridge
    * is implemented as a ns-3 net device, it is required to implement certain
    * functionality.  In this case, the TapBridge is automatically assigned a
-   * MAC address, but it is not used.  The MAC address assigned to the internet
-   * host actually comes from the bridged (N.B. the "ed") device and not from 
-   * the bridge device.
+   * MAC address, but it is not used.
    */
   Mac48Address m_address;
 
@@ -386,7 +426,18 @@
   /**
    * \internal
    *
-   * The MAC address to use as the hardware address on the host.
+   * 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
+   * 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;
 
--- a/src/devices/tap-bridge/tap-creator.cc	Wed Mar 11 11:16:25 2009 +0000
+++ b/src/devices/tap-bridge/tap-creator.cc	Fri Mar 13 17:37:35 2009 -0700
@@ -29,17 +29,10 @@
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/socket.h>
-#if 0
-#include <linux/un.h>
-#include <linux/if.h>
-#include <linux/if_tun.h>
-#include <linux/route.h>
-#else
 #include <sys/un.h>
 #include <net/if.h>
 #include <linux/if_tun.h>
 #include <net/route.h>
-#endif
 #include <netinet/in.h>
 
 #include "tap-encode-decode.h"
@@ -277,7 +270,7 @@
 }
 
   static int
-CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, const char *netmask)
+CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, const char *mode, const char *netmask)
 {
   //
   // Creation and management of Tap devices is done via the tun device
@@ -288,7 +281,9 @@
   //
   // Allocate a tap device, making sure that it will not send the tun_pi header.
   // If we provide a null name to the ifr.ifr_name, we tell the kernel to pick
-  // a name for us (i.e., tapn where n = 0..255
+  // a name for us (i.e., tapn where n = 0..255.
+  //
+  // If the device does not already exist, the system will create one.
   //
   struct ifreq ifr;
   ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
@@ -300,6 +295,17 @@
   LOG ("Allocated TAP device " << tapDeviceName);
 
   //
+  // Operating mode "2" corresponds to BRIDGED_DEVICE 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)
+    {
+      return tap;
+    }
+
+  //
   // Set the hardware (MAC) address of the new device
   //
   ifr.ifr_hwaddr.sa_family = 1; // this is ARPHRD_ETHER from if_arp.h
@@ -348,31 +354,35 @@
   char *ip = NULL;
   char *mac = NULL;
   char *netmask = NULL;
+  char *operatingMode = NULL;
   char *path = NULL;
 
   opterr = 0;
 
-  while ((c = getopt (argc, argv, "vd:g:i:m:n:p:")) != -1)
+  while ((c = getopt (argc, argv, "vd:g:i:m:n:o:p:")) != -1)
     {
       switch (c)
         {
         case 'd':
-          dev = optarg;     // name of the new tap device
+          dev = optarg;           // name of the new tap device
           break;
         case 'g':
-          gw = optarg;      // gateway address for the new device
+          gw = optarg;            // gateway address for the new device
           break;
         case 'i':
-          ip = optarg;      // ip address of the new device
+          ip = optarg;            // ip address of the new device
           break;
         case 'm':
-          mac = optarg;     // mac address of the new device
+          mac = optarg;           // mac address of the new device
           break;
         case 'n':
-          netmask = optarg; // net mask for the new device
+          netmask = optarg;       // net mask for the new device
+          break;
+        case 'o':
+          operatingMode = optarg; // operating mode of tap bridge
           break;
         case 'p':
-          path = optarg;    // path back to the tap bridge
+          path = optarg;          // path back to the tap bridge
           break;
         case 'v':
           gVerbose = true;
@@ -422,6 +432,12 @@
   LOG ("Provided Net Mask is \"" << netmask << "\"");
 
   //
+  // We have got to know whether or not to create the TAP.
+  //
+  ABORT_IF (operatingMode == NULL, "Operating Mode is a required argument", 0);
+  LOG ("Provided Operating Mode is \"" << operatingMode << "\"");
+
+  //
   // This program is spawned by a tap bridge running in a simulation.  It
   // wants to create a socket as described below.  We are going to do the
   // work here since we're running suid root.  Once we create the socket,
@@ -444,7 +460,7 @@
   // us to exeucte the following code:
   //
   LOG ("Creating Tap");
-  int sock = CreateTap (dev, gw, ip, mac, netmask);
+  int sock = CreateTap (dev, gw, ip, mac, operatingMode, netmask);
   ABORT_IF (sock == -1, "main(): Unable to create tap socket", 1);
 
   //
--- a/src/devices/tap-bridge/tap.h	Wed Mar 11 11:16:25 2009 +0000
+++ b/src/devices/tap-bridge/tap.h	Fri Mar 13 17:37:35 2009 -0700
@@ -6,46 +6,244 @@
  *
  * The Tap Bridge is designed to integrate "real" internet hosts (or more 
  * precisely, hosts that support Tun/Tap devices) into ns-3 simulations.  The 
- * goal is to make it appear to the host host node in question that it has an
- * ns-3 net device as a local device.  The concept of a "real host" is a bit
- * slippery the "real host" may actually be virtualized using readily avialable
+ * goal is to make it appear to a "real" host node in that it has an ns-3 net
+ * device as a local device.  The concept of a "real host" is a bit slippery
+ * since the "real host" may actually be virtualized using readily avialable
  * technologies such as VMware or OpenVZ.
  *
  * Since we are, in essence, connecting the inputs and outputs of an ns-3 net 
  * device to the inputs and outputs of a Linux Tap net device, we call this 
  * arrangement a Tap Bridge.
  *
- * The TapBridge appears to the Linux host computer as a network device just
- * like any arbitrary "eth0" or "ath0" might appear.  The creation and
- * configuration of the device is done by the ns-3 simulation, however.  You 
- * should not expect to be able to configure a net device via, for example,
- * wlanconfig.  The IP addresses, MAC addresses, gateway, etc., for the given
- * Tap device are also set up by the ns-3 simulation.  If you change the
- * or manipulate the configuration manually, you will almost certainly break
- * the simulation.
+ * There are two basic operating modes of this device available to users.  
+ * Basic functionality is essentially identical, but the two modes are 
+ * different in details regarding how the arrangement is configured.  In the
+ * first mode, the configuration is ns-3 configuration-centric.  Configuration
+ * information is taken from the ns-3 simulation and a tap device matching
+ * the ns-3 attributes is created for you.  In this mode, which we call 
+ * LocalDevice mode, an ns-3 net device is made to appear to be directly 
+ * connected to a real host.  In LocalDevice mode, configuration of the TAP
+ * device is almost completely handled by ns-3.  This is useful if you want
+ * to use real processes in your host to talk over simulated networks.
+ * 
+ * This is illustrated below
+ *
+ * \verbatim
+ *     +--------+
+ *     |  Linux |
+ *     |  host  |            +----------+
+ *     | ------ |            |   ghost  |
+ *     |  apps  |            |   node   |
+ *     | ------ |            | -------- |
+ *     |  stack |            |    IP    |     +----------+
+ *     | ------ |            |   stack  |     |   node   |
+ *     |  TAP   |            |==========|     | -------- |
+ *     | device | <-- IPC -> |   tap    |     |    IP    |
+ *     +--------+            |  bridge  |     |   stack  |
+ *                           | -------- |     | -------- |
+ *                           |   ns-3   |     |   ns-3   |
+ *                           |   net    |     |   net    |
+ *                           |  device  |     |  device  |
+ *                           +----------+     +----------+
+ *                                ||               ||
+ *                           +---------------------------+
+ *                           |        ns-3 channel       |
+ *                           +---------------------------+
+ *\endverbatim
+ *
+ * In this case, the ns-3 net device in the ghost node appears as if it were 
+ * actually replacing the TAP device in the Linux host.  The ns-3 process 
+ * configures the IP address and MAC address of the TAP device to match the
+ * values assigned to the ns-3 net device.  The IPC link is via the network 
+ * tap mechanism in the underlying OS.
+ *
+ * The LocalDevice mode is the default operating mode of the Tap Bridge.
+ *
+ * The second mode, BridgedDevice mode, is more oriented toward allowing existing
+ * host configurations.  This allows the Tap Bridge to be "further bridged" to 
+ * other existing devices via an existing TAP device.  This mode is especially 
+ * useful in the case of virtualization where the configuration of the virtual
+ * hosts may be dictated by an existing system and not easily changed.  For 
+ * example, a particular VM scheme may create virtual "vethx" or "vmnetx" 
+ * devices that appear local to virtual hosts.  In order to connect to such 
+ * systems, we need to manually create TAP devices on the host system and brigde
+ * these TAP devices to the existing virtual devices.  We then need to have a Tap 
+ * Bridge corresponding created to talk to each of these TAP devices.
+ *
+ * This is illustrated below:
+ *
+ * \verbatim
+ *     +---------+
+ *     |  Linux  |
+ *     |   VM    |                       +----------+
+ *     | ------- |                       |   ghost  |
+ *     |  apps   |                       |   node   |
+ *     | ------- |                       | -------- |
+ *     |  stack  |                       |    IP    |     +----------+
+ *     | ------- | +--------+            |   stack  |     |   node   |
+ *     | Virtual | |  TAP   |            |==========|     | -------- |
+ *     | device  | | device | <-- IPC -> |   tap    |     |    IP    |
+ *     +---------+ +--------+            |  bridge  |     |   stack  |
+ *         ||          ||                | -------- |     | -------- |
+ *     +--------------------+            |   ns-3   |     |   ns-3   |
+ *     | OS (brctl) Bridge  |            |   net    |     |   net    |
+ *     +--------------------+            |  device  |     |  device  |
+ *                                       +----------+     +----------+
+ *                                            ||               ||
+ *                                       +---------------------------+
+ *                                       |        ns-3 channel       |
+ *                                       +---------------------------+
+ *\endverbatim
+ *
+ * In this case, the ns-3 net device in the ghost node appears as a TAP device 
+ * in the collection of virtual machines.  The idea is that some existing 
+ * configuration of virtual machines is created using an external mechanism 
+ * such as OpenVZ or VMware.  It is desired to have some subset of these VMs be
+ * connected to an ns-3 simulation.  To accomplish this, there must be a TAP 
+ * device created for each connection and the appropriate VM virtual network 
+ * device bridged to the TAP device.  The ns-3 simulation determines which TAP
+ * to associate with which ns-3 net device via the name of the TAP which is
+ * provided via ns-3 Attribute.  Clearly there is considerably more 
+ * manual configuration which needs to be done here, but the result is much
+ * more flexible.
+ *
+ * \subsection TapBridgeLocalDeviceMode TapBridge LocalDevice Mode
+ * 
+ * In LocalDevice mode, the TapBridge and therefore its associated ns-3 net
+ * device appears to the Linux host computer as a network device just like any
+ * arbitrary "eth0" or "ath0" might appear.  The creation and configuration 
+ * of the TAP device is done by the ns-3 simulation and no manual configuration
+ * is required.  The IP addresses, MAC addresses, gateways, etc., for created
+ * TAP devices are extracted from the simulation itself by querying the 
+ * configuration of the ns-3 device and the TapBridge Attributes.
  *
  * The TapBridge appears to an ns-3 simulation as a channel-less net device.
- * This device, however, must _not_ have an IP address associated with it.  
- * Be aware that this is the inverse situation of an ns-3 BridgeNetDevice
- * which demands that its bridge ports not have IP addresses, but allows the
- * bridge to have an IP address.  
+ * This device must not have an IP address associated with it, but the bridged
+ * (ns-3) net device must have an IP adress.  Be aware that this is the inverse
+ * of an ns-3 BridgeNetDevice which demands that its bridge ports not have IP 
+ * addresses, but allows the bridge device itself to have an IP address.  
  *
  * The host computer will appear in a simulation as a "ghost" node that contains
- * pairs of net devices and Tap bridges that represent the host devices.  From
- * the perspective of a simulation, the only difference between a ghost node and
- * another node will be the presence of the TapBridge devices that connect to
- * the hosts.  Configuration of address information and the ns-3 devices is
- * not changed in any way.  A TapBridge will pick up the addressing info from
- * the ns-3 net device to which it is connected (its "bridged" net device) and
- * use that information to configure the device on the real host.
+ * one TapBridge for each NetDevice that is being bridged.  From the perspective
+ * of a simulation, the only difference between a ghost node and any other node 
+ * will be the presence of the TapBridge devices.  Note however, that the 
+ * presence of the TapBridge does affect the connectivity of the net device to 
+ * the IP stack of the ghost node.
+ *
+ * Configuration of address information and the ns-3 devices is not changed in 
+ * any way if a TapBridge is present.  A TapBridge will pick up the addressing
+ * information from the ns-3 net device to which it is connected (its "bridged"
+ * net device) and use that information to create and configure the TAP device
+ * on the real host.
  *
  * The end result of this is a situation where one can, for example, use the
- * standard ping utility on a real host to ping a simulated ns-3 net device.  If
- * correct routes are added to the internet host, the routing systems in ns-3
- * will enable correct routing of the packets across simulated ns-3 networks.
- * For an example of this, see the example program, tap-dumbbell.cc in the 
- * ns-3 distribution.
+ * standard ping utility on a real host to ping a simulated ns-3 node.  If
+ * correct routes are added to the internet host (this is expected to be done
+ * automatically in future ns-3 releases), the routing systems in ns-3 will
+ * enable correct routing of the packets across simulated ns-3 networks.
+ * For an example of this, see the example program, tap-wifi-dumbbell.cc in 
+ * the ns-3 distribution.
+ *
+ * \subsection TapBridgeLocalDeviceModeOperation TapBridge LocalDevice Mode Operation
+ *
+ * The Tap Bridge lives in a kind of a gray world somewhere between a Linux host
+ * and an ns-3 bridge device.  From the Linux perspective, this code appears as
+ * the user mode handler for a TAP net device.  In LocalDevice mode, this TAP is
+ * automatically created by the ns-3 simulation.  When the Linux host writes
+ * to one of these /dev/tap devices, the write is redirected into the TapBridge
+ * that lives in the ns-3 world; and from this perspective, the packet write on
+ * linux becomes a packet read.  In other words, a Linux process writes a packet
+ * to a tap device and this packet is redirected by the network tap mechanism to
+ * an ns-3 process where it is received by the TapBridge as a result of a read 
+ * operation there.  The TapBridge then forwards the packet to the ns-3 net 
+ * device to which it is bridged; and therefore it appears as if the Linux host
+ * sent a packet directly over an ns-3 net device.
+ *
+ * In the other direction, a packet received by an ns-3 net device is bridged 
+ * (in the ns-3 sense) to the TapBridge.  A packet sent to the ns-3 device then
+ * appears via a callback in the TapBridge.  The TapBridge then takes that 
+ * packet and writes it back to the host using the network tap mechanism.  This
+ * write to the device will appear to the Linux host as if a packet has arrived
+ * on its device; and therefore as if a packet received by the ns-3 net device
+ * has appeared on the Linux net device.
+ * 
+ * The upshot is that the Tap Bridge appears to bridge a tap device on a
+ * Linux host in the "real world" to an ns-3 net device in the simulation
+ * and make is appear that a ns-3 net device is actually installed in the
+ * Linux host.  In order to do this on the ns-3 side, we need a "ghost
+ * node" in the simulation to hold the bridged ns-3 net device and the
+ * TapBridge.  This node should not actually do anything else in the
+ * simulation since its job is simply to make the net device appear in
+ * Linux.  This is not just arbitrary policy, it is because:
+ *
+ * - Bits sent to the Tap Bridge from higher layers in the ghost node (using
+ *   the TapBridge Send() method) are completely ignored.  The Tap Bridge is 
+ *   not, itself, connected to any network, neither in Linux nor in ns-3.  You
+ *   can never send nor receive data over a Tap Bridge from the ghost node.
+ *
+ * - The bridged ns-3 net device has its receive callback disconnected
+ *   from the ns-3 node and reconnected to the Tap Bridge.  All data received 
+ *   by a bridged device will then be sent to the Linux host and will not be 
+ *   received by the node.  From the perspective of the ghost node, you can 
+ *   send over this device but you cannot ever receive.
  *
+ * Of course, if you understand all of the issues you can take control of
+ * your own destiny and do whatever you want -- we do not actively
+ * prevent you from using the ghost node for anything you decide.  You
+ * will be able to perform typical ns-3 operations on the ghost node if
+ * you so desire.  The internet stack, for example, must be there and
+ * functional on that node in order to participate in IP address
+ * assignment and global routing.  However, as mentioned above,
+ * interfaces talking any Tap Bridge or associated bridged net devices
+ * will not work completely.  If you understand exactly what you are
+ * doing, you can set up other interfaces and devices on the ghost node
+ * and use them; or take advantage of the operational send side of the
+ * bridged devices to create traffic generators.  We generally recommend
+ * that you treat this node as a ghost of the Linux host and leave it to
+ * itself, though.
+ *
+ * \subsection TapBridgeBridgedDeviceMode TapBridge BridgedDevice Mode
+ * 
+ * In BridgedDevice mode, the TapBridge and its associated ns-3 net device are
+ * arranged in a fundamentally similar was as in LocalDevice mode.  The bridging
+ * functionality is also accomplished in a fundamentally similar way.  The
+ * previous description applies except as noted below.
+ *
+ * The most user-visible difference in modes is how the creation and 
+ * configuration of the underlying TAP device is done.  In LocalDevice mode,
+ * both creation and configuration of the underlying TAP device are handled 
+ * completely by ns-3.  In BridgedDevice mode, creation and configuration is
+ * delegated (due to requirements) to the user.  No configuration is done in
+ * ns-3 other than settting the operating mode of the TapBridge to 
+ * "BridgedDevice" and specifying the name of the pre-configured TAP device,
+ * both via ns-3 Attributes of the TapBridge.
+ *
+ * Functionally, the primary difference between modes is due to the fact that
+ * MAC addresses of the TAPs will be pre-configured and will therefore be 
+ * different than those in the bridged device.  This necessitates spoofing
+ * MAC addresses in the ns-3 to TAP direction.
+ *
+ * \subsection TapBridgeBridgedDeviceModeOperation TapBridge BridgedDevice Mode Operation
+ *
+ * As described in the LocalDevice mode section, when the Linux host writes to 
+ * one of the /dev/tap devices, the write is redirected into the TapBridge
+ * that lives in the ns-3 world; and from this perspective, the packet write on
+ * linux becomes a packet read.  The packet at this point will contain a MAC
+ * source address corresponding to the address of the TAP device.  Before this
+ * packet is sent to the bridged ns-3 net device, the MAC headers are stripped
+ * off.  When the bridged net device actually executes the send, it will replace
+ * the MAC headers with its own.
+ *
+ * In the other direction, a packet received by an ns-3 net device is bridged 
+ * (in the ns-3 sense) to the TapBridge.  A packet sent to the ns-3 device then
+ * appears via a callback in the TapBridge.  At this point, there is no MAC 
+ * addressing information on the packet.  In LocalDevice mode, the TapBridge 
+ * adds back the MAC address that it found in the ns-3 bridged net device 
+ * configuration.  In the BridgedDevice mode, it needs to add back the MAC 
+ * address of the TAP device.  So the main difference is that the TapBridge
+ * learns the MAC address of the TAP device from received packets instead of 
+ * learning it from the ns-3 device configuration.
+ * 
  * \section TapBridgeChannelModel Tap Bridge Channel Model
  *
  * There is no channel model associated with the Tap Bridge.  In fact, the