From dd01873dfd3eae866de040d5efdb5002eb2fdb1a Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 2 Feb 2009 10:12:29 -0800 Subject: [PATCH] cleanup, doxygen, prepare for review --- examples/csma-tap-bridge.cc | 177 ------------------------ examples/wscript | 4 - src/devices/tap-bridge/tap-bridge.h | 186 +++++++++++++++++++++++++- src/devices/tap-bridge/tap-creator.cc | 18 +-- src/devices/tap-bridge/tap.h | 62 ++++++++- 5 files changed, 243 insertions(+), 204 deletions(-) delete mode 100644 examples/csma-tap-bridge.cc diff --git a/examples/csma-tap-bridge.cc b/examples/csma-tap-bridge.cc deleted file mode 100644 index ed957f215..000000000 --- a/examples/csma-tap-bridge.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -// Network topology -// -// +----------+ +----------+ -// | external | | external | -// | Linux | | Linux | -// | Host | | Host | -// | "left" | | "right" | -// +----------+ +----------+ -// | n0 n3 | -// | +--------+ +--------+ | -// +-------| tap | | tap |-------+ -// | bridge | ... | bridge | -// +--------+ +--------+ -// | CSMA | | CSMA | -// +--------+ +--------+ -// | | -// | | -// | n1 n2 | -// | | | | -// ================ -// LAN - -#include -#include - -#include "ns3/simulator-module.h" -#include "ns3/node-module.h" -#include "ns3/core-module.h" -#include "ns3/helper-module.h" - -using namespace ns3; - -NS_LOG_COMPONENT_DEFINE ("CsmaTapBridgeExample"); - -int -main (int argc, char *argv[]) -{ - // - // Users may find it convenient to turn on explicit debugging - // for selected modules; the below lines suggest how to do this - // -#if 0 - LogComponentEnable ("CsmaOneSubnetExample", LOG_LEVEL_INFO); -#endif - - // - // Make the random number generators generate reproducible results. - // - RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); - - // - // Allow the user to override any of the defaults and the above Bind() at - // run-time, via command-line arguments - // - CommandLine cmd; - cmd.Parse (argc, argv); - - // - // We need to enable the real-time simulator since we are going to be - // talking to the "real world." - GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl")); - - // - // Also, since the whole point of this exercise is to exchange packets - // with hosts running in the real world, we are going to need to enable - // checksums. - // - Config::SetDefault ("ns3::Ipv4L3Protocol::CalcChecksum", BooleanValue (true)); - Config::SetDefault ("ns3::Icmpv4L4Protocol::CalcChecksum", BooleanValue (true)); - Config::SetDefault ("ns3::TcpL4Protocol::CalcChecksum", BooleanValue (true)); - Config::SetDefault ("ns3::UdpL4Protocol::CalcChecksum", BooleanValue (true)); - - // - // Create the nodes required by the topology (shown above). - // - NS_LOG_INFO ("Create nodes."); - NodeContainer nodes; - nodes.Create (4); - - // - // Create and install the network. - // - NS_LOG_INFO ("Build Topology"); - CsmaHelper csma; - csma.SetChannelAttribute ("DataRate", DataRateValue (5000000)); - csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); - - NetDeviceContainer devices = csma.Install (nodes); - - InternetStackHelper internet; - internet.Install (nodes); - - // - // We've got the "hardware" in place. Now add IP addresses. - // - NS_LOG_INFO ("Assign IP Addresses."); - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.0"); - Ipv4InterfaceContainer interfaces = ipv4.Assign (devices); - - // - // 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)); - - // - // 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)); - - // - // 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)); - - // - // Configure tracing of all enqueue, dequeue, and NetDevice receive events. - // - NS_LOG_INFO ("Configure Tracing."); - CsmaHelper::EnablePcapAll ("csma-tap-bridge"); - - // - // Now, do the actual simulation. Run for a few minutes to allow the user a chance - // to run some applications on the Linux hosts. - // - Simulator::Stop (Seconds (60.)); - NS_LOG_INFO ("Run Simulation."); - Simulator::Run (); - Simulator::Destroy (); - NS_LOG_INFO ("Done."); -} diff --git a/examples/wscript b/examples/wscript index c49fe2f0e..adf7df771 100644 --- a/examples/wscript +++ b/examples/wscript @@ -48,10 +48,6 @@ def build(bld): ['csma', 'internet-stack']) obj.source = 'csma-one-subnet.cc' - obj = bld.create_ns3_program('csma-tap-bridge', - ['csma', 'tap-bridge', 'internet-stack']) - obj.source = 'csma-tap-bridge.cc' - obj = bld.create_ns3_program('tap-dumbbell', ['csma', 'point-to-point', 'tap-bridge', 'internet-stack']) obj.source = 'tap-dumbbell.cc' diff --git a/src/devices/tap-bridge/tap-bridge.h b/src/devices/tap-bridge/tap-bridge.h index a71be3ee3..ec1592817 100644 --- a/src/devices/tap-bridge/tap-bridge.h +++ b/src/devices/tap-bridge/tap-bridge.h @@ -46,7 +46,7 @@ class Node; * 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/tapx device that we create for it, the write is redirected into the TapBridge + * /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 @@ -78,6 +78,9 @@ public: virtual ~TapBridge (); /** \brief Get the bridged net device. + * + * The bridged net device is the ns-3 device to which this bridge is connected, + * * \returns the bridged net device. */ Ptr GetBridgedNetDevice (void); @@ -93,9 +96,16 @@ public: void SetBridgedNetDevice (Ptr bridgedDevice); /** - * Set a start time for the device. + * \brief Set a start time for the device. * - * @param tStart the start time + * The tap bridge consumes a non-trivial amount of time to start. It starts + * up in the context of a scheduled event to ensure that all configuration + * has been completed before extracting the configuration (IP addresses, etc.) + * In order to allow a more reasonable start-up sequence than a thundering + * herd of devices, the time at which each device starts is also configurable + * bot via the Attribute system and via this call. + * + * \param tStart the start time */ void Start (Time tStart); @@ -103,10 +113,15 @@ public: * Set a stop time for the device. * * @param tStop the stop time + * + * \see TapBridge::Start */ void Stop (Time tStop); - // inherited from NetDevice base class. + // + // The following methods are inherited from NetDevice base class and are + // documented there. + // virtual void SetName(const std::string name); virtual std::string GetName(void) const; virtual void SetIfIndex(const uint32_t index); @@ -134,6 +149,14 @@ public: virtual Address GetMulticast (Ipv6Address addr) const; protected: + /** + * \internal + * + * Call out to a separate process running as suid root in order to get our + * tap device created. We do this to avoid having the entire simulation + * running as root. If this method returns, we'll have a socket waiting + * for us in m_sock that we can use to talk to the tap device. + */ virtual void DoDispose (void); void ReceiveFromBridgedDevice (Ptr device, Ptr packet, uint16_t protocol, @@ -141,6 +164,8 @@ protected: private: /** + * \internal + * * Call out to a separate process running as suid root in order to get our * tap device created. We do this to avoid having the entire simulation * running as root. If this method returns, we'll have a socket waiting @@ -149,67 +174,218 @@ private: void CreateTap (void); /** + * \internal + * * Figure out where the tap creation program lives on the system. + * + * \param creatorName The name of the program used to create the Tap. + * \returns A path name to use when you want to create a Tap. */ std::string FindCreator (std::string creatorName); /** + * \internal + * * Spin up the device */ void StartTapDevice (void); /** + * \internal + * * Tear down the device */ void StopTapDevice (void); /** + * \internal + * * Loop to read and process packets */ void ReadThread (void); /* + * \internal + * * Forward a packet received from the tap device to the bridged ns-3 * device + * + * \param buf A character buffer containing the actaul packet bits that were + * received from the host. + * \param buf The length of the buffer. */ void ForwardToBridgedDevice (uint8_t *buf, uint32_t len); /** + * \internal + * * The host we are bridged to is in the evil real world. Do some sanity * checking on a received packet to make sure it isn't too evil for our * poor naive virginal simulator to handle. - */ + * + * \param packet The packet we received from the host, and which we need + * to check. + * \param src A pointer to the data structure that will get the source + * MAC address of the packet (extracted from the packet Ethernet + * header). + * \param dst A pointer to the data structure that will get the destination + * MAC address of the packet (extracted from the packet Ethernet + * header). + * \param type A pointer to the variable that will get the packet type from + * either the Ethernet header in the case of type interpretation + * (DIX framing) or from the 802.2 LLC header in the case of + * length interpretation (802.3 framing). + */ Ptr Filter (Ptr packet, Address *src, Address *dst, uint16_t *type); + /** + * \internal + * + * Callback used to hook the standard packet receive callback of the TapBridge + * ns-3 net device. This is never called, and therefore no packets will ever + * be received forwarded up the IP stack on the ghost node through this device. + */ NetDevice::ReceiveCallback m_rxCallback; + + /** + * \internal + * + * Callback used to hook the promiscuous packet receive callback of the TapBridge + * ns-3 net device. This is never called, and therefore no packets will ever + * be received forwarded up the IP stack on the ghost node through this device. + * + * Note that we intercept the similar callback in the bridged device in order to + * do the actual bridging between the bridged ns-3 net device and the Tap device + * on the host. + */ NetDevice::PromiscReceiveCallback m_promiscRxCallback; + /** + * \internal + * + * Pointer to the (ghost) Node to which we are connected. + */ Ptr m_node; + + /** + * \internal + * + * A possible name for the (ghost) Node to which we are connected. + */ std::string m_name; + + /** + * \internal + * + * The ns-3 interface index of this TapBridge net device. + */ uint32_t m_ifIndex; + + /** + * \internal + * + * The common mtu to use for the net devices + */ uint16_t m_mtu; + + /** + * \internal + * + * The socket (actually interpreted as fd) to use to talk to the Tap device on + * the real internet host. + */ int32_t m_sock; + + /** + * \internal + * + * The ID of the ns-3 event used to schedule the start up of the underlying + * host Tap device and ns-3 read thread. + */ EventId m_startEvent; + + /** + * \internal + * + * The ID of the ns-3 event used to schedule the tear down of the underlying + * host Tap device and ns-3 read thread. + */ EventId m_stopEvent; + + /** + * \internal + * + * Used to identify the ns-3 read thread used to do blocking reads on the + * socket (fd) corresponding to the host device. + */ Ptr m_readThread; + + /** + * \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. + */ Mac48Address m_address; /** + * \internal + * * Time to start spinning up the device */ Time m_tStart; /** + * \internal + * * Time to start tearing down the device */ Time m_tStop; + /** + * \internal + * + * The name of the device to create on the host. If the device name is the + * empty string, we allow the host kernel to choose a name. + */ std::string m_tapDeviceName; + + /** + * \internal + * + * The IP address to use as the device default gateway on the host. + */ Ipv4Address m_tapGateway; + + /** + * \internal + * + * The IP address to use as the device IP on the host. + */ Ipv4Address m_tapIp; + /** + * \internal + * + * The MAC address to use as the hardware address on the host. + */ Mac48Address m_tapMac; + + /** + * \internal + * + * The network mask to assign to the device created on the host. + */ Ipv4Mask m_tapNetmask; + /** + * \internal + * + * The ns-3 net device to which we are bridging. + */ Ptr m_bridgedDevice; }; diff --git a/src/devices/tap-bridge/tap-creator.cc b/src/devices/tap-bridge/tap-creator.cc index 322364b3f..c91c07551 100644 --- a/src/devices/tap-bridge/tap-creator.cc +++ b/src/devices/tap-bridge/tap-creator.cc @@ -61,7 +61,7 @@ static int gVerbose = 0; } // -// Thanks, Mathieu, for the beginning of these functions +// Lots of the following helper code taken from corresponding functions in src/node. // #define ASCII_DOT (0x2e) #define ASCII_ZERO (0x30) @@ -146,14 +146,6 @@ SetInetAddress (sockaddr *ad, uint32_t networkOrder) sin->sin_addr.s_addr = htonl (networkOrder); } -/** - * \brief Send the socket file descriptor we created back to the tap bridge, - * which will read it as soon as we're done. - * - * \param path The socket address information from the Unix socket we use - * to send the created socket back to. - * \param fd The socket we're going to send. - */ static void SendSocket (const char *path, int fd) { @@ -447,14 +439,6 @@ main (int argc, char *argv[]) int sock = CreateTap (dev, gw, ip, mac, netmask); ABORT_IF (sock == -1, "main(): Unable to create tap socket", 1); -#if 0 - for (;;) - { - LOG ("z"); - sleep (1); - } -#endif - // // Send the socket back to the tap net device so it can go about its business // diff --git a/src/devices/tap-bridge/tap.h b/src/devices/tap-bridge/tap.h index 65072e8b0..b4858cdd0 100644 --- a/src/devices/tap-bridge/tap.h +++ b/src/devices/tap-bridge/tap.h @@ -4,5 +4,65 @@ * * \section TapBridgeModelOverview TapBridge Model Overview * - * The tap bridge ... + * 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 + * 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. + * + * 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. + * + * 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. + * + * 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. + * + * \section TapBridgeChannelModel Tap Bridge Channel Model + * + * There is no channel model associated with the Tap Bridge. In fact, the + * intention is make it appear that the real internet host is connected to + * the channel of the bridged net device. + * + * \section TapBridgeTracingModel Tap Bridge Tracing Model + * + * Unlike most ns-3 devices, the TapBridge does not provide any standard trace + * sources. This is because the bridge is an intermediary that is essentially + * one function call away from the bridged device. We expect that the trace + * hooks in the bridged device will be sufficient for most users, + * + * \section TapBridgeUsage Using the Tap Bridge + * + * We expect that most users will interact with the TapBridge device through + * the TapBridgeHelper. Users of other helper classes, such as CSMA or Wifi, + * should be comfortable with the idioms used. */ +