1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/examples/emu-udp-echo.cc Thu Oct 30 10:00:41 2008 -0700
1.3 @@ -0,0 +1,156 @@
1.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
1.5 +/*
1.6 + * This program is free software; you can redistribute it and/or modify
1.7 + * it under the terms of the GNU General Public License version 2 as
1.8 + * published by the Free Software Foundation;
1.9 + *
1.10 + * This program is distributed in the hope that it will be useful,
1.11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.13 + * GNU General Public License for more details.
1.14 + *
1.15 + * You should have received a copy of the GNU General Public License
1.16 + * along with this program; if not, write to the Free Software
1.17 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.18 + */
1.19 +
1.20 +// Network topology
1.21 +//
1.22 +// Normally, the use case for emulated net devices is in collections of
1.23 +// small simulations that connect to the outside world through specific
1.24 +// interfaces. For example, one could construct a number of virtual
1.25 +// machines and connect them via a host-only network. To use the emulated
1.26 +// net device, you would need to set all of the host-only interfaces in
1.27 +// promiscuous mode and provide an appropriate device name (search for "eth1"
1.28 +// below). One could also use the emulated net device in a testbed situation
1.29 +// where the host on which the simulation is running has a specific interface
1.30 +// of interested. You would also need to set this specific interface into
1.31 +// promiscuous mode and provide an appropriate device name.
1.32 +//
1.33 +// This philosophy carries over to this simple example.
1.34 +//
1.35 +// We don't assume any special configuration and all of the ns-3 emulated net
1.36 +// devices will actually talk to the same underlying OS device. We rely on
1.37 +// the fact that the OS will deliver copies of our packets to the other ns-3
1.38 +// net devices since we operate in promiscuous mode.
1.39 +//
1.40 +// Packets will be sent out over the device, but we use MAC spoofing. The
1.41 +// MAC addresses will be generated using the Organizationally Unique Identifier
1.42 +// (OUI) 00:00:00 as a base. This vendor code is not assigned to any
1.43 +// organization and so should not conflict with any real hardware. We'll use
1.44 +// the first n of these addresses, where n is the number of nodes, in this
1.45 +// simualtion. It is up to you to determine that using these MAC addresses is
1.46 +// okay on your network and won't conflict with anything else (including another
1.47 +// simulation using emu devices) on your network. Once you have made this
1.48 +// determination, you need to put the interface you chose into promiscuous mode.
1.49 +// We don't do it for you since you need to think about it first.
1.50 +//
1.51 +// This simulation uses the real-time simulator and so will consume ten seconds
1.52 +// of real time.
1.53 +//
1.54 +// By default, we create the following topology
1.55 +//
1.56 +// n0 n1 n2 n3
1.57 +// | | | |
1.58 +// -----------------
1.59 +// "eth1"
1.60 +//
1.61 +// - UDP flows from n0 to n1 and back
1.62 +// - DropTail queues
1.63 +// - Tracing of queues and packet receptions to file "udp-echo.tr"
1.64 +// - pcap tracing on all devices
1.65 +//
1.66 +
1.67 +#include <fstream>
1.68 +#include "ns3/core-module.h"
1.69 +#include "ns3/simulator-module.h"
1.70 +#include "ns3/helper-module.h"
1.71 +
1.72 +using namespace ns3;
1.73 +
1.74 +NS_LOG_COMPONENT_DEFINE ("EmulatedUdpEchoExample");
1.75 +
1.76 +int
1.77 +main (int argc, char *argv[])
1.78 +{
1.79 + std::string deviceName ("eth1");
1.80 + uint32_t nNodes = 4;
1.81 +
1.82 + //
1.83 + // Allow the user to override any of the defaults at run-time, via command-line
1.84 + // arguments
1.85 + //
1.86 + CommandLine cmd;
1.87 + cmd.AddValue("deviceName", "device name", deviceName);
1.88 + cmd.AddValue("nNodes", "number of nodes to create (>= 2)", nNodes);
1.89 + cmd.Parse (argc, argv);
1.90 +
1.91 + GlobalValue::Bind ("SimulatorImplementationType",
1.92 + StringValue ("ns3::RealtimeSimulatorImpl"));
1.93 +
1.94 + //
1.95 + // need at least two nodes
1.96 + //
1.97 + nNodes = nNodes < 2 ? 2 : nNodes;
1.98 +
1.99 + //
1.100 + // Explicitly create the nodes required by the topology (shown above).
1.101 + //
1.102 + NS_LOG_INFO ("Create nodes.");
1.103 + NodeContainer n;
1.104 + n.Create (nNodes);
1.105 +
1.106 + InternetStackHelper internet;
1.107 + internet.Install (n);
1.108 +
1.109 + //
1.110 + // Explicitly create the channels required by the topology (shown above).
1.111 + //
1.112 + NS_LOG_INFO ("Create channels.");
1.113 + EmuHelper emu;
1.114 + emu.SetAttribute ("DeviceName", StringValue (deviceName));
1.115 + NetDeviceContainer d = emu.Install (n);
1.116 +
1.117 + //
1.118 + // We've got the "hardware" in place. Now we need to add IP addresses.
1.119 + //
1.120 + Ipv4AddressHelper ipv4;
1.121 + NS_LOG_INFO ("Assign IP Addresses.");
1.122 + ipv4.SetBase ("10.1.1.0", "255.255.255.0");
1.123 + Ipv4InterfaceContainer i = ipv4.Assign (d);
1.124 +
1.125 + //
1.126 + // Create a UdpEchoServer application on node one.
1.127 + //
1.128 + NS_LOG_INFO ("Create Applications.");
1.129 + UdpEchoServerHelper server (9);
1.130 + ApplicationContainer apps = server.Install (n.Get(1));
1.131 + apps.Start (Seconds (1.0));
1.132 + apps.Stop (Seconds (10.0));
1.133 +
1.134 + //
1.135 + // Create a UdpEchoClient application to send UDP datagrams from node zero to node one.
1.136 + //
1.137 + uint32_t packetSize = 1024;
1.138 + uint32_t maxPacketCount = 1;
1.139 + Time interPacketInterval = Seconds (1.);
1.140 + UdpEchoClientHelper client (i.GetAddress (1), 9);
1.141 + client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
1.142 + client.SetAttribute ("Interval", TimeValue (interPacketInterval));
1.143 + client.SetAttribute ("PacketSize", UintegerValue (packetSize));
1.144 + apps = client.Install (n.Get (0));
1.145 + apps.Start (Seconds (2.0));
1.146 + apps.Stop (Seconds (10.0));
1.147 +
1.148 + std::ofstream ascii;
1.149 + ascii.open ("emu-udp-echo.tr");
1.150 + EmuHelper::EnablePcapAll ("emu-udp-echo");
1.151 +
1.152 + //
1.153 + // Now, do the actual simulation.
1.154 + //
1.155 + NS_LOG_INFO ("Run Simulation.");
1.156 + Simulator::Run ();
1.157 + Simulator::Destroy ();
1.158 + NS_LOG_INFO ("Done.");
1.159 +}
2.1 --- a/examples/wscript Wed Oct 29 22:39:36 2008 -0700
2.2 +++ b/examples/wscript Thu Oct 30 10:00:41 2008 -0700
2.3 @@ -32,6 +32,10 @@
2.4 ['csma', 'internet-stack'])
2.5 obj.source = 'udp-echo.cc'
2.6
2.7 + obj = bld.create_ns3_program('emu-udp-echo',
2.8 + ['emu', 'internet-stack'])
2.9 + obj.source = 'emu-udp-echo.cc'
2.10 +
2.11 obj = bld.create_ns3_program('realtime-udp-echo',
2.12 ['csma', 'internet-stack'])
2.13 obj.source = 'realtime-udp-echo.cc'
3.1 --- a/src/devices/emu/emu-net-device.cc Wed Oct 29 22:39:36 2008 -0700
3.2 +++ b/src/devices/emu/emu-net-device.cc Thu Oct 30 10:00:41 2008 -0700
3.3 @@ -52,6 +52,8 @@
3.4
3.5 NS_OBJECT_ENSURE_REGISTERED (EmuNetDevice);
3.6
3.7 +#define EMU_MAGIC 65867
3.8 +
3.9 TypeId
3.10 EmuNetDevice::GetTypeId (void)
3.11 {
3.12 @@ -192,6 +194,25 @@
3.13 rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
3.14 NS_ASSERT_MSG (rc != -1, "EmuNetDevice::StartDevice(): Can't bind to specified interface");
3.15
3.16 + rc = ioctl(m_sock, SIOCGIFFLAGS, &ifr);
3.17 + NS_ASSERT_MSG (rc != -1, "EmuNetDevice::StartDevice(): Can't get interface flags");
3.18 +
3.19 + //
3.20 + // This device only works if the underlying interface is up in promiscuous
3.21 + // mode. We could have turned it on in the socket creator, but the situation
3.22 + // is that we expect these devices to be used in conjunction with virtual
3.23 + // machines with connected host-only (simulated) networks, or in a testbed.
3.24 + // There is a lot of setup and configuration happening outside of this one
3.25 + // issue, and we expect that configuration to include choosing a valid
3.26 + // interface (e.g, "ath1"), ensuring that the device supports promiscuous
3.27 + // mode, and placing it in promiscuous mode. We just make sure of the
3.28 + // end result.
3.29 + //
3.30 + if ((ifr.ifr_flags & IFF_PROMISC) == 0)
3.31 + {
3.32 + NS_FATAL_ERROR ("EmuNetDevice::StartDevice(): " << m_deviceName << " is not in promiscuous mode");
3.33 + }
3.34 +
3.35 //
3.36 // Now spin up a read thread to read packets.
3.37 //
3.38 @@ -236,6 +257,10 @@
3.39 NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not bind(): errno = " << strerror (errno));
3.40 }
3.41
3.42 + NS_LOG_INFO ("Created Unix socket");
3.43 + NS_LOG_INFO ("sun_family = " << un.sun_family);
3.44 + NS_LOG_INFO ("sun_path = " << un.sun_path);
3.45 +
3.46 //
3.47 // We have a socket here, but we want to get it there -- to the program we're
3.48 // going to exec. What we'll do is to do a getsockname and then encode the
3.49 @@ -250,10 +275,10 @@
3.50 }
3.51
3.52 //
3.53 - // Now encode that socket name (endpoint information) as a string
3.54 + // Now encode that socket name (family and path) as a string of hex digits
3.55 //
3.56 - std::string endpoint = EmuBufferToString((uint8_t *)&un, len);
3.57 -
3.58 + std::string path = EmuBufferToString((uint8_t *)&un, len);
3.59 + NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\"");
3.60 //
3.61 // Fork and exec the process to create our socket. If we're us (the parent)
3.62 // we wait for the child (the socket creator) to complete and read the
3.63 @@ -270,7 +295,8 @@
3.64 // the (now) parent process.
3.65 //
3.66 std::ostringstream oss;
3.67 - oss << "-p " << endpoint;
3.68 + oss << "-v -p" << path;
3.69 + NS_LOG_INFO ("Parameters set to \"" << oss.str () << "\"");
3.70
3.71 //
3.72 // Execute the socket creation process image.
3.73 @@ -386,10 +412,23 @@
3.74 if (cmsg->cmsg_level == SOL_SOCKET &&
3.75 cmsg->cmsg_type == SCM_RIGHTS)
3.76 {
3.77 - int *rawSocket = (int*)CMSG_DATA (cmsg);
3.78 - NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
3.79 - m_sock = *rawSocket;
3.80 - return;
3.81 + //
3.82 + // This is the type of message we want. Check to see if the magic
3.83 + // number is correct and then pull out the socket we care about if
3.84 + // it matches
3.85 + //
3.86 + if (magic == EMU_MAGIC)
3.87 + {
3.88 + NS_LOG_INFO ("Got SCM_RIGHTS with correct magic " << magic);
3.89 + int *rawSocket = (int*)CMSG_DATA (cmsg);
3.90 + NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
3.91 + m_sock = *rawSocket;
3.92 + return;
3.93 + }
3.94 + else
3.95 + {
3.96 + NS_LOG_INFO ("Got SCM_RIGHTS, but with bad magic " << magic);
3.97 + }
3.98 }
3.99 }
3.100 NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
4.1 --- a/src/devices/emu/emu-sock-creator.cc Wed Oct 29 22:39:36 2008 -0700
4.2 +++ b/src/devices/emu/emu-sock-creator.cc Thu Oct 30 10:00:41 2008 -0700
4.3 @@ -42,22 +42,21 @@
4.4 #define LOG(msg) \
4.5 if (gVerbose) \
4.6 { \
4.7 - std::cout << msg << std::endl; \
4.8 + std::cout << __FUNCTION__ << "(): " << msg << std::endl; \
4.9 }
4.10
4.11 -#define ABORT(msg) \
4.12 - std::cout << __FILE__ << __FUNCTION__ << ": fatal error at line " << __LINE__ << ": " << msg << std::endl; \
4.13 - exit (-1);
4.14 +#define ABORT(msg, printErrno) \
4.15 + std::cout << __FILE__ << ": fatal error at line " << __LINE__ << ": " << __FUNCTION__ << "(): " << msg << std::endl; \
4.16 + if (printErrno) \
4.17 + { \
4.18 + std::cout << " errno = " << errno << " (" << strerror (errno) << ")" << std::endl; \
4.19 + } \
4.20 + exit (-1);
4.21
4.22 #define ABORT_IF(cond, msg, printErrno) \
4.23 if (cond) \
4.24 { \
4.25 - std::cout << __FILE__ << __FUNCTION__ << ": fatal error at line " << __LINE__ << ": " << msg << std::endl; \
4.26 - if (printErrno) \
4.27 - { \
4.28 - std::cout << " errno = " << errno << "(" << strerror (errno) << ")" << std::endl; \
4.29 - } \
4.30 - exit (-1); \
4.31 + ABORT(msg, printErrno); \
4.32 }
4.33
4.34 /**
4.35 @@ -75,9 +74,9 @@
4.36 // Open a Unix (local interprocess) socket to call back to the emu net
4.37 // device.
4.38 //
4.39 - LOG ("SendSocket(): Create Unix socket");
4.40 + LOG ("Create Unix socket");
4.41 int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
4.42 - ABORT_IF (sock == -1, "SendSocket(): Unable to open socket", 1);
4.43 + ABORT_IF (sock == -1, "Unable to open socket", 1);
4.44
4.45 //
4.46 // We have this string called path, which is really a hex representation
4.47 @@ -89,15 +88,15 @@
4.48 socklen_t clientAddrLen;
4.49 struct sockaddr_un clientAddr;
4.50
4.51 - LOG ("SendSocket(): Decode address");
4.52 + LOG ("Decode address " << path);
4.53 bool rc = ns3::EmuStringToBuffer (path, (uint8_t *)&clientAddr, &clientAddrLen);
4.54 - ABORT_IF (rc == false, "SendSocket(): Unable to decode path", 0);
4.55 + ABORT_IF (rc == false, "Unable to decode path", 0);
4.56
4.57 - LOG ("SendSocket(): Connect");
4.58 + LOG ("Connect");
4.59 int status = connect (sock, (struct sockaddr*)&clientAddr, clientAddrLen);
4.60 - ABORT_IF (status != -1, "SendSocket(): Unable to connect to emu device", 1);
4.61 + ABORT_IF (status == -1, "Unable to connect to emu device", 1);
4.62
4.63 - LOG ("SendSocket(): Connected");
4.64 + LOG ("Connected");
4.65
4.66 //
4.67 // This is arcane enough that a few words are worthwhile to explain what's
4.68 @@ -189,7 +188,7 @@
4.69 ssize_t len = sendmsg(sock, &msg, 0);
4.70 ABORT_IF (len == -1, "Could not send socket back to emu net device", 1);
4.71
4.72 - LOG ("SendSocket(): sendmsg complete");
4.73 + LOG ("sendmsg complete");
4.74 }
4.75
4.76 int
4.77 @@ -225,7 +224,7 @@
4.78 // unless we have that string.
4.79 //
4.80 ABORT_IF (path == NULL, "path is a required argument", 0);
4.81 -
4.82 + LOG ("Provided path is \"" << path << "\"");
4.83 //
4.84 // The whole reason for all of the hoops we went through to call out to this
4.85 // program will pay off here. We created this program to run as suid root
4.86 @@ -234,6 +233,7 @@
4.87 // though. So all of these hoops are to allow us to exeucte the following
4.88 // single line of code:
4.89 //
4.90 + LOG ("Creating raw socket");
4.91 int sock = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
4.92 ABORT_IF (sock == -1, "CreateSocket(): Unable to open raw socket", 1);
4.93