From b5480583943f300576f27e30579f04a56398b53b Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 13 Mar 2009 17:37:35 -0700 Subject: [PATCH 01/67] first cut at enabling OpenVZ scenario --- src/devices/csma/csma-net-device.h | 1 - src/devices/tap-bridge/tap-bridge.cc | 147 +++++++++++---- src/devices/tap-bridge/tap-bridge.h | 147 ++++++++++----- src/devices/tap-bridge/tap-creator.cc | 50 +++-- src/devices/tap-bridge/tap.h | 252 +++++++++++++++++++++++--- 5 files changed, 471 insertions(+), 126 deletions(-) diff --git a/src/devices/csma/csma-net-device.h b/src/devices/csma/csma-net-device.h index e77b5e02e..9459c292e 100644 --- a/src/devices/csma/csma-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -61,7 +61,6 @@ public: /** * Enumeration of the types of packets supported in the class. - * */ enum EncapsulationMode { ILLEGAL, /**< Encapsulation mode not set */ diff --git a/src/devices/tap-bridge/tap-bridge.cc b/src/devices/tap-bridge/tap-bridge.cc index 1103f8c67..b62c49aee 100644 --- a/src/devices/tap-bridge/tap-bridge.cc +++ b/src/devices/tap-bridge/tap-bridge.cc @@ -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 @@ TapBridge::GetTypeId (void) 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 @@ TapBridge::CreateTap (void) { NS_LOG_FUNCTION_NOARGS (); -#ifdef NO_CREATOR + // + // 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. // - // 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. + // 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: // + // 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 // - // Creation and management of Tap devices is done via the tun device + // set the "Mode" Attribute to "BridgedDevice" and the "DeviceName" Attribute + // to "tap0" in this case. // - 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 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. // - // 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 - // - 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 - - // - // 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 + // 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 @@ TapBridge::CreateTap (void) // -i The IP address to assign to the new tap device; // -m The MAC-48 address to assign to the new tap device; // -n The network mask to assign to the new tap device; + // -o The operating mode of the bridge (1=LocalDevice, 2=BridgedDevice) // -p 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 @@ TapBridge::CreateTap (void) 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 @@ TapBridge::CreateTap (void) ossIp.str ().c_str (), // argv[3] (-i) ossMac.str ().c_str (), // argv[4] (-m) ossNetmask.str ().c_str (), // argv[5] (-n) - ossPath.str ().c_str (), // argv[6] (-p) + ossMode.str ().c_str (), // argv[6] (-o) + ossPath.str ().c_str (), // argv[7] (-p) (char *)NULL); // @@ -521,7 +530,6 @@ TapBridge::CreateTap (void) } NS_FATAL_ERROR ("Did not get the raw socket from the socket creator"); } -#endif // use the tap-creator } std::string @@ -634,6 +642,32 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) 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 @@ TapBridge::ReceiveFromBridgedDevice ( // 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 @@ TapBridge::ReceiveFromBridgedDevice ( 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 @@ TapBridge::GetAddress (void) const 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) { diff --git a/src/devices/tap-bridge/tap-bridge.h b/src/devices/tap-bridge/tap-bridge.h index 69739a8e2..1b399cad0 100644 --- a/src/devices/tap-bridge/tap-bridge.h +++ b/src/devices/tap-bridge/tap-bridge.h @@ -37,58 +37,78 @@ namespace ns3 { class Node; -/** - * \ingroup devices - * \defgroup tap-bridge TapBridge - * - * \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. - * - * 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. - * - * 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. - */ - /** * \ingroup tap-bridge - * \brief A bridge to make it appear that a host is connected to an ns-3 net device. + * + * \brief A bridge to make it appear that a real host process 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 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. + * + * 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. */ - 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 @@ public: */ 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. @@ -336,15 +370,21 @@ private: */ Ptr m_readThread; + /** + * \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 @@ private: /** * \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; diff --git a/src/devices/tap-bridge/tap-creator.cc b/src/devices/tap-bridge/tap-creator.cc index 2a664c9b1..7c82de7e6 100644 --- a/src/devices/tap-bridge/tap-creator.cc +++ b/src/devices/tap-bridge/tap-creator.cc @@ -29,17 +29,10 @@ #include #include #include -#if 0 -#include -#include -#include -#include -#else #include #include #include #include -#endif #include #include "tap-encode-decode.h" @@ -277,7 +270,7 @@ SendSocket (const char *path, int fd) } 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 @@ CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, con // // 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; @@ -299,6 +294,17 @@ CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, con std::string tapDeviceName = (char *)ifr.ifr_name; 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 // @@ -348,31 +354,35 @@ main (int argc, char *argv[]) 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; @@ -421,6 +431,12 @@ main (int argc, char *argv[]) ABORT_IF (netmask == NULL, "Net Mask is a required argument", 0); 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 @@ -444,7 +460,7 @@ main (int argc, char *argv[]) // 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); // diff --git a/src/devices/tap-bridge/tap.h b/src/devices/tap-bridge/tap.h index b4858cdd0..c5dff9071 100644 --- a/src/devices/tap-bridge/tap.h +++ b/src/devices/tap-bridge/tap.h @@ -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 From 17fc363e94f2575d2eb71093accbb5283d675f2f Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Sat, 14 Mar 2009 00:07:03 -0700 Subject: [PATCH 02/67] in BRIDGED_DEVICE mode, tap-bridge acts like a bridge between the tap and the bridged device --- src/devices/tap-bridge/tap-bridge.cc | 146 +++++++++++++++------------ 1 file changed, 83 insertions(+), 63 deletions(-) diff --git a/src/devices/tap-bridge/tap-bridge.cc b/src/devices/tap-bridge/tap-bridge.cc index b62c49aee..1d0f3d844 100644 --- a/src/devices/tap-bridge/tap-bridge.cc +++ b/src/devices/tap-bridge/tap-bridge.cc @@ -643,33 +643,51 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) 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. + // If we are operating in BRIDGED_DEVICE mode, we have the situation described + // below: + // + // Other Device <--> Tap Device <--> ns3 device + // Mac Addr A Mac Addr B Mac Addr C + // + // In Linux, "Other Device" and "Tap Device" are bridged together. This + // means that (modulo learning behavior) packets sent from "Other Device" + // are also sent out to "Tap Device" (i.e., in ns-3 lingo, "Tap Device" + // would call SendFrom on the "Tap Device" with the from address set to the + // original "Other Device" address. Packets received by "Tap Device" are + // (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 + // 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 + // 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 + // just call SendFrom on the bridged device ("ns3 Device") to ship the packet + // out. If you think about it, this is also a bridging operation, but the + // bridged devices happen to have the same MAC address. + // + // The bottom line is that at this point, the code does exactly the same thing + // even though they seem quite different at first glance. The only issue is + // what to do if the bridged device does not support SendFrom, which will be + // the case for Wifi STA nodes. // - 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); + + if (m_bridgedDevice->SupportsSendFrom ()) + { + m_bridgedDevice->SendFrom (packet, src, dst, type); + } + else + { + NS_FATAL_ERROR ("TapBridge::ForwardToBridgedDevice(): Bridged device does not support SendFrom"); + } } Ptr @@ -785,20 +803,48 @@ TapBridge::ReceiveFromBridgedDevice ( Mac48Address to = Mac48Address::ConvertFrom (dst); // - // 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 - // this device, but to some other address). We don't want to forward those - // 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 we are operating in BRIDGED_DEVICE mode, we have the situation described + // below: // - if (packetType == PACKET_OTHERHOST) + // Other Device <--> Tap Device <--> ns3 device + // Mac Addr A Mac Addr B Mac Addr C + // + // In Linux, "Other Device" and "Tap Device" are bridged together. This + // means that (modulo learning behavior) packets sent from "Other Device" + // are also sent out to "Tap Device" (i.e., in ns-3 lingo, "Tap Device" + // would call SendFrom on the "Tap Device" with the from address set to the + // original "Other Device" address. Packets received by "Tap Device" are + // (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 + // 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 + // 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 + // destination MAC addresses. If you think about it, this is also a bridging + // operation, but the bridged devices happen to have the same MAC address. + // + // The bottom line is that at this point, the code does exactly the same thing + // 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; } @@ -815,33 +861,7 @@ TapBridge::ReceiveFromBridgedDevice ( EthernetHeader header = EthernetHeader (false); header.SetSource (from); - - // - // 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.SetDestination (to); header.SetLengthType (protocol); p->AddHeader (header); From ac181370f3357d2be8238ae060f7ffa3edd9ca74 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Sat, 14 Mar 2009 00:54:18 -0700 Subject: [PATCH 03/67] Clean up some tap bridge dox --- src/devices/tap-bridge/tap.h | 137 +++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 61 deletions(-) diff --git a/src/devices/tap-bridge/tap.h b/src/devices/tap-bridge/tap.h index c5dff9071..f3abef4ce 100644 --- a/src/devices/tap-bridge/tap.h +++ b/src/devices/tap-bridge/tap.h @@ -31,31 +31,32 @@ * \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 | - * +---------------------------+ + * | host | +----------+ + * | ------ | | ghost | + * | apps | | node | + * | ------ | | -------- | + * | stack | | IP | +----------+ + * | ------ | | stack | | node | + * | TAP | |==========| | -------- | + * | device | <-- IPC Bridge --> | 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. + * tap mechanism in the underlying OS and acts as a bridge; but a bridge + * between devices that happen to have the same shared MAC address. * * The LocalDevice mode is the default operating mode of the Tap Bridge. * @@ -75,37 +76,39 @@ * \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 | - * +---------------------------+ + * | VM | +----------+ + * | ------- | | ghost | + * | apps | | node | + * | ------- | | -------- | + * | stack | | IP | +----------+ + * | ------- | +--------+ | stack | | node | + * | Virtual | | TAP | |==========| | -------- | + * | Device | | Device | <-- IPC Bridge-> | 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. + * In this case, a collection of virtual machines with associated Virtual + * Devices is created in the virtualization environment (for exampe, OpenVZ + * or VMware). A TAP device is then created for each Virtual Device that is + * desired to be bridged into the ns-3 simulation. The created TAP devices are + * then bridged together with the Virtual Devices using a native OS bridge + * mechanism shown as "OS (brctl) Bridge" in the illustration above.. + * + * In the ns-3 simulation a Tap Bridge is created for each TAP Device. The + * name of the TAP Device is assigned to the Tap Bridge using the "DeviceName" + * attribute. The Tap Bridge then opens a network tap to the TAP Device and + * extends the bridge to encompass the ns-3 net device. This makes it appear + * as if an ns-3 simulated net device is a member of the "OS (brctl) Bridge" + * and allows the Virtual Machines to communicate with the ns-3 simulation.. * * \subsection TapBridgeLocalDeviceMode TapBridge LocalDevice Mode * @@ -170,14 +173,19 @@ * 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: + * Linux host. The network tap used as IPC acts as a network bridge between + * two devices that happen to have the same MAC address. This is okay since + * the two fact that there are two devices with the same address is not known + * outside of the pair. + * + * In order to implement 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 + * 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. * @@ -218,10 +226,12 @@ * "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. + * The primary difference between modes is due to the fact that in BridgedDevice + * mode the MAC addresses of the TAPs will be pre-configured and will therefore + * be different than those in the bridged device. As in LocalDevice mode, the + * Tap Bridge functions as IPC bridge between the TAP device and the ns-3 net + * device, but in BridgedDevice configurations the two devices will have + * different MAC addresses. * * \subsection TapBridgeBridgedDeviceModeOperation TapBridge BridgedDevice Mode Operation * @@ -240,9 +250,14 @@ * 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. + * address of the TAP device. + * + * There is no functional difference between modes at this level, even though + * the configuration and conceptual models regarding what is going on are quite + * different -- the Tap Bridge is just a bridge. In the LocalDevice model, the + * bridge is between devices having the same MAC address and in the + * BridgedDevice model the bridge is between devices having different MAC + * addresses. * * \section TapBridgeChannelModel Tap Bridge Channel Model * From 3eff196614e82bf3ab303b7f95bf063643d45943 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 17 Mar 2009 16:00:46 -0700 Subject: [PATCH 04/67] a little more dox --- src/devices/tap-bridge/tap.h | 182 ++++++++++++++++++++--------------- 1 file changed, 102 insertions(+), 80 deletions(-) diff --git a/src/devices/tap-bridge/tap.h b/src/devices/tap-bridge/tap.h index f3abef4ce..d819061d0 100644 --- a/src/devices/tap-bridge/tap.h +++ b/src/devices/tap-bridge/tap.h @@ -22,9 +22,7 @@ * 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. + * connected to a real host. * * This is illustrated below * @@ -53,23 +51,25 @@ * * 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 and acts as a bridge; but a bridge - * between devices that happen to have the same shared MAC address. + * creates the TAP device 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 and acts as a + * conventional bridge; but a bridge between devices that happen to have the + * same shared MAC address. * * 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. + * host configurations. This allows ns-3 net devices to appear as part of a host + * operating system bridge (in Linux, we make the ns-3 device part of a "brctl" + * bridge. This mode is especially useful in the case of virtualization where + * the configuration of the virtual hosts may be dictated by another system and + * not be changable to suit ns-3. 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, one would need to manually create TAP devices + * on the host system and brigde these TAP devices to the existing (VM) virtual + * devices. The job of the Tap Bridge in this case is to extend the bridge to + * join the ns-3 net device. * * This is illustrated below: * @@ -98,17 +98,19 @@ * * In this case, a collection of virtual machines with associated Virtual * Devices is created in the virtualization environment (for exampe, OpenVZ - * or VMware). A TAP device is then created for each Virtual Device that is - * desired to be bridged into the ns-3 simulation. The created TAP devices are - * then bridged together with the Virtual Devices using a native OS bridge - * mechanism shown as "OS (brctl) Bridge" in the illustration above.. + * or VMware). A TAP device (with a specific name) is then manually created + * for each Virtual Device that will be bridged into the ns-3 simulation. + * These created TAP devices are then bridged together with the Virtual Devices + * using a native OS bridge mechanism shown as "OS (brctl) Bridge" in the + * illustration above. * - * In the ns-3 simulation a Tap Bridge is created for each TAP Device. The - * name of the TAP Device is assigned to the Tap Bridge using the "DeviceName" - * attribute. The Tap Bridge then opens a network tap to the TAP Device and - * extends the bridge to encompass the ns-3 net device. This makes it appear - * as if an ns-3 simulated net device is a member of the "OS (brctl) Bridge" - * and allows the Virtual Machines to communicate with the ns-3 simulation.. + * In the ns-3 simulation, a Tap Bridge is created to match each TAP Device. + * The name of the TAP Device is assigned to the Tap Bridge using the + * "DeviceName" attribute. The Tap Bridge then opens a network tap to the TAP + * Device and logically extends the bridge to encompass the ns-3 net device. + * This makes it appear as if an ns-3 simulated net device is a member of the + * "OS (brctl) Bridge" and allows the Virtual Machines to communicate with the + * ns-3 simulation.. * * \subsection TapBridgeLocalDeviceMode TapBridge LocalDevice Mode * @@ -116,15 +118,16 @@ * 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. + * is required by the user. 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 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. + * of an ns-3 BridgeNetDevice (or a conventional bridge in general) 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 * one TapBridge for each NetDevice that is being bridged. From the perspective @@ -151,32 +154,31 @@ * * 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. + * the user mode handler for a TAP net device. In LocalDevice mode, this TAP + * device is automatically created by the ns-3 simulation. When the Linux host + * writes to one of these automatically created /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 the Tap Bridge. + * In other words, a Linux process writes a packet to a tap device and this packet + * is redirected by the network tap mechanism toan ns-3 process where it is + * received by the TapBridge as a result of a read operation there. The TapBridge + * then writes 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 through an + * ns-3 net device onto an ns-3 network. * - * 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. + * In the other direction, a packet received by the ns-3 net device connected to + * the Tap Bridge is sent via promiscuous callback to 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 a 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. The network tap used as IPC acts as a network bridge between - * two devices that happen to have the same MAC address. This is okay since - * the two fact that there are two devices with the same address is not known - * outside of the pair. + * Linux host in the "real world" to an ns-3 net device in the simulation. + * Because the TAP device and the bridged ns-3 net device have the same MAC + * address and the network tap IPC link is not exernalized, this particular + * kind of bridge makes ti appear that a ns-3 net device is actually installed + * in the Linux host. * * In order to implement 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 @@ -213,9 +215,9 @@ * \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. + * arranged in a fundamentally similar was as in LocalDevice mode. The TAP + * device is bridged to the ns-3 net device in the same way. The description + * of LocalDevice mode 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, @@ -223,41 +225,61 @@ * 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. + * "BridgedDevice" and specifying the name of a pre-configured TAP device + * using ns-3 Attributes of the TapBridge. * - * The primary difference between modes is due to the fact that in BridgedDevice - * mode the MAC addresses of the TAPs will be pre-configured and will therefore - * be different than those in the bridged device. As in LocalDevice mode, the - * Tap Bridge functions as IPC bridge between the TAP device and the ns-3 net - * device, but in BridgedDevice configurations the two devices will have - * different MAC addresses. + * The primary conceptual difference between modes is due to the fact that in + * BridgedDevice mode the MAC addresses of the user-created TAPs will be pre- + * configured and will therefore be different than those in the bridged device. + * As in LocalDevice mode, the Tap Bridge functions as IPC bridge between the + * TAP device and the ns-3 net device, but in BridgedDevice configurations the + * two devices will have different MAC addresses and the bridging functionality + * will be fundamentally the same as in any bridge. Since this implies MAC + * address spoofing, the only ns-3 devices which may paritcipate in a bridge + * in BridgedDevice mode must support SendFrom (i.e., a call to the method + * SupportsSendFrom in the bridged net device must return true). * * \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. + * that lives in the ns-3 world. In the case of the BridgedDevice mode, these + * packets will need to be sent out on the ns-3 network as if they were sent on + * the Linux network. This means calling the SendFrom method on the bridged + * device and providing the source and destination MAC addresses found in the + * packet. * - * 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. + * In the other direction, a packet received by an ns-3 net device is hooked + * via callback to the TapBridge. This must be done in promiscuous mode since + * the goal is to bridge the ns-3 net device onto the OS (brctl) bridge of + * which the TAP device is a part. * * There is no functional difference between modes at this level, even though * the configuration and conceptual models regarding what is going on are quite - * different -- the Tap Bridge is just a bridge. In the LocalDevice model, the - * bridge is between devices having the same MAC address and in the + * different -- the Tap Bridge is just acting like a bridge. In the LocalDevice + * mode, the bridge is between devices having the same MAC address and in the * BridgedDevice model the bridge is between devices having different MAC * addresses. + * + * \subsection TapBridgeSingleSourceModeOperation TapBridge SingleSource Mode Operation + * + * As described in above, the Tap Bridge acts like a bridge. Just like every + * other bridge, there is a requirement that participating devices must have + * the ability to receive promiscuously and to spoof the source MAC addresses + * of packets. + * + * We do, however, have a specific requirement to be able to bridge Virtual + * Machines onto wireless STA nodes. Unfortunately, the 802.11 spec doesn't + * provide a good way to implement SendFrom. So we have to work around this. + * + * To this end, we provice the SingleSource mode of the Tap Bridge. This + * mode allows you to create a bridge as described in BridgedDevice mode, but + * only allows one source of packets on the Linux side of the bridge. The + * address on the Linux side is remembered in the Tap Bridge, and all packets + * coming from the Linux side are repeated out the ns-3 side using the ns-3 device + * MAC source address. All packets coming in from the ns-3 side are repeated + * out the Linux side using the remembered MAC address. This allows us to use + * SendFrom on the ns-3 device side which is available on all ns-3 net devices. * * \section TapBridgeChannelModel Tap Bridge Channel Model * From a0f8fdbfcc27065bf9ff8ae79190036060d45c5e Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 21 Mar 2009 15:40:49 -0700 Subject: [PATCH 05/67] initial modifications to tap-bridge --- src/devices/tap-bridge/tap-bridge.cc | 123 ++++++++++++++++---------- src/devices/tap-bridge/tap-bridge.h | 31 ++++--- src/devices/tap-bridge/tap-creator.cc | 8 +- src/devices/tap-bridge/wscript | 1 + src/helper/tap-bridge-helper.cc | 16 ++++ src/helper/tap-bridge-helper.h | 3 + 6 files changed, 118 insertions(+), 64 deletions(-) diff --git a/src/devices/tap-bridge/tap-bridge.cc b/src/devices/tap-bridge/tap-bridge.cc index 1d0f3d844..8e6a2e5c4 100644 --- a/src/devices/tap-bridge/tap-bridge.cc +++ b/src/devices/tap-bridge/tap-bridge.cc @@ -80,22 +80,22 @@ TapBridge::GetTypeId (void) 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 @@ TapBridge::GetTypeId (void) 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 @@ TapBridge::TapBridge () 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 @@ TapBridge::CreateTap (void) // // 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 @@ TapBridge::CreateTap (void) // -i The IP address to assign to the new tap device; // -m The MAC-48 address to assign to the new tap device; // -n The network mask to assign to the new tap device; - // -o The operating mode of the bridge (1=LocalDevice, 2=BridgedDevice) + // -o The operating mode of the bridge (1=ConfigureLocal, 2=UseLocal, 3=UseBridge) // -p 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,14 +383,18 @@ TapBridge::CreateTap (void) std::ostringstream ossMode; ossMode << "-o"; - if (m_mode == LOCAL_DEVICE) + if (m_mode == CONFIGURE_LOCAL) { ossMode << "1"; } - else + else if (m_mode == USE_LOCAL) { ossMode << "2"; } + else + { + ossMode << "3"; + } std::ostringstream ossPath; ossPath << "-p" << path; @@ -590,11 +596,12 @@ TapBridge::ReadThread (void) 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 @@ TapBridge::ReadThread (void) NS_LOG_INFO ("TapBridge::ReadThread(): Received packet"); NS_LOG_INFO ("TapBridge::ReadThread(): Scheduling handler"); DynamicCast (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 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) 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 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) // (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 @@ TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) // 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 @@ TapBridge::Filter (Ptr p, Address *src, Address *dst, uint16_t *type) // // 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 @@ TapBridge::SetBridgedNetDevice (Ptr bridgedDevice) 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 @@ TapBridge::SetBridgedNetDevice (Ptr bridgedDevice) // 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 device, Ptr packet, uint16_t protocol, @@ -799,11 +817,33 @@ TapBridge::ReceiveFromBridgedDevice ( 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 @@ TapBridge::ReceiveFromBridgedDevice ( // (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 @@ TapBridge::ReceiveFromBridgedDevice ( // 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 @@ TapBridge::ReceiveFromBridgedDevice ( 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 diff --git a/src/devices/tap-bridge/tap-bridge.h b/src/devices/tap-bridge/tap-bridge.h index 1b399cad0..8b5fae7e1 100644 --- a/src/devices/tap-bridge/tap-bridge.h +++ b/src/devices/tap-bridge/tap-bridge.h @@ -105,8 +105,9 @@ public: */ 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 @@ protected: */ virtual void DoDispose (void); - void ReceiveFromBridgedDevice (Ptr device, Ptr packet, uint16_t protocol, + void ReceiveFromSimDevice (Ptr device, Ptr packet, uint16_t protocol, Address const &src, Address const &dst, PacketType packetType); private: @@ -264,7 +265,7 @@ private: * 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 @@ private: /** * \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 @@ private: * The ns-3 net device to which we are bridging. */ Ptr 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 diff --git a/src/devices/tap-bridge/tap-creator.cc b/src/devices/tap-bridge/tap-creator.cc index 7c82de7e6..54ffe0b51 100644 --- a/src/devices/tap-bridge/tap-creator.cc +++ b/src/devices/tap-bridge/tap-creator.cc @@ -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 @@ CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, con 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; } diff --git a/src/devices/tap-bridge/wscript b/src/devices/tap-bridge/wscript index 0939c1a98..81db5e4ba 100644 --- a/src/devices/tap-bridge/wscript +++ b/src/devices/tap-bridge/wscript @@ -27,6 +27,7 @@ def build(bld): module.source.extend([ 'tap-bridge.cc', 'tap-encode-decode.cc', + 'tap-creator.cc', ]) headers.source.extend([ 'tap-bridge.h', diff --git a/src/helper/tap-bridge-helper.cc b/src/helper/tap-bridge-helper.cc index 70c638eb0..2087df5bd 100644 --- a/src/helper/tap-bridge-helper.cc +++ b/src/helper/tap-bridge-helper.cc @@ -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 @@ NS_LOG_COMPONENT_DEFINE ("TapBridgeHelper"); 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 @@ TapBridgeHelper::SetAttribute (std::string n1, const AttributeValue &v1) } +Ptr +TapBridgeHelper::Install (Ptr node, Ptr nd, const AttributeValue &v1) +{ + NS_LOG_FUNCTION (node << nd << &v1); + m_deviceFactory.Set ("DeviceName", v1); + return Install (node, nd); +} + Ptr TapBridgeHelper::Install (Ptr node, Ptr nd) { diff --git a/src/helper/tap-bridge-helper.h b/src/helper/tap-bridge-helper.h index 6e6a7a238..0ac7460a7 100644 --- a/src/helper/tap-bridge-helper.h +++ b/src/helper/tap-bridge-helper.h @@ -21,6 +21,7 @@ #include "net-device-container.h" #include "ns3/object-factory.h" +#include "ns3/tap-bridge.h" #include namespace ns3 { @@ -31,12 +32,14 @@ class AttributeValue; class TapBridgeHelper { public: + TapBridgeHelper (); TapBridgeHelper (Ipv4Address gateway); void SetAttribute (std::string n1, const AttributeValue &v1); Ptr Install (Ptr node, Ptr nd); Ptr Install (std::string nodeName, Ptr nd); Ptr Install (Ptr node, std::string ndName); Ptr Install (std::string nodeName, std::string ndName); + Ptr Install (Ptr node, Ptr nd, const AttributeValue &v1); private: ObjectFactory m_deviceFactory; }; From 00aec86b4138fc54c84e0cd237b696f4eddb2e26 Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Mon, 23 Mar 2009 14:22:54 +0100 Subject: [PATCH 06/67] must clear the list of routing protocols --- src/internet-stack/ipv4-l3-protocol.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/internet-stack/ipv4-l3-protocol.cc b/src/internet-stack/ipv4-l3-protocol.cc index 5970701f8..878ea0d9b 100644 --- a/src/internet-stack/ipv4-l3-protocol.cc +++ b/src/internet-stack/ipv4-l3-protocol.cc @@ -163,6 +163,7 @@ Ipv4L3Protocol::DoDispose (void) interface->Dispose (); } m_interfaces.clear (); + m_routingProtocols.clear (); m_node = 0; m_staticRouting->Dispose (); m_staticRouting = 0; From 04022b35bf4d90972b3f276c82d684b2fb1ccd6f Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 23 Mar 2009 11:26:39 -0700 Subject: [PATCH 07/67] Bugs 458, swap 2 LOC for 526 --- examples/tcp-large-transfer.cc | 13 +++++++++---- examples/tcp-nsc-lfn.cc | 9 +++++++++ .../point-to-point/point-to-point-net-device.cc | 3 ++- src/internet-stack/internet-stack.cc | 8 +++++++- src/internet-stack/ipv4-l3-protocol.cc | 6 ++---- src/internet-stack/nsc-tcp-l4-protocol.cc | 16 +++++++++++++++- src/internet-stack/nsc-tcp-l4-protocol.h | 2 ++ .../nsc-tcp-socket-factory-impl.cc | 2 +- src/internet-stack/tcp-l4-protocol.cc | 14 +++++++++++++- src/internet-stack/tcp-l4-protocol.h | 2 ++ 10 files changed, 62 insertions(+), 13 deletions(-) diff --git a/examples/tcp-large-transfer.cc b/examples/tcp-large-transfer.cc index 78b576834..18b6e9947 100644 --- a/examples/tcp-large-transfer.cc +++ b/examples/tcp-large-transfer.cc @@ -57,9 +57,14 @@ static uint32_t txBytes = 2000000; void StartFlow(Ptr, Ipv4Address, uint16_t); void WriteUntilBufferFull (Ptr, uint32_t); +static void +CwndTracer (uint32_t oldval, uint32_t newval) +{ + NS_LOG_INFO ("Moving cwnd from " << oldval << " to " << newval); +} + 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 // LogComponentEnable("TcpL4Protocol", LOG_LEVEL_ALL); @@ -67,9 +72,6 @@ int main (int argc, char *argv[]) // LogComponentEnable("PacketSink", LOG_LEVEL_ALL); // LogComponentEnable("TcpLargeTransfer", LOG_LEVEL_ALL); - - // Allow the user to override any of the defaults and the above - // Bind()s at run-time, via command-line arguments CommandLine cmd; cmd.Parse (argc, argv); @@ -140,6 +142,9 @@ int main (int argc, char *argv[]) Socket::CreateSocket (n0n1.Get (0), TcpSocketFactory::GetTypeId ()); localSocket->Bind (); + // Trace changes to the congestion window + Config::ConnectWithoutContext ("/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow", MakeCallback (&CwndTracer)); + // ...and schedule the sending "Application"; This is similar to what an // ns3::Application subclass would do internally. Simulator::ScheduleNow (&StartFlow, localSocket, diff --git a/examples/tcp-nsc-lfn.cc b/examples/tcp-nsc-lfn.cc index 4976e636e..b79674413 100644 --- a/examples/tcp-nsc-lfn.cc +++ b/examples/tcp-nsc-lfn.cc @@ -43,6 +43,11 @@ using namespace ns3; NS_LOG_COMPONENT_DEFINE ("TcpNscLfn"); +static void +CwndTracer (uint32_t oldval, uint32_t newval) +{ + NS_LOG_INFO ("Moving cwnd from " << oldval << " to " << newval); +} int main (int argc, char *argv[]) { @@ -133,6 +138,10 @@ int main (int argc, char *argv[]) clientApp.Stop (Seconds (runtime + 1.0 + i)); } + // Trace changes to the congestion window + Config::ConnectWithoutContext ("/NodeList/1/$ns3::NscTcpL4Protocol/SocketList/0/CongestionWindow", + MakeCallback (&CwndTracer)); + // This tells ns-3 to generate pcap traces. PointToPointHelper::EnablePcapAll ("tcp-nsc-lfn"); diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index e5cd12384..856ba6852 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -167,6 +167,7 @@ PointToPointNetDevice::PointToPointNetDevice () PointToPointNetDevice::~PointToPointNetDevice () { + NS_LOG_FUNCTION_NOARGS (); } void @@ -226,8 +227,8 @@ PointToPointNetDevice::TransmitStart (Ptr p) // NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit"); m_txMachineState = BUSY; - m_phyTxBeginTrace (m_currentPkt); m_currentPkt = p; + m_phyTxBeginTrace (m_currentPkt); Time txTime = Seconds (m_bps.CalculateTxTime(p->GetSize())); Time txCompleteTime = txTime + m_tInterframeGap; diff --git a/src/internet-stack/internet-stack.cc b/src/internet-stack/internet-stack.cc index 280f7bd6f..0e32c5cb6 100644 --- a/src/internet-stack/internet-stack.cc +++ b/src/internet-stack/internet-stack.cc @@ -54,6 +54,8 @@ AddUdpStack(Ptr node) Ptr udp = CreateObject (); udp->SetNode (node); ipv4->Insert (udp); + node->AggregateObject (udp); + Ptr udpFactory = CreateObject (); udpFactory->SetUdp (udp); node->AggregateObject (udpFactory); @@ -66,6 +68,8 @@ AddIcmpStack (Ptr node) Ptr icmp = CreateObject (); icmp->SetNode (node); ipv4->Insert (icmp); + node->AggregateObject (icmp); + Ptr rawFactory = CreateObject (); node->AggregateObject (rawFactory); } @@ -76,8 +80,8 @@ AddTcpStack(Ptr node) Ptr ipv4 = node->GetObject (); Ptr tcp = CreateObject (); tcp->SetNode (node); - ipv4->Insert (tcp); + node->AggregateObject (tcp); Ptr tcpFactory = CreateObject (); tcpFactory->SetTcp (tcp); @@ -114,6 +118,8 @@ AddNscStack(Ptr node, const std::string &soname) tcp->SetNscLibrary(soname); tcp->SetNode (node); ipv4->Insert (tcp); + node->AggregateObject (tcp); + Ptr tcpFactory = CreateObject (); tcpFactory->SetTcp (tcp); node->AggregateObject (tcpFactory); diff --git a/src/internet-stack/ipv4-l3-protocol.cc b/src/internet-stack/ipv4-l3-protocol.cc index 5970701f8..08755a51d 100644 --- a/src/internet-stack/ipv4-l3-protocol.cc +++ b/src/internet-stack/ipv4-l3-protocol.cc @@ -152,15 +152,13 @@ Ipv4L3Protocol::DoDispose (void) NS_LOG_FUNCTION (this); for (L4List_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i) { - (*i)->Dispose (); *i = 0; } m_protocols.clear (); - for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); ++i) + for (Ipv4InterfaceList::iterator i = m_interfaces.begin (); i != m_interfaces.end (); ++i) { - Ptr interface = *i; - interface->Dispose (); + *i = 0; } m_interfaces.clear (); m_node = 0; diff --git a/src/internet-stack/nsc-tcp-l4-protocol.cc b/src/internet-stack/nsc-tcp-l4-protocol.cc index 5be47abaa..ba030fffa 100644 --- a/src/internet-stack/nsc-tcp-l4-protocol.cc +++ b/src/internet-stack/nsc-tcp-l4-protocol.cc @@ -24,12 +24,13 @@ #include "ns3/packet.h" #include "ns3/node.h" +#include "ns3/object-vector.h" + #include "tcp-header.h" #include "ipv4-end-point-demux.h" #include "ipv4-end-point.h" #include "ipv4-l3-protocol.h" #include "nsc-tcp-l4-protocol.h" -#include "nsc-tcp-socket-impl.h" #include "nsc-sysctl.h" #include "tcp-typedefs.h" @@ -70,6 +71,10 @@ NscTcpL4Protocol::GetTypeId (void) ObjectFactoryValue (GetDefaultRttEstimatorFactory ()), MakeObjectFactoryAccessor (&NscTcpL4Protocol::m_rttFactory), MakeObjectFactoryChecker ()) + .AddAttribute ("SocketList", "The list of sockets associated to this protocol.", + ObjectVectorValue (), + MakeObjectVectorAccessor (&NscTcpL4Protocol::m_sockets), + MakeObjectVectorChecker ()) ; return tid; } @@ -154,6 +159,14 @@ void NscTcpL4Protocol::DoDispose (void) { NS_LOG_FUNCTION (this); + + for (std::vector >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++) + { + *i = 0; + } + m_sockets.clear (); + + if (m_endPoints != 0) { delete m_endPoints; @@ -173,6 +186,7 @@ NscTcpL4Protocol::CreateSocket (void) socket->SetNode (m_node); socket->SetTcp (this); socket->SetRtt (rtt); + m_sockets.push_back (socket); return socket; } diff --git a/src/internet-stack/nsc-tcp-l4-protocol.h b/src/internet-stack/nsc-tcp-l4-protocol.h index a9ca47345..22e799463 100644 --- a/src/internet-stack/nsc-tcp-l4-protocol.h +++ b/src/internet-stack/nsc-tcp-l4-protocol.h @@ -31,6 +31,7 @@ #include "ns3/timer.h" #include "sim_interface.h" +#include "nsc-tcp-socket-impl.h" namespace ns3 { @@ -116,6 +117,7 @@ private: INetStack* m_nscStack; void *m_dlopenHandle; Timer m_softTimer; + std::vector > m_sockets; }; }; // namespace ns3 diff --git a/src/internet-stack/nsc-tcp-socket-factory-impl.cc b/src/internet-stack/nsc-tcp-socket-factory-impl.cc index 60bcbac8d..6847a3576 100644 --- a/src/internet-stack/nsc-tcp-socket-factory-impl.cc +++ b/src/internet-stack/nsc-tcp-socket-factory-impl.cc @@ -13,8 +13,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "nsc-tcp-socket-factory-impl.h" #include "nsc-tcp-l4-protocol.h" +#include "nsc-tcp-socket-factory-impl.h" #include "ns3/socket.h" #include "ns3/assert.h" diff --git a/src/internet-stack/tcp-l4-protocol.cc b/src/internet-stack/tcp-l4-protocol.cc index f10ed9c5b..2e046b7a3 100644 --- a/src/internet-stack/tcp-l4-protocol.cc +++ b/src/internet-stack/tcp-l4-protocol.cc @@ -22,6 +22,7 @@ #include "ns3/log.h" #include "ns3/nstime.h" #include "ns3/boolean.h" +#include "ns3/object-vector.h" #include "ns3/packet.h" #include "ns3/node.h" @@ -31,7 +32,6 @@ #include "ipv4-end-point-demux.h" #include "ipv4-end-point.h" #include "ipv4-l3-protocol.h" -#include "tcp-socket-impl.h" #include "tcp-typedefs.h" @@ -334,6 +334,10 @@ TcpL4Protocol::GetTypeId (void) BooleanValue (false), MakeBooleanAccessor (&TcpL4Protocol::m_calcChecksum), MakeBooleanChecker ()) + .AddAttribute ("SocketList", "The list of sockets associated to this protocol.", + ObjectVectorValue (), + MakeObjectVectorAccessor (&TcpL4Protocol::m_sockets), + MakeObjectVectorChecker ()) ; return tid; } @@ -366,11 +370,18 @@ void TcpL4Protocol::DoDispose (void) { NS_LOG_FUNCTION_NOARGS (); + for (std::vector >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++) + { + *i = 0; + } + m_sockets.clear (); + if (m_endPoints != 0) { delete m_endPoints; m_endPoints = 0; } + m_node = 0; Ipv4L4Protocol::DoDispose (); } @@ -384,6 +395,7 @@ TcpL4Protocol::CreateSocket (void) socket->SetNode (m_node); socket->SetTcp (this); socket->SetRtt (rtt); + m_sockets.push_back (socket); return socket; } diff --git a/src/internet-stack/tcp-l4-protocol.h b/src/internet-stack/tcp-l4-protocol.h index 864df9d55..0d33031e5 100644 --- a/src/internet-stack/tcp-l4-protocol.h +++ b/src/internet-stack/tcp-l4-protocol.h @@ -31,6 +31,7 @@ #include "ipv4-l4-protocol.h" #include "ipv4-interface.h" +#include "tcp-socket-impl.h" #include "tcp-header.h" #include "tcp-typedefs.h" @@ -120,6 +121,7 @@ private: bool m_goodChecksum; bool m_calcChecksum; + std::vector > m_sockets; }; }; // namespace ns3 From 076f6cd0de1a577ad847568ec41284b5d3c49775 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 23 Mar 2009 18:28:08 -0700 Subject: [PATCH 08/67] test out the tap-bridge modes and update the example --- examples/tap-wifi-dumbbell.cc | 43 +++- src/devices/tap-bridge/tap-bridge.cc | 275 +++++++++++++++----------- src/devices/tap-bridge/tap-bridge.h | 4 +- src/devices/tap-bridge/tap-creator.cc | 9 +- 4 files changed, 208 insertions(+), 123 deletions(-) diff --git a/examples/tap-wifi-dumbbell.cc b/examples/tap-wifi-dumbbell.cc index f005c6a5a..f6dd8b5bc 100644 --- a/examples/tap-wifi-dumbbell.cc +++ b/examples/tap-wifi-dumbbell.cc @@ -20,7 +20,8 @@ // | external | // | Linux | // | Host | -// | "left" | +// | | +// | "mytap" | // +----------+ // | n0 n3 n4 // | +--------+ +------------+ +------------+ @@ -61,7 +62,7 @@ // item). // // ./waf --run tap-wifi-dumbbell& -// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev left gw 10.1.1.2 +// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev thetap gw 10.1.1.2 // ping 10.1.3.4 // // Take a look at the pcap traces and note that the timing reflects the @@ -77,9 +78,33 @@ // traffic data rate and watch the ping timing change dramatically. // // ./waf --run "tap-wifi-dumbbell --ns3::OnOffApplication::DataRate=100kb/s"& -// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev left gw 10.1.1.2 +// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev thetap gw 10.1.1.2 // ping 10.1.3.4 // +// 4) Try to run this in UseLocal mode. This allows you to provide an existing +// pre-configured tap device to the simulation. The IP address and MAC +// address in this mode do not have to match those of the ns-3 device. +// +// sudo tunctl -t mytap +// sudo ifconfig mytap hw ether 08:00:2e:00:00:01 +// sudo ifconfig mytap 10.1.1.1 netmask 255.255.255.0 up +// ./waf --run "tap-wifi-dumbbell --mode=UseLocal --tapName=mytap"& +// ping 10.1.1.3 +// +// 5) Try to run this in UseBridge mode. This allows you to bridge an ns-3 +// simulation to an existing pre-configured bridge. This uses tap devices +// just for illustration, you can create your own bridge if you want. +// +// sudo tunctl -t mytap1 +// sudo ifconfig mytap1 0.0.0.0 promisc up +// sudo tunctl -t mytap2 +// sudo ifconfig mytap2 0.0.0.0 promisc up +// sudo brctl addbr mybridge +// sudo brctl addif mybridge mytap1 +// sudo brctl addif mybridge mytap2 +// sudo ifconfig mybridge 10.1.1.5 netmask 255.255.255.0 up +// ./waf --run "tap-wifi-dumbbell --mode=UseBridge --tapName=mytap2"& +// ping 10.1.1.3 #include #include @@ -98,7 +123,12 @@ NS_LOG_COMPONENT_DEFINE ("TapDumbbellExample"); int main (int argc, char *argv[]) { + std::string mode = "ConfigureLocal"; + std::string tapName = "thetap"; + CommandLine cmd; + cmd.AddValue("mode", "Mode setting of TapBridge", mode); + cmd.AddValue("tapName", "Name of the OS tap device", tapName); cmd.Parse (argc, argv); GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl")); @@ -145,9 +175,10 @@ main (int argc, char *argv[]) ipv4Left.SetBase ("10.1.1.0", "255.255.255.0"); Ipv4InterfaceContainer interfacesLeft = ipv4Left.Assign (devicesLeft); - TapBridgeHelper bridgeLeft (interfacesLeft.GetAddress (1)); - bridgeLeft.SetAttribute ("DeviceName", StringValue ("left")); - bridgeLeft.Install (nodesLeft.Get (0), devicesLeft.Get (0)); + TapBridgeHelper tapBridge (interfacesLeft.GetAddress (1)); + tapBridge.SetAttribute ("Mode", StringValue (mode)); + tapBridge.SetAttribute ("DeviceName", StringValue (tapName)); + tapBridge.Install (nodesLeft.Get (0), devicesLeft.Get (0)); // // Now, create the right side. diff --git a/src/devices/tap-bridge/tap-bridge.cc b/src/devices/tap-bridge/tap-bridge.cc index 8e6a2e5c4..051793475 100644 --- a/src/devices/tap-bridge/tap-bridge.cc +++ b/src/devices/tap-bridge/tap-bridge.cc @@ -85,17 +85,20 @@ TapBridge::GetTypeId (void) MakeIpv4AddressAccessor (&TapBridge::m_tapGateway), MakeIpv4AddressChecker ()) .AddAttribute ("IpAddress", - "The IP address to assign to the tap device, when in ConfigureLocal mode.", + "The IP address to assign to the tap device, when in ConfigureLocal mode. " + "This address will override the discovered IP address of the simulated device.", Ipv4AddressValue ("255.255.255.255"), MakeIpv4AddressAccessor (&TapBridge::m_tapIp), MakeIpv4AddressChecker ()) .AddAttribute ("MacAddress", - "The MAC address to assign to the tap device, when in ConfigureLocal mode.", + "The MAC address to assign to the tap device, when in ConfigureLocal mode. " + "This address will override the discovered MAC address of the simulated device.", Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")), MakeMac48AddressAccessor (&TapBridge::m_tapMac), MakeMac48AddressChecker ()) .AddAttribute ("Netmask", - "The network mask to assign to the tap device, when in ConfigureLocal mode.", + "The network mask to assign to the tap device, when in ConfigureLocal mode. " + "This address will override the discovered MAC address of the simulated device.", Ipv4MaskValue ("255.255.255.255"), MakeIpv4MaskAccessor (&TapBridge::m_tapNetmask), MakeIpv4MaskChecker ()) @@ -222,29 +225,52 @@ TapBridge::CreateTap (void) NS_LOG_FUNCTION_NOARGS (); // - // 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 ConfigureLocal mode, the TapBridge has the - // responsibility for creating and configuring the TAP. + // The TapBridge has three distinct operating modes. At this point, the + // differences revolve around who is responsible for creating and configuring + // the underlying network tap that we use. In ConfigureLocal mode, the + // TapBridge has the responsibility for creating and configuring the TAP. // - // 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: + // In UseBridge or UseLocal modes, the user will provide us a configuration + // and we have to adapt to it. For example, in UseLocal mode, the user will + // be configuring a tap device outside the scope of the ns-3 simulation and + // will be expecting us to work with it. 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 "UseBridge" and the "DeviceName" Attribute - // to "tap0" in this case. + // The user will then set the "Mode" Attribute of the TapBridge to "UseLocal" + // and the "DeviceName" Attribute to "tap0" in this case. // - // 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. + // In ConfigureLocal mode, the user is asking the TapBridge to do the + // configuration and create a TAP with the provided "DeviceName" with which + // the user can later do what she wants. We need to extract values for the + // MAC address, IP address, net mask, etc, from the simualtion itself and + // use them to initialize corresponding values on the created tap device. // - // 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 + // In UseBridge mode, the user is asking us to use an existing tap device + // has been included in an OS bridge. She is asking us to take the simulated + // net device and logically add it to the existing bridge. We expect that + // the user has done something like: + // + // sudo brctl addbr mybridge + // sudo tunctl -t mytap + // sudo ifconfig mytap hw ether 00:00:00:00:00:01 + // sudo ifconfig mytap 0.0.0.0 up + // sudo brctl addif mybridge mytap + // sudo brctl addif mybridge ... + // sudo ifconfig mybridge 10.1.1.1 netmask 255.255.255.0 up + // + // The bottom line at this point is that we want to either create or use a + // tap device on the host based on the verb part "Use" or "Configure" of the + // operating mode. Unfortunately for us you have to have root privileges to + // do either. 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 just going to pass + // off the configuration information to that program and let it deal with + // the situation. + // + // We're going to fork and exec that program soon, but first we need to have // a socket to talk to it with. So we create a local interprocess (Unix) // socket for that purpose. // @@ -280,7 +306,8 @@ TapBridge::CreateTap (void) NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\""); // // Fork and exec the process to create our socket. If we're us (the parent) - // we wait for the child (the creator) to complete and read the socket it created using the ancillary data mechanism. + // we wait for the child (the creator) to complete and read the socket it + // created and passed back using the ancillary data mechanism. // pid_t pid = ::fork (); if (pid == 0) @@ -499,14 +526,14 @@ TapBridge::CreateTap (void) // // Now we can actually receive the interesting bits from the tap - // creator process. + // creator process. Lots of pain to get four bytes. // ssize_t bytesRead = recvmsg (sock, &msg, 0); NS_ABORT_MSG_IF (bytesRead != sizeof(int), "TapBridge::CreateTap(): Wrong byte count from socket creator"); // // There may be a number of message headers/ancillary data arrays coming in. - // Let's look for the one with a type SCM_RIGHTS which indicates it' the + // Let's look for the one with a type SCM_RIGHTS which indicates it's the // one we're interested in. // struct cmsghdr *cmsg; @@ -545,19 +572,19 @@ TapBridge::FindCreator (std::string creatorName) std::list locations; - // in repo + // The path to the bits if we're sitting in the root of the repo locations.push_back ("./build/optimized/src/devices/tap-bridge/"); locations.push_back ("./build/debug/src/devices/tap-bridge/"); - // in src + // if in src locations.push_back ("../build/optimized/src/devices/tap-bridge/"); locations.push_back ("../build/debug/src/devices/tap-bridge/"); - // in src/devices + // if in src/devices locations.push_back ("../../build/optimized/src/devices/tap-bridge/"); locations.push_back ("../../build/debug/src/devices/tap-bridge/"); - // in src/devices/tap-bridge + // if in src/devices/tap-bridge locations.push_back ("../../../build/optimized/src/devices/tap-bridge/"); locations.push_back ("../../../build/debug/src/devices/tap-bridge/"); @@ -582,12 +609,15 @@ TapBridge::ReadThread (void) NS_LOG_FUNCTION_NOARGS (); // - // It's important to remember that we're in a completely different thread than the simulator is running in. We - // need to synchronize with that other thread to get the packet up into ns-3. What we will need to do is to schedule - // a method to deal with the packet using the multithreaded simulator we are most certainly running. However, I just - // said it -- we are talking about two threads here, so it is very, very dangerous to do any kind of reference couning - // on a shared object. Just don't do it. So what we're going to do is to allocate a buffer on the heap and pass that - // buffer into the ns-3 context thread where it will create the packet. + // It's important to remember that we're in a completely different thread + // than the simulator is running in. We need to synchronize with that + // other thread to get the packet up into ns-3. What we will need to do + // is to schedule a method to deal with the packet using the multithreaded + // simulator we are most certainly running. However, I just said it -- we + // are talking about two threads here, so it is very, very dangerous to do + // any kind of reference counting on a shared object. Just don't do it. + // So what we're going to do is to allocate a buffer on the heap and pass + // that buffer into the ns-3 context thread where it will create the packet. // int32_t len = -1; @@ -610,18 +640,42 @@ TapBridge::ReadThread (void) NS_LOG_INFO ("TapBridge::ReadThread(): Received packet"); NS_LOG_INFO ("TapBridge::ReadThread(): Scheduling handler"); DynamicCast (Simulator::GetImplementation ())->ScheduleRealtimeNow ( - MakeEvent (&TapBridge::ForwardToSimDevice, this, buf, len)); + MakeEvent (&TapBridge::ForwardToBridgedDevice, this, buf, len)); buf = 0; } } void -TapBridge::ForwardToSimDevice (uint8_t *buf, uint32_t len) +TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len) { NS_LOG_FUNCTION (buf << len); // - // Create a packet out of the buffer we received and free that buffer. + // There are three operating modes for the TapBridge + // + // CONFIGURE_LOCAL means that ns-3 will create and configure a tap device + // and we are expected to use it. The tap device and the ns-3 net device + // will have the same MAC address by definition. Thus Send and SendFrom + // are equivalent in this case. We use Send to allow all ns-3 devices to + // participate in this mode. + // + // USE_LOCAL mode tells us that we have got to USE a pre-created tap device + // that will have a different MAC address from the ns-3 net device. We + // also enforce the requirement that there will only be one MAC address + // bridged on the Linux side so we can use Send (instead of SendFrom) in + // the linux to ns-3 direction. Again, all ns-3 devices can participate + // in this mode. + // + // USE_BRIDGE mode tells us that we are logically extending a Linux bridge + // on which lies our tap device. In this case there may be many linux + // net devices on the other side of the bridge and so we must use SendFrom + // to preserve the possibly many source addresses. Thus, ns-3 devices + // must support SendFrom in order to be considered for USE_BRIDGE mode. + // + + // + // First, create a packet out of the byte buffer we received and free that + // buffer. // Ptr packet = Create (reinterpret_cast (buf), len); free (buf); @@ -650,13 +704,28 @@ TapBridge::ForwardToSimDevice (uint8_t *buf, uint32_t len) 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"); + // + // Packets we are going to forward should not be from a broadcast src + // + NS_ASSERT_MSG (Mac48Address::ConvertFrom (src) != Mac48Address ("ff:ff:ff:ff:ff:ff"), + "TapBridge::ForwardToBridgedDevice: Source addr is broadcast"); + // + // Remember the Mac address since we are going to spoof it when we go + // the other way. + // 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"); + // device that does not support bridging (SupportsSendFrom returns false). + // The whole point of this mode is really to support this case. We allow + // only packets from one source MAC to flow across the TapBridge in this + // mode and will spoof that address when packets flow the other way. + // Since we will be doing this spoofing, we can relax the normal bridged + // device requirement to support SendFrom and use Send. + // + NS_LOG_LOGIC ("Forwarding packet to ns-3 device via Send()"); m_bridgedDevice->Send (packet, dst, type); return; } @@ -665,36 +734,30 @@ TapBridge::ForwardToSimDevice (uint8_t *buf, uint32_t len) // 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 + // Other Device <-bridge-> Tap Device <-bridge-> ns3 device + // Mac Addr A Mac Addr B Mac Addr C // - // In Linux, "Other Device" and "Tap Device" are bridged together. This - // means that (modulo learning behavior) packets sent from "Other Device" - // are also sent out to "Tap Device" (i.e., in ns-3 lingo, "Tap Device" - // would call SendFrom on the "Tap Device" with the from address set to the - // original "Other Device" address. Packets received by "Tap Device" are - // (modulo learning behavior) sent out to "Other Device." This makes it - // appear as if both devices are on a single subnet. + // In Linux, "Other Device" and "Tap Device" are bridged together. By this + // we mean that a user has sone something in Linux like: // - // 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 + // brctl addbr mybridge + // brctl addif other-device + // brctl addif tap-device + // + // In USE_BRIDGE mode, we want to logically extend this Linux behavior to the + // simulated 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" + // Linux bridge and take all packets that come from "Tap Device" and ask + // "ns3 Device" to send them down its directly connected network. Just like + // in a normal everyday bridge we need to call SendFrom in order to preserve + //the original packet's from address. // // 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 - // just call SendFrom on the bridged device ("ns3 Device") to ship the packet - // out. If you think about it, this is also a bridging operation, but the - // bridged devices happen to have the same MAC address. - // - // The bottom line is that at this point, the code does exactly the same thing - // even though they seem quite different at first glance. The only issue is - // what to do if the bridged device does not support SendFrom, which will be - // the case for Wifi STA nodes. + // directly connected network. A normal bridge would need to call SendFrom + // in order to preserve the original from address, but in CONFIGURE_LOCAL mode + // the tap device and the ns-3 device have the same MAC address by definition so + // we can call Send. // NS_LOG_LOGIC ("Forwarding packet"); @@ -704,6 +767,7 @@ TapBridge::ForwardToSimDevice (uint8_t *buf, uint32_t len) } else { + NS_ASSERT_MSG (m_mode == CONFIGURE_LOCAL, "TapBridge::ForwardToBridgedDevice(): Internal error"); m_bridgedDevice->Send (packet, dst, type); } } @@ -799,12 +863,12 @@ TapBridge::SetBridgedNetDevice (Ptr bridgedDevice) // 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::ReceiveFromSimDevice, this), 0, bridgedDevice, true); + m_node->RegisterProtocolHandler (MakeCallback (&TapBridge::ReceiveFromBridgedDevice, this), 0, bridgedDevice, true); m_bridgedDevice = bridgedDevice; } void -TapBridge::ReceiveFromSimDevice ( +TapBridge::ReceiveFromBridgedDevice ( Ptr device, Ptr packet, uint16_t protocol, @@ -814,11 +878,27 @@ TapBridge::ReceiveFromSimDevice ( { NS_LOG_FUNCTION (device << packet << protocol << src << dst << packetType); NS_ASSERT_MSG (device == m_bridgedDevice, "TapBridge::SetBridgedDevice: Received packet from unexpected device"); - NS_LOG_DEBUG ("Packet UID is " << packet->GetUid ()); + // + // There are three operating modes for the TapBridge + // + // CONFIGURE_LOCAL means that ns-3 will create and configure a tap device + // and we are expected to use it. The tap device and the ns-3 net device + // will have the same MAC address by definition. + // + // USE_LOCAL mode tells us that we have got to USE a pre-created tap device + // that will have a different MAC address from the ns-3 net device. In this + // case we will be spoofing the MAC address of a received packet to match + // the single allowed address on the Linux side. + // + // USE_BRIDGE mode tells us that we are logically extending a Linux bridge + // on which lies our tap device. + // + 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 @@ -826,11 +906,28 @@ TapBridge::ReceiveFromSimDevice ( // 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. + // 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 tap + // device on the Linux host. The only question we have to answer is, what + // should the destination address be? + // + // If we are in CONFIGURE_LOCAL mode, then the destination address is just + // left alone since it can only be the shared single MAC address, broadcast + // or multicast. + // + // If we are in USE_LOCAL mode, then we need to spoof the destination + // address with the one we saved. + // + // If we are in USE_BRIDGE mode, then we need to do the equvalent of a + // SendFrom and leave the source and destination alone. + // Mac48Address from = Mac48Address::ConvertFrom (src); Mac48Address to; if (m_mode == USE_LOCAL) @@ -842,48 +939,6 @@ TapBridge::ReceiveFromSimDevice ( to = Mac48Address::ConvertFrom (dst); } - // - // 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 - // - // In Linux, "Other Device" and "Tap Device" are bridged together. This - // means that (modulo learning behavior) packets sent from "Other Device" - // are also sent out to "Tap Device" (i.e., in ns-3 lingo, "Tap Device" - // would call SendFrom on the "Tap Device" with the from address set to the - // original "Other Device" address. Packets received by "Tap Device" are - // (modulo learning behavior) sent out to "Other Device." This makes it - // appear as if both devices are on a single subnet. - // - // 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 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 - // destination MAC addresses. If you think about it, this is also a bridging - // operation, but the bridged devices happen to have the same MAC address. - // - // The bottom line is that at this point, the code does exactly the same thing - // even though they seem quite different at first glance. - // - - // - // 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 - // Tap device on the Linux host. Once we do this, the bits in the packet will - // percolate up through the stack on the Linux host. - // - // The ns-3 net device that is the source of these bits has removed the MAC - // header, so we have to put one back on. - // Ptr p = packet->Copy (); EthernetHeader header = EthernetHeader (false); @@ -900,7 +955,7 @@ TapBridge::ReceiveFromSimDevice ( 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::ReceiveFromSimDevice(): Write error."); + NS_ABORT_MSG_IF (bytesWritten != p->GetSize (), "TapBridge::ReceiveFromBridgedDevice(): Write error."); } void diff --git a/src/devices/tap-bridge/tap-bridge.h b/src/devices/tap-bridge/tap-bridge.h index 8b5fae7e1..62d6a1350 100644 --- a/src/devices/tap-bridge/tap-bridge.h +++ b/src/devices/tap-bridge/tap-bridge.h @@ -210,7 +210,7 @@ protected: */ virtual void DoDispose (void); - void ReceiveFromSimDevice (Ptr device, Ptr packet, uint16_t protocol, + void ReceiveFromBridgedDevice (Ptr device, Ptr packet, uint16_t protocol, Address const &src, Address const &dst, PacketType packetType); private: @@ -265,7 +265,7 @@ private: * received from the host. * \param buf The length of the buffer. */ - void ForwardToSimDevice (uint8_t *buf, uint32_t len); + void ForwardToBridgedDevice (uint8_t *buf, uint32_t len); /** * \internal diff --git a/src/devices/tap-bridge/tap-creator.cc b/src/devices/tap-bridge/tap-creator.cc index 54ffe0b51..a80606e56 100644 --- a/src/devices/tap-bridge/tap-creator.cc +++ b/src/devices/tap-bridge/tap-creator.cc @@ -39,7 +39,7 @@ #define TAP_MAGIC 95549 -static int gVerbose = 1; // Set to true to turn on logging messages. +static int gVerbose = 0; // Set to true to turn on logging messages. #define LOG(msg) \ if (gVerbose) \ @@ -296,10 +296,9 @@ CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, con // // 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. + // 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 || strcmp (mode, "3") == 0) { From 0b1712ad1c46467b96ddd1e62cd5eb6e44216ad0 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 24 Mar 2009 00:51:10 -0700 Subject: [PATCH 09/67] tutorial changes for allinone --- doc/tutorial/getting-started.texi | 468 +++++++++++++++++++++--------- 1 file changed, 337 insertions(+), 131 deletions(-) diff --git a/doc/tutorial/getting-started.texi b/doc/tutorial/getting-started.texi index 1a1106893..b3fc4d6c6 100644 --- a/doc/tutorial/getting-started.texi +++ b/doc/tutorial/getting-started.texi @@ -44,78 +44,229 @@ the Getting Started section of the @command{ns-3} web site: @cindex tarball The @command{ns-3} code is available in Mercurial repositories on the server -code.nsnam.org. You can download a tarball release at +code.nsnam.org. You can also download a tarball release at @uref{http://www.nsnam.org/releases/}, or you can work with repositories -using Mercurial. +using Mercurial. We recommend using Mercurial unless there's a good reason +not to. See the end of this section for instructions on how to get a tarball +release. @cindex repository -If you go to the following link: @uref{http://code.nsnam.org/}, -you will see a number of repositories. Many are the private repositories of -the @command{ns-3} development team. The repositories of interest to you will -be prefixed with ``ns-3''. The current development snapshot (unreleased) -of @command{ns-3} may be found at: @uref{http://code.nsnam.org/ns-3-dev/}. -Official releases of @command{ns-3} will be numbered as @code{ns-3.} -with any required hotfixes added as minor release numbers. For example, a -second hotfix to a hypothetical release nine of @command{ns-3} would be -numbered @code{ns-3.9.2}. - -The current development snapshot (unreleased) of @command{ns-3} may be found -at: @uref{http://code.nsnam.org/ns-3-dev/}. The developers attempt to keep -this repository in a consistent, working state but it is a development area -with unreleased code present, so you may want to consider staying with an -official release if you do not need newly-introduced features. - -Since the release numbers are going to be changing, I will stick with -the more constant ns-3-dev here in the tutorial, but you can replace the -string ``ns-3-dev'' with your choice of release (e.g., ns-3.2) in the text -below. You can find the latest version of the code either by inspection of -the repository list or by going to the ``Getting Started'' web page and -looking for the latest release identifier. +The simplest way to get started using Mercurial repositories is to use the +@code{ns-3-allinone} environment. This is a set of scripts that manages the +downloading and building of various subystems of ns-3 for you. We recommend +that you begin your @command{ns-3} adventures in this environment as it can +really simplify your life at this point. +@subsection Downloading ns-3 Using Mercurial One practice is to create a directory called @code{repos} in one's home directory under which one can keep local Mercurial repositories. @emph{Hint: we will assume you do this later in the tutorial.} If you adopt -that approach, you can get a copy of the development version of -@command{ns-3} by typing the following into your Linux shell (assuming you -have installed Mercurial): +that approach, you can get a copy of @code{ns-3-allinone} by typing the +following into your Linux shell (assuming you have installed Mercurial): @verbatim cd mkdir repos cd repos - hg clone http://code.nanam.org/ns-3-dev + hg clone http://code.nsnam.org/ns-3-allinone +@end verbatim + +As the hg (Mercurial) command executes, you should see something like the +following displayed, + +@verbatim + destination directory: ns-3-allinone + requesting all changes + adding changesets + adding manifests + adding file changes + added 26 changesets with 40 changes to 7 files + 7 files updated, 0 files merged, 0 files removed, 0 files unresolved +@end verbatim + +After the clone command completes, you should have a directory called +@code{ns-3-allinone} under your @code{~/repos} directory, the contents of which should +look something like the following: + +@verbatim + build.py* constants.py dist.py* download.py* README util.py +@end verbatim + +Notice that you really just downloaded some Python scripts. The next step +will be to use those scripts to download and build the @command{ns-3} +distribution of your choice. + +@cindex repository +If you go to the following link: @uref{http://code.nsnam.org/}, +you will see a number of repositories. Many are the private repositories of +the @command{ns-3} development team. The repositories of interest to you will +be prefixed with ``ns-3''. Official releases of @command{ns-3} will be +numbered as @code{ns-3..}. For example, a second hotfix to a +still hypothetical release nine of @command{ns-3} would be numbered as +@code{ns-3.9.2}. + +We have had a regression testing framework in place since the first release. +For each release, a set of output files that define ``good behavior'' are saved. +These known good output files are called reference traces and are associated +with a given release by name. For example, in @uref{http://code.nsnam.org/} +you will find a repository named @code{ns-3.1} which is the first stable release +of @command{ns-3}. You will also find a separate repository named +@code{ns-3.1-ref-traces} that holds the reference traces for the @code{ns-3.1} +release. It is crucial to keep these files consistent if you want to do any +regression testing of your repository. This is a good idea to do at least once +to verify everything has built correctly. + +The current development snapshot (unreleased) of @command{ns-3} may be found +at @uref{http://code.nsnam.org/ns-3-dev/} and the associated reference traces +may be found at @uref{http://code.nsnam.org/ns-3-dev-ref-traces/}. The +developers attempt to keep these repository in consistent, working states but +they are in a development area with unreleased code present, so you may want +to consider staying with an official release if you do not need newly- +introduced features. + +Since the release numbers are going to be changing, I will stick with +the more constant ns-3-dev here in the tutorial, but you can replace the +string ``ns-3-dev'' with your choice of release (e.g., ns-3.4 and +ns-3.4-ref-traces) in the text below. You can find the latest version of the +code either by inspection of the repository list or by going to the ``Getting +Started'' web page and looking for the latest release identifier. + +Go ahead and change into the @code{ns-3-allinone} directory you created when +you cloned that repository. We are now going to use the @code{download.py} +script to pull down the various pieces of @code{ns-3} you will be using/ + +Go ahead and type the following into your shell (remember you can substitute +the name of your chosen release number instead of @code{ns-3-dev} -- like +@code{"ns-3.4"} and @code{"ns-3.4-ref-traces"} if you want to work with a +stable release). + +@verbatim + ./download.py -n ns-3-dev -r ns-3-dev-ref-traces @end verbatim As the hg (Mercurial) command executes, you should see something like the following, @verbatim - destination directory: ns-3-dev + # + # Get NS-3 + # + + Cloning ns-3 branch + => hg clone http://code.nsnam.org/ns-3-dev ns-3-dev requesting all changes adding changesets adding manifests adding file changes - added 3276 changesets with 12301 changes to 1353 files - 594 files updated, 0 files merged, 0 files removed, 0 files unresolved + added 4292 changesets with 15368 changes to 1671 files + 823 files updated, 0 files merged, 0 files removed, 0 files unresolved @end verbatim -After the clone command completes, you should have a directory called -ns-3-dev under your @code{~/repos} directory, the contents of which should -look something like the following: +This is output by the download script as it fetches the actual @code{ns-3} +code from the repository. Next, you should see something like, @verbatim - AUTHORS examples/ README samples/ utils/ waf.bat* - build/ LICENSE regression/ scratch/ VERSION wscript - doc/ ns3/ RELEASE_NOTES src/ waf* + # + # Get the regression traces + # + + Synchronizing reference traces using Mercurial. + => hg clone http://code.nsnam.org/ns-3-dev-ref-traces ns-3-dev-ref-traces + requesting all changes + adding changesets + adding manifests + adding file changes + added 79 changesets with 1102 changes to 222 files + 206 files updated, 0 files merged, 0 files removed, 0 files unresolved @end verbatim -Similarly, if working from a released version instead, you can simply +This is the download script fetching the reference trace files for you. +The download script is smart enough to know that on some platforms various +pieces of ns-3 are not supported. On your platform you may not see some +of these pieces come down. However, on most platforms, the process should +continue with something like, + +@verbatim + # + # Get PyBindGen + # + + Required pybindgen version: 0.10.0.630 + Trying to fetch pybindgen; this will fail if no network connection is available. Hit Ctrl-C to skip. + => bzr checkout -rrevno:630 https://launchpad.net/pybindgen pybindgen + Fetch was successful. +@end verbatim + +This was the download script getting the Python bindings generator for you. +Next you should see (modulo platform variations) something along the lines of, + +@verbatim + # + # Get NSC + # + + Required NSC version: nsc-0.5.0 + Retrieving nsc from https://secure.wand.net.nz/mercurial/nsc + => hg clone https://secure.wand.net.nz/mercurial/nsc nsc + requesting all changes + adding changesets + adding manifests + adding file changes + added 270 changesets with 17375 changes to 14991 files + 10614 files updated, 0 files merged, 0 files removed, 0 files unresolved +@end verbatim + +This part of the process is the script downloading the Network Simulation +Cradle for you. + +After the clone command completes, you should have several new directories +under @code{~/repos/ns-3-allinone}: + +@verbatim + build.py* constants.pyc download.py* ns-3-dev-ref-traces/ pybindgen/ util.py + constants.py dist.py* ns-3-dev/ nsc/ README util.pyc +@end verbatim + +Go ahead and change into @code{ns-3-dev} under your @code{~/repos/ns-3-allinone} +directory. You should see something like the following there: + +@verbatim + AUTHORS examples/ regression/ scratch/ waf* + bindings/ LICENSE regression.py src/ waf.bat* + CHANGES.html ns3/ RELEASE_NOTES utils/ wscript + doc/ README samples/ VERSION wutils.py +@end verbatim + +You are now ready to build the @command{ns-3} distribution. + +@subsection Downloading ns-3 Using a Tarball +The process for downloading @code{ns-3} via tarball is simpler than the +Mercurial process since all of the pieces are pre-packaged for you. You just +have to pick a release, download it and decompress it. + +As mentioned above, one practice is to create a directory called @code{repos} +in one's home directory under which one can keep local Mercurial repositories. +One could also keep a @code{tarballs} directory. @emph{Hint: the tutorial +will assume you downloaded into a @code{repos} directory, so remember the +placekeeper.} If you adopt the @code{tarballs} directory approach, you can +get a copy of a release by typing the following into your Linux shell +(substitute the appropriate version numbers, of course): + @verbatim cd - mkdir repos - wget http://www.nsnam.org/releases/ns-3.2.tar.bz2 - bunzip2 ns-3.2.tar.bz2 - tar xvf ns-3.2.tar + mkdir tarballs + cd tarballs + wget http://www.nsnam.org/releases/ns-allinone-3.4.tar.bz2 + bunzip2 ns-allinone-3.4.tar.bz2 + tar xf ns-3.4.tar +@end verbatim + +If you change into the directory @code{ns-allinone-3.4} you should see a +number of files: + +@verbatim +build.py* ns-3.4-RC2/ nsc-0.5.0/ util.py +constants.py ns-3.4-RC2-ref-traces/ pybindgen-0.10.0.630/ @end verbatim You are now ready to build the @command{ns-3} distribution. @@ -127,19 +278,61 @@ You are now ready to build the @command{ns-3} distribution. @node Building ns-3 @section Building ns-3 +@subsection Building with build.py +@cindex building with build.py +The first time you build the @command{ns-3} project you should build using the +@command{allinone} environment. This will get the project configured for you +in the most commonly useful way. + +Change into the directory you created in the download section above. If you +downloaded using Mercurial you should have a directory called +@code{ns-3-allinone} under your @code{~/repos} directory. If you downloaded +using a tarball you should have a directory called something like +@code{ns-3-allinone-3.4} under your @code{~/tarballs} directory. Take a deep +breath and type the following: + +@verbatim + ./build.py +@end verbatim + +You will see lots of typical compiler output messages displayed as the build +script builds the various pieces you downloaded. Eventually you should see the +following magic words: + +@verbatim + Build finished successfully (00:02:37) + Leaving directory `./ns-3-dev' +@end verbatim + +Once the project has built you can say goodbye to your old friends, the +@code{ns-3-allinone} scripts. You got what you needed from them and will now +interact directly with Waf and we do it in the @code{ns-3-dev} directory and +not in the @code{ns-3-allinone} directory. Go ahead and change into the +@code{ns-3-dev} directory (or the directory for the appropriate release you +downloaded. + +@verbatim + cd ns-3-dev +@end verbatim + +@subsection Building with Waf @cindex building with Waf @cindex configuring Waf @cindex building debug version with Waf @cindex compiling with Waf @cindex unit tests with Waf @cindex regression tests with Waf -We use Waf to build the @command{ns-3} project. The first thing you will need -to do is to configure the build. For reasons that will become clear later, -we are going to work with debug builds in the tutorial. To explain to Waf -that it should do debug builds you will need to execute the following command, +We use Waf to configure and build the @command{ns-3} project. It's not +strictly required at this point, but it will be valuable to take a slight +detour and look at how to make changes to the configuration of the project. +Probably the most useful configuration change you can make will be to +build the optimized version of the code. By default you have configured +your project to build the debug version. Let's tell the project to do +make an optimized build. To explain to Waf that it should do optimized +builds you will need to execute the following command, @verbatim - ./waf -d debug configure + ./waf -d optimized configure @end verbatim This runs Waf out of the local directory (which is provided as a convenience @@ -147,57 +340,82 @@ for you). As the build system checks for various dependencies you should see output that looks similar to the following, @verbatim -Checking for program g++ : ok /usr/bin/g++ -Checking for compiler version : ok Version 4.0.1 -Checking for program cpp : ok /usr/bin/cpp -Checking for program ar : ok /usr/bin/ar -Checking for program ranlib : ok /usr/bin/ranlib -Checking for compiler could create programs : ok -Checking for compiler could create shared libs : ok -Checking for compiler could create static libs : ok -Checking for flags -O2 -DNDEBUG : ok -Checking for flags -g -DDEBUG : ok -Checking for flags -g3 -O0 -DDEBUG : ok -Checking for flags -Wall : ok -Checking for g++ : ok -Checking for -Wno-error=deprecated-declarations compilation flag support : no -Checking for header stdlib.h : ok -Checking for header stdlib.h : ok -Checking for header signal.h : ok -Checking for library rt : not found -Checking for header pthread.h : ok -Checking for high precision time implementation: 128-bit integer -Checking for header stdint.h : ok -Checking for header inttypes.h : ok -Checking for header sys/inttypes.h : not found -Checking for package gtk+-2.0 >= 2.12 : not found -Checking for library sqlite3 : ok -Checking for package goocanvas gthread-2.0 : not found -Checking for program python : ok /usr/local/bin/python -Checking for Python version >= 2.3 : ok 2.4.3 -Checking for library python2.4 : not found -Checking for library python2.4 : not found -Checking for library python24 : not found -Checking for program python2.4-config : not found -Checking for header Python.h : not found -Checking for program diff : ok /usr/bin/diff -Checking for program hg : ok /opt/local/bin/hg +Checking for program g++ : ok /usr/bin/g++ +Checking for program cpp : ok /usr/bin/cpp +Checking for program ar : ok /usr/bin/ar +Checking for program ranlib : ok /usr/bin/ranlib +Checking for g++ : ok +Checking for program pkg-config : ok /usr/bin/pkg-config +Checking for regression reference traces : ok ../ns-3-dev-ref-traces (guessed) +Checking for -Wno-error=deprecated-declarations support : yes +Checking for header stdlib.h : ok +Checking for header signal.h : ok +Checking for header pthread.h : ok +Checking for high precision time implementation : 128-bit integer +Checking for header stdint.h : ok +Checking for header inttypes.h : ok +Checking for header sys/inttypes.h : not found +Checking for library rt : ok +Checking for header netpacket/packet.h : ok +Checking for header linux/if_tun.h : ok +Checking for pkg-config flags for GTK_CONFIG_STORE : ok +Package libxml-2.0 was not found in the pkg-config search path. +Perhaps you should add the directory containing `libxml-2.0.pc' +to the PKG_CONFIG_PATH environment variable +No package 'libxml-2.0' found +Checking for pkg-config flags for LIBXML2 : not found +Checking for library sqlite3 : ok +Checking for NSC location : ok ../nsc (guessed) +Checking for library dl : ok +Checking for NSC supported architecture x86_64 : ok +Package goocanvas was not found in the pkg-config search path. +Perhaps you should add the directory containing `goocanvas.pc' +to the PKG_CONFIG_PATH environment variable +No package 'goocanvas' found +Checking for pkg-config flags for MOBILITY_VISUALIZER : not found +Checking for program python : ok /usr/bin/python +Checking for Python version >= 2.3 : ok 2.5.2 +Checking for library python2.5 : ok +Checking for program python2.5-config : ok /usr/bin/python2.5-config +Checking for header Python.h : ok +Checking for -fvisibility=hidden support : yes +Checking for pybindgen location : ok ../pybindgen (guessed) +Checking for Python module pybindgen : ok +Checking for pybindgen version : ok 0.10.0.630 +Checking for Python module pygccxml : ok +Checking for pygccxml version : ok 0.9.5 +Checking for program gccxml : ok /usr/local/bin/gccxml +Checking for gccxml version : ok 0.9.0 +Checking for program sudo : ok /usr/bin/sudo +Checking for program hg : ok /usr/bin/hg +Checking for program valgrind : ok /usr/bin/valgrind ---- Summary of optional NS-3 features: -Threading Primitives : enabled -Real Time Simulator : enabled -GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found) -SQlite stats data output : enabled -Network Simulation Cradle : not enabled (--enable-nsc configure option not given) -Python Bindings : not enabled (Python development headers not found.) -Configuration finished successfully; project is now ready to build. +Threading Primitives : enabled +Real Time Simulator : enabled +Emulated Net Device : enabled +Tap Bridge : enabled +GtkConfigStore : enabled +XmlIo : not enabled (library 'libxml-2.0 >= 2.7' not found) +SQlite stats data output : enabled +Network Simulation Cradle : enabled +Python Bindings : enabled +Python API Scanning Support : enabled +Use sudo to set suid bit : not enabled (option --enable-sudo not selected) +Configuration finished successfully (00:00:02); project is now ready to build. @end verbatim -Note the trailing portion of the above output. Some ns-3 options are -not enabled by default or require support from the underlying system. -For instance, to enable Python bindings, Python development headers must -be installed on the host machine, and they were not found in the above -example, so Python scripting will not be supported in the resulting build. -For this tutorial, we will focus on the non-optional pieces of ns-3. +Note the last part of the above output. Some ns-3 options are not enabled by +default or require support from the underlying system to work properly +For instance, to enable XmlTo, the library libxml-2.0 must be found on the +system. in the example above, this library was not found and the corresponding +feature was not enabled. There is a feature to use sudo to set the suid bit of +certain programs. This was not enabled by default. + +Now go ahead and switch back to the debug build: + +@verbatim + ./waf -d debug configure +@end verbatim The build system is now configured and you can build the debug versions of the @command{ns-3} programs by simply typing, @@ -206,14 +424,8 @@ the @command{ns-3} programs by simply typing, ./waf @end verbatim -(Hint: if you have a multicore machine, use the "-j JOBS" option to speed -up your build, where JOBS is the number of cores) -You will see many Waf status messages displayed as the system compiles. The -most important is the last one: - -@verbatim - Compilation finished successfully -@end verbatim +Okay, sorry, I made you build the @command{ns-3} part of the system twice, +but now you know how to change the configuration and build optimized code. @c ======================================================================== @c Testing ns-3 @@ -234,19 +446,22 @@ You should see a report from each unit test that executes indicating that the test has passed. @verbatim - ~/repos/ns-3-dev > ./waf check - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Build finished successfully (00:00:00) + -- Running NS-3 C++ core unit tests... PASS AddressHelper PASS Wifi PASS DcfManager - ... - PASS Object PASS Ptr PASS Callback - ~/repos/ns-3-dev > + -- Running NS-3 Python bindings unit tests... + ........... + ---------------------------------------------------------------------- + Ran 11 tests in 0.003s + + OK @end verbatim This command is typically run by @code{users} to quickly verify that an @@ -281,34 +496,25 @@ they are identical, the regression tests report a PASS status. If the regression tests pass, you should see something like, @verbatim - ~/repos/ns-3-dev > ./waf --regression - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully - ========== Running Regression Tests ========== - Synchronizing reference traces using Mercurial. - Pulling http://code.nsnam.org/ns-3-dev-ref-traces from repo. - Skipping csma-bridge: Python bindings not available. - SKIP test-csma-bridge - PASS test-csma-broadcast + Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + [647/669] regression-test (test-csma-bridge) + [648/669] regression-test (test-csma-broadcast) + [649/669] regression-test (test-csma-multicast) + [650/669] regression-test (test-csma-one-subnet) PASS test-csma-multicast - PASS test-csma-one-subnet - PASS test-csma-packet-socket - PASS test-realtime-udp-echo - PASS test-simple-error-model - PASS test-simple-global-routing - PASS test-simple-point-to-point-olsr - PASS test-tcp-large-transfer - PASS test-udp-echo - PASS test-wifi-wired-bridging - - ~/repos/ns-3-dev > + [651/669] regression-test (test-csma-packet-socket) + PASS test-csma-bridge + ... + Regression testing summary: + PASS: 22 of 22 tests passed + Build finished successfully (00:00:23) @end verbatim If a regression tests fails you will see a FAIL indication along with a pointer to the offending trace file and its associated reference trace file along with a suggestion on diff parameters and options in order to see what -has gone awry. Python regression tests will be SKIPped if Python bindings -are not built. +has gone awry. Some regression tests wmay be SKIPped if the required support +is not present. @c ======================================================================== @c Running a Script From 0ed62f98e158dd80bf418af10e745145467765be Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 24 Mar 2009 12:45:30 -0700 Subject: [PATCH 10/67] clean up tutorial up through tweaking section --- doc/tutorial/conceptual-overview.texi | 119 +++++----- doc/tutorial/getting-started.texi | 73 +++--- doc/tutorial/introduction.texi | 56 ++--- doc/tutorial/tweaking.texi | 311 ++++++++++++++------------ 4 files changed, 302 insertions(+), 257 deletions(-) diff --git a/doc/tutorial/conceptual-overview.texi b/doc/tutorial/conceptual-overview.texi index 040ade27c..94b0b404d 100644 --- a/doc/tutorial/conceptual-overview.texi +++ b/doc/tutorial/conceptual-overview.texi @@ -362,21 +362,6 @@ enable on each component. These two lines of code enable debug logging at the INFO level for echo clients and servers. This will result in the application printing out messages as packets are sent and received during the simulation. -The next line of code is used to give a fixed seed to the random number -generators so that they will generate repeatable results. In the example -programs, it allows us to thouroughly document the output of the trace files -in a consistent way. Having a fixed seed also allows us to use the examples -in our regression testing framework. - -@verbatim - RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); -@end verbatim - -Random variables are very important in understanding how to get repeatable -results, so you are encouraged to read the Doxygen and manual sections to -understand what is going on there. For us, the main concern is in making -random backoff algorithms consistent across runs. - Now we will get directly to the business of creating a topology and running a simulation. We use the topology helper objects to make this job as easy as possible. @@ -439,7 +424,7 @@ The next three lines in the script are, pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); @end verbatim -The first line +The first line, @verbatim PointToPointHelper pointToPoint; @@ -738,34 +723,46 @@ built if you run Waf. Let's try it. Copy @code{examples/first.cc} into the @code{scratch} directory. @verbatim - ~/repos/ns-3-dev > cp examples/first.cc scratch/ + ~/repos/ns-3-dev > cp examples/first.cc scratch/myfirst.cc @end verbatim -and then build it using waf, +Warning: We use the file @code{first.cc} as one of our regression tests to +verify that it works exactly as we expect. This means that an executable +named @code{first} already exists in the project. If you want to execute +what you compile, and not a previously compiled program, please do the +renaming suggested below.) + +Now build your example using Waf: @verbatim - ~/repos/ns-3-dev > ./waf - Entering directory `/home/craigdo/repos/ns-3-dev/build' - [467/511] cxx: scratch/first.cc -> build/debug/scratch/first_1.o - [468/511] cxx: scratch/multiple-sources/simple-main.cc -> build/debug/scratch/multiple-sources/simple-main_2.o - [469/511] cxx: scratch/multiple-sources/simple-simulation.cc -> build/debug/scratch/multiple-sources/simple-simulation_2.o - [470/511] cxx: scratch/simple.cc -> build/debug/scratch/simple_3.o - [508/511] cxx_link: build/debug/scratch/first_1.o -> build/debug/scratch/first - Compilation finished successfully - ~/repos/ns-3-dev > + ./waf +@end verbatim + +You should see messages reporting that your @code{myfirst} example was built +successfully. + +@verbatim + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + [563/648] cxx: scratch/myfirst.cc -> build/debug/scratch/myfirst_3.o + [646/648] cxx_link: build/debug/scratch/myfirst_3.o -> build/debug/scratch/myfirst + Build finished successfully (00:00:02) @end verbatim You can now run the example (note that if you build your program in the scratch directory you must run it out of the scratch directory): @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/first - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + ./waf --run scratch/myfirst +@end verbatim + +You should see some output: + +@verbatim + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) Sent 1024 bytes to 10.1.1.2 Received 1024 bytes from 10.1.1.1 Received 1024 bytes from 10.1.1.2 - ~/repos/ns-3-dev > @end verbatim Here you see that the build system checks to make sure that the file has been @@ -793,38 +790,42 @@ links, one can browse the source tree. The top-level directory for one of our @emph{repositories} will look something like: + @verbatim -drwxr-xr-x [up] -drwxr-xr-x doc manifest -drwxr-xr-x examples manifest -drwxr-xr-x ns3 manifest -drwxr-xr-x regression manifest -drwxr-xr-x samples manifest -drwxr-xr-x scratch manifest -drwxr-xr-x src manifest -drwxr-xr-x tutorial manifest -drwxr-xr-x utils manifest --rw-r--r-- 135 .hgignore file | revisions | annotate --rw-r--r-- 891 .hgtags file | revisions | annotate --rw-r--r-- 441 AUTHORS file | revisions | annotate --rw-r--r-- 17987 LICENSE file | revisions | annotate --rw-r--r-- 4948 README file | revisions | annotate --rw-r--r-- 4917 RELEASE_NOTES file | revisions | annotate --rw-r--r-- 7 VERSION file | revisions | annotate --rwxr-xr-x 99143 waf file | revisions | annotate --rwxr-xr-x 28 waf.bat file | revisions | annotate --rw-r--r-- 30584 wscript file | revisions | annotate +drwxr-xr-x [up] +drwxr-xr-x bindings python files +drwxr-xr-x doc files +drwxr-xr-x examples files +drwxr-xr-x ns3 files +drwxr-xr-x regression files +drwxr-xr-x samples files +drwxr-xr-x scratch files +drwxr-xr-x src files +drwxr-xr-x utils files +-rw-r--r-- 2009-03-24 00:51 -0700 505 .hgignore file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 1682 .hgtags file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 686 AUTHORS file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 14893 CHANGES.html file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 17987 LICENSE file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 3742 README file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 13505 RELEASE_NOTES file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 6 VERSION file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 9257 regression.py file | revisions | annotate +-rwxr-xr-x 2009-03-24 00:51 -0700 81285 waf file | revisions | annotate +-rwxr-xr-x 2009-03-24 00:51 -0700 28 waf.bat file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 26270 wscript file | revisions | annotate +-rw-r--r-- 2009-03-24 00:51 -0700 6636 wutils.py file | revisions | annotate @end verbatim The source code is mainly in the @code{src} directory. You can view source -code by clicking on the @code{manifest} link to the right of the directory -name. If you click on the @code{manifest} link to the right of the src -directory you will find a subdirectory. If you click on the @code{manifest} -link next to the @code{core} subdirectory in under @code{src}, you will find -a list of files. The first file you will find is @code{assert.h}. If you -click on the @code{file} link, you will be sent to the source file for -@code{assert.h}. +code either by clicking on the directory name or by clicking on the @code{files} +link to the right of the directory name. If you click on the @code{src} +directory you be taken to the lising of the @code{src} subdirectories. If you +click on @code{core} subdirectory, you will find a list of files. The first file +you will find (as of this writing) is @code{abort.h}. If you +click on @code{abort.h} link, you will be sent to the source file for @code{abort.h}. Our example scripts are in the @code{examples} directory. The source code for the helpers we have used in this chapter can be found in the -@code{src/helpers} directory. +@code{src/helpers} directory. Feel free to poke around in the directory tree to +get a feel for what is there and the style of @command{ns-3} programs. diff --git a/doc/tutorial/getting-started.texi b/doc/tutorial/getting-started.texi index b3fc4d6c6..a8023c057 100644 --- a/doc/tutorial/getting-started.texi +++ b/doc/tutorial/getting-started.texi @@ -53,9 +53,9 @@ release. @cindex repository The simplest way to get started using Mercurial repositories is to use the @code{ns-3-allinone} environment. This is a set of scripts that manages the -downloading and building of various subystems of ns-3 for you. We recommend -that you begin your @command{ns-3} adventures in this environment as it can -really simplify your life at this point. +downloading and building of various subystems of @command{ns-3} for you. We +recommend that you begin your @command{ns-3} adventures in this environment +as it can really simplify your life at this point. @subsection Downloading ns-3 Using Mercurial One practice is to create a directory called @code{repos} in one's home @@ -133,7 +133,7 @@ Started'' web page and looking for the latest release identifier. Go ahead and change into the @code{ns-3-allinone} directory you created when you cloned that repository. We are now going to use the @code{download.py} -script to pull down the various pieces of @code{ns-3} you will be using/ +script to pull down the various pieces of @command{ns-3} you will be using/ Go ahead and type the following into your shell (remember you can substitute the name of your chosen release number instead of @code{ns-3-dev} -- like @@ -240,7 +240,7 @@ directory. You should see something like the following there: You are now ready to build the @command{ns-3} distribution. @subsection Downloading ns-3 Using a Tarball -The process for downloading @code{ns-3} via tarball is simpler than the +The process for downloading @command{ns-3} via tarball is simpler than the Mercurial process since all of the pieces are pre-packaged for you. You just have to pick a release, download it and decompress it. @@ -470,30 +470,33 @@ This command is typically run by @code{users} to quickly verify that an @cindex regression tests You can also run our regression test suite to ensure that your distribution and tool chain have produced binaries that generate output that is identical to -reference output files stored in a central location. To run the regression -tests, you provide Waf with the regression flag. +known-good reference output files. You downloaded these reference traces to +your machine during the download process above. (Warning: The @code{ns-3.2} +and @code{ns-3.3} releases do not use the @code{ns-3-allinone} environment +and require you to be online when you run regression tests because they +dynamically synchronize the reference traces directory with an online +repository immediately prior to the run). + +During regression testing Waf will run a number of tests that generate what we +call trace files. The content of these trace files are compared with the +reference traces. If they are identical, the regression tests report a PASS +status. If a regression test fails you will see a FAIL indication along with a +pointer to the offending trace file and its associated reference trace file +along with a suggestion on diff parameters and options in order to see what +has gone awry. If the error was discovered in a pcap file, it will be useful +to convert the pcap files to text using tcpdump prior to comparison. + +Some regression tests wmay be SKIPped if the required support +is not present. + +To run the regression tests, you provide Waf with the regression flag. @verbatim ./waf --regression @end verbatim -Waf will verify that the current files in the @command{ns-3} distribution are -built and will then look for trace files in the aforementioned centralized -location. If your tool chain includes Mercurial, the regression tests will -be downloaded from a repository at @code{code.nsnam.org}. If you do not have -Mercurial installed, the reference traces will be downloaded from a tarball -located in the releases section of @code{www.nsnam.org}. The particular name -of the reference trace location is built from the @command{ns-3} version -located in the VERSION file, so don't change that string yourself unless you -know what you are doing. (Warning: The ns-3.2 release requires you -to be online when you run regression tests because it synchronizes the -trace directory with an online repository). - -Once the reference traces are downloaded to your local machine, Waf will run -a number of tests that generate what we call trace files. The content of -these trace files are compared with the reference traces just downloaded. If -they are identical, the regression tests report a PASS status. If the -regression tests pass, you should see something like, +You should see messages indicating that many tests are being run and are +passing. @verbatim Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' @@ -510,11 +513,23 @@ regression tests pass, you should see something like, Build finished successfully (00:00:23) @end verbatim -If a regression tests fails you will see a FAIL indication along with a -pointer to the offending trace file and its associated reference trace file -along with a suggestion on diff parameters and options in order to see what -has gone awry. Some regression tests wmay be SKIPped if the required support -is not present. +If you want to take a look at an example of what might be checked during +a regression test, you can do the following: + +@verbatim + cd build/debug/regression/traces/second.ref + tcpdump -nn -tt -r second-1-1.pcap +@end verbatim + +The output should be clear to anyone who is familiar with tcpdump or net +sniffers. We'll have much more to say on pcap files later in this tutorial. + +Remember to cd back into the top-level @command{ns-3} directory +after you are done: + +@verbatim + cd ../../../../.. +@end verbatim @c ======================================================================== @c Running a Script diff --git a/doc/tutorial/introduction.texi b/doc/tutorial/introduction.texi index 6580bcbb7..299264155 100644 --- a/doc/tutorial/introduction.texi +++ b/doc/tutorial/introduction.texi @@ -24,7 +24,7 @@ The @command{ns-3} simulator is a discrete-event network simulator targeted primarily for research and educational use. The @uref{http://www.nsnam.org,,ns-3 project}, -started in 2006, is an open-source project developing ns-3. +started in 2006, is an open-source project developing @command{ns-3}. Primary documentation for the @command{ns-3} project is available in four forms: @@ -43,7 +43,7 @@ information into working simulations. In this tutorial, we will build several example simulations, introducing and explaining key concepts and features as we go. -As the tutorial unfolds, we will introduce the full ns-3 documentation +As the tutorial unfolds, we will introduce the full @command{ns-3} documentation and provide pointers to source code for those interested in delving deeper into the workings of the system. @@ -52,9 +52,9 @@ A few key points are worth noting at the onset: @item Ns-3 is not an extension of @uref{http://www.isi.edu/nsnam/ns,,ns-2}; it is a new simulator. The two simulators are both written in C++ but @command{ns-3} is a new simulator that does not support the ns-2 APIs. Some -models from ns-2 have already been ported from ns-2 to ns-3. The project will -continue to maintain ns-2 while ns-3 is being built, and will study transition -and integration mechanisms. +models from ns-2 have already been ported from ns-2 to @command{ns-3}. The +project will continue to maintain ns-2 while @command{ns-3} is being built, +and will study transition and integration mechanisms. @item @command{Ns-3} is open-source, and the project strives to maintain an open environment for researchers to contribute and share their software. @end itemize @@ -63,36 +63,36 @@ open environment for researchers to contribute and share their software. @section For ns-2 Users For those familiar with ns-2, the most visible outward change when moving to -ns-3 is the choice of scripting language. Ns-2 is +@command{ns-3} is the choice of scripting language. Ns-2 is scripted in OTcl and results of simulations can be visualized using the Network Animator @command{nam}. It is not possible to run a simulation in ns-2 purely from C++ (i.e., as a main() program without any OTcl). Moreover, some components of ns-2 are written in C++ and others in OTcl. -In ns-3, the simulator is written entirely in C++, with optional +In @command{ns-3}, the simulator is written entirely in C++, with optional Python bindings. Simulation scripts can therefore be written in C++ or in Python. The results of some simulations can be visualized by -@command{nam}, but new animators are under development. Since ns-3 +@command{nam}, but new animators are under development. Since @command{ns-3} generates pcap packet trace files, other utilities can be used to analyze traces as well. In this tutorial, we will first concentrate on scripting directly in C++ and interpreting results via ascii trace files. But there are similarities as well (both, for example, are based on C++ -objects, and some code from ns-2 has already been ported to ns-3). -We will try to highlight differences between ns-2 and ns-3 +objects, and some code from ns-2 has already been ported to @command{ns-3}). +We will try to highlight differences between ns-2 and @command{ns-3} as we proceed in this tutorial. A question that we often hear is "Should I still use ns-2 or move to -ns-3?" The answer is that it depends. ns-3 does not have all of the -models that ns-2 currently has, but on the other hand, ns-3 does have -new capabilities (such as handling multiple interfaces on nodes +@command{ns-3}?" The answer is that it depends. @command{ns-3} does not have +all of the models that ns-2 currently has, but on the other hand, @command{ns-3} +does have new capabilities (such as handling multiple interfaces on nodes correctly, use of IP addressing and more alignment with Internet protocols and designs, more detailed 802.11 models, etc.). ns-2 -models can usually be ported to ns-3 (a porting guide is under -development). There is active development on multiple fronts for ns-3. -The ns-3 developers believe (and certain early users have proven) that -ns-3 is ready for active use, and should be an attractive alternative -for users looking to start new simulation projects. +models can usually be ported to @command{ns-3} (a porting guide is under +development). There is active development on multiple fronts for +@command{ns-3}. The @command{ns-3} developers believe (and certain early users +have proven) that @command{ns-3} is ready for active use, and should be an +attractive alternative for users looking to start new simulation projects. @node Contributing @section Contributing @@ -119,7 +119,7 @@ We realize that if you are reading this document, contributing back to the project is probably not your foremost concern at this point, but we want you to be aware that contributing is in the spirit of the project and that even the act of dropping us a note about your early experience -with ns-3 (e.g. "this tutorial section was not clear..."), +with @command{ns-3} (e.g. "this tutorial section was not clear..."), reports of stale documentation, etc. are much appreciated. @node Tutorial Organization @@ -160,14 +160,14 @@ broad sequences of events. @cindex architecture There are several important resources of which any @command{ns-3} user must be aware. The main web site is located at @uref{http://www.nsnam.org} and -provides access to basic information about the ns-3 system. Detailed +provides access to basic information about the @command{ns-3} system. Detailed documentation is available through the main web site at @uref{http://www.nsnam.org/documents.html}. You can also find documents relating to the system architecture from this page. -There is a Wiki that complements the main ns-3 web site which you will find at -@uref{http://www.nsnam.org/wiki/}. You will find user and developer FAQs -there, as well as troubleshooting guides, third-party contributed code, +There is a Wiki that complements the main @command{ns-3} web site which you will +find at @uref{http://www.nsnam.org/wiki/}. You will find user and developer +FAQs there, as well as troubleshooting guides, third-party contributed code, papers, etc. @cindex mercurial repository @@ -221,7 +221,7 @@ using the Python language. The build system @code{Waf} is used on the @command{ns-3} project. It is one of the new generation of Python-based build systems. You will not need to -understand any Python to build the existing ns-3 system, and will +understand any Python to build the existing @command{ns-3} system, and will only have to understand a tiny and intuitively obvious subset of Python in order to extend the system in most cases. @@ -233,9 +233,9 @@ found at @uref{http://freehackers.org/~tnagy/waf.html}. @cindex C++ @cindex Python -As mentioned above, scripting in ns-3 is done in C++ or Python. -As of ns-3.2, most of the ns-3 API is available in Python, but the models -are written in C++ in either case. A working +As mentioned above, scripting in @command{ns-3} is done in C++ or Python. +As of ns-3.2, most of the @command{ns-3} API is available in Python, but the +models are written in C++ in either case. A working knowledge of C++ and object-oriented concepts is assumed in this document. We will take some time to review some of the more advanced concepts or possibly unfamiliar language features, idioms and design patterns as they @@ -255,7 +255,7 @@ The @command{ns-3} system uses several components of the GNU ``toolchain'' for development. A software toolchain is the set of programming tools available in the given environment. For a quick review of what is included in the GNU toolchain see, -@uref{http://en.wikipedia.org/wiki/GNU_toolchain}. ns-3 uses gcc, +@uref{http://en.wikipedia.org/wiki/GNU_toolchain}. @command{ns-3} uses gcc, GNU binutils, and gdb. However, we do not use the GNU build system, either make or autotools, using Waf instead. diff --git a/doc/tutorial/tweaking.texi b/doc/tutorial/tweaking.texi index 6736655e9..6767663f3 100644 --- a/doc/tutorial/tweaking.texi +++ b/doc/tutorial/tweaking.texi @@ -82,8 +82,8 @@ documentation and now would be a good time to peruse the Logging Module documentation if you have not done so. Now that you have read the documentation in great detail, let's use some of -that knowledge to get some interesting information out of the @code{first.cc} -example script you have already built. +that knowledge to get some interesting information out of the +@code{scratch/myfirst.cc} example script you have already built. @node Enabling Logging @subsection Enabling Logging @@ -92,17 +92,22 @@ Let's use the NS_LOG environment variable to turn on some more logging, but to get our bearings, go ahead and run the script just as you did previously, @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/first + ./waf --run scratch/myfirst +@end verbtim + +You should see the now familiar output of the first @command{ns-3} example +program + +@verbatim Entering directory `/home/craigdo/repos/ns-3-dev/build' Compilation finished successfully Sent 1024 bytes to 10.1.1.2 Received 1024 bytes from 10.1.1.1 Received 1024 bytes from 10.1.1.2 - ~/repos/ns-3-dev > @end verbatim -It turns out that the ``Sent'' and ``Received'' messages are actually logging -messages from the @code{UdpEchoClientApplication} and +It turns out that the ``Sent'' and ``Received'' messages you see above are +actually logging messages from the @code{UdpEchoClientApplication} and @code{UdpEchoServerApplication}. We can ask the client application, for example, to print more information by setting its logging level via the NS_LOG environment variable. @@ -113,7 +118,7 @@ will have to convert my examples to the ``setenv VARIABLE value'' syntax required by those shells. Right now, the UDP echo client application is responding to the following line -of code in @code{first.cc}, +of code in @code{scratch/myfirst.cc}, @verbatim LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); @@ -127,7 +132,7 @@ increase the logging level and get more information without changing the script and recompiling by setting the NS_LOG environment variable like this: @verbatim - ~/repos/ns-3-dev > export NS_LOG=UdpEchoClientApplication=level_all + export NS_LOG=UdpEchoClientApplication=level_all @end verbatim This sets the shell environment variable @code{NS_LOG} to the string, @@ -143,21 +148,19 @@ you run the script with NS_LOG set this way, the @command{ns-3} logging system will pick up the change and you should see the following output: @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/first - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) UdpEchoClientApplication:UdpEchoClient() UdpEchoClientApplication:StartApplication() UdpEchoClientApplication:ScheduleTransmit() UdpEchoClientApplication:Send() Sent 1024 bytes to 10.1.1.2 Received 1024 bytes from 10.1.1.1 - UdpEchoClientApplication:HandleRead(0x62c640, 0x62cd70) + UdpEchoClientApplication:HandleRead(0x638180, 0x6389b0) Received 1024 bytes from 10.1.1.2 UdpEchoClientApplication:StopApplication() UdpEchoClientApplication:DoDispose() UdpEchoClientApplication:~UdpEchoClient() - ~/repos/ns-3-dev > @end verbatim The additional debug information provided by the application is from @@ -198,21 +201,19 @@ that every message from the given log component is prefixed with the component name. @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/first - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) UdpEchoClientApplication:UdpEchoClient() UdpEchoClientApplication:StartApplication() UdpEchoClientApplication:ScheduleTransmit() UdpEchoClientApplication:Send() UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 Received 1024 bytes from 10.1.1.1 - UdpEchoClientApplication:HandleRead(0x62c710, 0x62ce40) + UdpEchoClientApplication:HandleRead(0x638180, 0x6389b0) UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 UdpEchoClientApplication:StopApplication() UdpEchoClientApplication:DoDispose() UdpEchoClientApplication:~UdpEchoClient() - ~/repos/ns-3-dev > @end verbatim You can now see all of the messages coming from the UDP echo client application @@ -227,17 +228,16 @@ the NS_LOG environment variable. UdpEchoServerApplication=level_all|prefix_func' @end verbatim -Note that you will need to remove the newline after the @code{:} in the -example text above. +Warning: You will need to remove the newline after the @code{:} in the +example text above which is only there for document formatting purposes. Now, if you run the script you will see all of the log messages from both the echo client and server applications. You may see that this can be very useful in debugging problems. @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/first - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) UdpEchoServerApplication:UdpEchoServer() UdpEchoClientApplication:UdpEchoClient() UdpEchoServerApplication:StartApplication() @@ -247,7 +247,7 @@ in debugging problems. UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 UdpEchoServerApplication:HandleRead(): Echoing packet - UdpEchoClientApplication:HandleRead(0x62c760, 0x62ce90) + UdpEchoClientApplication:HandleRead(0x638320, 0x638b50) UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 UdpEchoServerApplication:StopApplication() UdpEchoClientApplication:StopApplication() @@ -255,7 +255,6 @@ in debugging problems. UdpEchoServerApplication:DoDispose() UdpEchoClientApplication:~UdpEchoClient() UdpEchoServerApplication:~UdpEchoServer() - ~/repos/ns-3-dev > @end verbatim It is also sometimes useful to be able to see the simulation time at which a @@ -266,12 +265,12 @@ log message is generated. You can do this by ORing in the prefix_time bit. UdpEchoServerApplication=level_all|prefix_func|prefix_time' @end verbatim -If you run the script now, you should see the following output: +Again, you will have to remove the newline above. If you run the script now, +you should see the following output: @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/first - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) 0s UdpEchoServerApplication:UdpEchoServer() 0s UdpEchoClientApplication:UdpEchoClient() 1s UdpEchoServerApplication:StartApplication() @@ -281,7 +280,7 @@ If you run the script now, you should see the following output: 2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet - 2.00737s UdpEchoClientApplication:HandleRead(0x62c8c0, 0x62d020) + 2.00737s UdpEchoClientApplication:HandleRead(0x638490, 0x638cc0) 2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 10s UdpEchoServerApplication:StopApplication() 10s UdpEchoClientApplication:StopApplication() @@ -289,15 +288,14 @@ If you run the script now, you should see the following output: UdpEchoServerApplication:DoDispose() UdpEchoClientApplication:~UdpEchoClient() UdpEchoServerApplication:~UdpEchoServer() - ~/repos/ns-3-dev > @end verbatim You can see that the constructor for the UdpEchoServer was called at a simulation time of 0 seconds. This is actually happening before the simulation starts. The same for the UdpEchoClient constructor. -Recall that the @code{first.cc} script started the echo server application at -one second into the simulation. You can now see that the +Recall that the @code{scratch/first.cc} script started the echo server +application at one second into the simulation. You can now see that the @code{StartApplication} method of the server is, in fact, called at one second (or one billion nanoseconds). You can also see that the echo client application is started at a simulation time of two seconds as we requested in @@ -322,29 +320,29 @@ turning on all of the logging components in the system. Try setting the The asterisk above is the logging component wildcard. This will turn on all of the logging in all of the components used in the simulation. I won't -reproduce the output here (as of this writing it produces 772 lines of output +reproduce the output here (as of this writing it produces 974 lines of output for the single packet echo) but you can redirect this information into a file and look through it with your favorite editor if you like, @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/first >& log.out + ./waf --run scratch/myfirst > log.out 2>&1 @end verbatim -I personally use this quite a bit when I am presented with a problem and I -have no idea where things are going wrong. I can follow the progress of the -code quite easily without having to set breakpoints and step through code -in a debugger. When I have a general idea about what is going wrong, I -transition into a debugger for fine-grained examination of the problem. This -kind of output can be especially useful when your script does something -completely unexpected. If you are stepping using a debugger you may miss an -unexpected excursion completely. Logging the excursion makes it quickly -visible. +I personally use this volume of logging quite a bit when I am presented with +a problem and I have no idea where things are going wrong. I can follow the +progress of the code quite easily without having to set breakpoints and step +through code in a debugger. When I have a general idea about what is going +wrong, I transition into a debugger for fine-grained examination of the +problem. This kind of output can be especially useful when your script does +something completely unexpected. If you are stepping using a debugger you +may miss an unexpected excursion completely. Logging the excursion makes it +quickly visible. @node Adding Logging to your Code @subsection Adding Logging to your Code @cindex NS_LOG You can add new logging to your simulations by making calls to the log -component via several macros. Let's do so in the @code{first.cc} script we +component via several macros. Let's do so in the @code{myfirst.cc} script we have in the @code{scratch} directory. Recall that we have defined a logging component in that script: @@ -357,43 +355,56 @@ You now know that you can enable all of the logging for this component by setting the @code{NS_LOG} environment variable to the various levels. Let's go ahead add some logging to the script. The macro used to add an informational level log message is @code{NS_LOG_INFO}. Go ahead and add one -just before we start creating the nodes that tells you that the script is +(just before we start creating the nodes) that tells you that the script is ``Creating Topology.'' This is done as in this code snippet, +Open @code{scratch/myfirst.cc} in your favorite editor and add the line, + @verbatim NS_LOG_INFO ("Creating Topology"); @end verbatim +right before the lines, + +@verbatim + NodeContainer nodes; + nodes.Create (2); +@end verbatim + Now build the script using waf and clear the @code{NS_LOG} variable to turn off the torrent of logging we previously enabled: @verbatim - ~/repos/ns-3-dev > export NS_LOG= + ./waf + export NS_LOG= @end verbatim -Now, if you run the script, you will not see your new message since its -associated logging component (@code{FirstScriptExample}) has not been enabled. -In order to see your message you will have to enable the -@code{FirstScriptExample} logging component with a level greater than or equal -to @code{NS_LOG_INFO}. If you just want to see this particular level of -logging, you can enable it by, +Now, if you run the script, @verbatim - ~/repos/ns-3-dev > export NS_LOG=FirstScriptExample=info + ./waf --run scratch/myfirst +@end verbatim + +you will @emph{not} see your new message since its associated logging +component (@code{FirstScriptExample}) has not been enabled. In order to see your +message you will have to enable the @code{FirstScriptExample} logging component +with a level greater than or equal to @code{NS_LOG_INFO}. If you just want to +see this particular level of logging, you can enable it by, + +@verbatim + export NS_LOG=FirstScriptExample=info @end verbatim If you now run the script you will see your new ``Creating Topology'' log message, @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/first - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) Creating Topology Sent 1024 bytes to 10.1.1.2 Received 1024 bytes from 10.1.1.1 Received 1024 bytes from 10.1.1.2 - ~/repos/ns-3-dev > @end verbatim @c ======================================================================== @@ -428,30 +439,28 @@ in the following code, This simple two line snippet is actually very useful by itself. It opens the door to the @command{ns-3} global variable and attribute systems. Go ahead -and add that two lines of code to the @code{first.cc} script at the start of -@code{main}. Go ahead and build the script and run it, but ask the script +and add that two lines of code to the @code{scratch/first.cc} script at the +start of @code{main}. Go ahead and build the script and run it, but ask the script for help in the following way, @verbatim - ~/repos/ns-3-dev > ./waf --run "scratch/first --PrintHelp" + ./waf --run "scratch/myfirst --PrintHelp" @end verbatim -This will ask Waf to run the @code{scratch/first} script and pass the command +This will ask Waf to run the @code{scratch/myfirst} script and pass the command line argument @code{--PrintHelp} to the script. The quotes are required to sort out which program gets which argument. The command line parser will now see the @code{--PrintHelp} argument and respond with, @verbatim - ~/repos/ns-3-dev > ./waf --run ``scratch/first --PrintHelp'' - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) --PrintHelp: Print this help message. --PrintGroups: Print the list of groups. --PrintTypeIds: Print all TypeIds. --PrintGroup=[group]: Print all TypeIds of group. --PrintAttributes=[typeid]: Print all attributes of typeid. --PrintGlobals: Print the list of globals. - ~/repos/ns-3-dev > @end verbatim Let's focus on the @code{--PrintAttributes} option. We have already hinted @@ -472,7 +481,7 @@ class name of the class to which the attributes belong. In this case it will be @code{ns3::PointToPointNetDevice}. Let's go ahead and type in, @verbatim - ./waf --run "scratch/first --PrintAttributes=ns3::PointToPointNetDevice" + ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice" @end verbatim The system will print out all of the attributes of this kind of net device. @@ -518,24 +527,26 @@ time prefix. If you run the script, you should now see the following output, @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/first - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully - 0ns UdpEchoServerApplication:UdpEchoServer() - 1000000000ns UdpEchoServerApplication:StartApplication() + Build finished successfully (00:00:00) + 0s UdpEchoServerApplication:UdpEchoServer() + 1s UdpEchoServerApplication:StartApplication() Sent 1024 bytes to 10.1.1.2 - 2257324218ns Received 1024 bytes from 10.1.1.1 - 2257324218ns Echoing packet + 2.25732s Received 1024 bytes from 10.1.1.1 + 2.25732s Echoing packet Received 1024 bytes from 10.1.1.2 - 10000000000ns UdpEchoServerApplication:StopApplication() + 10s UdpEchoServerApplication:StopApplication() UdpEchoServerApplication:DoDispose() UdpEchoServerApplication:~UdpEchoServer() - ~/repos/ns-3-dev > @end verbatim Recall that the last time we looked at the simulation time at which the packet -was received by the echo server, it was at 2.0036864 seconds. Now it is -receiving the packet at about 2.257 seconds. This is because we just dropped +was received by the echo server, it was at 2.00369 seconds. + +@verbatim + 2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 +@end verbatim + +Now it is receiving the packet at 2.25732 seconds. This is because we just dropped the data rate of the @code{PointToPointNetDevice} down to its default of 32768 bits per second from five megabits per second. @@ -544,17 +555,18 @@ speed our simulation up again. We do this in the following way, according to the formula implied by the help item: @verbatim - ./waf --run "scratch/first --ns3::PointToPointNetDevice::DataRate=5Mbps" + ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps" @end verbatim This will set the default value of the @code{DataRate} attribute back to -five megabits per second. To get the original behavior of the script back, -we will have to set the speed-of-light delay of the channel. We can ask the -command line system to print out the @code{Attributes} of the channel just -like we did the net device: +five megabits per second. Are you surprised by the result? It turns out that +in order to get the original behavior of the script back, we will have to set +the speed-of-light delay of the channel as well. We can ask the command line +system to print out the @code{Attributes} of the channel just like we did for +the net device: @verbatim - ./waf --run "scratch/first --PrintAttributes=ns3::PointToPointChannel" + ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel" @end verbatim We discover the @code{Delay} attribute of the channel is set in the following @@ -568,7 +580,7 @@ way: We can then set both of these default values through the command line system, @verbatim - ./waf --run "scratch/first + ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps --ns3::PointToPointChannel::Delay=2ms" @end verbatim @@ -577,19 +589,20 @@ in which case we recover the timing we had when we explicitly set the @code{DataRate} and @code{Delay} in the script: @verbatim - Compilation finished successfully - 0ns UdpEchoServerApplication:UdpEchoServer() - 1000000000ns UdpEchoServerApplication:StartApplication() + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) + 0s UdpEchoServerApplication:UdpEchoServer() + 1s UdpEchoServerApplication:StartApplication() Sent 1024 bytes to 10.1.1.2 - 2003686400ns Received 1024 bytes from 10.1.1.1 - 2003686400ns Echoing packet + 2.00369s Received 1024 bytes from 10.1.1.1 + 2.00369s Echoing packet Received 1024 bytes from 10.1.1.2 - 10000000000ns UdpEchoServerApplication:StopApplication() + 10s UdpEchoServerApplication:StopApplication() UdpEchoServerApplication:DoDispose() UdpEchoServerApplication:~UdpEchoServer() @end verbatim -Note that the packet is again received by the server at 2.0036864 seconds. We +Note that the packet is again received by the server at 2.00369 seconds. We could actually set any of the attributes used in the script in this way. In particular we could set the @code{UdpEchoClient} attribute @code{MaxPackets} to some other value than one. @@ -604,7 +617,7 @@ folks, we'll tell you that your command line should end up looking something like, @verbatim - ./waf --run "scratch/first + ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps --ns3::PointToPointChannel::Delay=2ms --ns3::UdpEchoClient::MaxPackets=2" @@ -619,7 +632,7 @@ completely different way. Let's add a local variable called @code{nPackets} to the @code{main} function. We'll initialize it to one to match our previous default behavior. To allow the command line parser to change this value, we need to hook the value into the parser. We do this by adding a call to -@code{AddValue}. Go ahead and change the @code{scratch/first.cc} script to +@code{AddValue}. Go ahead and change the @code{scratch/myfirst.cc} script to start with the following code, @verbatim @@ -646,10 +659,15 @@ instead of the constant @code{1} as is shown below. Now if you run the script and provide the @code{--PrintHelp} argument, you should see your new @code{User Argument} listed in the help display. +Try, + @verbatim - ~/repos/ns-3-dev > ./waf --run "scratch/first --PrintHelp" - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + ./waf --run "scratch/myfirst --PrintHelp" +@end verbatim + +@verbatim + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) --PrintHelp: Print this help message. --PrintGroups: Print the list of groups. --PrintTypeIds: Print all TypeIds. @@ -658,23 +676,33 @@ should see your new @code{User Argument} listed in the help display. --PrintGlobals: Print the list of globals. User Arguments: --nPackets: Number of packets to echo - ~/repos/ns-3-dev > @end verbatim If you want to specify the number of packets to echo, you can now do so by setting the @code{--nPackets} argument in the command line, @verbatim - ~/repos/ns-3-dev > ./waf --run "scratch/first --nPackets=2" - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + ./waf --run "scratch/myfirst --nPackets=2" +@end verbatim + +You should now see + +@verbatim + Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) + 0s UdpEchoServerApplication:UdpEchoServer() + 1s UdpEchoServerApplication:StartApplication() Sent 1024 bytes to 10.1.1.2 - Received 1024 bytes from 10.1.1.1 + 2.25732s Received 1024 bytes from 10.1.1.1 + 2.25732s Echoing packet Received 1024 bytes from 10.1.1.2 Sent 1024 bytes to 10.1.1.2 - Received 1024 bytes from 10.1.1.1 + 3.25732s Received 1024 bytes from 10.1.1.1 + 3.25732s Echoing packet Received 1024 bytes from 10.1.1.2 - ~/repos/ns-3-dev > + 10s UdpEchoServerApplication:StopApplication() + UdpEchoServerApplication:DoDispose() + UdpEchoServerApplication:~UdpEchoServer() @end verbatim You have now echoed two packets. @@ -764,17 +792,26 @@ generated by many scripts. @cindex tracing packets Let's just jump right in and add some ASCII tracing output to our -@code{first.cc} script. The first thing you need to do is to add the -following code to the script just before the call to @code{Simulator::Run ()}. +@code{scratch/myfirst.cc} script. + +The first thing you need to do is to add the following include to the top of +the script just after the GNU GPL comment: + +@verbatim + #include +@end verbatim + +Then, right before the before the call to @code{Simulator::Run ()}, add the +following lines of code. @verbatim std::ofstream ascii; - ascii.open ("first.tr"); + ascii.open ("myfirst.tr"); PointToPointHelper::EnableAsciiAll (ascii); @end verbatim The first two lines are just vanilla C++ code to open a stream that will be -written to a file named ``first.tr.'' See your favorite C++ tutorial if you +written to a file named ``myfirst.tr.'' See your favorite C++ tutorial if you are unfamiliar with this code. The last line of code in the snippet above tells @command{ns-3} that you want to enable ASCII tracing on all point-to-point devices in your simulation; and you want the (provided) trace @@ -782,32 +819,24 @@ sinks to write out information about packet movement in ASCII format to the stream provided. For those familiar with @command{ns-2}, the traced events are equivalent to the popular trace points that log "+", "-", "d", and "r" events. -Since we have used a @code{std::ofstream} object, we also need to include the -appropriate header. Add the following line to the script (I typically add it -above the ns-3 includes): - -@verbatim - #include -@end verbatim - You can now build the script and run it from the command line: @verbatim - ./waf --run scratch/first + ./waf --run scratch/myfirst @end verbatim -@cindex first.tr -Just as you have seen previously, you may see some messages from Waf and then -the ``Compilation finished successfully'' with some number of messages from +@cindex myfirst.tr +Just as you have seen many times before, you will see some messages from Waf and then +the ``Build finished successfully'' with some number of messages from the running program. -When it ran, the program will have created a file named @code{first.tr}. +When it ran, the program will have created a file named @code{myfirst.tr}. Because of the way that Waf works, the file is not created in the local directory, it is created at the top-level directory of the repository by default. If you want to control where the traces are saved you can use the @code{--cwd} option of Waf to specify this. We have not done so, thus we need to change into the top level directory of our repo and take a look at -the ASCII trace file @code{first.tr} in your favorite editor. +the ASCII trace file @code{myfirst.tr} in your favorite editor. @subsubsection Parsing Ascii Traces @cindex parsing ascii traces @@ -844,7 +873,7 @@ number on the left side: 03 ns3::PppHeader ( 04 Point-to-Point Protocol: IP (0x0021)) 05 ns3::Ipv4Header ( - 06 tos 0x0 ttl 64 id 0 offset 0 flags [none] + 06 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none] 07 length: 1052 10.1.1.1 > 10.1.1.2) 08 ns3::UdpHeader ( 09 length: 1032 49153 > 9) @@ -917,7 +946,7 @@ be familiar as you have seen it before in a previous section. The trace source namespace entry (reference 02) has changed to reflect that this event is coming from node 1 (@code{/NodeList/1}) and the packet reception -trace source (@code{/Rx}). It should be quite easy for you to follow the +trace source (@code{/MacRx}). It should be quite easy for you to follow the progress of the packet through the topology by looking at the rest of the traces in the file. @@ -937,54 +966,54 @@ traces. In this tutorial, we concentrate on viewing pcap traces with tcpdump. The code used to enable pcap tracing is a one-liner. @verbatim - PointToPointHelper::EnablePcapAll ("first"); + PointToPointHelper::EnablePcapAll ("myfirst"); @end verbatim Go ahead and insert this line of code after the ASCII tracing code we just -added to @code{scratch/first.cc}. Notice that we only passed the string -``first,'' and not ``first.pcap'' or something similar. This is because the +added to @code{scratch/myfirst.cc}. Notice that we only passed the string +``myfirst,'' and not ``myfirst.pcap'' or something similar. This is because the parameter is a prefix, not a complete file name. The helper will actually create a trace file for every point-to-point device in the simulation. The file names will be built using the prefix, the node number, the device number and a ``.pcap'' suffix. -In our example script, we will eventually see files named ``first-0-0.pcap'' -and ``first.1-0.pcap'' which are the pcap traces for node 0-device 0 and +In our example script, we will eventually see files named ``myfirst-0-0.pcap'' +and ``myfirst.1-0.pcap'' which are the pcap traces for node 0-device 0 and node 1-device 0, respectively. Once you have added the line of code to enable pcap tracing, you can run the script in the usual way: @verbatim - ./waf --run scratch/first + ./waf --run scratch/myfirst @end verbatim If you look at the top level directory of your distribution, you should now -see three log files: @code{first.tr} is the ASCII trace file we have -previously examined. @code{first-0-0.pcap} and @code{first-1-0.pcap} +see three log files: @code{myfirst.tr} is the ASCII trace file we have +previously examined. @code{myfirst-0-0.pcap} and @code{myfirst-1-0.pcap} are the new pcap files we just generated. @subsubsection Reading output with tcpdump @cindex tcpdump The easiest thing to do at this point will be to use @code{tcpdump} to look -at the @code{pcap} files. Output from dumping both files is shown below: +at the @code{pcap} files. @verbatim - ~/repos/ns-3-dev > /usr/sbin/tcpdump -r first-0-0.pcap -nn -tt - reading from file first-0-0.pcap, link-type PPP (PPP) + tcpdump -nn -tt -r myfirst-0-0.pcap + reading from file myfirst-0-0.pcap, link-type PPP (PPP) 2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024 2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024 - ~/repos/ns-3-dev > /usr/sbin/tcpdump -r first-1-0.pcap -nn -tt - reading from file first-1-0.pcap, link-type PPP (PPP) + + tcpdump -nn -tt -r myfirst-1-0.pcap + reading from file myfirst-1-0.pcap, link-type PPP (PPP) 2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024 2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024 - ~/repos/ns-3-dev > @end verbatim -You can see in the dump of ``first-0.0.pcap'' (the client device) that the +You can see in the dump of @code{myfirst-0.0.pcap} (the client device) that the echo packet is sent at 2 seconds into the simulation. If you look at the -second dump (of ``first-1-0.pcap'') you can see that packet being received -at 2.257324 seconds. You see the packet being echoed at 2.257324 seconds +second dump (@code{first-1-0.pcap}) you can see that packet being received +at 2.257324 seconds. You see the packet being echoed back at 2.257324 seconds in the second dump, and finally, you see the packet being received back at the client in the first dump at 2.514648 seconds. From f2c609494d6c9072646cea1b49a85aaed7be0ee6 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 24 Mar 2009 17:53:30 -0700 Subject: [PATCH 11/67] wrap up tutorial updates --- doc/tutorial/building-topologies.texi | 727 +++++++++++++++----------- doc/tutorial/conceptual-overview.texi | 12 +- doc/tutorial/getting-started.texi | 4 +- doc/tutorial/tweaking.texi | 20 +- examples/second.cc | 8 +- examples/third.cc | 5 +- 6 files changed, 453 insertions(+), 323 deletions(-) diff --git a/doc/tutorial/building-topologies.texi b/doc/tutorial/building-topologies.texi index 3819b124f..b50b7608b 100644 --- a/doc/tutorial/building-topologies.texi +++ b/doc/tutorial/building-topologies.texi @@ -53,6 +53,17 @@ example, but we will go over the entire script and examine some of the output. Just as in the @code{first.cc} example (and in all ns-3 examples) the file begins with an emacs mode line and some GPL boilerplate. +The actual code begins by loading module include files just as was done in the +@code{first.cc} example. + +@verbatim + #include "ns3/core-module.h" + #include "ns3/simulator-module.h" + #include "ns3/node-module.h" + #include "ns3/helper-module.h" + #include "ns3/global-routing-module.h" +@end verbatim + One thing that can be surprisingly useful is a small bit of ASCII art that shows a cartoon of the network topology constructed in the example. You will find a similar ``drawing'' in most of our examples. @@ -75,53 +86,47 @@ three ``extra'' nodes as seen below: // LAN 10.1.2.0 @end verbatim -The actual code begins by loading module include files just as was done in the -@code{first.cc} example. Then the ns-3 namespace is @code{used} and a logging -component is defined. This is all just as it was in @code{first.cc}, so there -is nothing new yet. +Then the ns-3 namespace is @code{used} and a logging component is defined. +This is all just as it was in @code{first.cc}, so there is nothing new yet. -@verbatim - #include "ns3/core-module.h" - #include "ns3/simulator-module.h" - #include "ns3/node-module.h" - #include "ns3/helper-module.h" - #include "ns3/global-routing-module.h" - +@verbatim using namespace ns3; NS_LOG_COMPONENT_DEFINE ("SecondScriptExample"); @end verbatim -The main program begins by enabling the @code{UdpEchoClientApplication} and -@code{UdpEchoServerApplication} logging components at @code{INFO} level so -we can see some output when we run the example. This should be entirely -familiar to you so far. +The main program begins with a slightly different twist. We use a verbose +flag to determine whether or not the @code{UdpEchoClientApplication} and +@code{UdpEchoServerApplication} logging components are enabled. This flag +defaults to true (the logging components are enabled) but allows us to turn +off logging during regression testing of this example. -@verbatim - int - main (int argc, char *argv[]) - { - LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); - LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); -@end verbatim - -A fixed seed is provided to the random number generators so that they will -generate repeatable results. - -@verbatim - RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); -@end verbatim - -Next, you will see some familiar code that will allow you to change the number +You will see some familiar code that will allow you to change the number of devices on the CSMA network via command line argument. We did something similar when we allowed the number of packets sent to be changed in the section -on command line arguments. +on command line arguments. The last line makes sure you have at least one +``extra'' node. + +The code consists of variations of previously covered API so you should be +entirely comfortable with the following code at this point in the tutorial. @verbatim + bool verbose = true; uint32_t nCsma = 3; + CommandLine cmd; - cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); + cmd.AddValue (``nCsma'', ``Number of \"extra\" CSMA nodes/devices'', nCsma); + cmd.AddValue (``verbose'', ``Tell echo applications to log if true'', verbose); + cmd.Parse (argc,argv); + + if (verbose) + { + LogComponentEnable(``UdpEchoClientApplication'', LOG_LEVEL_INFO); + LogComponentEnable(``UdpEchoServerApplication'', LOG_LEVEL_INFO); + } + + nCsma = nCsma == 0 ? 1 : nCsma; @end verbatim The next step is to create two nodes that we will connect via the @@ -147,7 +152,10 @@ The next line of code @code{Gets} the first node (as in having an index of one) from the point-to-point node container and adds it to the container of nodes that will get CSMA devices. The node in question is going to end up with a point-to-point device @emph{and} a CSMA device. We then create a number of -``extra'' nodes that compose the remainder of the CSMA network. +``extra'' nodes that compose the remainder of the CSMA network. Since we +already have one node in the CSMA network -- the one that will have both a +point-to-point and CSMA net device, the number of ``extra'' nodes means the +number nodes you desire in the CSMA section minus one. The next bit of code should be quite familiar by now. We instantiate a @code{PointToPointHelper} and set the associated default attributes so that @@ -286,7 +294,7 @@ leftmost point-to-point node seen in the topology illustration. @end verbatim Since we have actually built an internetwork here, we need some form of -internetwork routing. @command{Ns-3} provides what we call a global route +internetwork routing. @command{ns-3} provides what we call a global route manager to set up the routing tables on nodes. This route manager has a global function that runs though the nodes created for the simulation and does the hard work of setting up routing for you. @@ -302,15 +310,40 @@ is a one-liner: GlobalRouteManager::PopulateRoutingTables (); @end verbatim -The remainder of the script should be very familiar to you. We just enable -pcap tracing, run the simulation and exit the script. Notice that enabling -pcap tracing using the CSMA helper is done in the same way as for the pcap -tracing with the point-to-point helper. +Next we enable pcap tracing. The first line of code to enable pcap tracing +in the point-to-point helper should be familiar to you by now. The second +line enables pcap tracing in the CSMA helper and there is an extra parameter +you haven't encountered yet. + +@verbatim + PointToPointHelper::EnablePcapAll ("second"); + CsmaHelper::EnablePcap ("second", csmaDevices.Get (0), true); +@end verbatim + +The CSMA network is a multi-point-to-point network. This means that there +can (and are in this case) multiple endpoints on a shared medium. Each of +these endpoints has a net device associated with it. There are two basic +alternatives to gathering trace information from such a network. One way +is to create a trace file for each net device and store only the packets +that are emitted or consumed by that net device. Another way is to pick +one of the devices and place it in promiscuous mode. That single device +then ``sniffs'' the network for all packets and stores them in a single +pcap file. This is how @code{tcpdump}, for example, works. That final +parameter tells the CSMA helper whether or not to capture packets in +promiscuous mode. + +In this example, we are going to select one of the devices on the CSMA +network and ask it to perform a promiscuous sniff of the network, thereby +emulating what @code{tcpdump} would do. If you were on a Linux machine +you might do something like @code{tcpdump -i eth0} to get the trace. +In this case, we specify the device using @code{csmaDevices.Get(0)}, +which selects the zeroth device in the container. Setting the final +parameter to true enables promiscuous captures. + +The last section of code just runs and cleans up the simulation just like +the @code{first.cc} example. @verbatim - PointToPointHelper::EnablePcapAll ("second"); - CsmaHelper::EnablePcapAll ("second"); - Simulator::Run (); Simulator::Destroy (); return 0; @@ -318,27 +351,40 @@ tracing with the point-to-point helper. @end verbatim In order to run this example, you have to copy the @code{second.cc} example -script into the scratch directory and use Waf to build just as you did with +script into the scratch directory and use waf to build just as you did with the @code{first.cc} example. If you are in the top-level directory of the repository you would type, @verbatim - cp examples/second.cc scratch/ + cp examples/second.cc scratch/mysecond.cc ./waf - ./waf --run scratch/second @end verbatim +Warning: We use the file @code{second.cc} as one of our regression tests to +verify that it works exactly as we think it should in order to make your +tutorial experience a positive one. This means that an executable named +@code{second} already exists in the project. To avoid any confusion +about what you are executing, please do the renaming to @code{mysecond.cc} +suggested above. + +If you are following the tutorial religiously (you are, aren't you) you will +still have the NS_LOG variable set, so go ahead and clear that variable and +run the program. + +@verbatim + export NS_LOG= + ./waf --run scratch/mysecond +#end verbatim + Since we have set up the UDP echo applications to log just as we did in @code{first.cc}, you will see similar output when you run the script. @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/second - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Entering directory `repos/ns-3-allinone/ns-3-dev/build' + Build finished successfully (00:00:00) Sent 1024 bytes to 10.1.2.4 Received 1024 bytes from 10.1.1.1 Received 1024 bytes from 10.1.2.4 - ~/repos/ns-3-dev > @end verbatim Recall that the first message, @code{Sent 1024 bytes to 10.1.2.4} is the @@ -349,38 +395,41 @@ the echo packet. The final message, @code{Received 1024 bytes from 10.1.2.4} is from the echo client, indicating that it has received its echo back from the server. -If you now go and look in the top level directory, you will find a number of -trace files: +If you now go and look in the top level directory, you will find two trace +files: @verbatim - ~/repos/ns-3-dev > ls *.pcap - second-0-0.pcap second-1-1.pcap second-3-0.pcap - second-1-0.pcap second-2-0.pcap second-4-0.pcap - ~/repos/ns-3-dev > + second-0-0.pcap second-1-0.pcap second-2-0.pcap @end verbatim Let's take a moment to look at the naming of these files. They all have the same form, @code{--.pcap}. For example, the first file in the listing is @code{second-0-0.pcap} which is the pcap trace from node -zero - device zero. There are no other devices on node zero so this is the -only trace from that node. +zero, device zero. This is the point-to-point net device on node zero. The +file @code{second-1-0.pcap} is the pcap trace for device zero on node one, +also a point-to-point net device; and the file @code{second-2-0.pcap} is the +pcap trace for device zero on node two. -Now look at @code{second-1-0.pcap} and @code{second-1-1.pcap}. The former is -the pcap trace for device zero on node one and the latter is the trace file -for device one on node one. If you refer back to the topology illustration at -the start of the section, you will see that node one is the node that has -both a point-to-point device and a CSMA device, so we should expect two pcap -traces for that node. +If you refer back to the topology illustration at the start of the section, +you will see that node zero is the leftmost node of the point-to-point link +and node one is the node that has both a point-to-point device and a CSMA +device. You will see that node two is the first ``extra'' node on the CSMA +network and its device zero was selected as the device to capture the +promiscuous-mode trace. Now, let's follow the echo packet through the internetwork. First, do a tcpdump of the trace file for the leftmost point-to-point node --- node zero. @verbatim - ~/repos/ns-3-dev > tcpdump -r second-0-0.pcap -nn -tt + tcpdump -nn -tt -r second-0-0.pcap +@end verbatim + +You should see the contents of the pcap file displayed: + +@verbatim reading from file second-0-0.pcap, link-type PPP (PPP) 2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 - 2.007382 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 - ~/repos/ns-3-dev > + 2.007602 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 @end verbatim The first line of the dump indicates that the link type is PPP (point-to-point) @@ -391,134 +440,163 @@ point-to-point link and be received by the point-to-point net device on node one. Let's take a look: @verbatim - ~/repos/ns-3-dev > tcpdump -r second-1-0.pcap -nn -tt - reading from file second-1-0.pcap, link-type PPP (PPP) - 2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 - 2.003695 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 - ~/repos/ns-3-dev > + tcpdump -nn -tt -r second-1-0.pcap +@end verbatim + +You should now see the pcap trace output of the other side of the point-to-point +link: + +@verbatim +reading from file second-1-0.pcap, link-type PPP (PPP) +2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 +2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 @end verbatim Here we see that the link type is also PPP as we would expect. You see the -packet from IP address 10.1.1.1 headed toward 10.1.2.4 appear on this -interface. Now, internally to this node, the packet will be forwarded to the -CSMA interface and we should see it pop out the other device headed for its -ultimate destination. Let's then look at second-1-1.pcap and see if its there. +packet from IP address 10.1.1.1 (that was sent at 2.000000 seconds) headed +toward IP address 10.1.2.4 appear on this interface. Now, internally to this +node, the packet will be forwarded to the CSMA interface and we should see it +pop out on that device headed for its ultimate destination. + +Remember that we selected node 2 as the promiscuous sniffer node for the CSMA +network so let's then look at second-2-0.pcap and see if its there. @verbatim - ~/repos/ns-3-dev > tcpdump -r second-1-1.pcap -nn -tt - reading from file second-1-1.pcap, link-type EN10MB (Ethernet) - 2.003686 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.003687 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 - 2.003687 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 - 2.003691 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 - 2.003691 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 - 2.003695 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 - ~/repos/ns-3-dev > + tcpdump -nn -tt -r second-2-0.pcap +@end verbatim + +You should now see the promiscuous dump of node two, device zero: + +@verbatim + reading from file second-2-0.pcap, link-type EN10MB (Ethernet) + 2.003696 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003707 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 + 2.003801 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + 2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 + 2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 @end verbatim As you can see, the link type is now ``Ethernet''. Something new has appeared, though. The bus network needs @code{ARP}, the Address Resolution Protocol. -The node knows it needs to send the packet to IP address 10.1.2.4, but it +Node one knows it needs to send the packet to IP address 10.1.2.4, but it doesn't know the MAC address of the corresponding node. It broadcasts on the CSMA network (ff:ff:ff:ff:ff:ff) asking for the device that has IP address 10.1.2.4. In this case, the rightmost node replies saying it is at MAC address -00:00:00:00:00:06. This exchange is seen in the following lines, +00:00:00:00:00:06. (Note that node two is not directly involved in this +exchange, but is sniffing the network and reporting all of the traffic it sees.) + +This exchange is seen in the following lines, @verbatim - 2.003686 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.003687 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 + 2.003696 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003707 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 @end verbatim Then node one, device one goes ahead and sends the echo packet to the UDP echo -server at IP address 10.1.2.4. We can now look at the pcap trace for the -echo server, +server at IP address 10.1.2.4. @verbatim - ~/repos/ns-3-dev > tcpdump -r second-4-0.pcap -nn -tt - reading from file second-4-0.pcap, link-type EN10MB (Ethernet) - 2.003686 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.003686 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 - 2.003690 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 - 2.003690 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 - 2.003692 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 - 2.003692 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 - ~/repos/ns-3-dev > + 2.003801 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 @end verbatim -Again, you see that the link type is ``Ethernet''. The first two entries are -the ARP exchange we just explained. The third packet is the echo packet -being delivered to its final destination. - -The echo server turns the packet around and needs to send it back to the echo -client on 10.1.1.1 but it knows that this address is on another network that -it reaches via IP address 10.1.2.1. This is because we initialized global +The server receives the echo request and turns the packet around trying to send +it back to the source. The server knows that this address is on another network +that it reaches via IP address 10.1.2.1. This is because we initialized global routing and it has figured all of this out for us. But, the echo server node doesn't know the MAC address of the first CSMA node, so it has to ARP for it -just like the first CSMA node had to do. We leave it as an exercise for you -to find the entries corresponding to the packet returning back on its way to -the client (we have already dumped the traces and you can find them in those -tcpdumps above. - -Let's take a look at one of the CSMA nodes that wasn't involved in the packet -exchange: +just like the first CSMA node had to do. @verbatim - ~/repos/ns-3-dev > tcpdump -r second-2-0.pcap -nn -tt - reading from file second-2-0.pcap, link-type EN10MB (Ethernet) - 2.003686 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.003691 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 - ~/repos/ns-3-dev > + 2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + 2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 @end verbatim -You can see that the CSMA channel is a broadcast medium and so all of the -devices see the ARP requests involved in the packet exchange. The remaining -pcap trace will be identical to this one. +The server then sends the echo back to the forwarding node. + +@verbatim + 2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 +@end verbatim + +Looking back at the rightmost node of the point-to-point link, + +@verbatim + tcpdump -nn -tt -r second-1-0.pcap +@end verbatim + +You can now see the echoed packet coming back onto the point-to-point link as +the last line of the trace dump. + +@verbatim +reading from file second-1-0.pcap, link-type PPP (PPP) +2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 +2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 +@end verbatim + +Lastly, you can look back at the node that originated the echo +@verbatim + tcpdump -nn -tt -r second-0-0.pcap +@end verbatim + +and see that the echoed packet arrives back at the source at 2.007602 seconds, + +@verbatim + reading from file second-0-0.pcap, link-type PPP (PPP) + 2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.007602 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 +@end verbatim Finally, recall that we added the ability to control the number of CSMA devices in the simulation by command line argument. You can change this argument in the same way as when we looked at changing the number of packets echoed in the -@code{first.cc} example. Try setting the number of ``extra'' devices to four: +@code{first.cc} example. Try running the program with the number of ``extra'' +devices set to four: @verbatim - ~/repos/ns-3-dev > ./waf --run "scratch/second --nCsma=4" - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + ./waf --run "scratch/mysecond --nCsma=4" +@end verbatim + +You should now see, + +@verbatim + Entering directory `repos/ns-3-allinone/ns-3-dev/build' + Build finished successfully (00:00:00) Sent 1024 bytes to 10.1.2.5 Received 1024 bytes from 10.1.1.1 Received 1024 bytes from 10.1.2.5 - ~/repos/ns-3-dev > @end verbatim Notice that the echo server has now been relocated to the last of the CSMA -nodes, which is 10.1.2.5 instead of the default case, 10.1.2.4. You can -increase the number to your hearts content, but remember that you will get a -pcap trace file for every node in the simulation. One thing you can do to -keep from getting all of those pcap traces with nothing but ARP exchanges in -them is to be more specific about which nodes and devices you want to trace. +nodes, which is 10.1.2.5 instead of the default case, 10.1.2.4. -Let's take a look at @code{scratch/second.cc} and add that code enabling us -to be more specific. The file we provided used the @code{EnablePcapAll} -methods of the helpers to enable pcap on all devices. We now want to use the -more specific method, @code{EnablePcap}, which takes a node number and device -number as parameters. Go ahead and replace the @code{EnablePcapAll} calls -with the calls below. +It is possible that you may not be satisfied with a trace file generated by +a bystander in the CSMA network. You may really want to get a trace from +a single device and you may not be interested in any other traffic on the +network. You can do this, + +Let's take a look at @code{scratch/mysecond.cc} and add that code enabling us +to be more specific. @code{ns-3} helpers provide methods that take a node +number and device number as parameters. Go ahead and replace the +@code{EnablePcap} calls with the calls below. @verbatim PointToPointHelper::EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0); - CsmaHelper::EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0); + CsmaHelper::EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0, false); + CsmaHelper::EnablePcap ("second", csmaNodes.Get (nCsma-1)->GetId (), 0, false); @end verbatim We know that we want to create a pcap file with the base name "second" and we also know that the device of interest in both cases is going to be zero, -so those parameters are not really interesting. In order to get the node -number, you have two choices: first, nodes are numbered in a monotonically -increasing fashion starting from zero in the order in which you created them. -One way to get a node number is to figure this number out ``manually'' by -contemplating the order of node creation. If you take a look at the network -topology illustration at the beginning of the file, we did this for you and -you can see that the last CSMA node is going to be node number -@code{nCsma + 1}. This approach can become annoyingly difficult in larger -simulations. +so those parameters are not really interesting. + +In order to get the node number, you have two choices: first, nodes are +numbered in a monotonically increasing fashion starting from zero in the +order in which you created them. One way to get a node number is to figure +this number out ``manually'' by contemplating the order of node creation. +If you take a look at the network topology illustration at the beginning of +the file, we did this for you and you can see that the last CSMA node is +going to be node number @code{nCsma + 1}. This approach can become +annoyingly difficult in larger simulations. An alternate way, which we use here, is to realize that the @code{NodeContainers} contain pointers to @command{ns-3} @code{Node} Objects. @@ -537,35 +615,54 @@ to the documentation for the @code{Node} class. If you now scroll down to the documentation for the method. Using the @code{GetId} method can make determining node numbers much easier in complex topologies. -Now that we have got some trace filtering in place, it is reasonable to start -increasing the number of CSMA devices in our simulation. If you build the -new script and run the simulation setting @code{nCsma} to 100, you will see -the following output: +If you build the new script and run the simulation setting @code{nCsma} to 100, @verbatim - ~/repos/ns-3-dev > ./waf --run "scratch/second --nCsma=100" - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + ./waf --run "scratch/mysecond --nCsma=100" +@end verbatim + +you will see the following output: + +@verbatim + Entering directory `repos/ns-3-allinone/ns-3-dev/build' + Build finished successfully (00:00:00) Sent 1024 bytes to 10.1.2.101 Received 1024 bytes from 10.1.1.1 Received 1024 bytes from 10.1.2.101 - ~/repos/ns-3-dev > @end verbatim Note that the echo server is now located at 10.1.2.101 which corresponds to having 100 ``extra'' CSMA nodes with the echo server on the last one. If you -list the pcap files in the top level directory, +list the pcap files in the top level directory you will see, @verbatim - ~/repos/ns-3-dev > ls *.pcap - second-0-0.pcap second-101-0.pcap - ~/repos/ns-3-dev > + second-0-0.pcap second-100-0.pcap second-101-0.pcap @end verbatim -you will see that we have, in fact, only created two trace files. The trace -file @code{second-0-0.pcap} is the ``leftmost'' point-to-point device which is -the echo packet source. The file @code{second-101-0.pcap} corresponds to the -rightmost CSMA device which is where the echo server resides. +The trace file @code{second-0-0.pcap} is the ``leftmost'' point-to-point device +which is the echo packet source. The file @code{second-101-0.pcap} corresponds +to the rightmost CSMA device which is where the echo server resides. You may +have noticed that the final parameter on the call to enable pcap tracing on the +echo server node was false. This means that the trace gathered on that node +was in non-promiscuous mode. + +To illustrate the difference between promiscuous and non-promiscuous traces, we +also requested a non-promiscuous trace for the next-to-last node. Go ahead and +take a look at the @code{tcpdump} for @code{second-10-0.pcap}. + +@verbatim + tcpdump -nn -tt -r second-100-0.pcap +@end verbatim + +You can now see that node 100 is really a bystander in the echo exchange. The +only packets that it receives are the ARP requests which are broadcast to the +entire CSMA network. + +@verbatim +reading from file second-100-0.pcap, link-type EN10MB (Ethernet) +2.003696 arp who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 +2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101 +@end verbatim @c ======================================================================== @c Building a Wireless Network Topology @@ -651,36 +748,27 @@ component is defined. This should all be quite familiar by now. NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample"); @end verbatim -As has become the norm in this tutorial, the main program begins by enabling -the @code{UdpEchoClientApplication} and @code{UdpEchoServerApplication} -logging components at @code{INFO} level so we can see some output when we run -the simulation. - -@verbatim - int - main (int argc, char *argv[]) - { - LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); - LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); -@end verbatim - -A fixed seed is provided to the random number generators so that they will -generate repeatable results. - -@verbatim - RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8); -@end verbatim - -Next, you will see more familiar code that will allow you to change the number -of devices on the CSMA and Wifi networks via command line argument. +The main program begins just like @code{second.cc} by adding some command line +parameters for enabling or disabling logging components and for changing the +number of devices created. @verbatim + bool verbose = true; uint32_t nCsma = 3; uint32_t nWifi = 3; + CommandLine cmd; - cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); - cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi); + cmd.AddValue (``nCsma'', ``Number of \"extra\" CSMA nodes/devices'', nCsma); + cmd.AddValue (``nWifi'', ``Number of wifi STA devices'', nWifi); + cmd.AddValue (``verbose'', ``Tell echo applications to log if true'', verbose); + cmd.Parse (argc,argv); + + if (verbose) + { + LogComponentEnable(``UdpEchoClientApplication'', LOG_LEVEL_INFO); + LogComponentEnable(``UdpEchoServerApplication'', LOG_LEVEL_INFO); + } @end verbatim Just as in all of the previous examples, the next step is to create two nodes @@ -775,7 +863,6 @@ Once the PHY helper is configured, we can focus on the MAC layer: wifi.SetRemoteStationManager ("ns3::AarfWifiManager"); @end verbatim - The @code{SetRemoteStationManager} method tells the helper the type of rate control algorithm to use. Here, it is asking the helper to use the AARF algorithm --- details are, of course, available in Doxygen. @@ -873,10 +960,10 @@ STA nodes. We want the access point to remain in a fixed position during the simulation. We accomplish this by setting the mobility model for this node to be the -@code{ns3::StaticMobilityModel}: +@code{ns3::ConstantPositionMobilityModel}: @verbatim - mobility.SetMobilityModel ("ns3::StaticMobilityModel"); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); mobility.Install (wifiApNode); @end verbatim @@ -960,18 +1047,20 @@ loop. Simulator::Stop (Seconds (10.0)); @end verbatim -We use the same trick as in the @code{second.cc} script to only generate -pcap traces from the nodes we find interesting. Note that we use the same -``formula'' to get pcap tracing enabled on Wifi devices as we did on the -CSMA and point-to-point devices. +We create just enough tracing to cover all three networks: @verbatim - WifiHelper::EnablePcap ("third", - wifiStaNodes.Get (nWifi - 1)->GetId (), 0); - CsmaHelper::EnablePcap ("third", - csmaNodes.Get (nCsma)->GetId (), 0); + PointToPointHelper::EnablePcapAll ("third"); + YansWifiPhyHelper::EnablePcap ("third", apDevices.Get (0)); + CsmaHelper::EnablePcap ("third", csmaDevices.Get (0), true); @end verbatim +These three lines of code will start pcap tracing on both of the point-to-point +nodes that serves as our backbone, will start a promiscuous (monitor) mode +trace on the Wifi network, and will start a promiscuous trace on the CSMA +network. This will let us see all of the traffic with a minimum number of +trace files. + Finally, we actually run the simulation, clean up and then exit the program. @verbatim @@ -987,22 +1076,20 @@ the @code{second.cc} example. If you are in the top-level directory of the repository you would type, @verbatim - cp examples/third.cc scratch/ + cp examples/third.cc scratch/mythird.cc ./waf - ./waf --run scratch/third + ./waf --run scratch/mythird @end verbatim Since we have set up the UDP echo applications just as we did in the @code{second.cc} script, you will see similar output. @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/third - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Entering directory `repos/ns-3-allinone-dev/ns-3-dev/build' + Build finished successfully (00:00:00) Sent 1024 bytes to 10.1.2.4 Received 1024 bytes from 10.1.3.3 Received 1024 bytes from 10.1.2.4 - ~/repos/ns-3-dev > @end verbatim Recall that the first message, @code{Sent 1024 bytes to 10.1.2.4} is the @@ -1013,74 +1100,123 @@ generated when it receives the echo packet. The final message, @code{Received 1024 bytes from 10.1.2.4} is from the echo client, indicating that it has received its echo back from the server. -If you now go and look in the top level directory, you will find two trace -files: +If you now go and look in the top level directory, you will find four trace +files, two from node zero and two from node one: @verbatim - ~/repos/ns-3-dev > ls *.pcap - third-4-0.pcap third-7-0.pcap - ~/repos/ns-3-dev > +third-0-0.pcap third-0-1.pcap third-1-0.pcap third-1-1.pcap @end verbatim -The file ``third-4-0.pcap'' corresponds to the pcap trace for node four - -device zero. This is the CSMA network node that acted as the echo server. -Take a look at the tcpdump for this device: +The file ``third-0-0.pcap'' corresponds to the point-to-point device on node +zero -- the left side of the ``backbone.'' The file ``third-1-0.pcap'' +corresponds to the point-to-point device on node one -- the right side of the +``backbone.'' The file ``third-0-1.pcap'' will be the promiscuous (monitor +mode) trace from the Wifi network and the file ``third-1-1.pcap'' will be the +promiscuous trace from the CSMA network. Can you verify this by inspecting +the code? + +Since the echo client is on the Wifi network, let's start there. Let's take +a look at the promiscuous (monitor mode) trace we captured on that network. @verbatim - ~/repos/ns-3-dev > tcpdump -r third-4-0.pcap -nn -tt - reading from file third-4-0.pcap, link-type EN10MB (Ethernet) + tcpdump -nn -tt -r third-0-1.pcap +@end verbatim + +You should see some wifi-looking contents you haven't seen here before: + +@verbatim + reading from file third-0-1.pcap, link-type IEEE802_11 (802.11) + 0.000025 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS + 0.000263 Assoc Request () [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] + 0.000279 Acknowledgment RA:00:00:00:00:00:07 + 0.000357 Assoc Response AID(0) :: Succesful + 0.000501 Acknowledgment RA:00:00:00:00:00:0a + 0.000748 Assoc Request () [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] + 0.000764 Acknowledgment RA:00:00:00:00:00:08 + 0.000842 Assoc Response AID(0) :: Succesful + 0.000986 Acknowledgment RA:00:00:00:00:00:0a + 0.001242 Assoc Request () [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] + 0.001258 Acknowledgment RA:00:00:00:00:00:09 + 0.001336 Assoc Response AID(0) :: Succesful + 0.001480 Acknowledgment RA:00:00:00:00:00:0a + 2.000112 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 + 2.000128 Acknowledgment RA:00:00:00:00:00:09 + 2.000206 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 + 2.000487 arp reply 10.1.3.4 is-at 00:00:00:00:00:0a + 2.000659 Acknowledgment RA:00:00:00:00:00:0a + 2.002169 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.002185 Acknowledgment RA:00:00:00:00:00:09 + 2.009771 arp who-has 10.1.3.3 (ff:ff:ff:ff:ff:ff) tell 10.1.3.4 + 2.010029 arp reply 10.1.3.3 is-at 00:00:00:00:00:09 + 2.010045 Acknowledgment RA:00:00:00:00:00:09 + 2.010231 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 + 2.011767 Acknowledgment RA:00:00:00:00:00:0a + 2.500000 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS + 5.000000 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS + 7.500000 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS +@end verbatim + +You can see that the link type is now 802.11 as you would expect. You can +probably understand what is going on and find the IP echo request and response +packets in this trace. We leave it as an exercise to completely parse the +trace dump. + +Now, look at the pcap file of the right side of the point-to-point link, + +@verbatim + tcpdump -nn -tt -r third-0-0.pcap +@end verbatim + +Again, you should see some familiar looking contents: + +@verbatim + reading from file third-0-0.pcap, link-type PPP (PPP) + 2.002169 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.009771 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 +@end verbatim + +This is the echo packet going from left to right (from Wifi to CSMA) and back +again across the point-to-point link. + +Now, look at the pcap file of the right side of the point-to-point link, + +@verbatim + tcpdump -nn -tt -r third-1-0.pcap +@end verbatim + +Again, you should see some familiar looking contents: + +@verbatim + reading from file third-1-0.pcap, link-type PPP (PPP) + 2.005855 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.006084 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 +@end verbatim + +This is also the echo packet going from left to right (from Wifi to CSMA) and +back again across the point-to-point link with slightly different timings +as you might expect. + +The echo server is on the CSMA network, let's look at the promiscuous trace +there: + +@verbatim + tcpdump -nn -tt -r third-1-1.pcap +@end verbatim + +You should see some familiar looking contents: + +@verbatim + reading from file third-1-1.pcap, link-type EN10MB (Ethernet) 2.005855 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.005855 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 - 2.005859 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 - 2.005859 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 - 2.005861 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 - 2.005861 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 - ~/repos/ns-3-dev > + 2.005877 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 + 2.005877 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.005980 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + 2.005980 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 + 2.006084 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 @end verbatim -This should be familiar and easily understood. If you've forgotten, go back -and look at the discussion in @code{second.cc}. This is the same sequence. - -Now, take a look at the other trace file, ``third-7-0.pcap.'' This is the -trace file for the wireless STA node that acts as the echo client. - -@verbatim - ~/repos/ns-3-dev > tcpdump -r third-7-0.pcap -nn -tt - reading from file third-7-0.pcap, link-type IEEE802_11 (802.11) - 0.000146 Beacon (ns-3-ssid) ... - H: 0 - 0.000180 Assoc Request (ns-3-ssid) ... - 0.000336 Acknowledgment RA:00:00:00:00:00:07 - 0.000454 Assoc Response AID(0) :: Succesful - 0.000514 Acknowledgment RA:00:00:00:00:00:0a - 0.000746 Assoc Request (ns-3-ssid) ... - 0.000902 Acknowledgment RA:00:00:00:00:00:09 - 0.001020 Assoc Response AID(0) :: Succesful - 0.001036 Acknowledgment RA:00:00:00:00:00:0a - 0.001219 Assoc Request (ns-3-ssid) ... - 0.001279 Acknowledgment RA:00:00:00:00:00:08 - 0.001478 Assoc Response AID(0) :: Succesful - 0.001538 Acknowledgment RA:00:00:00:00:00:0a - 2.000000 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 - 2.000172 Acknowledgment RA:00:00:00:00:00:09 - 2.000318 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 - 2.000581 arp reply 10.1.3.4 is-at 00:00:00:00:00:0a - 2.000597 Acknowledgment RA:00:00:00:00:00:0a - 2.000693 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 - 2.002229 Acknowledgment RA:00:00:00:00:00:09 - 2.009663 arp who-has 10.1.3.3 (ff:ff:ff:ff:ff:ff) tell 10.1.3.4 - 2.009697 arp reply 10.1.3.3 is-at 00:00:00:00:00:09 - 2.009869 Acknowledgment RA:00:00:00:00:00:09 - 2.011487 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 - 2.011503 Acknowledgment RA:00:00:00:00:00:0a - 2.500112 Beacon[|802.11] - 5.000112 Beacon[|802.11] - 7.500112 Beacon[|802.11] - ~/repos/ns-3-dev > -@end verbatim - -You can see that the link type is now 802.11 as you would expect. We leave -it as an exercise to parse the dump and trace packets across the internetwork. +This should be easily understood. If you've forgotten, go back and look at +the discussion in @code{second.cc}. This is the same sequence. Now, we spent a lot of time setting up mobility models for the wireless network and so it would be a shame to finish up without even showing that the STA @@ -1088,13 +1224,13 @@ nodes are actually moving around. Let's do this by hooking into the @code{MobilityModel} course change trace source. This is usually considered a fairly advanced topic, but let's just go for it. -As mentioned in the Tweaking Ns-3 section, the @command{ns-3} tracing system +As mentioned in the ``Tweaking ns-3'' section, the @command{ns-3} tracing system is divided into trace sources and trace sinks, and we provide functions to connect the two. We will use the mobility model predefined course change trace source to originate the trace events. We will need to write a trace sink to connect to that source that will display some pretty information for us. Despite its reputation as being difficult, it's really quite simple. -Just before the main program of the @code{scratch/third.cc} script, add the +Just before the main program of the @code{scratch/mythird.cc} script, add the following function: @verbatim @@ -1150,41 +1286,40 @@ If you now run the simulation, you will see the course changes displayed as they happen. @verbatim - ~/repos/ns-3-dev > ./waf --run scratch/third - Entering directory `/home/craigdo/repos/ns-3-dev/build' - Compilation finished successfully + Build finished successfully (00:00:01) /NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.1304, y = 0.493761 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.70417, y = 1.39837 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.94799, y = 2.05274 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.82597, y = 1.57404 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.3003, y = 0.723347 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.41539, y = -0.811313 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.46199, y = -1.11303 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.52738, y = -1.46869 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.67099, y = -1.98503 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 5.6835, y = -2.14268 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.70932, y = -1.91689 Sent 1024 bytes to 10.1.2.4 Received 1024 bytes from 10.1.3.3 Received 1024 bytes from 10.1.2.4 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.74083, y = 1.62109 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.00146, y = 0.655647 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.98731, y = 0.823279 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.50206, y = 1.69766 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.68108, y = 2.26862 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.25992, y = 1.45317 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.55655, y = 0.742346 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.21992, y = 1.68398 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.81273, y = 0.878638 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.83171, y = 1.07256 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.60027, y = 0.0997156 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.45367, y = 0.620978 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.68484, y = 1.26043 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.53659, y = 0.736479 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.51876, y = 0.548502 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.89778, y = 1.47389 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.98984, y = 1.893 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.91524, y = 1.51402 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.98761, y = 1.14054 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.16617, y = 0.570239 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.02954, y = 1.56086 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.09551, y = 2.55868 - ~/repos/ns-3-dev > + /NodeList/7/$ns3::MobilityModel/CourseChange x = 5.53175, y = -2.48576 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.58021, y = -2.17821 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.18915, y = -1.25785 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.7572, y = -0.434856 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.62404, y = 0.556238 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.74127, y = 1.54934 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 5.73934, y = 1.48729 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.18521, y = 0.59219 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.58121, y = 1.51044 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y = 2.22677 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.42888, y = 1.70014 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.40519, y = 1.91654 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.51981, y = 1.45166 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.34588, y = 2.01523 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.81046, y = 2.90077 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.89186, y = 3.29596 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.46617, y = 2.47732 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.05492, y = 1.56579 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.00393, y = 1.25054 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.00968, y = 1.35768 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.33503, y = 2.30328 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.18682, y = 3.29223 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.96865, y = 2.66873 @end verbatim If you are feeling brave, there is a list of all trace sources in the diff --git a/doc/tutorial/conceptual-overview.texi b/doc/tutorial/conceptual-overview.texi index 94b0b404d..bae4f2290 100644 --- a/doc/tutorial/conceptual-overview.texi +++ b/doc/tutorial/conceptual-overview.texi @@ -726,13 +726,7 @@ the @code{scratch} directory. ~/repos/ns-3-dev > cp examples/first.cc scratch/myfirst.cc @end verbatim -Warning: We use the file @code{first.cc} as one of our regression tests to -verify that it works exactly as we expect. This means that an executable -named @code{first} already exists in the project. If you want to execute -what you compile, and not a previously compiled program, please do the -renaming suggested below.) - -Now build your example using Waf: +Now build your first example script using waf: @verbatim ./waf @@ -742,7 +736,7 @@ You should see messages reporting that your @code{myfirst} example was built successfully. @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone-dev/ns-3-dev/build' [563/648] cxx: scratch/myfirst.cc -> build/debug/scratch/myfirst_3.o [646/648] cxx_link: build/debug/scratch/myfirst_3.o -> build/debug/scratch/myfirst Build finished successfully (00:00:02) @@ -758,7 +752,7 @@ directory you must run it out of the scratch directory): You should see some output: @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone-dev/ns-3-dev/build' Build finished successfully (00:00:00) Sent 1024 bytes to 10.1.1.2 Received 1024 bytes from 10.1.1.1 diff --git a/doc/tutorial/getting-started.texi b/doc/tutorial/getting-started.texi index a8023c057..ef06acbb4 100644 --- a/doc/tutorial/getting-started.texi +++ b/doc/tutorial/getting-started.texi @@ -446,7 +446,7 @@ You should see a report from each unit test that executes indicating that the test has passed. @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) -- Running NS-3 C++ core unit tests... PASS AddressHelper @@ -499,7 +499,7 @@ You should see messages indicating that many tests are being run and are passing. @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' [647/669] regression-test (test-csma-bridge) [648/669] regression-test (test-csma-broadcast) [649/669] regression-test (test-csma-multicast) diff --git a/doc/tutorial/tweaking.texi b/doc/tutorial/tweaking.texi index 6767663f3..ff1f70125 100644 --- a/doc/tutorial/tweaking.texi +++ b/doc/tutorial/tweaking.texi @@ -99,7 +99,7 @@ You should see the now familiar output of the first @command{ns-3} example program @verbatim - Entering directory `/home/craigdo/repos/ns-3-dev/build' + Entering directory `repos/ns-3-dev/build' Compilation finished successfully Sent 1024 bytes to 10.1.1.2 Received 1024 bytes from 10.1.1.1 @@ -148,7 +148,7 @@ you run the script with NS_LOG set this way, the @command{ns-3} logging system will pick up the change and you should see the following output: @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) UdpEchoClientApplication:UdpEchoClient() UdpEchoClientApplication:StartApplication() @@ -201,7 +201,7 @@ that every message from the given log component is prefixed with the component name. @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) UdpEchoClientApplication:UdpEchoClient() UdpEchoClientApplication:StartApplication() @@ -236,7 +236,7 @@ echo client and server applications. You may see that this can be very useful in debugging problems. @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) UdpEchoServerApplication:UdpEchoServer() UdpEchoClientApplication:UdpEchoClient() @@ -269,7 +269,7 @@ Again, you will have to remove the newline above. If you run the script now, you should see the following output: @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) 0s UdpEchoServerApplication:UdpEchoServer() 0s UdpEchoClientApplication:UdpEchoClient() @@ -399,7 +399,7 @@ If you now run the script you will see your new ``Creating Topology'' log message, @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) Creating Topology Sent 1024 bytes to 10.1.1.2 @@ -453,7 +453,7 @@ sort out which program gets which argument. The command line parser will now see the @code{--PrintHelp} argument and respond with, @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) --PrintHelp: Print this help message. --PrintGroups: Print the list of groups. @@ -589,7 +589,7 @@ in which case we recover the timing we had when we explicitly set the @code{DataRate} and @code{Delay} in the script: @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) 0s UdpEchoServerApplication:UdpEchoServer() 1s UdpEchoServerApplication:StartApplication() @@ -666,7 +666,7 @@ Try, @end verbatim @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) --PrintHelp: Print this help message. --PrintGroups: Print the list of groups. @@ -688,7 +688,7 @@ setting the @code{--nPackets} argument in the command line, You should now see @verbatim - Entering directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' + Entering directory `repos/ns-3-allinone/ns-3-dev/build' Build finished successfully (00:00:00) 0s UdpEchoServerApplication:UdpEchoServer() 1s UdpEchoServerApplication:StartApplication() diff --git a/examples/second.cc b/examples/second.cc index c6a4d0f79..10ab69418 100644 --- a/examples/second.cc +++ b/examples/second.cc @@ -37,8 +37,8 @@ int main (int argc, char *argv[]) { bool verbose = true; - uint32_t nCsma = 3; + CommandLine cmd; cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose); @@ -51,6 +51,8 @@ main (int argc, char *argv[]) LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); } + nCsma = nCsma == 0 ? 1 : nCsma; + NodeContainer p2pNodes; p2pNodes.Create (2); @@ -102,8 +104,8 @@ main (int argc, char *argv[]) GlobalRouteManager::PopulateRoutingTables (); - PointToPointHelper::EnablePcap ("second", p2pDevices.Get (1)); - CsmaHelper::EnablePcap ("second", csmaDevices.Get (0), true); + PointToPointHelper::EnablePcapAll ("second"); + CsmaHelper::EnablePcap ("second", csmaDevices.Get (1), true); Simulator::Run (); Simulator::Destroy (); diff --git a/examples/third.cc b/examples/third.cc index 996bbbd74..b6a5551bc 100644 --- a/examples/third.cc +++ b/examples/third.cc @@ -40,11 +40,10 @@ NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample"); int main (int argc, char *argv[]) { - bool verbose = true; - uint32_t nCsma = 3; uint32_t nWifi = 3; + CommandLine cmd; cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi); @@ -162,7 +161,7 @@ main (int argc, char *argv[]) Simulator::Stop (Seconds (10.0)); - PointToPointHelper::EnablePcap ("third", p2pDevices.Get (0)); + PointToPointHelper::EnablePcapAll ("third"); YansWifiPhyHelper::EnablePcap ("third", apDevices.Get (0)); CsmaHelper::EnablePcap ("third", csmaDevices.Get (0), true); From 0bc0bc5d15e8598ff1ea69410f4e8313cd5bba1d Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Wed, 25 Mar 2009 09:34:39 -0700 Subject: [PATCH 12/67] fix some tutorial nits --- doc/tutorial/building-topologies.texi | 49 +++++++++++++------------- doc/tutorial/conceptual-overview.texi | 45 ++++++++++++------------ doc/tutorial/getting-started.texi | 24 +++++++++++-- doc/tutorial/tweaking.texi | 50 +++++++++++++-------------- 4 files changed, 95 insertions(+), 73 deletions(-) diff --git a/doc/tutorial/building-topologies.texi b/doc/tutorial/building-topologies.texi index b50b7608b..62ab61d42 100644 --- a/doc/tutorial/building-topologies.texi +++ b/doc/tutorial/building-topologies.texi @@ -158,9 +158,9 @@ point-to-point and CSMA net device, the number of ``extra'' nodes means the number nodes you desire in the CSMA section minus one. The next bit of code should be quite familiar by now. We instantiate a -@code{PointToPointHelper} and set the associated default attributes so that -we create a five megabit per second transmitter on devices created using the -helper and a two millisecond delay on channels created by the helper. +@code{PointToPointHelper} and set the associated default @code{Attributes} so +that we create a five megabit per second transmitter on devices created using +the helper and a two millisecond delay on channels created by the helper. @verbatim PointToPointHelper pointToPoint; @@ -179,13 +179,13 @@ We mentioned above that you were going to see a helper for CSMA devices and channels, and the next lines introduce them. The @code{CsmaHelper} works just like a @code{PointToPointHelper}, but it creates and connects CSMA devices and channels. In the case of a CSMA device and channel pair, notice that the data -rate is specified by a @emph{channel} attribute instead of a device attribute. -This is because a real CSMA network does not allow one to mix, for example, -10Base-T and 100Base-T devices on a given channel. We first set the data rate -to 100 megabits per second, and then set the speed-of-light delay of the channel -to 6560 nano-seconds (arbitrarily chosen as 1 nanosecond per foot over a 100 -meter segment). Notice that you can set an attribute using its native data -type. +rate is specified by a @emph{channel} @code{Attribute} instead of a device +@code{Attribute}. This is because a real CSMA network does not allow one to mix, +for example, 10Base-T and 100Base-T devices on a given channel. We first set +the data rate to 100 megabits per second, and then set the speed-of-light delay +of the channel to 6560 nano-seconds (arbitrarily chosen as 1 nanosecond per foot +over a 100 meter segment). Notice that you can set an @code{Attribute} using +its native data type. @verbatim CsmaHelper csma; @@ -252,8 +252,8 @@ nodes that has a CSMA node and the client on the node having only a point-to-point device. First, we set up the echo server. We create a @code{UdpEchoServerHelper} and -provide a required attribute value to the constructor which is the server port -number. Recall that this port can be changed later using the +provide a required @code{Attribute} value to the constructor which is the server +port number. Recall that this port can be changed later using the @code{SetAttribute} method if desired, but we require it to be provided to the constructor. @@ -276,7 +276,7 @@ if we create @code{nCsma} ``extra'' nodes the last one will be at index code. The client application is set up exactly as we did in the @code{first.cc} -example script. Again, we provide required attributes to the +example script. Again, we provide required @code{Attributes} to the @code{UdpEchoClientHelper} in the constructor (in this case the remote address and port). We tell the client to send packets to the server we just installed on the last of the ``extra'' CSMA nodes. We install the client on the @@ -780,8 +780,8 @@ that we will connect via the point-to-point link. @end verbatim Next, we see an old friend. We instantiate a @code{PointToPointHelper} and -set the associated default attributes so that we create a five megabit per -second transmitter on devices created using the helper and a two millisecond +set the associated default @code{Attributes} so that we create a five megabit +per second transmitter on devices created using the helper and a two millisecond delay on channels created by the helper. We then @code{Intall} the devices on the nodes and the channel between them. @@ -809,8 +809,8 @@ that will get CSMA devices. The node in question is going to end up with a point-to-point device and a CSMA device. We then create a number of ``extra'' nodes that compose the remainder of the CSMA network. -We then instantiate a @code{CsmaHelper} and set its attributes as we did in -the previous example. We create a @code{NetDeviceContainer} to keep track of +We then instantiate a @code{CsmaHelper} and set its @code{Attributes} as we did +in the previous example. We create a @code{NetDeviceContainer} to keep track of the created CSMA net devices and then we @code{Install} CSMA devices on the selected nodes. @@ -882,8 +882,8 @@ will be used to set the value of the ``Ssid'' @code{Attribute} of the MAC layer implementation. The particular kind of MAC layer is specified by @code{Attribute} as being of the "ns3::NqstaWifiMac" type. This means that the MAC will use a ``non-QoS station'' (nqsta) state machine. Finally, the -``ActiveProbing'' attribute is set to false. This means that probe requests -will not be sent by MACs created by this helper. +``ActiveProbing'' @code{Attribute} is set to false. This means that probe +requests will not be sent by MACs created by this helper. Once all the station-specific parameters are fully configured, both at the MAC and PHY layers, we can invoke our now-familiar @code{Install} method to @@ -908,11 +908,11 @@ requirements of the AP. In this case, the @code{WifiHelper} is going to create MAC layers of the ``ns3::NqapWifiMac'' (Non-Qos Access Point) type. We set the -``BeaconGeneration'' attribute to true and also set an interval between +``BeaconGeneration'' @code{Attribute} to true and also set an interval between beacons of 2.5 seconds. The next lines create the single AP which shares the same set of PHY-level -attributes (and channel) as the stations: +@code{Attributes} (and channel) as the stations: @verbatim NetDeviceContainer apDevices; @@ -922,8 +922,8 @@ attributes (and channel) as the stations: Now, we are going to add mobility models. We want the STA nodes to be mobile, wandering around inside a bounding box, and we want to make the AP node stationary. We use the @code{MobilityHelper} to make this easy for us. -First, we instantiate a @code{MobilityHelper} object and set some attributes -controlling the ``position allocator'' functionality. +First, we instantiate a @code{MobilityHelper} object and set some +@code{Attributes} controlling the ``position allocator'' functionality. @verbatim MobilityHelper mobility; @@ -1329,7 +1329,8 @@ Under the ``core'' section, you will find a link to ``The list of all trace sources.'' You may find it interesting to try and hook some of these traces yourself. Additionally in the ``Modules'' documentation, there is a link to ``The list of all attributes.'' You can set the default value of -any of these attributes via the command line as we have previously discussed. +any of these @code{Attributes} via the command line as we have previously +discussed. We have just scratched the surface of @command{ns-3} in this tutorial, but we hope we have covered enough to get you started doing useful work. diff --git a/doc/tutorial/conceptual-overview.texi b/doc/tutorial/conceptual-overview.texi index bae4f2290..cb38386bb 100644 --- a/doc/tutorial/conceptual-overview.texi +++ b/doc/tutorial/conceptual-overview.texi @@ -446,12 +446,12 @@ to what we call an @code{Attribute} of the @code{PointToPointNetDevice}. If you look at the Doxygen for class @code{ns3::PointToPointNetDevice} and find the documentation for the @code{GetTypeId} method, you will find a list of @code{Attributes} defined for the device. Among these is the ``DataRate'' -attribute. Most user-visible @command{ns-3} objects have similar lists of -attributes. We use this mechanism to easily configure simulations without +@code{Attribute}. Most user-visible @command{ns-3} objects have similar lists of +@code{Attributes}. We use this mechanism to easily configure simulations without recompiling as you will see in a following section. Similar to the ``DataRate'' on the @code{PointToPointNetDevice} you will find a -``Delay'' attribute associated with the @code{PointToPointChannel}. The +``Delay'' @code{Attribute} associated with the @code{PointToPointChannel}. The final line, @verbatim @@ -487,8 +487,9 @@ is created. For each node in the @code{NodeContainer} (there must be exactly two for a point-to-point link) a @code{PointToPointNetDevice} is created and saved in the device container. A @code{PointToPointChannel} is created and the two @code{PointToPointNetDevices} are attached. When objects are created -by the @code{PointToPointHelper}, the attributes previously set in the helper -are used to initialize the corresponding attributes in the created objects. +by the @code{PointToPointHelper}, the @code{Attributes} previously set in the +helper are used to initialize the corresponding @code{Attributes} in the +created objects. After executing the @code{pointToPoint.Install (nodes)} call we will have two nodes, each with an installed point-to-point net device and a @@ -575,13 +576,13 @@ created. The first line of code in the above snippet declares the @code{UdpEchoServerHelper}. As usual, this isn't the application itself, it is an object used to help us create the actual applications. One of our -conventions is to place required attributes in the helper constructor. In this -case, the helper can't do anything useful unless it is provided with a port -number that the client also knows about. Rather than just picking one and -hoping it all works out, we require the port number as a parameter to the +conventions is to place required @code{Attributes} in the helper constructor. +In this case, the helper can't do anything useful unless it is provided with +a port number that the client also knows about. Rather than just picking one +and hoping it all works out, we require the port number as a parameter to the constructor. The constructor, in turn, simply does a @code{SetAttribute} -with the passed value. You can, if desired, set the ``Port'' attribute to -another value later. +with the passed value. You can, if desired, set the ``Port'' @code{Attribute} +to another value later. Similar to many other helper objects, the @code{UdpEchoServerHelper} object has an @code{Install} method. It is the execution of this method that actually @@ -634,12 +635,12 @@ that is managed by an @code{UdpEchoClientHelper}. clientApps.Stop (Seconds (10.0)); @end verbatim -For the echo client, however, we need to set five different attributes. The -first two attributes are set during construction of the +For the echo client, however, we need to set five different @code{Attributes}. +The first two @code{Attributes} are set during construction of the @code{UdpEchoClientHelper}. We pass parameters that are used (internally to -the helper) to set the ``RemoteAddress'' and ``RemotePort'' attributes in -accordance with our convention to make required attributes parameters in the -helper constructors. +the helper) to set the ``RemoteAddress'' and ``RemotePort'' @code{Attributes} +in accordance with our convention to make required @code{Attributes} parameters +in the helper constructors. Recall that we used an @code{Ipv4InterfaceContainer} to keep track of the IP addresses we assigned to our devices. The zeroth interface in the @@ -651,12 +652,12 @@ are creating the helper and telling it so set the remote address of the client to be the IP address assigned to the node on which the server resides. We also tell it to arrange to send packets to port nine. -The ``MaxPackets'' attribute tells the client the maximum number of packets -we allow it to send during the simulation. The ``Interval'' attribute tells -the client how long to wait between packets, and the ``PacketSize'' attribute -tells the client how large its packet payloads should be. With this -particular combination of attributes, we are telling the client to send one -1024-byte packet. +The ``MaxPackets'' @code{Attribute} tells the client the maximum number of +packets we allow it to send during the simulation. The ``Interval'' +@code{Attribute} tells the client how long to wait between packets, and the +``PacketSize'' @code{Attribute} tells the client how large its packet payloads +should be. With this particular combination of @code{Attributes}, we are +telling the client to send one 1024-byte packet. Just as in the case of the echo server, we tell the echo client to @code{Start} and @code{Stop}, but here we start the client one second after the server is diff --git a/doc/tutorial/getting-started.texi b/doc/tutorial/getting-started.texi index ef06acbb4..d0b18cd94 100644 --- a/doc/tutorial/getting-started.texi +++ b/doc/tutorial/getting-started.texi @@ -411,7 +411,7 @@ system. in the example above, this library was not found and the corresponding feature was not enabled. There is a feature to use sudo to set the suid bit of certain programs. This was not enabled by default. -Now go ahead and switch back to the debug build: +Now go ahead and switch back to the debug build. @verbatim ./waf -d debug configure @@ -424,6 +424,26 @@ the @command{ns-3} programs by simply typing, ./waf @end verbatim +Some waf commands are meaningful during the build phase and some commands are valid +in the configuration phase. For example, if you wanted to use the emulation +features of @command{ns-3} you might want to enable setting the suid bit using +sudo. This is a configuration command, and so you could have run the following +command + +@verbatim + ./waf -d debug --enable-sudo configure +@end verbatim + +If you had done this, waf would have run sudo to change the socket creator +programs to run as root. There are many other configure- and build-time options +available in waf. To explore these options, type: + +@verbatim + ./waf -- help +@end verbatim + +We'll use some of the testing-related commands in the next section. + Okay, sorry, I made you build the @command{ns-3} part of the system twice, but now you know how to change the configuration and build optimized code. @@ -518,7 +538,7 @@ a regression test, you can do the following: @verbatim cd build/debug/regression/traces/second.ref - tcpdump -nn -tt -r second-1-1.pcap + tcpdump -nn -tt -r second-2-0.pcap @end verbatim The output should be clear to anyone who is familiar with tcpdump or net diff --git a/doc/tutorial/tweaking.texi b/doc/tutorial/tweaking.texi index ff1f70125..8a7ebcbf5 100644 --- a/doc/tutorial/tweaking.texi +++ b/doc/tutorial/tweaking.texi @@ -93,7 +93,7 @@ to get our bearings, go ahead and run the script just as you did previously, @verbatim ./waf --run scratch/myfirst -@end verbtim +@end verbatim You should see the now familiar output of the first @command{ns-3} example program @@ -438,10 +438,10 @@ in the following code, @end verbatim This simple two line snippet is actually very useful by itself. It opens the -door to the @command{ns-3} global variable and attribute systems. Go ahead -and add that two lines of code to the @code{scratch/first.cc} script at the -start of @code{main}. Go ahead and build the script and run it, but ask the script -for help in the following way, +door to the @command{ns-3} global variable and @code{Attribute} systems. Go +ahead and add that two lines of code to the @code{scratch/first.cc} script at +the start of @code{main}. Go ahead and build the script and run it, but ask +the script for help in the following way, @verbatim ./waf --run "scratch/myfirst --PrintHelp" @@ -464,7 +464,7 @@ now see the @code{--PrintHelp} argument and respond with, @end verbatim Let's focus on the @code{--PrintAttributes} option. We have already hinted -at the @command{ns-3} attribute system while walking through the +at the @command{ns-3} @code{Attribute} system while walking through the @code{first.cc} script. We looked at the following lines of code, @verbatim @@ -475,17 +475,17 @@ at the @command{ns-3} attribute system while walking through the and mentioned that @code{DataRate} was actually an @code{Attribute} of the @code{PointToPointNetDevice}. Let's use the command line argument parser -to take a look at the attributes of the PointToPointNetDevice. The help +to take a look at the @code{Attributes} of the PointToPointNetDevice. The help listing says that we should provide a @code{TypeId}. This corresponds to the -class name of the class to which the attributes belong. In this case it will -be @code{ns3::PointToPointNetDevice}. Let's go ahead and type in, +class name of the class to which the @code{Attributes} belong. In this case it +will be @code{ns3::PointToPointNetDevice}. Let's go ahead and type in, @verbatim ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice" @end verbatim -The system will print out all of the attributes of this kind of net device. -Among the attributes you will see listed is, +The system will print out all of the @code{Attributes} of this kind of net device. +Among the @code{Attributes} you will see listed is, @verbatim --ns3::PointToPointNetDevice::DataRate=[32768bps]: @@ -493,7 +493,7 @@ Among the attributes you will see listed is, @end verbatim This is the default value that will be used when a @code{PointToPointNetDevice} -is created in the system. We overrode this default with the attribute +is created in the system. We overrode this default with the @code{Attribute} setting in the @code{PointToPointHelper} above. Let's use the default values for the point-to-point devices and channels by deleting the @code{SetDeviceAttribute} call and the @code{SetChannelAttribute} call from @@ -558,7 +558,7 @@ the formula implied by the help item: ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps" @end verbatim -This will set the default value of the @code{DataRate} attribute back to +This will set the default value of the @code{DataRate} @code{Attribute} back to five megabits per second. Are you surprised by the result? It turns out that in order to get the original behavior of the script back, we will have to set the speed-of-light delay of the channel as well. We can ask the command line @@ -569,7 +569,7 @@ the net device: ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel" @end verbatim -We discover the @code{Delay} attribute of the channel is set in the following +We discover the @code{Delay} @code{Attribute} of the channel is set in the following way: @verbatim @@ -603,12 +603,12 @@ in which case we recover the timing we had when we explicitly set the @end verbatim Note that the packet is again received by the server at 2.00369 seconds. We -could actually set any of the attributes used in the script in this way. In -particular we could set the @code{UdpEchoClient} attribute @code{MaxPackets} +could actually set any of the @code{Attributes} used in the script in this way. +In particular we could set the @code{UdpEchoClient Attribute MaxPackets} to some other value than one. How would you go about that? Give it a try. Remember you have to comment -out the place we override the default attribute in the script. Then you +out the place we override the default @code{Attribute} in the script. Then you have to rebuild the script using the default. You will also have to find the syntax for actually setting the new default atribute value using the command line help facility. Once you have this figured out you should be able to @@ -649,11 +649,11 @@ start with the following code, @end verbatim Scroll down to the point in the script where we set the @code{MaxPackets} -attribute and change it so that it is set to the variable @code{nPackets} +@code{Attribute} and change it so that it is set to the variable @code{nPackets} instead of the constant @code{1} as is shown below. @verbatim - echoClient.SetAppAttribute ("MaxPackets", UintegerValue (nPackets)); + echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets)); @end verbatim Now if you run the script and provide the @code{--PrintHelp} argument, you @@ -708,11 +708,11 @@ You should now see You have now echoed two packets. You can see that if you are an @command{ns-3} user, you can use the command -line argument system to control global values and attributes. If you are a -model author, you can add new attributes to your Objects and they will -automatically be available for setting by your users through the command line -system. If you are a script author, you can add new variables to your scripts -and hook them into the command line system quite painlessly. +line argument system to control global values and @code{Attributes}. If you are +a model author, you can add new @code{Attributes} to your @code{Objects} and +they will automatically be available for setting by your users through the +command line system. If you are a script author, you can add new variables to +your scripts and hook them into the command line system quite painlessly. @c ======================================================================== @c Using the Tracing System @@ -927,7 +927,7 @@ device on the node with the echo server. I have reproduced that event below. @verbatim 00 r 01 2.25732 - 02 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/Rx + 02 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx 03 ns3::PppHeader ( 04 Point-to-Point Protocol: IP (0x0021)) 05 ns3::Ipv4Header ( From d565da8710ba4430bf40957439d5b334c5197fac Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 25 Mar 2009 10:34:11 -0700 Subject: [PATCH 13/67] wifi-wired-bridging does not need to call GlobalRouteManager --- examples/wifi-wired-bridging.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/wifi-wired-bridging.cc b/examples/wifi-wired-bridging.cc index f75ce7810..0ce26cab5 100644 --- a/examples/wifi-wired-bridging.cc +++ b/examples/wifi-wired-bridging.cc @@ -157,8 +157,6 @@ int main (int argc, char *argv[]) wifiX += 20.0; } - GlobalRouteManager::PopulateRoutingTables (); - Address dest; std::string protocol; if (sendIp) From b7ab01edef749cae2e5540621eb339d8a2a1a6f4 Mon Sep 17 00:00:00 2001 From: Tom Henderson Date: Wed, 25 Mar 2009 10:40:01 -0700 Subject: [PATCH 14/67] Fix a previous regexp substitution that went too far --- .../global-route-manager-impl.cc | 40 +++++++++---------- .../global-route-manager-impl.h | 6 +-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/routing/global-routing/global-route-manager-impl.cc b/src/routing/global-routing/global-route-manager-impl.cc index 9315ad828..7b5f8fce8 100644 --- a/src/routing/global-routing/global-route-manager-impl.cc +++ b/src/routing/global-routing/global-route-manager-impl.cc @@ -154,14 +154,14 @@ SPFVertex::GetDistanceFromRoot (void) const } void -SPFVertex::SetOutgoingTypeId (uint32_t id) +SPFVertex::SetOutgoingInterfaceId (uint32_t id) { NS_LOG_FUNCTION (id); m_rootOif = id; } uint32_t -SPFVertex::GetOutgoingTypeId (void) const +SPFVertex::GetOutgoingInterfaceId (void) const { NS_LOG_FUNCTION_NOARGS (); return m_rootOif; @@ -872,14 +872,14 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( // from the perspective of -- remember that is the link "from" // "to" . // - w->SetOutgoingTypeId ( - FindOutgoingTypeId (l->GetLinkData ())); + w->SetOutgoingInterfaceId ( + FindOutgoingInterfaceId (l->GetLinkData ())); w->SetDistanceFromRoot (distance); w->SetParent (v); NS_LOG_LOGIC ("Next hop from " << v->GetVertexId () << " to " << w->GetVertexId () << " goes through next hop " << w->GetNextHop () << - " via outgoing interface " << w->GetOutgoingTypeId () << + " via outgoing interface " << w->GetOutgoingInterfaceId () << " with distance " << distance); } // end W is a router vertes else @@ -889,14 +889,14 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( GlobalRoutingLSA* w_lsa = w->GetLSA (); NS_ASSERT (w_lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA); // Find outgoing interface ID for this network - w->SetOutgoingTypeId ( - FindOutgoingTypeId (w_lsa->GetLinkStateId (), + w->SetOutgoingInterfaceId ( + FindOutgoingInterfaceId (w_lsa->GetLinkStateId (), w_lsa->GetNetworkLSANetworkMask () )); w->SetDistanceFromRoot (distance); w->SetParent (v); NS_LOG_LOGIC ("Next hop from " << v->GetVertexId () << " to network " << w->GetVertexId () << - " via outgoing interface " << w->GetOutgoingTypeId () << + " via outgoing interface " << w->GetOutgoingInterfaceId () << " with distance " << distance); return 1; } @@ -921,17 +921,17 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( * it can be inherited from the parent network). */ w->SetNextHop (linkRemote->GetLinkData ()); - w->SetOutgoingTypeId (v->GetOutgoingTypeId ()); + w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); NS_LOG_LOGIC ("Next hop from " << v->GetVertexId () << " to " << w->GetVertexId () << " goes through next hop " << w->GetNextHop () << - " via outgoing interface " << w->GetOutgoingTypeId ()); + " via outgoing interface " << w->GetOutgoingInterfaceId ()); } } else { w->SetNextHop (v->GetNextHop ()); - w->SetOutgoingTypeId (v->GetOutgoingTypeId ()); + w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); } } else @@ -950,7 +950,7 @@ GlobalRouteManagerImpl::SPFNexthopCalculation ( // (are inherited). // w->SetNextHop (v->GetNextHop ()); - w->SetOutgoingTypeId (v->GetOutgoingTypeId ()); + w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ()); } // // In all cases, we need valid values for the distance metric and a parent. @@ -1328,7 +1328,7 @@ GlobalRouteManagerImpl::SPFIntraAddStub (GlobalRoutingLinkRecord *l, SPFVertex* " add route to " << tempip << " with mask " << tempmask << " using next hop " << v->GetNextHop () << - " via interface " << v->GetOutgoingTypeId ()); + " via interface " << v->GetOutgoingInterfaceId ()); // // Here's why we did all of that work. We're going to add a host route to the // host address found in the m_linkData field of the point-to-point link @@ -1344,7 +1344,7 @@ GlobalRouteManagerImpl::SPFIntraAddStub (GlobalRoutingLinkRecord *l, SPFVertex* // Ptr gr = GetGlobalRoutingProtocol (node->GetId ()); NS_ASSERT (gr); - gr->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (), v->GetOutgoingTypeId ()); + gr->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (), v->GetOutgoingInterfaceId ()); return; } // if } // for @@ -1356,7 +1356,7 @@ GlobalRouteManagerImpl::SPFIntraAddStub (GlobalRoutingLinkRecord *l, SPFVertex* // have to find the right node pointer to pass to that function. // uint32_t -GlobalRouteManagerImpl::FindOutgoingTypeId (Ipv4Address a, Ipv4Mask amask) +GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask) { NS_LOG_FUNCTION (a << amask); // @@ -1399,7 +1399,7 @@ GlobalRouteManagerImpl::FindOutgoingTypeId (Ipv4Address a, Ipv4Mask amask) // Ptr ipv4 = node->GetObject (); NS_ASSERT_MSG (ipv4, - "GlobalRouteManagerImpl::FindOutgoingTypeId (): " + "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): " "QI for interface failed"); // // Look through the interfaces on this node for one that has the IP address @@ -1526,7 +1526,7 @@ GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) NS_LOG_LOGIC (" Node " << node->GetId () << " add route to " << lr->GetLinkData () << " using next hop " << v->GetNextHop () << - " via interface " << v->GetOutgoingTypeId ()); + " via interface " << v->GetOutgoingInterfaceId ()); // // Here's why we did all of that work. We're going to add a host route to the // host address found in the m_linkData field of the point-to-point link @@ -1543,7 +1543,7 @@ GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v) Ptr gr = GetGlobalRoutingProtocol (node->GetId ()); NS_ASSERT (gr); gr->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (), - v->GetOutgoingTypeId ()); + v->GetOutgoingInterfaceId ()); } // // Done adding the routes for the selected node. @@ -1627,11 +1627,11 @@ GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v) Ptr gr = GetGlobalRoutingProtocol (node->GetId ()); NS_ASSERT (gr); gr->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (), - v->GetOutgoingTypeId ()); + v->GetOutgoingInterfaceId ()); NS_LOG_LOGIC ("Node " << node->GetId () << " add network route to " << tempip << " using next hop " << v->GetNextHop () << - " via interface " << v->GetOutgoingTypeId ()); + " via interface " << v->GetOutgoingInterfaceId ()); } } } diff --git a/src/routing/global-routing/global-route-manager-impl.h b/src/routing/global-routing/global-route-manager-impl.h index 0ba699cf6..65a79800d 100644 --- a/src/routing/global-routing/global-route-manager-impl.h +++ b/src/routing/global-routing/global-route-manager-impl.h @@ -295,7 +295,7 @@ public: * @returns The interface index to use when forwarding packets to the host * or network represented by "this" SPFVertex. */ - uint32_t GetOutgoingTypeId (void) const; + uint32_t GetOutgoingInterfaceId (void) const; /** * @brief Set the interface ID that should be used to begin forwarding packets @@ -337,7 +337,7 @@ public: * @param id The interface index to use when forwarding packets to the host or * network represented by "this" SPFVertex. */ - void SetOutgoingTypeId (uint32_t id); + void SetOutgoingInterfaceId (uint32_t id); /** * @brief Get the IP address that should be used to begin forwarding packets @@ -799,7 +799,7 @@ private: void SPFIntraAddRouter (SPFVertex* v); void SPFIntraAddTransit (SPFVertex* v); void SPFIntraAddStub (GlobalRoutingLinkRecord *l, SPFVertex* v); - uint32_t FindOutgoingTypeId (Ipv4Address a, + uint32_t FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask = Ipv4Mask("255.255.255.255")); // Local cache of the Ipv4GlobalRouting objects, indexed by nodeId From 4d17b00ad47120134501c4ff418f7bfae4e0695a Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Thu, 26 Mar 2009 17:39:20 -0700 Subject: [PATCH 15/67] Make Names API return void not bool, rescan for Python Bindings --- bindings/python/ns3_module_core.py | 24 +++---- bindings/python/ns3_module_helper.py | 6 ++ bindings/python/ns3_module_tap_bridge.py | 10 +++ src/core/names.cc | 79 ++++++++++++------------ src/core/names.h | 22 ++----- 5 files changed, 75 insertions(+), 66 deletions(-) diff --git a/bindings/python/ns3_module_core.py b/bindings/python/ns3_module_core.py index 155e889e5..71322205c 100644 --- a/bindings/python/ns3_module_core.py +++ b/bindings/python/ns3_module_core.py @@ -479,34 +479,34 @@ def register_Ns3Names_methods(root_module, cls): cls.add_constructor([param('ns3::Names const &', 'arg0')]) ## names.h: ns3::Names::Names() [constructor] cls.add_constructor([]) - ## names.h: static bool ns3::Names::Add(std::string name, ns3::Ptr obj) [member function] + ## names.h: static void ns3::Names::Add(std::string name, ns3::Ptr obj) [member function] cls.add_method('Add', - 'bool', + 'void', [param('std::string', 'name'), param('ns3::Ptr< ns3::Object >', 'obj')], is_static=True) - ## names.h: static bool ns3::Names::Add(std::string path, std::string name, ns3::Ptr object) [member function] + ## names.h: static void ns3::Names::Add(std::string path, std::string name, ns3::Ptr object) [member function] cls.add_method('Add', - 'bool', + 'void', [param('std::string', 'path'), param('std::string', 'name'), param('ns3::Ptr< ns3::Object >', 'object')], is_static=True) - ## names.h: static bool ns3::Names::Add(ns3::Ptr context, std::string name, ns3::Ptr object) [member function] + ## names.h: static void ns3::Names::Add(ns3::Ptr context, std::string name, ns3::Ptr object) [member function] cls.add_method('Add', - 'bool', + 'void', [param('ns3::Ptr< ns3::Object >', 'context'), param('std::string', 'name'), param('ns3::Ptr< ns3::Object >', 'object')], is_static=True) - ## names.h: static bool ns3::Names::Rename(std::string oldpath, std::string newname) [member function] + ## names.h: static void ns3::Names::Rename(std::string oldpath, std::string newname) [member function] cls.add_method('Rename', - 'bool', + 'void', [param('std::string', 'oldpath'), param('std::string', 'newname')], is_static=True) - ## names.h: static bool ns3::Names::Rename(std::string path, std::string oldname, std::string newname) [member function] + ## names.h: static void ns3::Names::Rename(std::string path, std::string oldname, std::string newname) [member function] cls.add_method('Rename', - 'bool', + 'void', [param('std::string', 'path'), param('std::string', 'oldname'), param('std::string', 'newname')], is_static=True) - ## names.h: static bool ns3::Names::Rename(ns3::Ptr context, std::string oldname, std::string newname) [member function] + ## names.h: static void ns3::Names::Rename(ns3::Ptr context, std::string oldname, std::string newname) [member function] cls.add_method('Rename', - 'bool', + 'void', [param('ns3::Ptr< ns3::Object >', 'context'), param('std::string', 'oldname'), param('std::string', 'newname')], is_static=True) ## names.h: static std::string ns3::Names::FindName(ns3::Ptr object) [member function] diff --git a/bindings/python/ns3_module_helper.py b/bindings/python/ns3_module_helper.py index bdcf01d60..583c388bf 100644 --- a/bindings/python/ns3_module_helper.py +++ b/bindings/python/ns3_module_helper.py @@ -946,6 +946,8 @@ def register_Ns3StaticMulticastRouteHelper_methods(root_module, cls): def register_Ns3TapBridgeHelper_methods(root_module, cls): ## tap-bridge-helper.h: ns3::TapBridgeHelper::TapBridgeHelper(ns3::TapBridgeHelper const & arg0) [copy constructor] cls.add_constructor([param('ns3::TapBridgeHelper const &', 'arg0')]) + ## tap-bridge-helper.h: ns3::TapBridgeHelper::TapBridgeHelper() [constructor] + cls.add_constructor([]) ## tap-bridge-helper.h: ns3::TapBridgeHelper::TapBridgeHelper(ns3::Ipv4Address gateway) [constructor] cls.add_constructor([param('ns3::Ipv4Address', 'gateway')]) ## tap-bridge-helper.h: void ns3::TapBridgeHelper::SetAttribute(std::string n1, ns3::AttributeValue const & v1) [member function] @@ -968,6 +970,10 @@ def register_Ns3TapBridgeHelper_methods(root_module, cls): cls.add_method('Install', 'ns3::Ptr< ns3::NetDevice >', [param('std::string', 'nodeName'), param('std::string', 'ndName')]) + ## tap-bridge-helper.h: ns3::Ptr ns3::TapBridgeHelper::Install(ns3::Ptr node, ns3::Ptr nd, ns3::AttributeValue const & v1) [member function] + cls.add_method('Install', + 'ns3::Ptr< ns3::NetDevice >', + [param('ns3::Ptr< ns3::Node >', 'node'), param('ns3::Ptr< ns3::NetDevice >', 'nd'), param('ns3::AttributeValue const &', 'v1')]) return def register_Ns3UdpEchoClientHelper_methods(root_module, cls): diff --git a/bindings/python/ns3_module_tap_bridge.py b/bindings/python/ns3_module_tap_bridge.py index 66185dc52..49b6e651f 100644 --- a/bindings/python/ns3_module_tap_bridge.py +++ b/bindings/python/ns3_module_tap_bridge.py @@ -5,6 +5,8 @@ def register_types(module): ## tap-bridge.h: ns3::TapBridge [class] module.add_class('TapBridge', parent=root_module['ns3::NetDevice']) + ## tap-bridge.h: ns3::TapBridge::Mode [enumeration] + module.add_enum('Mode', ['ILLEGAL', 'CONFIGURE_LOCAL', 'USE_LOCAL', 'USE_BRIDGE'], outer_class=root_module['ns3::TapBridge']) ## Register a nested module for the namespace Config @@ -76,6 +78,14 @@ def register_Ns3TapBridge_methods(root_module, cls): cls.add_method('Stop', 'void', [param('ns3::Time', 'tStop')]) + ## tap-bridge.h: void ns3::TapBridge::SetMode(ns3::TapBridge::Mode mode) [member function] + cls.add_method('SetMode', + 'void', + [param('ns3::TapBridge::Mode', 'mode')]) + ## tap-bridge.h: ns3::TapBridge::Mode ns3::TapBridge::GetMode() [member function] + cls.add_method('GetMode', + 'ns3::TapBridge::Mode', + []) ## tap-bridge.h: void ns3::TapBridge::SetName(std::string const name) [member function] cls.add_method('SetName', 'void', diff --git a/src/core/names.cc b/src/core/names.cc index 2cb1e88b2..b7d6f4464 100644 --- a/src/core/names.cc +++ b/src/core/names.cc @@ -623,40 +623,47 @@ Names::Delete (void) NamesPriv::Delete (); } -bool +void Names::Add (std::string name, Ptr object) { - return NamesPriv::Get ()->Add (name, object); + bool result = NamesPriv::Get ()->Add (name, object); + NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name); } -bool +void Names::Rename (std::string oldpath, std::string newname) { - return NamesPriv::Get ()->Rename (oldpath, newname); + bool result = NamesPriv::Get ()->Rename (oldpath, newname); + NS_ABORT_MSG_UNLESS (result, "Names::Rename(): Error renaming " << oldpath << " to " << newname); } -bool +void Names::Add (std::string path, std::string name, Ptr object) { - return NamesPriv::Get ()->Add (path, name, object); + bool result = NamesPriv::Get ()->Add (path, name, object); + NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding " << path << " " << name); } -bool +void Names::Rename (std::string path, std::string oldname, std::string newname) { - return NamesPriv::Get ()->Rename (path, oldname, newname); + bool result = NamesPriv::Get ()->Rename (path, oldname, newname); + NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << path << " " << oldname << " to " << newname); } -bool +void Names::Add (Ptr context, std::string name, Ptr object) { - return NamesPriv::Get ()->Add (context, name, object); + bool result = NamesPriv::Get ()->Add (context, name, object); + NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name << " under context " << &context); } -bool +void Names::Rename (Ptr context, std::string oldname, std::string newname) { - return NamesPriv::Get ()->Rename (context, oldname, newname); + bool result = NamesPriv::Get ()->Rename (context, oldname, newname); + NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << oldname << " to " << newname << " under context " << + &context); } std::string @@ -730,50 +737,53 @@ NamesTest::RunTests (void) { bool result = true; + // + // Names::Add and Names::Rename return void to align with the Config API. + // The private versions of these functions do return error codes so we + // can test to make sure errors are detected. Names::Add and + // Names::Rename check for these error codes and abort if an error was + // detected. So when we expect that an error should be detected, we + // have to call the private routine to avoid a fatal error popping. // // Name a couple of objects at the root level // Ptr client = CreateObject (); - result = Names::Add ("Client", client); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Add ("Client", client); Ptr server = CreateObject (); - result = Names::Add ("Server", server); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Add ("Server", server); // // We shouldn't be able to add another name to a previously named object // - result = Names::Add ("Not Client", client); + result = NamesPriv::Get ()->Add ("Not Client", client); NS_TEST_ASSERT_EQUAL (result, false); // // We shouldn't be able to duplicate a name at the root level. // Ptr secondClient = CreateObject (); - result = Names::Add ("Client", secondClient); + result = NamesPriv::Get ()->Add ("Client", secondClient); NS_TEST_ASSERT_EQUAL (result, false); // // We should be able to add a new name in the first object's context // Ptr clientEth0 = CreateObject (); - result = Names::Add (client, "eth0", clientEth0); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Add (client, "eth0", clientEth0); // // We shouldn't be able to duplicate a name in that context. // Ptr secondClientEth0 = CreateObject (); - result = Names::Add (client, "eth0", secondClientEth0); + result = NamesPriv::Get ()->Add (client, "eth0", secondClientEth0); NS_TEST_ASSERT_EQUAL (result, false); // // We should be able to add the same name in the second object's context // Ptr serverEth0 = CreateObject (); - result = Names::Add (server, "eth0", serverEth0); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Add (server, "eth0", serverEth0); // // We should be able to find the short names for the objects we created @@ -879,32 +889,28 @@ NamesTest::RunTests (void) // in the name. // Ptr router1 = CreateObject (); - result = Names::Add ("/Names/Router1", router1); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Add ("/Names/Router1", router1); // // We should be able to add objects while not including the root of the namespace // in the name. // Ptr router2 = CreateObject (); - result = Names::Add ("Router2", router2); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Add ("Router2", router2); // // We should be able to add sub-objects while including the root of the namespace // in the name. // Ptr router1Eth0 = CreateObject (); - result = Names::Add ("/Names/Router1/eth0", router1Eth0); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Add ("/Names/Router1/eth0", router1Eth0); // // We should be able to add sub-objects while not including the root of the namespace // in the name. // Ptr router2Eth0 = CreateObject (); - result = Names::Add ("Router2/eth0", router2Eth0); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Add ("Router2/eth0", router2Eth0); // // We should be able to find these objects in the same two ways @@ -937,20 +943,17 @@ NamesTest::RunTests (void) // We have a pile of names defined. We should be able to rename them in the // usual ways. // - result = Names::Rename ("/Names/Router1", "RouterX"); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Rename ("/Names/Router1", "RouterX"); foundObject = Names::Find ("/Names/RouterX"); NS_TEST_ASSERT_EQUAL (foundObject, router1); - result = Names::Rename ("Router2", "RouterY"); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Rename ("Router2", "RouterY"); foundObject = Names::Find ("RouterY"); NS_TEST_ASSERT_EQUAL (foundObject, router2); - result = Names::Rename ("/Names/RouterX/eth0", "ath0"); - NS_TEST_ASSERT_EQUAL (result, true); + Names::Rename ("/Names/RouterX/eth0", "ath0"); foundObject = Names::Find ("/Names/RouterX/ath0"); NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0); @@ -963,7 +966,7 @@ NamesTest::RunTests (void) // object. // - result = Names::Rename ("/Names/RouterX", "RouterY"); + result = NamesPriv::Get ()->Rename ("/Names/RouterX", "RouterY"); NS_TEST_ASSERT_EQUAL (result, false); Names::Delete (); diff --git a/src/core/names.h b/src/core/names.h index 7f163e2fb..cbb61bef2 100644 --- a/src/core/names.h +++ b/src/core/names.h @@ -65,7 +65,7 @@ public: * prepended with a path to that object. * \param obj A smart pointer to the object itself. */ - static bool Add (std::string name, Ptr obj); + static void Add (std::string name, Ptr obj); /** * \brief An intermediate form of Names::Add allowing you to provide a path to @@ -96,11 +96,9 @@ public: * \param name The name of the object you want to associate. * \param obj A smart pointer to the object itself. * - * \returns true if the association was successfully completed, false otherwise - * * \see Names::Add (Ptr context, std::string name, Ptr object); */ - static bool Add (std::string path, std::string name, Ptr object); + static void Add (std::string path, std::string name, Ptr object); /** * \brief A low-level form of Names::Add allowing you to specify the path to @@ -148,10 +146,8 @@ public: * under which you want this new name to be defined. * \param name The name of the object you want to associate. * \param obj A smart pointer to the object itself. - * - * \returns true if the association was successfully completed, false otherwise */ - static bool Add (Ptr context, std::string name, Ptr object); + static void Add (Ptr context, std::string name, Ptr object); /** * \brief Rename a previously associated name. @@ -178,11 +174,9 @@ public: * \param oldpath The current path name to the object you want to change. * \param newname The new name of the object you want to change. * - * \returns true if the name change was successfully completed, false otherwise - * * \see Names::Add (std::string name, Ptr obj) */ - static bool Rename (std::string oldpath, std::string newname); + static void Rename (std::string oldpath, std::string newname); /** * \brief An intermediate form of Names::Rename allowing you to provide a path to @@ -203,10 +197,8 @@ public: * you want this name change to occur (cf. directory). * \param oldname The currently defined name of the object. * \param newname The new name you want the object to have. - * - * \returns true if the name change was successfully completed, false otherwise */ - static bool Rename (std::string path, std::string oldname, std::string newname); + static void Rename (std::string path, std::string oldname, std::string newname); /** * \brief A low-level form of Names::Rename allowing you to specify the path to @@ -244,10 +236,8 @@ public: * under which you want this new name to be defined. * \param oldname The current shortname of the object you want to change. * \param newname The new shortname of the object you want to change. - * - * \returns true if the name change was successfully completed, false otherwise */ - static bool Rename (Ptr context, std::string oldname, std::string newname); + static void Rename (Ptr context, std::string oldname, std::string newname); /** * Given a pointer to an object, look to see if that object has a name From 49056cac7d47dc15e74b88cbe5260f2d83d60899 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Fri, 27 Mar 2009 11:18:54 +0000 Subject: [PATCH 16/67] fix mac osx python bindings --- bindings/python/ns3modulegen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/python/ns3modulegen.py b/bindings/python/ns3modulegen.py index 12363b1e4..50f6f2653 100755 --- a/bindings/python/ns3modulegen.py +++ b/bindings/python/ns3modulegen.py @@ -145,6 +145,7 @@ def main(): if 'TapBridge' not in enabled_features: for clsname in ['TapBridge', 'TapBridgeHelper']: root_module.classes.remove(root_module['ns3::%s' % clsname]) + root_module.enums.remove(root_module['ns3::TapBridge::Mode']) root_module.generate(out, '_ns3') From 4d1839e95f3b849f41ffe124010a38dc648c9192 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 27 Mar 2009 09:58:04 -0700 Subject: [PATCH 17/67] don't use pthread option under cygwin --- src/core/wscript | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/wscript b/src/core/wscript index a15b6fee6..faa028cdc 100644 --- a/src/core/wscript +++ b/src/core/wscript @@ -11,7 +11,7 @@ def configure(conf): # Check for POSIX threads test_env = conf.env.copy() - if Options.platform != 'darwin': + if Options.platform != 'darwin' and Options.platform != 'cygwin': test_env.append_value('LINKFLAGS', '-pthread') test_env.append_value('CXXFLAGS', '-pthread') test_env.append_value('CCFLAGS', '-pthread') @@ -30,7 +30,7 @@ int main () mandatory=False) if have_pthread: # darwin accepts -pthread but prints a warning saying it is ignored - if Options.platform != 'darwin': + if Options.platform != 'darwin' and Options.platform != 'cygwin': conf.env['CXXFLAGS_PTHREAD'] = '-pthread' conf.env['CCFLAGS_PTHREAD'] = '-pthread' conf.env['LINKFLAGS_PTHREAD'] = '-pthread' From 3b663898ae8692775761c962f7e7964983830f21 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 30 Mar 2009 15:47:38 -0700 Subject: [PATCH 18/67] Update CHANGES for ns-3.4 from hg log --- CHANGES.html | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/CHANGES.html b/CHANGES.html index bac58e3c1..2bc0c7509 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -46,7 +46,33 @@ us a note on ns-developers mailing list.


changes from ns-3.3 to ns-3.4

+

changes to build system

+
    +
  • A major option regarding the downloading and building of ns-3 has been
  • +
  • added for ns-3.4 -- the ns-3-allinone feature. This allows a user to
  • +
  • get the most common options for ns-3 downloaded and built with a minimum
  • +
  • amount of trouble. See the ns-3 tutorial for a detailed explanation of
  • +
  • how to use this new feature.
  • +
+ +
    +
  • The build system now runs build items in parallel by default. This
  • +
  • includes the regression tests.
  • +
+

new API:

+
    +
  • XML support has been added to the ConfigStore in /src/contrib/config-store.cc
  • +
+ +
    +
  • The ns-2 calendar queue scheduler option has been ported to src/simulator
  • +
+ +
    +
  • A ThreeLogDistancePropagationLossModel has been added to src/devices/wifi
  • +
+
  • ConstantAccelerationMobilityModel in src/mobility/constant-acceleration-mobility-model.h
@@ -61,8 +87,18 @@ us a note on ns-developers mailing list.

  • src/core/names.{cc,h})
  • +
      +
    • Wifi multicast support has been added in src/devices/wifi
    • +
    +

    changes to existing API:

    +
      +
    • Some fairly significant changes have been made to the API of the
    • +
    • random variable code. Please see the ns-3 manual and src/core/random-variable.cc
    • +
    • for details.
    • +
    +
    • The trace sources in the various NetDevice classes has been completely
    • reworked to allow for a consistent set of trace sources across the
    • @@ -81,6 +117,30 @@ us a note on ns-developers mailing list.

    • StaticSpeedMobilityModel has been renamed ConstantVelocityMobilityModel
    +
      +
    • The Callback templates have been extended to support more parameters.
    • +
    • See src/core/callback.h
    • +
    + +
      +
    • Many helper API have been changed to allow passing Object-based parameters
    • +
    • as string names to ease working with the object name service.
    • +
    + +
      +
    • The Config APIs now accept path segments that are names defined by the
    • +
    • object name service.
    • +
    + +
      +
    • Minor changes were made to make the system build under the Intel C++ compiler.
    • +
    + +
      +
    • Trace hooks for association and deassociation to/from an access point were
    • +
    • added to src/devices/wifi/nqsta-wifi-mac.cc
    • +
    +

    changes from ns-3.2 to ns-3.3

    From 2a083e6095be3fb683078e245c2b0f7545d53b08 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 30 Mar 2009 16:32:42 -0700 Subject: [PATCH 19/67] RELEASE_NOTES for ns-3.4 --- RELEASE_NOTES | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 40196af8e..da851c62b 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -18,7 +18,7 @@ http://www.nsnam.org/releases/ns-3.4.tar.bz2 Supported platforms ------------------- -ns-3.2 has been tested on the following platforms: +ns-3.4 has been tested on the following platforms: - linux x86 gcc 4.2, 4.1, and, 3.4.6. - linux x86_64 gcc 4.3.2, 4.2.3, 4.2.1, 4.1.3, 3.4.6 - MacOS X ppc and x86 @@ -34,6 +34,19 @@ New user-visible features propagation loss model based on the ns-2 models. Fabian Mauchle contributed multicast support. + b) Object Name Service: A facility allowing ns-3 Objects to be assigned + names has been added. + + c) Tap Bridge: A second option for integrating ns-3 with real-world hosts + has been added. This allows for real hosts to talk over ns-3 net devices + and simulated networks. + + d) A new build option (ns-3-allinone) has been provided to make it easier for + users to download and bulid commonly used ns-3 configurations. + + e) The ns-3 calendar queue scheduler has been ported to ns-3. + + f) XML support has been added to the ConfigStore. API changes from ns-3.3 ----------------------- From 99f822add2739d6661cc5016bdf1e14058399fdc Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 30 Mar 2009 16:36:19 -0700 Subject: [PATCH 20/67] RELEASE_NOTES shouldn't refer to past releases as future releases --- RELEASE_NOTES | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index da851c62b..bed5b44b9 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -8,8 +8,8 @@ http://www.nsnam.org including tutorials: http://www.nsnam.org/tutorials.html -Release 3.4 (pending) -===================== +Release 3.4 +=========== Availability ------------ @@ -69,7 +69,8 @@ Future releases Our next release, which is expected to happen in 2 to 4 months from now, will feature the merging of some of our projects currently in development including fuller IPv6 support, and IPv4 and routing protocol refactoring, and some smaller -features such as an object naming facility and a new Global ARP package. +features such as a new Global ARP package and possibly a new Testing and Validation +suite, Release 3.3 =========== @@ -81,7 +82,7 @@ http://www.nsnam.org/releases/ns-3.3.tar.bz2 Supported platforms ------------------- -ns-3.2 has been tested on the following platforms: +ns-3.3 has been tested on the following platforms: - linux x86 gcc 4.2, 4.1, and, 3.4.6. - linux x86_64 gcc 4.3.2, 4.2.3, 4.2.1, 4.1.3, 3.4.6 - MacOS X ppc and x86 From 44d76f210b0bec812b38245b6196cfc1f121fb68 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Mon, 30 Mar 2009 16:54:50 -0700 Subject: [PATCH 21/67] use tar xjf instead of bunzip in tutorial --- doc/tutorial/getting-started.texi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/tutorial/getting-started.texi b/doc/tutorial/getting-started.texi index d0b18cd94..a4bc52aac 100644 --- a/doc/tutorial/getting-started.texi +++ b/doc/tutorial/getting-started.texi @@ -257,8 +257,7 @@ get a copy of a release by typing the following into your Linux shell mkdir tarballs cd tarballs wget http://www.nsnam.org/releases/ns-allinone-3.4.tar.bz2 - bunzip2 ns-allinone-3.4.tar.bz2 - tar xf ns-3.4.tar + tar xjf ns-3.4.tar.bz2 @end verbatim If you change into the directory @code{ns-allinone-3.4} you should see a From d6c8c9d556f1dce36a7f2b9738d87745dcc97ce3 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Tue, 31 Mar 2009 10:32:16 -0700 Subject: [PATCH 22/67] prettify CHANGES and add behavior changed section for ns-3.4 --- CHANGES.html | 143 +++++++++++++++++++++++---------------------------- 1 file changed, 65 insertions(+), 78 deletions(-) diff --git a/CHANGES.html b/CHANGES.html index 2bc0c7509..8e9f45398 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -44,113 +44,100 @@ to this file based on your experience, please contribute a patch or drop us a note on ns-developers mailing list.


    -

    changes from ns-3.3 to ns-3.4

    +

    Changes from ns-3.3 to ns-3.4

    -

    changes to build system

    +

    Changes to build system

      -
    • A major option regarding the downloading and building of ns-3 has been
    • -
    • added for ns-3.4 -- the ns-3-allinone feature. This allows a user to
    • -
    • get the most common options for ns-3 downloaded and built with a minimum
    • -
    • amount of trouble. See the ns-3 tutorial for a detailed explanation of
    • -
    • how to use this new feature.
    • +
    • A major option regarding the downloading and building of ns-3 has been +added for ns-3.4 -- the ns-3-allinone feature. This allows a user to +get the most common options for ns-3 downloaded and built with a minimum +amount of trouble. See the ns-3 tutorial for a detailed explanation of +how to use this new feature.
    • + +
    • The build system now runs build items in parallel by default. This includes +the regression tests.
    -
      -
    • The build system now runs build items in parallel by default. This
    • -
    • includes the regression tests.
    • -
    - -

    new API:

    +

    New API:

    • XML support has been added to the ConfigStore in /src/contrib/config-store.cc
    • -
    -
    • The ns-2 calendar queue scheduler option has been ported to src/simulator
    • -
    -
    • A ThreeLogDistancePropagationLossModel has been added to src/devices/wifi
    • -
    -
    • ConstantAccelerationMobilityModel in src/mobility/constant-acceleration-mobility-model.h
    • -
    -
      -
    • A new emulation mode is supported with the TapBridge net device (see
    • -
    • src/devices/tap-bridge)
    • -
    +
  • A new emulation mode is supported with the TapBridge net device (see +src/devices/tap-bridge)
  • -
      -
    • A new facility for naming ns-3 Objects is included (see
    • -
    • src/core/names.{cc,h})
    • -
    +
  • A new facility for naming ns-3 Objects is included (see +src/core/names.{cc,h})
  • -
    • Wifi multicast support has been added in src/devices/wifi
    -

    changes to existing API:

    +

    Changes to existing API:

      -
    • Some fairly significant changes have been made to the API of the
    • -
    • random variable code. Please see the ns-3 manual and src/core/random-variable.cc
    • -
    • for details.
    • -
    +
  • Some fairly significant changes have been made to the API of the +random variable code. Please see the ns-3 manual and src/core/random-variable.cc +for details.
  • -
      -
    • The trace sources in the various NetDevice classes has been completely
    • -
    • reworked to allow for a consistent set of trace sources across the
    • -
    • devices. The names of the trace sources have been changed to provide
    • -
    • some context with respect to the level at which the trace occurred.
    • -
    • A new set of trace sources has been added which emulates the behavior
    • -
    • of packet sniffers. These sources have been used to implement tcpdump-
    • -
    • like functionality and are plumbed up into the helper classes. The
    • -
    • user-visible changes are the trace source name changes and the ability
    • -
    • to do promiscuous-mode pcap tracing via helpers. For further information
    • -
    • regarding these changes, please see the ns-3 manual
    • -
    +
  • The trace sources in the various NetDevice classes has been completely +reworked to allow for a consistent set of trace sources across the +devices. The names of the trace sources have been changed to provide +some context with respect to the level at which the trace occurred. +A new set of trace sources has been added which emulates the behavior +of packet sniffers. These sources have been used to implement tcpdump- +like functionality and are plumbed up into the helper classes. The +user-visible changes are the trace source name changes and the ability +to do promiscuous-mode pcap tracing via helpers. For further information +regarding these changes, please see the ns-3 manual
  • -
      -
    • StaticMobilityModel has been renamed ConstantPositionMobilityModel
    • -
    • StaticSpeedMobilityModel has been renamed ConstantVelocityMobilityModel
    • -
    +
  • StaticMobilityModel has been renamed ConstantPositionMobilityModel +StaticSpeedMobilityModel has been renamed ConstantVelocityMobilityModel
  • -
      -
    • The Callback templates have been extended to support more parameters.
    • -
    • See src/core/callback.h
    • -
    +
  • The Callback templates have been extended to support more parameters. +See src/core/callback.h
  • -
      -
    • Many helper API have been changed to allow passing Object-based parameters
    • -
    • as string names to ease working with the object name service.
    • -
    +
  • Many helper API have been changed to allow passing Object-based parameters +as string names to ease working with the object name service.
  • -
      -
    • The Config APIs now accept path segments that are names defined by the
    • -
    • object name service.
    • -
    +
  • The Config APIs now accept path segments that are names defined by the +object name service.
  • -
    • Minor changes were made to make the system build under the Intel C++ compiler.
    • + +
    • Trace hooks for association and deassociation to/from an access point were +added to src/devices/wifi/nqsta-wifi-mac.cc
    +

    Changed behavior:

    +
      -
    • Trace hooks for association and deassociation to/from an access point were
    • -
    • added to src/devices/wifi/nqsta-wifi-mac.cc
    • +
    • The tracing system rework has introduced some significant changes in the +behavior of some trace sources, specifically in the positioning of trace sources +in the device code. For example, there were cases where the packet transmit +trace source was hit before the packet was enqueued on the device transmit quueue. +This now happens just before the packet is transmitted over the channel medium. +The scope of the changes is too large to be included here. If you have concerns +regarding trace semantics, please consult the net device documentation for details. +As is usual, the ultimate source for documentation is the net device source code.

    -

    changes from ns-3.2 to ns-3.3

    +

    Changes from ns-3.2 to ns-3.3

    -

    new API:

    +

    New API:

      -
    • ns-3 ABORT macros in src/core/abort.h
    • -
    • Config::MatchContainer
    • -
    • ConstCast and DynamicCast helper functions for Ptr casting
    • -
    • StarTopology added to several topology helpers
    • -
    • NetDevice::IsBridge ()
    • +
    • +ns-3 ABORT macros in src/core/abort.h +Config::MatchContainer +ConstCast and DynamicCast helper functions for Ptr casting +StarTopology added to several topology helpers +NetDevice::IsBridge () +
    • 17-11-2008; changeset 4c1c3f6bcd03
    • @@ -180,7 +167,7 @@ hook ascii trace to the drop trace events in Ipv4L3Protocol and ArpL3Protocol.
    -

    changes to existing API:

    +

    Changes to existing API:

    • NetDevice::MakeMulticastAddress() was renamed to NetDevice::GetMulticast() @@ -247,9 +234,9 @@ Global routing supports bridge devices.

    -

    changes from ns-3.1 to ns-3.2

    +

    Changes from ns-3.1 to ns-3.2

    -

    new API:

    +

    New API:

    • 26-08-2008; changeset @@ -273,7 +260,7 @@ multithreaded simulator implementation.
    -

    new API in existing classes:

    +

    New API in existing classes:

    • 01-08-2008; changeset @@ -286,7 +273,7 @@ mostly for internal use.
    -

    changes to existing API:

    +

    Changes to existing API:

    • 05-09-2008; changeset @@ -424,7 +411,7 @@ Rename all instances method names using "Set..Parameter" to "Set..Attribute"
    -

    changed behavior:

    +

    Changed behavior: