--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emu/emu-encode-decode.cc Wed Oct 29 22:39:36 2008 -0700
@@ -0,0 +1,110 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+
+namespace ns3 {
+
+/**
+ * \brief Convert a byte buffer to a string containing a hex representation
+ * of the buffer. Make the string pretty by adding a colon (':') between
+ * the hex.
+ *
+ * \param buffer The input buffer to be converted.
+ * \param len The length of the input buffer.
+ * \returns A string containing a hex representation of the data in buffer.
+ */
+ std::string
+EmuBufferToString (uint8_t *buffer, uint32_t len)
+{
+ std::ostringstream oss;
+ //
+ // Tell the stream to make hex characters, zero-filled
+ //
+ oss.setf (std::ios::hex, std::ios::basefield);
+ oss.fill('0');
+
+ //
+ // Loop through the buffer, separating the two-digit-wide hex bytes
+ // with a colon.
+ //
+ for (uint8_t i = 0; i < len; i++)
+ {
+ oss << ":" << std::setw (2) << (uint32_t)buffer[i];
+ }
+ return oss.str ();
+}
+
+/**
+ * \brief Convert string encoded by the inverse function (EmuBufferToString)
+ * back into a byte buffer.
+ *
+ * \param s The input string.
+ * \param buffer The buffer to initialize with the converted bits.
+ * \param len The length of the data that is valid in the buffer.
+ * \returns True indicates a successful conversion.
+ */
+ bool
+EmuStringToBuffer (std::string s, uint8_t *buffer, uint32_t *len)
+{
+ //
+ // If the string was made by our inverse function, the string length must
+ // be a multiple of three characters in length. Use this fact to do a
+ // quick reasonableness test.
+ //
+ if ((s.length () % 3) != 0)
+ {
+ return false;
+ }
+
+ std::istringstream iss;
+ iss.str (s);
+
+ uint8_t n = 0;
+
+ while (iss.good ())
+ {
+ //
+ // The first character in the "triplet" we're working on is always the
+ // the ':' separator. Read that into a char and make sure we're skipping
+ // what we think we're skipping.
+ //
+ char c;
+ iss.read (&c, 1);
+ if (c != ':')
+ {
+ return false;
+ }
+
+ //
+ // And then read in the real bits and convert them.
+ //
+ uint32_t tmp;
+ iss >> std::hex >> tmp;
+ buffer[n] = tmp;
+ n++;
+ }
+
+ *len = n;
+ return true;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emu/emu-encode-decode.h Wed Oct 29 22:39:36 2008 -0700
@@ -0,0 +1,33 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef EMU_ENCODE_DECODE_H
+#define EMU_ENCODE_DECODE_H
+
+#include <string>
+
+namespace ns3 {
+
+ std::string EmuBufferToString (uint8_t *buffer, uint32_t len);
+ bool EmuStringToBuffer (std::string s, uint8_t *buffer, uint32_t *len);
+
+
+} // namespace ns3
+
+#endif // EMU_ENCODE_DECODE_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emu/emu-net-device.cc Wed Oct 29 22:39:36 2008 -0700
@@ -0,0 +1,861 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "emu-net-device.h"
+#include "emu-encode-decode.h"
+
+#include "ns3/log.h"
+#include "ns3/queue.h"
+#include "ns3/simulator.h"
+#include "ns3/realtime-simulator-impl.h"
+#include "ns3/mac48-address.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/ethernet-trailer.h"
+#include "ns3/llc-snap-header.h"
+#include "ns3/trace-source-accessor.h"
+#include "ns3/pointer.h"
+#include "ns3/channel.h"
+#include "ns3/system-thread.h"
+#include "ns3/string.h"
+#include "ns3/boolean.h"
+
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netpacket/packet.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+NS_LOG_COMPONENT_DEFINE ("EmuNetDevice");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (EmuNetDevice);
+
+TypeId
+EmuNetDevice::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::EmuNetDevice")
+ .SetParent<NetDevice> ()
+ .AddConstructor<EmuNetDevice> ()
+ .AddAttribute ("Address",
+ "The ns-3 MAC address of this (virtual) device.",
+ Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
+ MakeMac48AddressAccessor (&EmuNetDevice::m_address),
+ MakeMac48AddressChecker ())
+ .AddAttribute ("DeviceName",
+ "The name of the underlying real device (e.g. eth1).",
+ StringValue ("eth1"),
+ MakeStringAccessor (&EmuNetDevice::m_deviceName),
+ MakeStringChecker ())
+ .AddAttribute ("Start",
+ "The simulation time at which to spin up the device thread.",
+ TimeValue (Seconds (0.)),
+ MakeTimeAccessor (&EmuNetDevice::m_tStart),
+ MakeTimeChecker ())
+ .AddAttribute ("Stop",
+ "The simulation time at which to tear down the device thread.",
+ TimeValue (Seconds (0.)),
+ MakeTimeAccessor (&EmuNetDevice::m_tStop),
+ MakeTimeChecker ())
+ .AddAttribute ("TxQueue",
+ "A queue to use as the transmit queue in the device.",
+ PointerValue (),
+ MakePointerAccessor (&EmuNetDevice::m_queue),
+ MakePointerChecker<Queue> ())
+ .AddTraceSource ("Rx",
+ "Trace source to fire on reception of a MAC packet.",
+ MakeTraceSourceAccessor (&EmuNetDevice::m_rxTrace))
+ .AddTraceSource ("Drop",
+ "Trace source to fire on when a MAC packet is dropped.",
+ MakeTraceSourceAccessor (&EmuNetDevice::m_dropTrace))
+ ;
+ return tid;
+}
+
+
+EmuNetDevice::EmuNetDevice ()
+:
+ m_startEvent (),
+ m_stopEvent (),
+ m_sock (-1),
+ m_readThread (0),
+ m_ifIndex (-1),
+ m_sll_ifindex (-1),
+ m_name ("Emu NetDevice")
+{
+ NS_LOG_FUNCTION (this);
+ Start (m_tStart);
+}
+
+EmuNetDevice::~EmuNetDevice ()
+{
+}
+
+void
+EmuNetDevice::DoDispose()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_node = 0;
+ NetDevice::DoDispose ();
+}
+
+void
+EmuNetDevice::Start (Time tStart)
+{
+ NS_LOG_FUNCTION (tStart);
+
+ //
+ // Cancel any pending start event and schedule a new one at some relative time in the future.
+ //
+ Simulator::Cancel (m_startEvent);
+ m_startEvent = Simulator::Schedule (tStart, &EmuNetDevice::StartDevice, this);
+}
+
+ void
+EmuNetDevice::Stop (Time tStop)
+{
+ NS_LOG_FUNCTION (tStop);
+ //
+ // Cancel any pending stop event and schedule a new one at some relative time in the future.
+ //
+ Simulator::Cancel (m_stopEvent);
+ m_startEvent = Simulator::Schedule (tStop, &EmuNetDevice::StopDevice, this);
+}
+
+ void
+EmuNetDevice::StartDevice (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ //
+ // Spin up the emu net device and start receiving packets.
+ //
+ NS_ASSERT_MSG (m_sock == -1, "EmuNetDevice::StartDevice(): Device is already started");
+
+ NS_LOG_LOGIC ("Creating socket");
+ //
+ // Call out to a separate process running as suid root in order to get a raw
+ // socket. We do this to avoid having the entire simulation running as root.
+ // If this method returns, we'll have a raw socket waiting for us in m_sock.
+ //
+ CreateSocket ();
+
+ //
+ // Figure out which interface index corresponds to the device name in the corresponding attribute.
+ //
+ struct ifreq ifr;
+ bzero (&ifr, sizeof(ifr));
+ strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
+
+ NS_LOG_LOGIC ("Getting interface index");
+ int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
+ NS_ASSERT_MSG (rc != -1, "EmuNetDevice::StartDevice(): Can't get interface index");
+
+ //
+ // Save the real interface index for later calls to sendto
+ //
+ m_sll_ifindex = ifr.ifr_ifindex;
+
+ //
+ // Bind the socket to the interface we just found.
+ //
+ struct sockaddr_ll ll;
+ bzero (&ll, sizeof(ll));
+
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = m_sll_ifindex;
+ ll.sll_protocol = htons(ETH_P_ALL);
+
+ NS_LOG_LOGIC ("Binding socket to interface");
+
+ rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
+ NS_ASSERT_MSG (rc != -1, "EmuNetDevice::StartDevice(): Can't bind to specified interface");
+
+ //
+ // Now spin up a read thread to read packets.
+ //
+ NS_ASSERT_MSG (m_readThread == 0, "EmuNetDevice::StartDevice(): Receive thread is already running");
+
+ NS_LOG_LOGIC ("Spinning up read thread");
+
+ m_readThread = Create<SystemThread> (MakeCallback (&EmuNetDevice::ReadThread, this));
+ m_readThread->Start ();
+
+ NotifyLinkUp ();
+}
+
+void
+EmuNetDevice::CreateSocket (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ //
+ // We want to create a raw socket for our net device. 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 create a raw socket. We're
+ // going to fork and exec that program soon, but we need to have a socket
+ // to talk to it with. So we create a local interprocess (Unix) socket
+ // for that purpose.
+ //
+ int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
+ if (sock == -1)
+ {
+ NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Unix socket creation error, errno = " << strerror (errno));
+ }
+
+ //
+ // Bind to that socket and let the kernel allocate an endpoint
+ //
+ struct sockaddr_un un;
+ memset (&un, 0, sizeof (un));
+ un.sun_family = AF_UNIX;
+ int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t));
+ if (status == -1)
+ {
+ NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not bind(): errno = " << strerror (errno));
+ }
+
+ //
+ // We have a socket here, but we want to get it there -- to the program we're
+ // going to exec. What we'll do is to do a getsockname and then encode the
+ // resulting address information as a string, and then send the string to the
+ // program as an argument. So we need to get the sock name.
+ //
+ socklen_t len = sizeof (un);
+ status = getsockname (sock, (struct sockaddr*)&un, &len);
+ if (status == -1)
+ {
+ NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not getsockname(): errno = " << strerror (errno));
+ }
+
+ //
+ // Now encode that socket name (endpoint information) as a string
+ //
+ std::string endpoint = EmuBufferToString((uint8_t *)&un, len);
+
+ //
+ // Fork and exec the process to create our socket. If we're us (the parent)
+ // we wait for the child (the socket creator) to complete and read the
+ // socket it created using the ancillary data mechanism.
+ //
+ pid_t pid = ::fork ();
+ if (pid == 0)
+ {
+ NS_LOG_DEBUG ("Child process");
+
+ //
+ // build a command line argument from the encoded endpoint string that
+ // the socket creation process will use to figure out how to respond to
+ // the (now) parent process.
+ //
+ std::ostringstream oss;
+ oss << "-p " << endpoint;
+
+ //
+ // Execute the socket creation process image.
+ //
+ status = ::execl (FindCreator ().c_str (), "emu-sock-creator", oss.str ().c_str (), (char *)NULL);
+
+ //
+ // If the execl successfully completes, it never returns. If it returns it failed or the OS is
+ // broken. In either case, we bail.
+ //
+ NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Back from execl(), errno = " << ::strerror (errno));
+ }
+ else
+ {
+ NS_LOG_DEBUG ("Parent process");
+ //
+ // We're the process running the emu net device. We need to wait for the
+ // socket creator process to finish its job.
+ //
+ int st;
+ pid_t waited = waitpid (pid, &st, 0);
+ if (waited == -1)
+ {
+ NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): waitpid() fails, errno = " << strerror (errno));
+ }
+ NS_ASSERT_MSG (pid == waited, "EmuNetDevice::CreateSocket(): pid mismatch");
+
+ //
+ // Check to see if the socket creator exited normally and then take a
+ // look at the exit code. If it bailed, so should we. If it didn't
+ // even exit normally, we bail too.
+ //
+ if (WIFEXITED (st))
+ {
+ int exitStatus = WEXITSTATUS (st);
+ if (exitStatus != 0)
+ {
+ NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited normally with status " << exitStatus);
+ }
+ }
+ else
+ {
+ NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited abnormally");
+ }
+
+ //
+ // At this point, the socket creator has run successfully and should
+ // have created our raw socket and sent it back to the socket address
+ // we provided. Our socket should be waiting on the Unix socket. We've
+ // got to do a bunch of grunto work to get at it, though.
+ //
+ // The struct iovec below is part of a scatter-gather list. It describes a
+ // buffer. In this case, it describes a buffer (an integer) that will
+ // get the data that comes back from the socket creator process. It will
+ // be a magic number that we use as a consistency/sanity check.
+ //
+ struct iovec iov;
+ uint32_t magic;
+ iov.iov_base = &magic;
+ iov.iov_len = sizeof(magic);
+
+ //
+ // The CMSG macros you'll see below are used to create and access control
+ // messages (which is another name for ancillary data). The ancillary
+ // data is made up of pairs of struct cmsghdr structures and associated
+ // data arrays.
+ //
+ // First, we're going to allocate a buffer on the stack to receive our
+ // data array (that contains the socket). Sometimes you'll see this called
+ // an "ancillary element" but the msghdr uses the control message termimology
+ // so we call it "control."
+ //
+ size_t msg_size = sizeof(int);
+ char control[CMSG_SPACE(msg_size)];
+
+ //
+ // There is a msghdr that is used to minimize the number of parameters
+ // passed to recvmsg (which we will use to receive our ancillary data).
+ // This structure uses terminology corresponding to control messages, so
+ // you'll see msg_control, which is the pointer to the ancillary data and
+ // controllen which is the size of the ancillary data array.
+ //
+ // So, initialize the message header that describes the ancillary/control
+ // data we expect to receive and point it to buffer.
+ //
+ struct msghdr msg;
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control;
+ msg.msg_controllen = sizeof (control);
+ msg.msg_flags = 0;
+
+ //
+ // Now we can actually receive the interesting bits from the socket
+ // creator process.
+ //
+ ssize_t bytesRead = recvmsg (sock, &msg, 0);
+ if (bytesRead != sizeof(int))
+ {
+ NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): 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
+ // one we're interested in.
+ //
+ struct cmsghdr *cmsg;
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS)
+ {
+ int *rawSocket = (int*)CMSG_DATA (cmsg);
+ NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
+ m_sock = *rawSocket;
+ return;
+ }
+ }
+ NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
+ }
+}
+
+std::string
+EmuNetDevice::FindCreator (void)
+{
+ struct stat st;
+ std::string debug = "./build/debug/src/devices/emu/emu-sock-creator";
+ std::string optimized = "./build/optimized/src/devices/emu/emu-sock-creator";
+
+ if (::stat (debug.c_str (), &st) == 0)
+ {
+ return debug;
+ }
+
+ if (::stat (optimized.c_str (), &st) == 0)
+ {
+ return optimized;
+ }
+
+ NS_FATAL_ERROR ("EmuNetDevice::FindCreator(): Couldn't find creator");
+ return ""; // quiet compiler
+}
+
+void
+EmuNetDevice::StopDevice (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ close (m_sock);
+ m_sock = -1;
+
+ NS_ASSERT_MSG (m_readThread != 0, "EmuNetDevice::StopDevice(): Receive thread is not running");
+
+ NS_LOG_LOGIC ("Joining read thread");
+ m_readThread->Join ();
+ m_readThread = 0;
+}
+
+void
+EmuNetDevice::ForwardUp (uint8_t *buf, uint32_t len)
+{
+ NS_LOG_FUNCTION (buf << len);
+
+ //
+ // Create a packet out of the buffer we received and free that buffer.
+ //
+ Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
+ free (buf);
+ buf = 0;
+
+ //
+ // Trace sinks will expect complete packets, not packets without some of the
+ // headers.
+ //
+ Ptr<Packet> originalPacket = packet->Copy ();
+
+ //
+ // Checksum the packet
+ //
+ EthernetTrailer trailer;
+ packet->RemoveTrailer (trailer);
+ trailer.CheckFcs (packet);
+
+ EthernetHeader header (false);
+ packet->RemoveHeader (header);
+
+ NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
+ NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
+
+ //
+ // An IP host group address is mapped to an Ethernet multicast address
+ // by placing the low-order 23-bits of the IP address into the low-order
+ // 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex).
+ //
+ // We are going to receive all packets destined to any multicast address,
+ // which means clearing the low-order 23 bits the header destination
+ //
+ Mac48Address mcDest;
+ uint8_t mcBuf[6];
+
+ header.GetDestination ().CopyTo (mcBuf);
+ mcBuf[3] &= 0x80;
+ mcBuf[4] = 0;
+ mcBuf[5] = 0;
+ mcDest.CopyFrom (mcBuf);
+
+ Mac48Address multicast = Mac48Address::ConvertFrom (GetMulticast ());
+ Mac48Address broadcast = Mac48Address::ConvertFrom (GetBroadcast ());
+ Mac48Address destination = Mac48Address::ConvertFrom (GetAddress ());
+
+ LlcSnapHeader llc;
+ packet->RemoveHeader (llc);
+ uint16_t protocol = llc.GetType ();
+
+ PacketType packetType;
+
+ if (header.GetDestination () == broadcast)
+ {
+ NS_LOG_LOGIC ("Pkt destination is PACKET_BROADCAST");
+ packetType = NS3_PACKET_BROADCAST;
+ }
+ else if (mcDest == multicast)
+ {
+ NS_LOG_LOGIC ("Pkt destination is PACKET_MULTICAST");
+ packetType = NS3_PACKET_MULTICAST;
+ }
+ else if (header.GetDestination () == destination)
+ {
+ NS_LOG_LOGIC ("Pkt destination is PACKET_HOST");
+ packetType = NS3_PACKET_HOST;
+ }
+ else
+ {
+ NS_LOG_LOGIC ("Pkt destination is PACKET_OTHERHOST");
+ packetType = NS3_PACKET_OTHERHOST;
+ }
+
+ if (!m_promiscRxCallback.IsNull ())
+ {
+ NS_LOG_LOGIC ("calling m_promiscRxCallback");
+ m_promiscRxCallback (this, packet->Copy (), protocol, header.GetSource (), header.GetDestination (), packetType);
+ }
+
+ if (packetType != NS3_PACKET_OTHERHOST)
+ {
+ m_rxTrace (originalPacket);
+ NS_LOG_LOGIC ("calling m_rxCallback");
+ m_rxCallback (this, packet, protocol, header.GetSource ());
+ }
+}
+
+void
+EmuNetDevice::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 forward up 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.
+ //
+
+ int32_t len = -1;
+ struct sockaddr_ll addr;
+ socklen_t addrSize = sizeof (addr);
+
+ for (;;)
+ {
+ uint32_t bufferSize = 65536;
+ uint8_t *buf = (uint8_t *)malloc (bufferSize);
+ NS_ASSERT_MSG (buf, "EmuNetDevice::ReadThread(): malloc packet buffer failed");
+ NS_LOG_LOGIC ("Calling recvfrom");
+ len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr, &addrSize);
+
+ if (len == -1)
+ {
+ free (buf);
+ buf = 0;
+ return;
+ }
+
+ NS_LOG_INFO ("EmuNetDevice::ReadThread(): Received packet");
+ NS_LOG_INFO ("EmuNetDevice::ReadThread(): Scheduling handler");
+ DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->ScheduleRealtimeNow (
+ MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
+ buf = 0;
+ }
+}
+
+bool
+EmuNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
+{
+ NS_LOG_FUNCTION (packet << dest << protocolNumber);
+ //
+ // The immediate questions here are how are we going to encapsulate packets and what do we use as the MAC source and
+ // destination (hardware) addresses?
+ //
+ // If we return false from EmuNetDevice::NeedsArp, the ArpIpv4Interface will pass the broadcast address as the
+ // hardware (Ethernet) destination by default. If we return true from EmuNetDevice::NeedsArp, then the hardware
+ // destination is actually meaningful, but we'll have an ns-3 ARP running on this device. There can also be an ARP
+ // running on the underlying OS so we have to be very careful, both about multiple ARPs and also about TCP, UDP, etc.
+ //
+ // We are operating in promiscuous mode on the receive side (all ns-3 net devices are required to implement the
+ // promiscuous callback in a meaningful way), so we have an option regarding the hardware addresses. We don't actually have
+ // to use the real hardware addresses and IP addresses of the underlying system. We can completely use MAC-spoofing to
+ // fake out the OS by using the ns-3 assigned MAC address (and also the ns-3 assigned IP addresses). Ns-3 starts its
+ // MAC address allocation using the OUI (vendor-code) 00:00:00 which is unassigned to any organization and is a globally
+ // administered address, so there shouldn't be any collisions with real hardware.
+ //
+ // So what we do is we return true from EmuNetDevice::NeedsArp which tells ns-3 to use its own ARP. We spoof the
+ // MAC address of the device and use promiscuous mode to receive traffic destined to that address.
+ //
+ return SendFrom (packet, m_address, dest, protocolNumber);
+}
+
+bool
+EmuNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &dest, uint16_t protocolNumber)
+{
+ NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
+
+ if (IsLinkUp () == false)
+ {
+ NS_LOG_LOGIC ("Link is down, returning");
+ return false;
+ }
+
+ Mac48Address destination = Mac48Address::ConvertFrom (dest);
+ Mac48Address source = Mac48Address::ConvertFrom (src);
+
+ NS_LOG_LOGIC ("Transmit packet with UID " << packet->GetUid ());
+ NS_LOG_LOGIC ("Transmit packet from " << source);
+ NS_LOG_LOGIC ("Transmit packet to " << destination);
+
+#if 0
+ {
+ struct ifreq ifr;
+ bzero (&ifr, sizeof(ifr));
+ strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
+
+ NS_LOG_LOGIC ("Getting MAC address");
+ int32_t rc = ioctl (m_sock, SIOCGIFHWADDR, &ifr);
+ NS_ASSERT_MSG (rc != -1, "EmuNetDevice::SendFrom(): Can't get MAC address");
+
+ std::ostringstream oss;
+ oss << std::hex <<
+ (ifr.ifr_hwaddr.sa_data[0] & 0xff) << ":" <<
+ (ifr.ifr_hwaddr.sa_data[1] & 0xff) << ":" <<
+ (ifr.ifr_hwaddr.sa_data[2] & 0xff) << ":" <<
+ (ifr.ifr_hwaddr.sa_data[3] & 0xff) << ":" <<
+ (ifr.ifr_hwaddr.sa_data[4] & 0xff) << ":" <<
+ (ifr.ifr_hwaddr.sa_data[5] & 0xff) << std::dec;
+
+ NS_LOG_LOGIC ("Fixup source to HW MAC " << oss.str ());
+ source = Mac48Address (oss.str ().c_str ());
+ NS_LOG_LOGIC ("source now " << source);
+ }
+#endif
+
+ LlcSnapHeader llc;
+ llc.SetType (protocolNumber);
+ packet->AddHeader (llc);
+
+ EthernetHeader header (false);
+ header.SetSource (source);
+ header.SetDestination (destination);
+ header.SetLengthType (packet->GetSize ());
+ packet->AddHeader (header);
+
+ EthernetTrailer trailer;
+ trailer.CalcFcs (packet);
+ packet->AddTrailer (trailer);
+
+ //
+ // Enqueue and dequeue the packet to hit the tracing hooks.
+ //
+ m_queue->Enqueue (packet);
+ packet = m_queue->Dequeue ();
+
+ struct sockaddr_ll ll;
+ bzero (&ll, sizeof (ll));
+
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = m_sll_ifindex;
+ ll.sll_protocol = htons(ETH_P_ALL);
+
+ NS_LOG_LOGIC ("calling sendto");
+
+ int32_t rc;
+ rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
+
+ NS_LOG_LOGIC ("sendto returns " << rc);
+
+ return rc == -1 ? false : true;
+}
+
+void
+EmuNetDevice::SetDataRate(DataRate bps)
+{
+ NS_LOG_FUNCTION (this << bps);
+ NS_ASSERT_MSG (false, "EmuNetDevice::SetDataRate(): Unable.");
+}
+
+void
+EmuNetDevice::SetQueue (Ptr<Queue> q)
+{
+ NS_LOG_FUNCTION (this << q);
+ m_queue = q;
+}
+
+Ptr<Queue>
+EmuNetDevice::GetQueue(void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_queue;
+}
+
+void
+EmuNetDevice::NotifyLinkUp (void)
+{
+ m_linkUp = true;
+ if (!m_linkChangeCallback.IsNull ())
+ {
+ m_linkChangeCallback ();
+ }
+}
+
+void
+EmuNetDevice::SetName(const std::string name)
+{
+ m_name = name;
+}
+
+std::string
+EmuNetDevice::GetName(void) const
+{
+ return m_name;
+}
+
+void
+EmuNetDevice::SetIfIndex(const uint32_t index)
+{
+ m_ifIndex = index;
+}
+
+uint32_t
+EmuNetDevice::GetIfIndex(void) const
+{
+ return m_ifIndex;
+}
+
+Ptr<Channel>
+EmuNetDevice::GetChannel (void) const
+{
+ NS_ASSERT_MSG (false, "EmuNetDevice::GetChannel(): Unable.");
+ return 0;
+}
+
+void
+EmuNetDevice::SetAddress (Mac48Address addr)
+{
+ NS_LOG_FUNCTION (addr);
+ m_address = addr;
+}
+
+Address
+EmuNetDevice::GetAddress (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_address;
+}
+
+bool
+EmuNetDevice::SetMtu (const uint16_t mtu)
+{
+ NS_ASSERT_MSG (false, "EmuNetDevice::SetMtu(): Unable.");
+ return false;
+}
+
+uint16_t
+EmuNetDevice::GetMtu (void) const
+{
+ struct ifreq ifr;
+ bzero (&ifr, sizeof (ifr));
+ strcpy(ifr.ifr_name, m_deviceName.c_str ());
+
+ int32_t fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+ int32_t rc = ioctl(fd, SIOCGIFMTU, &ifr);
+ NS_ASSERT_MSG (rc != -1, "EmuNetDevice::GetMtu(): Can't ioctl SIOCGIFMTU");
+
+ close (fd);
+
+ return ifr.ifr_mtu;
+}
+
+bool
+EmuNetDevice::IsLinkUp (void) const
+{
+ return m_linkUp;
+}
+
+void
+EmuNetDevice::SetLinkChangeCallback (Callback<void> callback)
+{
+ m_linkChangeCallback = callback;
+}
+
+bool
+EmuNetDevice::IsBroadcast (void) const
+{
+ return true;
+}
+
+Address
+EmuNetDevice::GetBroadcast (void) const
+{
+ return Mac48Address ("ff:ff:ff:ff:ff:ff");
+}
+
+bool
+EmuNetDevice::IsMulticast (void) const
+{
+ return false;
+}
+
+Address
+EmuNetDevice::GetMulticast (void) const
+{
+ return Mac48Address ("01:00:5e:00:00:00");
+}
+
+Address
+EmuNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const
+{
+ return Mac48Address ("01:00:5e:00:00:00");
+}
+
+bool
+EmuNetDevice::IsPointToPoint (void) const
+{
+ return false;
+}
+
+void
+EmuNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
+{
+ NS_ASSERT_MSG (false, "EmuNetDevice::SetPromiscReceiveCallback(): Not implemented");
+}
+
+ bool
+EmuNetDevice::SupportsSendFrom () const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+
+Ptr<Node>
+EmuNetDevice::GetNode (void) const
+{
+ return m_node;
+}
+
+void
+EmuNetDevice::SetNode (Ptr<Node> node)
+{
+ m_node = node;
+}
+
+bool
+EmuNetDevice::NeedsArp (void) const
+{
+ return true;
+}
+
+void
+EmuNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
+{
+ m_rxCallback = cb;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emu/emu-net-device.h Wed Oct 29 22:39:36 2008 -0700
@@ -0,0 +1,333 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef EMU_NET_DEVICE_H
+#define EMU_NET_DEVICE_H
+
+#include <string.h>
+#include "ns3/address.h"
+#include "ns3/net-device.h"
+#include "ns3/node.h"
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/traced-callback.h"
+#include "ns3/event-id.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ptr.h"
+#include "ns3/mac48-address.h"
+#include "ns3/system-thread.h"
+
+namespace ns3 {
+
+class Queue;
+
+/**
+ * \class EmuNetDevice
+ * \brief A Device for an Emu Network Link.
+ */
+class EmuNetDevice : public NetDevice
+{
+public:
+ static TypeId GetTypeId (void);
+
+ /**
+ * Construct a EmuNetDevice
+ *
+ * This is the constructor for the EmuNetDevice. It takes as a
+ */
+ EmuNetDevice ();
+
+ /**
+ * Destroy a EmuNetDevice
+ *
+ * This is the destructor for the EmuNetDevice.
+ */
+ virtual ~EmuNetDevice ();
+
+ /**
+ * Set the Data Rate used for transmission of packets.
+ *
+ * @see Attach ()
+ * @param bps the data rate at which this object operates
+ */
+ void SetDataRate (DataRate bps);
+
+ /**
+ * Set the inteframe gap used to separate packets. The interframe gap
+ * defines the minimum space required between packets sent by this device.
+ *
+ * @param t the interframe gap time
+ */
+ void SetInterframeGap (Time t);
+
+ /**
+ * Set a start time for the device.
+ *
+ * @param tStart the start time
+ */
+ void Start (Time tStart);
+
+ /**
+ * Set a stop time for the device.
+ *
+ * @param tStop the stop time
+ */
+ void Stop (Time tStop);
+
+ /**
+ * Attach a queue to the EmuNetDevice.
+ *
+ * The EmuNetDevice "owns" a queue that implements a queueing
+ * method such as DropTail or RED.
+ *
+ * @see Queue
+ * @see DropTailQueue
+ * @param queue Ptr to the new queue.
+ */
+ void SetQueue (Ptr<Queue> queue);
+
+ /**
+ * Receive a packet.
+ *
+ * The EmuNetDevice receives packets from its socket reader
+ * and forwards them up the protocol stack. This is the public method
+ * used by the reader to indicate that a packet has arrived at the device.
+ *
+ * @param p Ptr to the received packet.
+ */
+ void Receive (Ptr<Packet> p);
+
+ /**
+ * Assign a MAC address to this device.
+ *
+ * @see Mac48Address
+ * @param addr The new address.
+ */
+ void SetAddress (Mac48Address addr);
+
+//
+// Pure virtual methods inherited from NetDevice we must implement.
+//
+ virtual void SetName(const std::string name);
+ virtual std::string GetName(void) const;
+
+ virtual void SetIfIndex(const uint32_t index);
+ virtual uint32_t GetIfIndex(void) const;
+
+ virtual Ptr<Channel> GetChannel (void) const;
+ virtual Address GetAddress (void) const;
+
+ virtual bool SetMtu (const uint16_t mtu);
+ virtual uint16_t GetMtu (void) const;
+
+ virtual bool IsLinkUp (void) const;
+
+ virtual void SetLinkChangeCallback (Callback<void> callback);
+
+ virtual bool IsBroadcast (void) const;
+ virtual Address GetBroadcast (void) const;
+
+ virtual bool IsMulticast (void) const;
+ virtual Address GetMulticast (void) const;
+ virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+
+ virtual bool IsPointToPoint (void) const;
+
+ virtual bool Send(Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber);
+
+ virtual bool SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
+
+ virtual Ptr<Node> GetNode (void) const;
+ virtual void SetNode (Ptr<Node> node);
+
+ virtual bool NeedsArp (void) const;
+
+ virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
+ virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb);
+
+ virtual bool SupportsSendFrom (void) const;
+
+private:
+
+ virtual void DoDispose (void);
+
+ /**
+ * Call out to a separate process running as suid root in order to get a raw
+ * socket. We do this to avoid having the entire simulation running as root.
+ * If this method returns, we'll have a raw socket waiting for us in m_sock.
+ */
+ void CreateSocket (void);
+
+ /**
+ * Figure out where the raw socket creation process lives on the system.
+ */
+ std::string FindCreator (void);
+
+ /**
+ * Get a copy of the attached Queue.
+ *
+ * This method is provided for any derived class that may need to get
+ * direct access to the underlying queue.
+ *
+ * @returns Ptr to the queue.
+ */
+ Ptr<Queue> GetQueue(void) const;
+
+ /**
+ * Spin up the device
+ */
+ void StartDevice (void);
+
+ /**
+ * Tear down the device
+ */
+ void StopDevice (void);
+
+ /**
+ * Loop to read and process packets
+ */
+ void ReadThread (void);
+
+ /**
+ * Method to handle received packets. Synchronized with simulator via ScheduleNow from ReadThread.
+ */
+ void ForwardUp (uint8_t *buf, uint32_t len);
+
+ /**
+ * Adds the necessary headers and trailers to a packet of data in order to
+ * respect the protocol implemented by the agent.
+ */
+ void AddHeader(Ptr<Packet> p, uint16_t protocolNumber);
+
+ /**
+ * Removes, from a packet of data, all headers and trailers that
+ * relate to the protocol implemented by the agent
+ * \return Returns true if the packet should be forwarded up the
+ * protocol stack.
+ */
+ bool ProcessHeader(Ptr<Packet> p, uint16_t& param);
+
+ /**
+ * Start Sending a Packet Down the Wire.
+ *
+ * @returns true if success, false on failure
+ */
+ bool TransmitStart (Ptr<Packet> p);
+
+ void NotifyLinkUp (void);
+
+ /**
+ * The Queue which this EmuNetDevice uses as a packet source.
+ * Management of this Queue has been delegated to the EmuNetDevice
+ * and it has the responsibility for deletion.
+ * @see class Queue
+ * @see class DropTailQueue
+ */
+ Ptr<Queue> m_queue;
+
+ /**
+ * The trace source for the packet reception events that the device can
+ * fire.
+ *
+ * @see class CallBackTraceSource
+ */
+ TracedCallback<Ptr<const Packet> > m_rxTrace;
+
+ /**
+ * The trace source for the packet drop events that the device can
+ * fire.
+ *
+ * @see class CallBackTraceSource
+ */
+ TracedCallback<Ptr<const Packet> > m_dropTrace;
+
+ /**
+ * Time to start spinning up the device
+ */
+ Time m_tStart;
+
+ /**
+ * Time to start tearing down the device
+ */
+ Time m_tStop;
+
+ EventId m_startEvent;
+ EventId m_stopEvent;
+
+ int32_t m_sock;
+
+ Ptr<SystemThread> m_readThread;
+
+ /**
+ * The Node to which this device is attached.
+ */
+ Ptr<Node> m_node;
+
+ /**
+ * The MAC address which has been assigned to this device.
+ */
+ Mac48Address m_address;
+
+ /**
+ * The callback used to notify higher layers that a packet has been received.
+ */
+ NetDevice::ReceiveCallback m_rxCallback;
+
+ /**
+ * The callback used to notify higher layers that a packet has been received in promiscuous mode.
+ */
+ NetDevice::PromiscReceiveCallback m_promiscRxCallback;
+
+ /**
+ * The ns-3 interface index (in the sense of net device index) that has been assigned to this network device.
+ */
+ uint32_t m_ifIndex;
+
+ /**
+ * The Unix interface index that we got from the system and which corresponds to the interface (e.g., "eth1")
+ * we are using to talk to the network. Valid when m_sock is valid.
+ */
+ int32_t m_sll_ifindex;
+
+ /**
+ * The human readable name of this device.
+ */
+ std::string m_name;
+
+ /**
+ * Flag indicating whether or not the link is up. In this case,
+ * whether or not the device is connected to a channel.
+ */
+ bool m_linkUp;
+
+ /**
+ * Callback to fire if the link changes state (up or down).
+ */
+ Callback<void> m_linkChangeCallback;
+
+ /**
+ * The unix/linux name of the underlying device (e.g., eth0)
+ */
+ std::string m_deviceName;
+};
+
+} // namespace ns3
+
+#endif // EMU_NET_DEVICE_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emu/emu-sock-creator.cc Wed Oct 29 22:39:36 2008 -0700
@@ -0,0 +1,246 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) University of Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <unistd.h>
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ioctl.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netpacket/packet.h>
+#include <arpa/inet.h>
+
+#include "emu-encode-decode.h"
+
+#define EMU_MAGIC 65867
+
+static int gVerbose = 0;
+
+#define LOG(msg) \
+ if (gVerbose) \
+ { \
+ std::cout << msg << std::endl; \
+ }
+
+#define ABORT(msg) \
+ std::cout << __FILE__ << __FUNCTION__ << ": fatal error at line " << __LINE__ << ": " << msg << std::endl; \
+ exit (-1);
+
+#define ABORT_IF(cond, msg, printErrno) \
+ if (cond) \
+ { \
+ std::cout << __FILE__ << __FUNCTION__ << ": fatal error at line " << __LINE__ << ": " << msg << std::endl; \
+ if (printErrno) \
+ { \
+ std::cout << " errno = " << errno << "(" << strerror (errno) << ")" << std::endl; \
+ } \
+ exit (-1); \
+ }
+
+/**
+ * \brief Send the socket file descriptor we created back to the emu device,
+ * which will read it as soon as we're done.
+ *
+ * \param path The socket address information from the Unix socket we use
+ * to send the created socket back to.
+ * \param fd The socket we're going to send.
+ */
+ static void
+SendSocket (const char *path, int fd)
+{
+ //
+ // Open a Unix (local interprocess) socket to call back to the emu net
+ // device.
+ //
+ LOG ("SendSocket(): Create Unix socket");
+ int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
+ ABORT_IF (sock == -1, "SendSocket(): Unable to open socket", 1);
+
+ //
+ // We have this string called path, which is really a hex representation
+ // of the endpoint that the net device created. It used a forward encoding
+ // method (EmuBufferToString) to take the sockaddr_un it made and passed
+ // the resulting string to us. So we need to take the inverse method
+ // (EmuStringToBuffer) and build the same sockaddr_un over here.
+ //
+ socklen_t clientAddrLen;
+ struct sockaddr_un clientAddr;
+
+ LOG ("SendSocket(): Decode address");
+ bool rc = ns3::EmuStringToBuffer (path, (uint8_t *)&clientAddr, &clientAddrLen);
+ ABORT_IF (rc == false, "SendSocket(): Unable to decode path", 0);
+
+ LOG ("SendSocket(): Connect");
+ int status = connect (sock, (struct sockaddr*)&clientAddr, clientAddrLen);
+ ABORT_IF (status != -1, "SendSocket(): Unable to connect to emu device", 1);
+
+ LOG ("SendSocket(): Connected");
+
+ //
+ // This is arcane enough that a few words are worthwhile to explain what's
+ // going on here.
+ //
+ // The interesting information (the socket FD) is going to go back to the
+ // emu net device as an integer of ancillary data. Ancillary data is bits
+ // that are not a part a socket payload (out-of-band data). We're also
+ // going to send one integer back. It's just initialized to a magic number
+ // we use to make sure that the emu device is talking to the emu socket
+ // creator and not some other creator process.
+ //
+ // The struct iovec below is part of a scatter-gather list. It describes a
+ // buffer. In this case, it describes a buffer (an integer) containing the
+ // data that we're going to send back to the emu net device (that magic
+ // number).
+ //
+ struct iovec iov;
+ uint32_t magic = EMU_MAGIC;
+ iov.iov_base = &magic;
+ iov.iov_len = sizeof(magic);
+
+ //
+ // The CMSG macros you'll see below are used to create and access control
+ // messages (which is another name for ancillary data). The ancillary
+ // data is made up of pairs of struct cmsghdr structures and associated
+ // data arrays.
+ //
+ // First, we're going to allocate a buffer on the stack to contain our
+ // data array (that contains the socket). Sometimes you'll see this called
+ // an "ancillary element" but the msghdr uses the control message termimology
+ // so we call it "control."
+ //
+ size_t msg_size = sizeof(int);
+ char control[CMSG_SPACE(msg_size)];
+
+ //
+ // There is a msghdr that is used to minimize the number of parameters
+ // passed to sendmsg (which we will use to send our ancillary data). This
+ // structure uses terminology corresponding to control messages, so you'll
+ // see msg_control, which is the pointer to the ancillary data and controllen
+ // which is the size of the ancillary data array.
+ //
+ // So, initialize the message header that describes our ancillary/control data
+ // and point it to the control message/ancillary data we just allocated space
+ // for.
+ //
+ struct msghdr msg;
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control;
+ msg.msg_controllen = sizeof (control);
+ msg.msg_flags = 0;
+
+ //
+ // A cmsghdr contains a length field that is the length of the header and
+ // the data. It has a cmsg_level field corresponding to the originating
+ // protocol. This takes values which are legal levels for getsockopt and
+ // setsockopt (here SOL_SOCKET). We're going to use the SCM_RIGHTS type of
+ // cmsg, that indicates that the ancillary data array contains access rights
+ // that we are sending back to the emu net device.
+ //
+ // We have to put together the first (and only) cmsghdr that will describe
+ // the whole package we're sending.
+ //
+ struct cmsghdr *cmsg;
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(msg_size);
+ //
+ // We also have to update the controllen in case other stuff is actually
+ // in there we may not be aware of (due to macros).
+ //
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ //
+ // Finally, we get a pointer to the start of the ancillary data array and
+ // put our file descriptor in.
+ //
+ int *fdptr = (int*) (CMSG_DATA(cmsg));
+ *fdptr = fd; //
+
+ //
+ // Actually send the file descriptor back to the emulated net device.
+ //
+ ssize_t len = sendmsg(sock, &msg, 0);
+ ABORT_IF (len == -1, "Could not send socket back to emu net device", 1);
+
+ LOG ("SendSocket(): sendmsg complete");
+}
+
+ int
+main (int argc, char *argv[])
+{
+ int c;
+ char *path = NULL;
+
+ opterr = 0;
+
+ while ((c = getopt (argc, argv, "vp:")) != -1)
+ {
+ switch (c)
+ {
+ case 'v':
+ gVerbose = true;
+ break;
+ case 'p':
+ path = optarg;
+ break;
+ }
+ }
+
+ //
+ // This program is spawned by an emu net device running in a simulation. It
+ // wants to create a raw socket as described below. We are going to do the
+ // work here since we're running suid root. Once we create the raw socket,
+ // we have to send it back to the emu net device. We do that over a Unix
+ // (local interprocess) socket. The emu net device created a socket to
+ // listen for our response on, and it is expected to have encoded the address
+ // information as a string and to have passed that string as an argument to
+ // us. We see it here as the "path" string. We can't do anything useful
+ // unless we have that string.
+ //
+ ABORT_IF (path == NULL, "path is a required argument", 0);
+
+ //
+ // The whole reason for all of the hoops we went through to call out to this
+ // program will pay off here. We created this program to run as suid root
+ // in order to keep the main simulation program from having to be run with
+ // root privileges. We need root privileges to be able to open a raw socket
+ // though. So all of these hoops are to allow us to exeucte the following
+ // single line of code:
+ //
+ int sock = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ ABORT_IF (sock == -1, "CreateSocket(): Unable to open raw socket", 1);
+
+ //
+ // Send the socket back to the emu net device so it can go about its business
+ //
+ SendSocket (path, sock);
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emu/emu.h Wed Oct 29 22:39:36 2008 -0700
@@ -0,0 +1,10 @@
+/**
+ * \ingroup devices
+ * \defgroup Emulated Emulated Net Device Model
+ *
+ * \section Emulated Net Device Model
+ *
+ * This is a description of the emulated network device model.
+ *
+ * It is very detailed and comprehensive and answers all possible questions.
+ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emu/waf Wed Oct 29 22:39:36 2008 -0700
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emu/wscript Wed Oct 29 22:39:36 2008 -0700
@@ -0,0 +1,22 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+
+def build(bld):
+ obj = bld.create_suid_program('emu-sock-creator')
+ obj.source = [
+ 'emu-sock-creator.cc',
+ 'emu-encode-decode.cc',
+ ]
+
+ module = bld.create_ns3_module('emu', ['node'])
+ module.source = [
+ 'emu-net-device.cc',
+ 'emu-encode-decode.cc',
+ ]
+
+ headers = bld.create_obj('ns3header')
+ headers.module = 'emu'
+ headers.source = [
+ 'emu-net-device.h',
+ ]
+
--- a/src/devices/emulated/emulated-net-device.cc Wed Oct 29 11:49:21 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,642 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2008 University of Washington
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "emulated-net-device.h"
-
-#include "ns3/log.h"
-#include "ns3/queue.h"
-#include "ns3/simulator.h"
-#include "ns3/realtime-simulator-impl.h"
-#include "ns3/mac48-address.h"
-#include "ns3/ethernet-header.h"
-#include "ns3/ethernet-trailer.h"
-#include "ns3/llc-snap-header.h"
-#include "ns3/trace-source-accessor.h"
-#include "ns3/pointer.h"
-#include "ns3/channel.h"
-#include "ns3/system-thread.h"
-#include "ns3/string.h"
-#include "ns3/boolean.h"
-
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <net/ethernet.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <netpacket/packet.h>
-#include <arpa/inet.h>
-
-NS_LOG_COMPONENT_DEFINE ("EmulatedNetDevice");
-
-namespace ns3 {
-
-NS_OBJECT_ENSURE_REGISTERED (EmulatedNetDevice);
-
-TypeId
-EmulatedNetDevice::GetTypeId (void)
-{
- static TypeId tid = TypeId ("ns3::EmulatedNetDevice")
- .SetParent<NetDevice> ()
- .AddConstructor<EmulatedNetDevice> ()
- .AddAttribute ("Address",
- "The ns-3 MAC address of this (virtual) device.",
- Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
- MakeMac48AddressAccessor (&EmulatedNetDevice::m_address),
- MakeMac48AddressChecker ())
- .AddAttribute ("DeviceName",
- "The name of the underlying real device (e.g. eth1).",
- StringValue ("eth1"),
- MakeStringAccessor (&EmulatedNetDevice::m_deviceName),
- MakeStringChecker ())
- .AddAttribute ("Start",
- "The simulation time at which to spin up the device thread.",
- TimeValue (Seconds (0.)),
- MakeTimeAccessor (&EmulatedNetDevice::m_tStart),
- MakeTimeChecker ())
- .AddAttribute ("Stop",
- "The simulation time at which to tear down the device thread.",
- TimeValue (Seconds (0.)),
- MakeTimeAccessor (&EmulatedNetDevice::m_tStop),
- MakeTimeChecker ())
- .AddAttribute ("TxQueue",
- "A queue to use as the transmit queue in the device.",
- PointerValue (),
- MakePointerAccessor (&EmulatedNetDevice::m_queue),
- MakePointerChecker<Queue> ())
- .AddTraceSource ("Rx",
- "Trace source to fire on reception of a MAC packet.",
- MakeTraceSourceAccessor (&EmulatedNetDevice::m_rxTrace))
- .AddTraceSource ("Drop",
- "Trace source to fire on when a MAC packet is dropped.",
- MakeTraceSourceAccessor (&EmulatedNetDevice::m_dropTrace))
- ;
- return tid;
-}
-
-
-EmulatedNetDevice::EmulatedNetDevice ()
-:
- m_startEvent (),
- m_stopEvent (),
- m_sock (-1),
- m_readThread (0),
- m_ifIndex (-1),
- m_sll_ifindex (-1),
- m_name ("Emulated NetDevice")
-{
- NS_LOG_FUNCTION (this);
- Start (m_tStart);
-}
-
-EmulatedNetDevice::~EmulatedNetDevice ()
-{
-}
-
-void
-EmulatedNetDevice::DoDispose()
-{
- NS_LOG_FUNCTION_NOARGS ();
- m_node = 0;
- NetDevice::DoDispose ();
-}
-
-void
-EmulatedNetDevice::Start (Time tStart)
-{
- NS_LOG_FUNCTION (tStart);
-
- //
- // Cancel any pending start event and schedule a new one at some relative time in the future.
- //
- Simulator::Cancel (m_startEvent);
- m_startEvent = Simulator::Schedule (tStart, &EmulatedNetDevice::StartDevice, this);
-}
-
- void
-EmulatedNetDevice::Stop (Time tStop)
-{
- NS_LOG_FUNCTION (tStop);
- //
- // Cancel any pending stop event and schedule a new one at some relative time in the future.
- //
- Simulator::Cancel (m_stopEvent);
- m_startEvent = Simulator::Schedule (tStop, &EmulatedNetDevice::StopDevice, this);
-}
-
- void
-EmulatedNetDevice::StartDevice (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
-
- //
- // Spin up the emulated net device and start receiving packets.
- //
- NS_ASSERT_MSG (m_sock == -1, "EmulatedNetDevice::StartDevice(): Device is already started");
-
- NS_LOG_LOGIC ("Creating socket");
-
- m_sock = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- // m_sock = socket (AF_INET, SOCK_PACKET, htons(ETH_P_ALL));
- NS_ASSERT_MSG (m_sock != -1, "EmulatedNetDevice::StartDevice(): Unable to open socket");
-
- //
- // Figure out which interface index corresponds to the device name in the corresponding attribute.
- //
- struct ifreq ifr;
- bzero (&ifr, sizeof(ifr));
- strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
-
- NS_LOG_LOGIC ("Getting interface index");
- int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
- NS_ASSERT_MSG (rc != -1, "EmulatedNetDevice::StartDevice(): Can't get interface index");
-
- //
- // Save the real interface index for later calls to sendto
- //
- m_sll_ifindex = ifr.ifr_ifindex;
-
- //
- // Bind the socket to the interface we just found.
- //
- struct sockaddr_ll ll;
- bzero (&ll, sizeof(ll));
-
- ll.sll_family = AF_PACKET;
- ll.sll_ifindex = m_sll_ifindex;
- ll.sll_protocol = htons(ETH_P_ALL);
-
- NS_LOG_LOGIC ("Binding socket to interface");
-
- rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
- NS_ASSERT_MSG (rc != -1, "EmulatedNetDevice::StartDevice(): Can't bind to specified interface");
-
- //
- // Now spin up a read thread to read packets.
- //
- NS_ASSERT_MSG (m_readThread == 0, "EmulatedNetDevice::StartDevice(): Receive thread is already running");
-
- NS_LOG_LOGIC ("Spinning up read thread");
-
- m_readThread = Create<SystemThread> (MakeCallback (&EmulatedNetDevice::ReadThread, this));
- m_readThread->Start ();
-
- NotifyLinkUp ();
-}
-
-void
-EmulatedNetDevice::StopDevice (void)
-{
- NS_LOG_FUNCTION_NOARGS ();
-
- close (m_sock);
- m_sock = -1;
-
- NS_ASSERT_MSG (m_readThread != 0, "EmulatedNetDevice::StopDevice(): Receive thread is not running");
-
- NS_LOG_LOGIC ("Joining read thread");
- m_readThread->Join ();
- m_readThread = 0;
-}
-
-void
-EmulatedNetDevice::ForwardUp (uint8_t *buf, uint32_t len)
-{
- NS_LOG_FUNCTION (buf << len);
-
- //
- // Create a packet out of the buffer we received and free that buffer.
- //
- Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
- free (buf);
- buf = 0;
-
- //
- // Trace sinks will expect complete packets, not packets without some of the
- // headers.
- //
- Ptr<Packet> originalPacket = packet->Copy ();
-
- //
- // Checksum the packet
- //
- EthernetTrailer trailer;
- packet->RemoveTrailer (trailer);
- trailer.CheckFcs (packet);
-
- EthernetHeader header (false);
- packet->RemoveHeader (header);
-
- NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
- NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
-
- //
- // An IP host group address is mapped to an Ethernet multicast address
- // by placing the low-order 23-bits of the IP address into the low-order
- // 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex).
- //
- // We are going to receive all packets destined to any multicast address,
- // which means clearing the low-order 23 bits the header destination
- //
- Mac48Address mcDest;
- uint8_t mcBuf[6];
-
- header.GetDestination ().CopyTo (mcBuf);
- mcBuf[3] &= 0x80;
- mcBuf[4] = 0;
- mcBuf[5] = 0;
- mcDest.CopyFrom (mcBuf);
-
- Mac48Address multicast = Mac48Address::ConvertFrom (GetMulticast ());
- Mac48Address broadcast = Mac48Address::ConvertFrom (GetBroadcast ());
- Mac48Address destination = Mac48Address::ConvertFrom (GetAddress ());
-
- LlcSnapHeader llc;
- packet->RemoveHeader (llc);
- uint16_t protocol = llc.GetType ();
-
- PacketType packetType;
-
- if (header.GetDestination () == broadcast)
- {
- NS_LOG_LOGIC ("Pkt destination is PACKET_BROADCAST");
- packetType = NS3_PACKET_BROADCAST;
- }
- else if (mcDest == multicast)
- {
- NS_LOG_LOGIC ("Pkt destination is PACKET_MULTICAST");
- packetType = NS3_PACKET_MULTICAST;
- }
- else if (header.GetDestination () == destination)
- {
- NS_LOG_LOGIC ("Pkt destination is PACKET_HOST");
- packetType = NS3_PACKET_HOST;
- }
- else
- {
- NS_LOG_LOGIC ("Pkt destination is PACKET_OTHERHOST");
- packetType = NS3_PACKET_OTHERHOST;
- }
-
- if (!m_promiscRxCallback.IsNull ())
- {
- NS_LOG_LOGIC ("calling m_promiscRxCallback");
- m_promiscRxCallback (this, packet->Copy (), protocol, header.GetSource (), header.GetDestination (), packetType);
- }
-
- if (packetType != NS3_PACKET_OTHERHOST)
- {
- m_rxTrace (originalPacket);
- NS_LOG_LOGIC ("calling m_rxCallback");
- m_rxCallback (this, packet, protocol, header.GetSource ());
- }
-}
-
-void
-EmulatedNetDevice::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 forward up 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.
- //
-
- int32_t len = -1;
- struct sockaddr_ll addr;
- socklen_t addrSize = sizeof (addr);
-
- for (;;)
- {
- uint32_t bufferSize = 65536;
- uint8_t *buf = (uint8_t *)malloc (bufferSize);
- NS_ASSERT_MSG (buf, "EmulatedNetDevice::ReadThread(): malloc packet buffer failed");
- NS_LOG_LOGIC ("Calling recvfrom");
- len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr, &addrSize);
-
- if (len == -1)
- {
- free (buf);
- buf = 0;
- return;
- }
-
- NS_LOG_INFO ("EmulatedNetDevice::ReadThread(): Received packet");
- NS_LOG_INFO ("EmulatedNetDevice::ReadThread(): Scheduling handler");
- DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->ScheduleRealtimeNow (
- MakeEvent (&EmulatedNetDevice::ForwardUp, this, buf, len));
- buf = 0;
- }
-}
-
-bool
-EmulatedNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
-{
- NS_LOG_FUNCTION (packet << dest << protocolNumber);
- //
- // The immediate questions here are how are we going to encapsulate packets and what do we use as the MAC source and
- // destination (hardware) addresses?
- //
- // If we return false from EmulatedNetDevice::NeedsArp, the ArpIpv4Interface will pass the broadcast address as the
- // hardware (Ethernet) destination by default. If we return true from EmulatedNetDevice::NeedsArp, then the hardware
- // destination is actually meaningful, but we'll have an ns-3 ARP running on this device. There can also be an ARP
- // running on the underlying OS so we have to be very careful, both about multiple ARPs and also about TCP, UDP, etc.
- //
- // We are operating in promiscuous mode on the receive side (all ns-3 net devices are required to implement the
- // promiscuous callback in a meaningful way), so we have an option regarding the hardware addresses. We don't actually have
- // to use the real hardware addresses and IP addresses of the underlying system. We can completely use MAC-spoofing to
- // fake out the OS by using the ns-3 assigned MAC address (and also the ns-3 assigned IP addresses). Ns-3 starts its
- // MAC address allocation using the OUI (vendor-code) 00:00:00 which is unassigned to any organization and is a globally
- // administered address, so there shouldn't be any collisions with real hardware.
- //
- // So what we do is we return true from EmulatedNetDevice::NeedsArp which tells ns-3 to use its own ARP. We spoof the
- // MAC address of the device and use promiscuous mode to receive traffic destined to that address.
- //
- return SendFrom (packet, m_address, dest, protocolNumber);
-}
-
-bool
-EmulatedNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &dest, uint16_t protocolNumber)
-{
- NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
-
- if (IsLinkUp () == false)
- {
- NS_LOG_LOGIC ("Link is down, returning");
- return false;
- }
-
- Mac48Address destination = Mac48Address::ConvertFrom (dest);
- Mac48Address source = Mac48Address::ConvertFrom (src);
-
- NS_LOG_LOGIC ("Transmit packet with UID " << packet->GetUid ());
- NS_LOG_LOGIC ("Transmit packet from " << source);
- NS_LOG_LOGIC ("Transmit packet to " << destination);
-
-#if 0
- {
- struct ifreq ifr;
- bzero (&ifr, sizeof(ifr));
- strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
-
- NS_LOG_LOGIC ("Getting MAC address");
- int32_t rc = ioctl (m_sock, SIOCGIFHWADDR, &ifr);
- NS_ASSERT_MSG (rc != -1, "EmulatedNetDevice::SendFrom(): Can't get MAC address");
-
- std::ostringstream oss;
- oss << std::hex <<
- (ifr.ifr_hwaddr.sa_data[0] & 0xff) << ":" <<
- (ifr.ifr_hwaddr.sa_data[1] & 0xff) << ":" <<
- (ifr.ifr_hwaddr.sa_data[2] & 0xff) << ":" <<
- (ifr.ifr_hwaddr.sa_data[3] & 0xff) << ":" <<
- (ifr.ifr_hwaddr.sa_data[4] & 0xff) << ":" <<
- (ifr.ifr_hwaddr.sa_data[5] & 0xff) << std::dec;
-
- NS_LOG_LOGIC ("Fixup source to HW MAC " << oss.str ());
- source = Mac48Address (oss.str ().c_str ());
- NS_LOG_LOGIC ("source now " << source);
- }
-#endif
-
- LlcSnapHeader llc;
- llc.SetType (protocolNumber);
- packet->AddHeader (llc);
-
- EthernetHeader header (false);
- header.SetSource (source);
- header.SetDestination (destination);
- header.SetLengthType (packet->GetSize ());
- packet->AddHeader (header);
-
- EthernetTrailer trailer;
- trailer.CalcFcs (packet);
- packet->AddTrailer (trailer);
-
- //
- // Enqueue and dequeue the packet to hit the tracing hooks.
- //
- m_queue->Enqueue (packet);
- packet = m_queue->Dequeue ();
-
- struct sockaddr_ll ll;
- bzero (&ll, sizeof (ll));
-
- ll.sll_family = AF_PACKET;
- ll.sll_ifindex = m_sll_ifindex;
- ll.sll_protocol = htons(ETH_P_ALL);
-
- NS_LOG_LOGIC ("calling sendto");
-
- int32_t rc;
- rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
-
- NS_LOG_LOGIC ("sendto returns " << rc);
-
- return rc == -1 ? false : true;
-}
-
-void
-EmulatedNetDevice::SetDataRate(DataRate bps)
-{
- NS_LOG_FUNCTION (this << bps);
- NS_ASSERT_MSG (false, "EmulatedNetDevice::SetDataRate(): Unable.");
-}
-
-void
-EmulatedNetDevice::SetQueue (Ptr<Queue> q)
-{
- NS_LOG_FUNCTION (this << q);
- m_queue = q;
-}
-
-Ptr<Queue>
-EmulatedNetDevice::GetQueue(void) const
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_queue;
-}
-
-void
-EmulatedNetDevice::NotifyLinkUp (void)
-{
- m_linkUp = true;
- if (!m_linkChangeCallback.IsNull ())
- {
- m_linkChangeCallback ();
- }
-}
-
-void
-EmulatedNetDevice::SetName(const std::string name)
-{
- m_name = name;
-}
-
-std::string
-EmulatedNetDevice::GetName(void) const
-{
- return m_name;
-}
-
-void
-EmulatedNetDevice::SetIfIndex(const uint32_t index)
-{
- m_ifIndex = index;
-}
-
-uint32_t
-EmulatedNetDevice::GetIfIndex(void) const
-{
- return m_ifIndex;
-}
-
-Ptr<Channel>
-EmulatedNetDevice::GetChannel (void) const
-{
- NS_ASSERT_MSG (false, "EmulatedNetDevice::GetChannel(): Unable.");
- return 0;
-}
-
-void
-EmulatedNetDevice::SetAddress (Mac48Address addr)
-{
- NS_LOG_FUNCTION (addr);
- m_address = addr;
-}
-
-Address
-EmulatedNetDevice::GetAddress (void) const
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_address;
-}
-
-bool
-EmulatedNetDevice::SetMtu (const uint16_t mtu)
-{
- NS_ASSERT_MSG (false, "EmulatedNetDevice::SetMtu(): Unable.");
- return false;
-}
-
-uint16_t
-EmulatedNetDevice::GetMtu (void) const
-{
- struct ifreq ifr;
- bzero (&ifr, sizeof (ifr));
- strcpy(ifr.ifr_name, m_deviceName.c_str ());
-
- int32_t fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
-
- int32_t rc = ioctl(fd, SIOCGIFMTU, &ifr);
- NS_ASSERT_MSG (rc != -1, "EmulatedNetDevice::GetMtu(): Can't ioctl SIOCGIFMTU");
-
- close (fd);
-
- return ifr.ifr_mtu;
-}
-
-bool
-EmulatedNetDevice::IsLinkUp (void) const
-{
- return m_linkUp;
-}
-
-void
-EmulatedNetDevice::SetLinkChangeCallback (Callback<void> callback)
-{
- m_linkChangeCallback = callback;
-}
-
-bool
-EmulatedNetDevice::IsBroadcast (void) const
-{
- return true;
-}
-
-Address
-EmulatedNetDevice::GetBroadcast (void) const
-{
- return Mac48Address ("ff:ff:ff:ff:ff:ff");
-}
-
-bool
-EmulatedNetDevice::IsMulticast (void) const
-{
- return false;
-}
-
-Address
-EmulatedNetDevice::GetMulticast (void) const
-{
- return Mac48Address ("01:00:5e:00:00:00");
-}
-
-Address
-EmulatedNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const
-{
- return Mac48Address ("01:00:5e:00:00:00");
-}
-
-bool
-EmulatedNetDevice::IsPointToPoint (void) const
-{
- return false;
-}
-
-void
-EmulatedNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
-{
- NS_ASSERT_MSG (false, "EmulatedNetDevice::SetPromiscReceiveCallback(): Not implemented");
-}
-
- bool
-EmulatedNetDevice::SupportsSendFrom () const
-{
- NS_LOG_FUNCTION_NOARGS ();
- return true;
-}
-
-
-Ptr<Node>
-EmulatedNetDevice::GetNode (void) const
-{
- return m_node;
-}
-
-void
-EmulatedNetDevice::SetNode (Ptr<Node> node)
-{
- m_node = node;
-}
-
-bool
-EmulatedNetDevice::NeedsArp (void) const
-{
- return true;
-}
-
-void
-EmulatedNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
-{
- m_rxCallback = cb;
-}
-
-} // namespace ns3
--- a/src/devices/emulated/emulated-net-device.h Wed Oct 29 11:49:21 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,321 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2008 University of Washington
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation;
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef EMULATED_NET_DEVICE_H
-#define EMULATED_NET_DEVICE_H
-
-#include <string.h>
-#include "ns3/address.h"
-#include "ns3/net-device.h"
-#include "ns3/node.h"
-#include "ns3/callback.h"
-#include "ns3/packet.h"
-#include "ns3/traced-callback.h"
-#include "ns3/event-id.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-#include "ns3/ptr.h"
-#include "ns3/mac48-address.h"
-#include "ns3/system-thread.h"
-
-namespace ns3 {
-
-class Queue;
-
-/**
- * \class EmulatedNetDevice
- * \brief A Device for an Emulated Network Link.
- */
-class EmulatedNetDevice : public NetDevice
-{
-public:
- static TypeId GetTypeId (void);
-
- /**
- * Construct a EmulatedNetDevice
- *
- * This is the constructor for the EmulatedNetDevice. It takes as a
- */
- EmulatedNetDevice ();
-
- /**
- * Destroy a EmulatedNetDevice
- *
- * This is the destructor for the EmulatedNetDevice.
- */
- virtual ~EmulatedNetDevice ();
-
- /**
- * Set the Data Rate used for transmission of packets.
- *
- * @see Attach ()
- * @param bps the data rate at which this object operates
- */
- void SetDataRate (DataRate bps);
-
- /**
- * Set the inteframe gap used to separate packets. The interframe gap
- * defines the minimum space required between packets sent by this device.
- *
- * @param t the interframe gap time
- */
- void SetInterframeGap (Time t);
-
- /**
- * Set a start time for the device.
- *
- * @param tStart the start time
- */
- void Start (Time tStart);
-
- /**
- * Set a stop time for the device.
- *
- * @param tStop the stop time
- */
- void Stop (Time tStop);
-
- /**
- * Attach a queue to the EmulatedNetDevice.
- *
- * The EmulatedNetDevice "owns" a queue that implements a queueing
- * method such as DropTail or RED.
- *
- * @see Queue
- * @see DropTailQueue
- * @param queue Ptr to the new queue.
- */
- void SetQueue (Ptr<Queue> queue);
-
- /**
- * Receive a packet.
- *
- * The EmulatedNetDevice receives packets from its socket reader
- * and forwards them up the protocol stack. This is the public method
- * used by the reader to indicate that a packet has arrived at the device.
- *
- * @param p Ptr to the received packet.
- */
- void Receive (Ptr<Packet> p);
-
- /**
- * Assign a MAC address to this device.
- *
- * @see Mac48Address
- * @param addr The new address.
- */
- void SetAddress (Mac48Address addr);
-
-//
-// Pure virtual methods inherited from NetDevice we must implement.
-//
- virtual void SetName(const std::string name);
- virtual std::string GetName(void) const;
-
- virtual void SetIfIndex(const uint32_t index);
- virtual uint32_t GetIfIndex(void) const;
-
- virtual Ptr<Channel> GetChannel (void) const;
- virtual Address GetAddress (void) const;
-
- virtual bool SetMtu (const uint16_t mtu);
- virtual uint16_t GetMtu (void) const;
-
- virtual bool IsLinkUp (void) const;
-
- virtual void SetLinkChangeCallback (Callback<void> callback);
-
- virtual bool IsBroadcast (void) const;
- virtual Address GetBroadcast (void) const;
-
- virtual bool IsMulticast (void) const;
- virtual Address GetMulticast (void) const;
- virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
-
- virtual bool IsPointToPoint (void) const;
-
- virtual bool Send(Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber);
-
- virtual bool SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
-
- virtual Ptr<Node> GetNode (void) const;
- virtual void SetNode (Ptr<Node> node);
-
- virtual bool NeedsArp (void) const;
-
- virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
- virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb);
-
- virtual bool SupportsSendFrom (void) const;
-
-private:
-
- virtual void DoDispose (void);
-
- /**
- * Get a copy of the attached Queue.
- *
- * This method is provided for any derived class that may need to get
- * direct access to the underlying queue.
- *
- * @returns Ptr to the queue.
- */
- Ptr<Queue> GetQueue(void) const;
-
- /**
- * Spin up the device
- */
- void StartDevice (void);
-
- /**
- * Tear down the device
- */
- void StopDevice (void);
-
- /**
- * Loop to read and process packets
- */
- void ReadThread (void);
-
- /**
- * Method to handle received packets. Synchronized with simulator via ScheduleNow from ReadThread.
- */
- void ForwardUp (uint8_t *buf, uint32_t len);
-
- /**
- * Adds the necessary headers and trailers to a packet of data in order to
- * respect the protocol implemented by the agent.
- */
- void AddHeader(Ptr<Packet> p, uint16_t protocolNumber);
-
- /**
- * Removes, from a packet of data, all headers and trailers that
- * relate to the protocol implemented by the agent
- * \return Returns true if the packet should be forwarded up the
- * protocol stack.
- */
- bool ProcessHeader(Ptr<Packet> p, uint16_t& param);
-
- /**
- * Start Sending a Packet Down the Wire.
- *
- * @returns true if success, false on failure
- */
- bool TransmitStart (Ptr<Packet> p);
-
- void NotifyLinkUp (void);
-
- /**
- * The Queue which this EmulatedNetDevice uses as a packet source.
- * Management of this Queue has been delegated to the EmulatedNetDevice
- * and it has the responsibility for deletion.
- * @see class Queue
- * @see class DropTailQueue
- */
- Ptr<Queue> m_queue;
-
- /**
- * The trace source for the packet reception events that the device can
- * fire.
- *
- * @see class CallBackTraceSource
- */
- TracedCallback<Ptr<const Packet> > m_rxTrace;
-
- /**
- * The trace source for the packet drop events that the device can
- * fire.
- *
- * @see class CallBackTraceSource
- */
- TracedCallback<Ptr<const Packet> > m_dropTrace;
-
- /**
- * Time to start spinning up the device
- */
- Time m_tStart;
-
- /**
- * Time to start tearing down the device
- */
- Time m_tStop;
-
- EventId m_startEvent;
- EventId m_stopEvent;
-
- int32_t m_sock;
-
- Ptr<SystemThread> m_readThread;
-
- /**
- * The Node to which this device is attached.
- */
- Ptr<Node> m_node;
-
- /**
- * The MAC address which has been assigned to this device.
- */
- Mac48Address m_address;
-
- /**
- * The callback used to notify higher layers that a packet has been received.
- */
- NetDevice::ReceiveCallback m_rxCallback;
-
- /**
- * The callback used to notify higher layers that a packet has been received in promiscuous mode.
- */
- NetDevice::PromiscReceiveCallback m_promiscRxCallback;
-
- /**
- * The ns-3 interface index (in the sense of net device index) that has been assigned to this network device.
- */
- uint32_t m_ifIndex;
-
- /**
- * The Unix interface index that we got from the system and which corresponds to the interface (e.g., "eth1")
- * we are using to talk to the network. Valid when m_sock is valid.
- */
- int32_t m_sll_ifindex;
-
- /**
- * The human readable name of this device.
- */
- std::string m_name;
-
- /**
- * Flag indicating whether or not the link is up. In this case,
- * whether or not the device is connected to a channel.
- */
- bool m_linkUp;
-
- /**
- * Callback to fire if the link changes state (up or down).
- */
- Callback<void> m_linkChangeCallback;
-
- /**
- * The unix/linux name of the underlying device (e.g., eth0)
- */
- std::string m_deviceName;
-};
-
-} // namespace ns3
-
-#endif // EMULATED_NET_DEVICE_H
-
--- a/src/devices/emulated/emulated.h Wed Oct 29 11:49:21 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-/**
- * \ingroup devices
- * \defgroup Emulated Emulated Net Device Model
- *
- * \section Emulated Net Device Model
- *
- * This is a description of the emulated network device model.
- *
- * It is very detailed and comprehensive and answers all possible questions.
- */
--- a/src/devices/emulated/waf Wed Oct 29 11:49:21 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-exec "`dirname "$0"`"/../../../waf "$@"
--- a/src/devices/emulated/wscript Wed Oct 29 11:49:21 2008 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-
-def build(bld):
- module = bld.create_ns3_module('emulated', ['node'])
- module.source = [
- 'emulated-net-device.cc',
- ]
- headers = bld.create_obj('ns3header')
- headers.module = 'emulated'
- headers.source = [
- 'emulated-net-device.h',
- ]
-
--- a/src/helper/emu-helper.cc Wed Oct 29 11:49:21 2008 -0700
+++ b/src/helper/emu-helper.cc Wed Oct 29 22:39:36 2008 -0700
@@ -22,7 +22,7 @@
#include "ns3/simulator.h"
#include "ns3/object-factory.h"
#include "ns3/queue.h"
-#include "ns3/emulated-net-device.h"
+#include "ns3/emu-net-device.h"
#include "ns3/pcap-writer.h"
#include "ns3/config.h"
#include "ns3/packet.h"
@@ -37,7 +37,7 @@
{
NS_LOG_FUNCTION_NOARGS ();
m_queueFactory.SetTypeId ("ns3::DropTailQueue");
- m_deviceFactory.SetTypeId ("ns3::EmulatedNetDevice");
+ m_deviceFactory.SetTypeId ("ns3::EmuNetDevice");
}
void
@@ -78,13 +78,13 @@
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
- "/$ns3::EmulatedNetDevice/Rx";
+ "/$ns3::EmuNetDevice/Rx";
Config::ConnectWithoutContext (oss.str (),
MakeBoundCallback (&EmuHelper::RxEvent, pcap));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
- "/$ns3::EmulatedNetDevice/TxQueue/Enqueue";
+ "/$ns3::EmuNetDevice/TxQueue/Enqueue";
Config::ConnectWithoutContext (oss.str (),
MakeBoundCallback (&EmuHelper::EnqueueEvent, pcap));
}
@@ -131,25 +131,25 @@
std::ostringstream oss;
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
- "/$ns3::EmulatedNetDevice/Rx";
+ "/$ns3::EmuNetDevice/Rx";
Config::Connect (oss.str (),
MakeBoundCallback (&EmuHelper::AsciiRxEvent, &os));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
- "/$ns3::EmulatedNetDevice/TxQueue/Enqueue";
+ "/$ns3::EmuNetDevice/TxQueue/Enqueue";
Config::Connect (oss.str (),
MakeBoundCallback (&EmuHelper::AsciiEnqueueEvent, &os));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
- "/$ns3::EmulatedNetDevice/TxQueue/Dequeue";
+ "/$ns3::EmuNetDevice/TxQueue/Dequeue";
Config::Connect (oss.str (),
MakeBoundCallback (&EmuHelper::AsciiDequeueEvent, &os));
oss.str ("");
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
- "/$ns3::EmulatedNetDevice/TxQueue/Drop";
+ "/$ns3::EmuNetDevice/TxQueue/Drop";
Config::Connect (oss.str (),
MakeBoundCallback (&EmuHelper::AsciiDropEvent, &os));
}
@@ -197,7 +197,7 @@
{
Ptr<Node> node = *i;
- Ptr<EmulatedNetDevice> device = m_deviceFactory.Create<EmulatedNetDevice> ();
+ Ptr<EmuNetDevice> device = m_deviceFactory.Create<EmuNetDevice> ();
//
// This is a mac address used for ns-3 internal things. It cannot override the real MAC address on the NIC in
// question.
--- a/src/helper/emu-helper.h Wed Oct 29 11:49:21 2008 -0700
+++ b/src/helper/emu-helper.h Wed Oct 29 22:39:36 2008 -0700
@@ -25,7 +25,7 @@
#include "ns3/object-factory.h"
#include "ns3/net-device-container.h"
#include "ns3/node-container.h"
-#include "ns3/emulated-net-device.h"
+#include "ns3/emu-net-device.h"
namespace ns3 {
--- a/src/wscript Wed Oct 29 11:49:21 2008 -0700
+++ b/src/wscript Wed Oct 29 22:39:36 2008 -0700
@@ -21,7 +21,7 @@
'devices/csma',
'devices/bridge',
'devices/tap',
- 'devices/emulated',
+ 'devices/emu',
'applications/onoff',
'applications/packet-sink',
'applications/udp-echo',