1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/devices/emu/emu-encode-decode.cc Wed Oct 29 22:39:36 2008 -0700
1.3 @@ -0,0 +1,110 @@
1.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
1.5 +/*
1.6 + * Copyright (c) University of Washington
1.7 + *
1.8 + * This program is free software; you can redistribute it and/or modify
1.9 + * it under the terms of the GNU General Public License version 2 as
1.10 + * published by the Free Software Foundation;
1.11 + *
1.12 + * This program is distributed in the hope that it will be useful,
1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.15 + * GNU General Public License for more details.
1.16 + *
1.17 + * You should have received a copy of the GNU General Public License
1.18 + * along with this program; if not, write to the Free Software
1.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.20 + */
1.21 +
1.22 +#include <string>
1.23 +#include <iostream>
1.24 +#include <iomanip>
1.25 +#include <sstream>
1.26 +
1.27 +namespace ns3 {
1.28 +
1.29 +/**
1.30 + * \brief Convert a byte buffer to a string containing a hex representation
1.31 + * of the buffer. Make the string pretty by adding a colon (':') between
1.32 + * the hex.
1.33 + *
1.34 + * \param buffer The input buffer to be converted.
1.35 + * \param len The length of the input buffer.
1.36 + * \returns A string containing a hex representation of the data in buffer.
1.37 + */
1.38 + std::string
1.39 +EmuBufferToString (uint8_t *buffer, uint32_t len)
1.40 +{
1.41 + std::ostringstream oss;
1.42 + //
1.43 + // Tell the stream to make hex characters, zero-filled
1.44 + //
1.45 + oss.setf (std::ios::hex, std::ios::basefield);
1.46 + oss.fill('0');
1.47 +
1.48 + //
1.49 + // Loop through the buffer, separating the two-digit-wide hex bytes
1.50 + // with a colon.
1.51 + //
1.52 + for (uint8_t i = 0; i < len; i++)
1.53 + {
1.54 + oss << ":" << std::setw (2) << (uint32_t)buffer[i];
1.55 + }
1.56 + return oss.str ();
1.57 +}
1.58 +
1.59 +/**
1.60 + * \brief Convert string encoded by the inverse function (EmuBufferToString)
1.61 + * back into a byte buffer.
1.62 + *
1.63 + * \param s The input string.
1.64 + * \param buffer The buffer to initialize with the converted bits.
1.65 + * \param len The length of the data that is valid in the buffer.
1.66 + * \returns True indicates a successful conversion.
1.67 + */
1.68 + bool
1.69 +EmuStringToBuffer (std::string s, uint8_t *buffer, uint32_t *len)
1.70 +{
1.71 + //
1.72 + // If the string was made by our inverse function, the string length must
1.73 + // be a multiple of three characters in length. Use this fact to do a
1.74 + // quick reasonableness test.
1.75 + //
1.76 + if ((s.length () % 3) != 0)
1.77 + {
1.78 + return false;
1.79 + }
1.80 +
1.81 + std::istringstream iss;
1.82 + iss.str (s);
1.83 +
1.84 + uint8_t n = 0;
1.85 +
1.86 + while (iss.good ())
1.87 + {
1.88 + //
1.89 + // The first character in the "triplet" we're working on is always the
1.90 + // the ':' separator. Read that into a char and make sure we're skipping
1.91 + // what we think we're skipping.
1.92 + //
1.93 + char c;
1.94 + iss.read (&c, 1);
1.95 + if (c != ':')
1.96 + {
1.97 + return false;
1.98 + }
1.99 +
1.100 + //
1.101 + // And then read in the real bits and convert them.
1.102 + //
1.103 + uint32_t tmp;
1.104 + iss >> std::hex >> tmp;
1.105 + buffer[n] = tmp;
1.106 + n++;
1.107 + }
1.108 +
1.109 + *len = n;
1.110 + return true;
1.111 +}
1.112 +
1.113 +} // namespace ns3
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/src/devices/emu/emu-encode-decode.h Wed Oct 29 22:39:36 2008 -0700
2.3 @@ -0,0 +1,33 @@
2.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2.5 +/*
2.6 + * Copyright (c) 2008 University of Washington
2.7 + *
2.8 + * This program is free software; you can redistribute it and/or modify
2.9 + * it under the terms of the GNU General Public License version 2 as
2.10 + * published by the Free Software Foundation;
2.11 + *
2.12 + * This program is distributed in the hope that it will be useful,
2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.15 + * GNU General Public License for more details.
2.16 + *
2.17 + * You should have received a copy of the GNU General Public License
2.18 + * along with this program; if not, write to the Free Software
2.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2.20 + */
2.21 +
2.22 +#ifndef EMU_ENCODE_DECODE_H
2.23 +#define EMU_ENCODE_DECODE_H
2.24 +
2.25 +#include <string>
2.26 +
2.27 +namespace ns3 {
2.28 +
2.29 + std::string EmuBufferToString (uint8_t *buffer, uint32_t len);
2.30 + bool EmuStringToBuffer (std::string s, uint8_t *buffer, uint32_t *len);
2.31 +
2.32 +
2.33 +} // namespace ns3
2.34 +
2.35 +#endif // EMU_ENCODE_DECODE_H
2.36 +
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/src/devices/emu/emu-net-device.cc Wed Oct 29 22:39:36 2008 -0700
3.3 @@ -0,0 +1,861 @@
3.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
3.5 +/*
3.6 + * Copyright (c) 2008 University of Washington
3.7 + *
3.8 + * This program is free software; you can redistribute it and/or modify
3.9 + * it under the terms of the GNU General Public License version 2 as
3.10 + * published by the Free Software Foundation;
3.11 + *
3.12 + * This program is distributed in the hope that it will be useful,
3.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.15 + * GNU General Public License for more details.
3.16 + *
3.17 + * You should have received a copy of the GNU General Public License
3.18 + * along with this program; if not, write to the Free Software
3.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3.20 + */
3.21 +
3.22 +#include "emu-net-device.h"
3.23 +#include "emu-encode-decode.h"
3.24 +
3.25 +#include "ns3/log.h"
3.26 +#include "ns3/queue.h"
3.27 +#include "ns3/simulator.h"
3.28 +#include "ns3/realtime-simulator-impl.h"
3.29 +#include "ns3/mac48-address.h"
3.30 +#include "ns3/ethernet-header.h"
3.31 +#include "ns3/ethernet-trailer.h"
3.32 +#include "ns3/llc-snap-header.h"
3.33 +#include "ns3/trace-source-accessor.h"
3.34 +#include "ns3/pointer.h"
3.35 +#include "ns3/channel.h"
3.36 +#include "ns3/system-thread.h"
3.37 +#include "ns3/string.h"
3.38 +#include "ns3/boolean.h"
3.39 +
3.40 +#include <sys/wait.h>
3.41 +#include <sys/stat.h>
3.42 +#include <sys/socket.h>
3.43 +#include <sys/un.h>
3.44 +#include <sys/ioctl.h>
3.45 +#include <net/ethernet.h>
3.46 +#include <net/if.h>
3.47 +#include <netinet/in.h>
3.48 +#include <netpacket/packet.h>
3.49 +#include <arpa/inet.h>
3.50 +#include <errno.h>
3.51 +
3.52 +NS_LOG_COMPONENT_DEFINE ("EmuNetDevice");
3.53 +
3.54 +namespace ns3 {
3.55 +
3.56 +NS_OBJECT_ENSURE_REGISTERED (EmuNetDevice);
3.57 +
3.58 +TypeId
3.59 +EmuNetDevice::GetTypeId (void)
3.60 +{
3.61 + static TypeId tid = TypeId ("ns3::EmuNetDevice")
3.62 + .SetParent<NetDevice> ()
3.63 + .AddConstructor<EmuNetDevice> ()
3.64 + .AddAttribute ("Address",
3.65 + "The ns-3 MAC address of this (virtual) device.",
3.66 + Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
3.67 + MakeMac48AddressAccessor (&EmuNetDevice::m_address),
3.68 + MakeMac48AddressChecker ())
3.69 + .AddAttribute ("DeviceName",
3.70 + "The name of the underlying real device (e.g. eth1).",
3.71 + StringValue ("eth1"),
3.72 + MakeStringAccessor (&EmuNetDevice::m_deviceName),
3.73 + MakeStringChecker ())
3.74 + .AddAttribute ("Start",
3.75 + "The simulation time at which to spin up the device thread.",
3.76 + TimeValue (Seconds (0.)),
3.77 + MakeTimeAccessor (&EmuNetDevice::m_tStart),
3.78 + MakeTimeChecker ())
3.79 + .AddAttribute ("Stop",
3.80 + "The simulation time at which to tear down the device thread.",
3.81 + TimeValue (Seconds (0.)),
3.82 + MakeTimeAccessor (&EmuNetDevice::m_tStop),
3.83 + MakeTimeChecker ())
3.84 + .AddAttribute ("TxQueue",
3.85 + "A queue to use as the transmit queue in the device.",
3.86 + PointerValue (),
3.87 + MakePointerAccessor (&EmuNetDevice::m_queue),
3.88 + MakePointerChecker<Queue> ())
3.89 + .AddTraceSource ("Rx",
3.90 + "Trace source to fire on reception of a MAC packet.",
3.91 + MakeTraceSourceAccessor (&EmuNetDevice::m_rxTrace))
3.92 + .AddTraceSource ("Drop",
3.93 + "Trace source to fire on when a MAC packet is dropped.",
3.94 + MakeTraceSourceAccessor (&EmuNetDevice::m_dropTrace))
3.95 + ;
3.96 + return tid;
3.97 +}
3.98 +
3.99 +
3.100 +EmuNetDevice::EmuNetDevice ()
3.101 +:
3.102 + m_startEvent (),
3.103 + m_stopEvent (),
3.104 + m_sock (-1),
3.105 + m_readThread (0),
3.106 + m_ifIndex (-1),
3.107 + m_sll_ifindex (-1),
3.108 + m_name ("Emu NetDevice")
3.109 +{
3.110 + NS_LOG_FUNCTION (this);
3.111 + Start (m_tStart);
3.112 +}
3.113 +
3.114 +EmuNetDevice::~EmuNetDevice ()
3.115 +{
3.116 +}
3.117 +
3.118 +void
3.119 +EmuNetDevice::DoDispose()
3.120 +{
3.121 + NS_LOG_FUNCTION_NOARGS ();
3.122 + m_node = 0;
3.123 + NetDevice::DoDispose ();
3.124 +}
3.125 +
3.126 +void
3.127 +EmuNetDevice::Start (Time tStart)
3.128 +{
3.129 + NS_LOG_FUNCTION (tStart);
3.130 +
3.131 + //
3.132 + // Cancel any pending start event and schedule a new one at some relative time in the future.
3.133 + //
3.134 + Simulator::Cancel (m_startEvent);
3.135 + m_startEvent = Simulator::Schedule (tStart, &EmuNetDevice::StartDevice, this);
3.136 +}
3.137 +
3.138 + void
3.139 +EmuNetDevice::Stop (Time tStop)
3.140 +{
3.141 + NS_LOG_FUNCTION (tStop);
3.142 + //
3.143 + // Cancel any pending stop event and schedule a new one at some relative time in the future.
3.144 + //
3.145 + Simulator::Cancel (m_stopEvent);
3.146 + m_startEvent = Simulator::Schedule (tStop, &EmuNetDevice::StopDevice, this);
3.147 +}
3.148 +
3.149 + void
3.150 +EmuNetDevice::StartDevice (void)
3.151 +{
3.152 + NS_LOG_FUNCTION_NOARGS ();
3.153 +
3.154 + //
3.155 + // Spin up the emu net device and start receiving packets.
3.156 + //
3.157 + NS_ASSERT_MSG (m_sock == -1, "EmuNetDevice::StartDevice(): Device is already started");
3.158 +
3.159 + NS_LOG_LOGIC ("Creating socket");
3.160 + //
3.161 + // Call out to a separate process running as suid root in order to get a raw
3.162 + // socket. We do this to avoid having the entire simulation running as root.
3.163 + // If this method returns, we'll have a raw socket waiting for us in m_sock.
3.164 + //
3.165 + CreateSocket ();
3.166 +
3.167 + //
3.168 + // Figure out which interface index corresponds to the device name in the corresponding attribute.
3.169 + //
3.170 + struct ifreq ifr;
3.171 + bzero (&ifr, sizeof(ifr));
3.172 + strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
3.173 +
3.174 + NS_LOG_LOGIC ("Getting interface index");
3.175 + int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
3.176 + NS_ASSERT_MSG (rc != -1, "EmuNetDevice::StartDevice(): Can't get interface index");
3.177 +
3.178 + //
3.179 + // Save the real interface index for later calls to sendto
3.180 + //
3.181 + m_sll_ifindex = ifr.ifr_ifindex;
3.182 +
3.183 + //
3.184 + // Bind the socket to the interface we just found.
3.185 + //
3.186 + struct sockaddr_ll ll;
3.187 + bzero (&ll, sizeof(ll));
3.188 +
3.189 + ll.sll_family = AF_PACKET;
3.190 + ll.sll_ifindex = m_sll_ifindex;
3.191 + ll.sll_protocol = htons(ETH_P_ALL);
3.192 +
3.193 + NS_LOG_LOGIC ("Binding socket to interface");
3.194 +
3.195 + rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
3.196 + NS_ASSERT_MSG (rc != -1, "EmuNetDevice::StartDevice(): Can't bind to specified interface");
3.197 +
3.198 + //
3.199 + // Now spin up a read thread to read packets.
3.200 + //
3.201 + NS_ASSERT_MSG (m_readThread == 0, "EmuNetDevice::StartDevice(): Receive thread is already running");
3.202 +
3.203 + NS_LOG_LOGIC ("Spinning up read thread");
3.204 +
3.205 + m_readThread = Create<SystemThread> (MakeCallback (&EmuNetDevice::ReadThread, this));
3.206 + m_readThread->Start ();
3.207 +
3.208 + NotifyLinkUp ();
3.209 +}
3.210 +
3.211 +void
3.212 +EmuNetDevice::CreateSocket (void)
3.213 +{
3.214 + NS_LOG_FUNCTION_NOARGS ();
3.215 + //
3.216 + // We want to create a raw socket for our net device. Unfortunately for us
3.217 + // you have to have root privileges to do that. Instead of running the
3.218 + // entire simulation as root, we decided to make a small program who's whole
3.219 + // reason for being is to run as suid root and create a raw socket. We're
3.220 + // going to fork and exec that program soon, but we need to have a socket
3.221 + // to talk to it with. So we create a local interprocess (Unix) socket
3.222 + // for that purpose.
3.223 + //
3.224 + int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
3.225 + if (sock == -1)
3.226 + {
3.227 + NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Unix socket creation error, errno = " << strerror (errno));
3.228 + }
3.229 +
3.230 + //
3.231 + // Bind to that socket and let the kernel allocate an endpoint
3.232 + //
3.233 + struct sockaddr_un un;
3.234 + memset (&un, 0, sizeof (un));
3.235 + un.sun_family = AF_UNIX;
3.236 + int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t));
3.237 + if (status == -1)
3.238 + {
3.239 + NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not bind(): errno = " << strerror (errno));
3.240 + }
3.241 +
3.242 + //
3.243 + // We have a socket here, but we want to get it there -- to the program we're
3.244 + // going to exec. What we'll do is to do a getsockname and then encode the
3.245 + // resulting address information as a string, and then send the string to the
3.246 + // program as an argument. So we need to get the sock name.
3.247 + //
3.248 + socklen_t len = sizeof (un);
3.249 + status = getsockname (sock, (struct sockaddr*)&un, &len);
3.250 + if (status == -1)
3.251 + {
3.252 + NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Could not getsockname(): errno = " << strerror (errno));
3.253 + }
3.254 +
3.255 + //
3.256 + // Now encode that socket name (endpoint information) as a string
3.257 + //
3.258 + std::string endpoint = EmuBufferToString((uint8_t *)&un, len);
3.259 +
3.260 + //
3.261 + // Fork and exec the process to create our socket. If we're us (the parent)
3.262 + // we wait for the child (the socket creator) to complete and read the
3.263 + // socket it created using the ancillary data mechanism.
3.264 + //
3.265 + pid_t pid = ::fork ();
3.266 + if (pid == 0)
3.267 + {
3.268 + NS_LOG_DEBUG ("Child process");
3.269 +
3.270 + //
3.271 + // build a command line argument from the encoded endpoint string that
3.272 + // the socket creation process will use to figure out how to respond to
3.273 + // the (now) parent process.
3.274 + //
3.275 + std::ostringstream oss;
3.276 + oss << "-p " << endpoint;
3.277 +
3.278 + //
3.279 + // Execute the socket creation process image.
3.280 + //
3.281 + status = ::execl (FindCreator ().c_str (), "emu-sock-creator", oss.str ().c_str (), (char *)NULL);
3.282 +
3.283 + //
3.284 + // If the execl successfully completes, it never returns. If it returns it failed or the OS is
3.285 + // broken. In either case, we bail.
3.286 + //
3.287 + NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Back from execl(), errno = " << ::strerror (errno));
3.288 + }
3.289 + else
3.290 + {
3.291 + NS_LOG_DEBUG ("Parent process");
3.292 + //
3.293 + // We're the process running the emu net device. We need to wait for the
3.294 + // socket creator process to finish its job.
3.295 + //
3.296 + int st;
3.297 + pid_t waited = waitpid (pid, &st, 0);
3.298 + if (waited == -1)
3.299 + {
3.300 + NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): waitpid() fails, errno = " << strerror (errno));
3.301 + }
3.302 + NS_ASSERT_MSG (pid == waited, "EmuNetDevice::CreateSocket(): pid mismatch");
3.303 +
3.304 + //
3.305 + // Check to see if the socket creator exited normally and then take a
3.306 + // look at the exit code. If it bailed, so should we. If it didn't
3.307 + // even exit normally, we bail too.
3.308 + //
3.309 + if (WIFEXITED (st))
3.310 + {
3.311 + int exitStatus = WEXITSTATUS (st);
3.312 + if (exitStatus != 0)
3.313 + {
3.314 + NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited normally with status " << exitStatus);
3.315 + }
3.316 + }
3.317 + else
3.318 + {
3.319 + NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): socket creator exited abnormally");
3.320 + }
3.321 +
3.322 + //
3.323 + // At this point, the socket creator has run successfully and should
3.324 + // have created our raw socket and sent it back to the socket address
3.325 + // we provided. Our socket should be waiting on the Unix socket. We've
3.326 + // got to do a bunch of grunto work to get at it, though.
3.327 + //
3.328 + // The struct iovec below is part of a scatter-gather list. It describes a
3.329 + // buffer. In this case, it describes a buffer (an integer) that will
3.330 + // get the data that comes back from the socket creator process. It will
3.331 + // be a magic number that we use as a consistency/sanity check.
3.332 + //
3.333 + struct iovec iov;
3.334 + uint32_t magic;
3.335 + iov.iov_base = &magic;
3.336 + iov.iov_len = sizeof(magic);
3.337 +
3.338 + //
3.339 + // The CMSG macros you'll see below are used to create and access control
3.340 + // messages (which is another name for ancillary data). The ancillary
3.341 + // data is made up of pairs of struct cmsghdr structures and associated
3.342 + // data arrays.
3.343 + //
3.344 + // First, we're going to allocate a buffer on the stack to receive our
3.345 + // data array (that contains the socket). Sometimes you'll see this called
3.346 + // an "ancillary element" but the msghdr uses the control message termimology
3.347 + // so we call it "control."
3.348 + //
3.349 + size_t msg_size = sizeof(int);
3.350 + char control[CMSG_SPACE(msg_size)];
3.351 +
3.352 + //
3.353 + // There is a msghdr that is used to minimize the number of parameters
3.354 + // passed to recvmsg (which we will use to receive our ancillary data).
3.355 + // This structure uses terminology corresponding to control messages, so
3.356 + // you'll see msg_control, which is the pointer to the ancillary data and
3.357 + // controllen which is the size of the ancillary data array.
3.358 + //
3.359 + // So, initialize the message header that describes the ancillary/control
3.360 + // data we expect to receive and point it to buffer.
3.361 + //
3.362 + struct msghdr msg;
3.363 + msg.msg_name = 0;
3.364 + msg.msg_namelen = 0;
3.365 + msg.msg_iov = &iov;
3.366 + msg.msg_iovlen = 1;
3.367 + msg.msg_control = control;
3.368 + msg.msg_controllen = sizeof (control);
3.369 + msg.msg_flags = 0;
3.370 +
3.371 + //
3.372 + // Now we can actually receive the interesting bits from the socket
3.373 + // creator process.
3.374 + //
3.375 + ssize_t bytesRead = recvmsg (sock, &msg, 0);
3.376 + if (bytesRead != sizeof(int))
3.377 + {
3.378 + NS_FATAL_ERROR ("EmuNetDevice::CreateSocket(): Wrong byte count from socket creator");
3.379 + }
3.380 +
3.381 + //
3.382 + // There may be a number of message headers/ancillary data arrays coming in.
3.383 + // Let's look for the one with a type SCM_RIGHTS which indicates it' the
3.384 + // one we're interested in.
3.385 + //
3.386 + struct cmsghdr *cmsg;
3.387 + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
3.388 + {
3.389 + if (cmsg->cmsg_level == SOL_SOCKET &&
3.390 + cmsg->cmsg_type == SCM_RIGHTS)
3.391 + {
3.392 + int *rawSocket = (int*)CMSG_DATA (cmsg);
3.393 + NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
3.394 + m_sock = *rawSocket;
3.395 + return;
3.396 + }
3.397 + }
3.398 + NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
3.399 + }
3.400 +}
3.401 +
3.402 +std::string
3.403 +EmuNetDevice::FindCreator (void)
3.404 +{
3.405 + struct stat st;
3.406 + std::string debug = "./build/debug/src/devices/emu/emu-sock-creator";
3.407 + std::string optimized = "./build/optimized/src/devices/emu/emu-sock-creator";
3.408 +
3.409 + if (::stat (debug.c_str (), &st) == 0)
3.410 + {
3.411 + return debug;
3.412 + }
3.413 +
3.414 + if (::stat (optimized.c_str (), &st) == 0)
3.415 + {
3.416 + return optimized;
3.417 + }
3.418 +
3.419 + NS_FATAL_ERROR ("EmuNetDevice::FindCreator(): Couldn't find creator");
3.420 + return ""; // quiet compiler
3.421 +}
3.422 +
3.423 +void
3.424 +EmuNetDevice::StopDevice (void)
3.425 +{
3.426 + NS_LOG_FUNCTION_NOARGS ();
3.427 +
3.428 + close (m_sock);
3.429 + m_sock = -1;
3.430 +
3.431 + NS_ASSERT_MSG (m_readThread != 0, "EmuNetDevice::StopDevice(): Receive thread is not running");
3.432 +
3.433 + NS_LOG_LOGIC ("Joining read thread");
3.434 + m_readThread->Join ();
3.435 + m_readThread = 0;
3.436 +}
3.437 +
3.438 +void
3.439 +EmuNetDevice::ForwardUp (uint8_t *buf, uint32_t len)
3.440 +{
3.441 + NS_LOG_FUNCTION (buf << len);
3.442 +
3.443 + //
3.444 + // Create a packet out of the buffer we received and free that buffer.
3.445 + //
3.446 + Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
3.447 + free (buf);
3.448 + buf = 0;
3.449 +
3.450 + //
3.451 + // Trace sinks will expect complete packets, not packets without some of the
3.452 + // headers.
3.453 + //
3.454 + Ptr<Packet> originalPacket = packet->Copy ();
3.455 +
3.456 + //
3.457 + // Checksum the packet
3.458 + //
3.459 + EthernetTrailer trailer;
3.460 + packet->RemoveTrailer (trailer);
3.461 + trailer.CheckFcs (packet);
3.462 +
3.463 + EthernetHeader header (false);
3.464 + packet->RemoveHeader (header);
3.465 +
3.466 + NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
3.467 + NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
3.468 +
3.469 + //
3.470 + // An IP host group address is mapped to an Ethernet multicast address
3.471 + // by placing the low-order 23-bits of the IP address into the low-order
3.472 + // 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex).
3.473 + //
3.474 + // We are going to receive all packets destined to any multicast address,
3.475 + // which means clearing the low-order 23 bits the header destination
3.476 + //
3.477 + Mac48Address mcDest;
3.478 + uint8_t mcBuf[6];
3.479 +
3.480 + header.GetDestination ().CopyTo (mcBuf);
3.481 + mcBuf[3] &= 0x80;
3.482 + mcBuf[4] = 0;
3.483 + mcBuf[5] = 0;
3.484 + mcDest.CopyFrom (mcBuf);
3.485 +
3.486 + Mac48Address multicast = Mac48Address::ConvertFrom (GetMulticast ());
3.487 + Mac48Address broadcast = Mac48Address::ConvertFrom (GetBroadcast ());
3.488 + Mac48Address destination = Mac48Address::ConvertFrom (GetAddress ());
3.489 +
3.490 + LlcSnapHeader llc;
3.491 + packet->RemoveHeader (llc);
3.492 + uint16_t protocol = llc.GetType ();
3.493 +
3.494 + PacketType packetType;
3.495 +
3.496 + if (header.GetDestination () == broadcast)
3.497 + {
3.498 + NS_LOG_LOGIC ("Pkt destination is PACKET_BROADCAST");
3.499 + packetType = NS3_PACKET_BROADCAST;
3.500 + }
3.501 + else if (mcDest == multicast)
3.502 + {
3.503 + NS_LOG_LOGIC ("Pkt destination is PACKET_MULTICAST");
3.504 + packetType = NS3_PACKET_MULTICAST;
3.505 + }
3.506 + else if (header.GetDestination () == destination)
3.507 + {
3.508 + NS_LOG_LOGIC ("Pkt destination is PACKET_HOST");
3.509 + packetType = NS3_PACKET_HOST;
3.510 + }
3.511 + else
3.512 + {
3.513 + NS_LOG_LOGIC ("Pkt destination is PACKET_OTHERHOST");
3.514 + packetType = NS3_PACKET_OTHERHOST;
3.515 + }
3.516 +
3.517 + if (!m_promiscRxCallback.IsNull ())
3.518 + {
3.519 + NS_LOG_LOGIC ("calling m_promiscRxCallback");
3.520 + m_promiscRxCallback (this, packet->Copy (), protocol, header.GetSource (), header.GetDestination (), packetType);
3.521 + }
3.522 +
3.523 + if (packetType != NS3_PACKET_OTHERHOST)
3.524 + {
3.525 + m_rxTrace (originalPacket);
3.526 + NS_LOG_LOGIC ("calling m_rxCallback");
3.527 + m_rxCallback (this, packet, protocol, header.GetSource ());
3.528 + }
3.529 +}
3.530 +
3.531 +void
3.532 +EmuNetDevice::ReadThread (void)
3.533 +{
3.534 + NS_LOG_FUNCTION_NOARGS ();
3.535 +
3.536 + //
3.537 + // It's important to remember that we're in a completely different thread than the simulator is running in. We
3.538 + // need to synchronize with that other thread to get the packet up into ns-3. What we will need to do is to schedule
3.539 + // a method to forward up the packet using the multithreaded simulator we are most certainly running. However, I just
3.540 + // said it -- we are talking about two threads here, so it is very, very dangerous to do any kind of reference couning
3.541 + // 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
3.542 + // buffer into the ns-3 context thread where it will create the packet.
3.543 + //
3.544 +
3.545 + int32_t len = -1;
3.546 + struct sockaddr_ll addr;
3.547 + socklen_t addrSize = sizeof (addr);
3.548 +
3.549 + for (;;)
3.550 + {
3.551 + uint32_t bufferSize = 65536;
3.552 + uint8_t *buf = (uint8_t *)malloc (bufferSize);
3.553 + NS_ASSERT_MSG (buf, "EmuNetDevice::ReadThread(): malloc packet buffer failed");
3.554 + NS_LOG_LOGIC ("Calling recvfrom");
3.555 + len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr, &addrSize);
3.556 +
3.557 + if (len == -1)
3.558 + {
3.559 + free (buf);
3.560 + buf = 0;
3.561 + return;
3.562 + }
3.563 +
3.564 + NS_LOG_INFO ("EmuNetDevice::ReadThread(): Received packet");
3.565 + NS_LOG_INFO ("EmuNetDevice::ReadThread(): Scheduling handler");
3.566 + DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->ScheduleRealtimeNow (
3.567 + MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
3.568 + buf = 0;
3.569 + }
3.570 +}
3.571 +
3.572 +bool
3.573 +EmuNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
3.574 +{
3.575 + NS_LOG_FUNCTION (packet << dest << protocolNumber);
3.576 + //
3.577 + // The immediate questions here are how are we going to encapsulate packets and what do we use as the MAC source and
3.578 + // destination (hardware) addresses?
3.579 + //
3.580 + // If we return false from EmuNetDevice::NeedsArp, the ArpIpv4Interface will pass the broadcast address as the
3.581 + // hardware (Ethernet) destination by default. If we return true from EmuNetDevice::NeedsArp, then the hardware
3.582 + // destination is actually meaningful, but we'll have an ns-3 ARP running on this device. There can also be an ARP
3.583 + // running on the underlying OS so we have to be very careful, both about multiple ARPs and also about TCP, UDP, etc.
3.584 + //
3.585 + // We are operating in promiscuous mode on the receive side (all ns-3 net devices are required to implement the
3.586 + // promiscuous callback in a meaningful way), so we have an option regarding the hardware addresses. We don't actually have
3.587 + // to use the real hardware addresses and IP addresses of the underlying system. We can completely use MAC-spoofing to
3.588 + // fake out the OS by using the ns-3 assigned MAC address (and also the ns-3 assigned IP addresses). Ns-3 starts its
3.589 + // MAC address allocation using the OUI (vendor-code) 00:00:00 which is unassigned to any organization and is a globally
3.590 + // administered address, so there shouldn't be any collisions with real hardware.
3.591 + //
3.592 + // So what we do is we return true from EmuNetDevice::NeedsArp which tells ns-3 to use its own ARP. We spoof the
3.593 + // MAC address of the device and use promiscuous mode to receive traffic destined to that address.
3.594 + //
3.595 + return SendFrom (packet, m_address, dest, protocolNumber);
3.596 +}
3.597 +
3.598 +bool
3.599 +EmuNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &dest, uint16_t protocolNumber)
3.600 +{
3.601 + NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
3.602 +
3.603 + if (IsLinkUp () == false)
3.604 + {
3.605 + NS_LOG_LOGIC ("Link is down, returning");
3.606 + return false;
3.607 + }
3.608 +
3.609 + Mac48Address destination = Mac48Address::ConvertFrom (dest);
3.610 + Mac48Address source = Mac48Address::ConvertFrom (src);
3.611 +
3.612 + NS_LOG_LOGIC ("Transmit packet with UID " << packet->GetUid ());
3.613 + NS_LOG_LOGIC ("Transmit packet from " << source);
3.614 + NS_LOG_LOGIC ("Transmit packet to " << destination);
3.615 +
3.616 +#if 0
3.617 + {
3.618 + struct ifreq ifr;
3.619 + bzero (&ifr, sizeof(ifr));
3.620 + strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
3.621 +
3.622 + NS_LOG_LOGIC ("Getting MAC address");
3.623 + int32_t rc = ioctl (m_sock, SIOCGIFHWADDR, &ifr);
3.624 + NS_ASSERT_MSG (rc != -1, "EmuNetDevice::SendFrom(): Can't get MAC address");
3.625 +
3.626 + std::ostringstream oss;
3.627 + oss << std::hex <<
3.628 + (ifr.ifr_hwaddr.sa_data[0] & 0xff) << ":" <<
3.629 + (ifr.ifr_hwaddr.sa_data[1] & 0xff) << ":" <<
3.630 + (ifr.ifr_hwaddr.sa_data[2] & 0xff) << ":" <<
3.631 + (ifr.ifr_hwaddr.sa_data[3] & 0xff) << ":" <<
3.632 + (ifr.ifr_hwaddr.sa_data[4] & 0xff) << ":" <<
3.633 + (ifr.ifr_hwaddr.sa_data[5] & 0xff) << std::dec;
3.634 +
3.635 + NS_LOG_LOGIC ("Fixup source to HW MAC " << oss.str ());
3.636 + source = Mac48Address (oss.str ().c_str ());
3.637 + NS_LOG_LOGIC ("source now " << source);
3.638 + }
3.639 +#endif
3.640 +
3.641 + LlcSnapHeader llc;
3.642 + llc.SetType (protocolNumber);
3.643 + packet->AddHeader (llc);
3.644 +
3.645 + EthernetHeader header (false);
3.646 + header.SetSource (source);
3.647 + header.SetDestination (destination);
3.648 + header.SetLengthType (packet->GetSize ());
3.649 + packet->AddHeader (header);
3.650 +
3.651 + EthernetTrailer trailer;
3.652 + trailer.CalcFcs (packet);
3.653 + packet->AddTrailer (trailer);
3.654 +
3.655 + //
3.656 + // Enqueue and dequeue the packet to hit the tracing hooks.
3.657 + //
3.658 + m_queue->Enqueue (packet);
3.659 + packet = m_queue->Dequeue ();
3.660 +
3.661 + struct sockaddr_ll ll;
3.662 + bzero (&ll, sizeof (ll));
3.663 +
3.664 + ll.sll_family = AF_PACKET;
3.665 + ll.sll_ifindex = m_sll_ifindex;
3.666 + ll.sll_protocol = htons(ETH_P_ALL);
3.667 +
3.668 + NS_LOG_LOGIC ("calling sendto");
3.669 +
3.670 + int32_t rc;
3.671 + rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
3.672 +
3.673 + NS_LOG_LOGIC ("sendto returns " << rc);
3.674 +
3.675 + return rc == -1 ? false : true;
3.676 +}
3.677 +
3.678 +void
3.679 +EmuNetDevice::SetDataRate(DataRate bps)
3.680 +{
3.681 + NS_LOG_FUNCTION (this << bps);
3.682 + NS_ASSERT_MSG (false, "EmuNetDevice::SetDataRate(): Unable.");
3.683 +}
3.684 +
3.685 +void
3.686 +EmuNetDevice::SetQueue (Ptr<Queue> q)
3.687 +{
3.688 + NS_LOG_FUNCTION (this << q);
3.689 + m_queue = q;
3.690 +}
3.691 +
3.692 +Ptr<Queue>
3.693 +EmuNetDevice::GetQueue(void) const
3.694 +{
3.695 + NS_LOG_FUNCTION_NOARGS ();
3.696 + return m_queue;
3.697 +}
3.698 +
3.699 +void
3.700 +EmuNetDevice::NotifyLinkUp (void)
3.701 +{
3.702 + m_linkUp = true;
3.703 + if (!m_linkChangeCallback.IsNull ())
3.704 + {
3.705 + m_linkChangeCallback ();
3.706 + }
3.707 +}
3.708 +
3.709 +void
3.710 +EmuNetDevice::SetName(const std::string name)
3.711 +{
3.712 + m_name = name;
3.713 +}
3.714 +
3.715 +std::string
3.716 +EmuNetDevice::GetName(void) const
3.717 +{
3.718 + return m_name;
3.719 +}
3.720 +
3.721 +void
3.722 +EmuNetDevice::SetIfIndex(const uint32_t index)
3.723 +{
3.724 + m_ifIndex = index;
3.725 +}
3.726 +
3.727 +uint32_t
3.728 +EmuNetDevice::GetIfIndex(void) const
3.729 +{
3.730 + return m_ifIndex;
3.731 +}
3.732 +
3.733 +Ptr<Channel>
3.734 +EmuNetDevice::GetChannel (void) const
3.735 +{
3.736 + NS_ASSERT_MSG (false, "EmuNetDevice::GetChannel(): Unable.");
3.737 + return 0;
3.738 +}
3.739 +
3.740 +void
3.741 +EmuNetDevice::SetAddress (Mac48Address addr)
3.742 +{
3.743 + NS_LOG_FUNCTION (addr);
3.744 + m_address = addr;
3.745 +}
3.746 +
3.747 +Address
3.748 +EmuNetDevice::GetAddress (void) const
3.749 +{
3.750 + NS_LOG_FUNCTION_NOARGS ();
3.751 + return m_address;
3.752 +}
3.753 +
3.754 +bool
3.755 +EmuNetDevice::SetMtu (const uint16_t mtu)
3.756 +{
3.757 + NS_ASSERT_MSG (false, "EmuNetDevice::SetMtu(): Unable.");
3.758 + return false;
3.759 +}
3.760 +
3.761 +uint16_t
3.762 +EmuNetDevice::GetMtu (void) const
3.763 +{
3.764 + struct ifreq ifr;
3.765 + bzero (&ifr, sizeof (ifr));
3.766 + strcpy(ifr.ifr_name, m_deviceName.c_str ());
3.767 +
3.768 + int32_t fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
3.769 +
3.770 + int32_t rc = ioctl(fd, SIOCGIFMTU, &ifr);
3.771 + NS_ASSERT_MSG (rc != -1, "EmuNetDevice::GetMtu(): Can't ioctl SIOCGIFMTU");
3.772 +
3.773 + close (fd);
3.774 +
3.775 + return ifr.ifr_mtu;
3.776 +}
3.777 +
3.778 +bool
3.779 +EmuNetDevice::IsLinkUp (void) const
3.780 +{
3.781 + return m_linkUp;
3.782 +}
3.783 +
3.784 +void
3.785 +EmuNetDevice::SetLinkChangeCallback (Callback<void> callback)
3.786 +{
3.787 + m_linkChangeCallback = callback;
3.788 +}
3.789 +
3.790 +bool
3.791 +EmuNetDevice::IsBroadcast (void) const
3.792 +{
3.793 + return true;
3.794 +}
3.795 +
3.796 +Address
3.797 +EmuNetDevice::GetBroadcast (void) const
3.798 +{
3.799 + return Mac48Address ("ff:ff:ff:ff:ff:ff");
3.800 +}
3.801 +
3.802 +bool
3.803 +EmuNetDevice::IsMulticast (void) const
3.804 +{
3.805 + return false;
3.806 +}
3.807 +
3.808 +Address
3.809 +EmuNetDevice::GetMulticast (void) const
3.810 +{
3.811 + return Mac48Address ("01:00:5e:00:00:00");
3.812 +}
3.813 +
3.814 +Address
3.815 +EmuNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const
3.816 +{
3.817 + return Mac48Address ("01:00:5e:00:00:00");
3.818 +}
3.819 +
3.820 +bool
3.821 +EmuNetDevice::IsPointToPoint (void) const
3.822 +{
3.823 + return false;
3.824 +}
3.825 +
3.826 +void
3.827 +EmuNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
3.828 +{
3.829 + NS_ASSERT_MSG (false, "EmuNetDevice::SetPromiscReceiveCallback(): Not implemented");
3.830 +}
3.831 +
3.832 + bool
3.833 +EmuNetDevice::SupportsSendFrom () const
3.834 +{
3.835 + NS_LOG_FUNCTION_NOARGS ();
3.836 + return true;
3.837 +}
3.838 +
3.839 +
3.840 +Ptr<Node>
3.841 +EmuNetDevice::GetNode (void) const
3.842 +{
3.843 + return m_node;
3.844 +}
3.845 +
3.846 +void
3.847 +EmuNetDevice::SetNode (Ptr<Node> node)
3.848 +{
3.849 + m_node = node;
3.850 +}
3.851 +
3.852 +bool
3.853 +EmuNetDevice::NeedsArp (void) const
3.854 +{
3.855 + return true;
3.856 +}
3.857 +
3.858 +void
3.859 +EmuNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
3.860 +{
3.861 + m_rxCallback = cb;
3.862 +}
3.863 +
3.864 +} // namespace ns3
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/src/devices/emu/emu-net-device.h Wed Oct 29 22:39:36 2008 -0700
4.3 @@ -0,0 +1,333 @@
4.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
4.5 +/*
4.6 + * Copyright (c) 2008 University of Washington
4.7 + *
4.8 + * This program is free software; you can redistribute it and/or modify
4.9 + * it under the terms of the GNU General Public License version 2 as
4.10 + * published by the Free Software Foundation;
4.11 + *
4.12 + * This program is distributed in the hope that it will be useful,
4.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.15 + * GNU General Public License for more details.
4.16 + *
4.17 + * You should have received a copy of the GNU General Public License
4.18 + * along with this program; if not, write to the Free Software
4.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4.20 + */
4.21 +
4.22 +#ifndef EMU_NET_DEVICE_H
4.23 +#define EMU_NET_DEVICE_H
4.24 +
4.25 +#include <string.h>
4.26 +#include "ns3/address.h"
4.27 +#include "ns3/net-device.h"
4.28 +#include "ns3/node.h"
4.29 +#include "ns3/callback.h"
4.30 +#include "ns3/packet.h"
4.31 +#include "ns3/traced-callback.h"
4.32 +#include "ns3/event-id.h"
4.33 +#include "ns3/nstime.h"
4.34 +#include "ns3/data-rate.h"
4.35 +#include "ns3/ptr.h"
4.36 +#include "ns3/mac48-address.h"
4.37 +#include "ns3/system-thread.h"
4.38 +
4.39 +namespace ns3 {
4.40 +
4.41 +class Queue;
4.42 +
4.43 +/**
4.44 + * \class EmuNetDevice
4.45 + * \brief A Device for an Emu Network Link.
4.46 + */
4.47 +class EmuNetDevice : public NetDevice
4.48 +{
4.49 +public:
4.50 + static TypeId GetTypeId (void);
4.51 +
4.52 + /**
4.53 + * Construct a EmuNetDevice
4.54 + *
4.55 + * This is the constructor for the EmuNetDevice. It takes as a
4.56 + */
4.57 + EmuNetDevice ();
4.58 +
4.59 + /**
4.60 + * Destroy a EmuNetDevice
4.61 + *
4.62 + * This is the destructor for the EmuNetDevice.
4.63 + */
4.64 + virtual ~EmuNetDevice ();
4.65 +
4.66 + /**
4.67 + * Set the Data Rate used for transmission of packets.
4.68 + *
4.69 + * @see Attach ()
4.70 + * @param bps the data rate at which this object operates
4.71 + */
4.72 + void SetDataRate (DataRate bps);
4.73 +
4.74 + /**
4.75 + * Set the inteframe gap used to separate packets. The interframe gap
4.76 + * defines the minimum space required between packets sent by this device.
4.77 + *
4.78 + * @param t the interframe gap time
4.79 + */
4.80 + void SetInterframeGap (Time t);
4.81 +
4.82 + /**
4.83 + * Set a start time for the device.
4.84 + *
4.85 + * @param tStart the start time
4.86 + */
4.87 + void Start (Time tStart);
4.88 +
4.89 + /**
4.90 + * Set a stop time for the device.
4.91 + *
4.92 + * @param tStop the stop time
4.93 + */
4.94 + void Stop (Time tStop);
4.95 +
4.96 + /**
4.97 + * Attach a queue to the EmuNetDevice.
4.98 + *
4.99 + * The EmuNetDevice "owns" a queue that implements a queueing
4.100 + * method such as DropTail or RED.
4.101 + *
4.102 + * @see Queue
4.103 + * @see DropTailQueue
4.104 + * @param queue Ptr to the new queue.
4.105 + */
4.106 + void SetQueue (Ptr<Queue> queue);
4.107 +
4.108 + /**
4.109 + * Receive a packet.
4.110 + *
4.111 + * The EmuNetDevice receives packets from its socket reader
4.112 + * and forwards them up the protocol stack. This is the public method
4.113 + * used by the reader to indicate that a packet has arrived at the device.
4.114 + *
4.115 + * @param p Ptr to the received packet.
4.116 + */
4.117 + void Receive (Ptr<Packet> p);
4.118 +
4.119 + /**
4.120 + * Assign a MAC address to this device.
4.121 + *
4.122 + * @see Mac48Address
4.123 + * @param addr The new address.
4.124 + */
4.125 + void SetAddress (Mac48Address addr);
4.126 +
4.127 +//
4.128 +// Pure virtual methods inherited from NetDevice we must implement.
4.129 +//
4.130 + virtual void SetName(const std::string name);
4.131 + virtual std::string GetName(void) const;
4.132 +
4.133 + virtual void SetIfIndex(const uint32_t index);
4.134 + virtual uint32_t GetIfIndex(void) const;
4.135 +
4.136 + virtual Ptr<Channel> GetChannel (void) const;
4.137 + virtual Address GetAddress (void) const;
4.138 +
4.139 + virtual bool SetMtu (const uint16_t mtu);
4.140 + virtual uint16_t GetMtu (void) const;
4.141 +
4.142 + virtual bool IsLinkUp (void) const;
4.143 +
4.144 + virtual void SetLinkChangeCallback (Callback<void> callback);
4.145 +
4.146 + virtual bool IsBroadcast (void) const;
4.147 + virtual Address GetBroadcast (void) const;
4.148 +
4.149 + virtual bool IsMulticast (void) const;
4.150 + virtual Address GetMulticast (void) const;
4.151 + virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
4.152 +
4.153 + virtual bool IsPointToPoint (void) const;
4.154 +
4.155 + virtual bool Send(Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber);
4.156 +
4.157 + virtual bool SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
4.158 +
4.159 + virtual Ptr<Node> GetNode (void) const;
4.160 + virtual void SetNode (Ptr<Node> node);
4.161 +
4.162 + virtual bool NeedsArp (void) const;
4.163 +
4.164 + virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
4.165 + virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb);
4.166 +
4.167 + virtual bool SupportsSendFrom (void) const;
4.168 +
4.169 +private:
4.170 +
4.171 + virtual void DoDispose (void);
4.172 +
4.173 + /**
4.174 + * Call out to a separate process running as suid root in order to get a raw
4.175 + * socket. We do this to avoid having the entire simulation running as root.
4.176 + * If this method returns, we'll have a raw socket waiting for us in m_sock.
4.177 + */
4.178 + void CreateSocket (void);
4.179 +
4.180 + /**
4.181 + * Figure out where the raw socket creation process lives on the system.
4.182 + */
4.183 + std::string FindCreator (void);
4.184 +
4.185 + /**
4.186 + * Get a copy of the attached Queue.
4.187 + *
4.188 + * This method is provided for any derived class that may need to get
4.189 + * direct access to the underlying queue.
4.190 + *
4.191 + * @returns Ptr to the queue.
4.192 + */
4.193 + Ptr<Queue> GetQueue(void) const;
4.194 +
4.195 + /**
4.196 + * Spin up the device
4.197 + */
4.198 + void StartDevice (void);
4.199 +
4.200 + /**
4.201 + * Tear down the device
4.202 + */
4.203 + void StopDevice (void);
4.204 +
4.205 + /**
4.206 + * Loop to read and process packets
4.207 + */
4.208 + void ReadThread (void);
4.209 +
4.210 + /**
4.211 + * Method to handle received packets. Synchronized with simulator via ScheduleNow from ReadThread.
4.212 + */
4.213 + void ForwardUp (uint8_t *buf, uint32_t len);
4.214 +
4.215 + /**
4.216 + * Adds the necessary headers and trailers to a packet of data in order to
4.217 + * respect the protocol implemented by the agent.
4.218 + */
4.219 + void AddHeader(Ptr<Packet> p, uint16_t protocolNumber);
4.220 +
4.221 + /**
4.222 + * Removes, from a packet of data, all headers and trailers that
4.223 + * relate to the protocol implemented by the agent
4.224 + * \return Returns true if the packet should be forwarded up the
4.225 + * protocol stack.
4.226 + */
4.227 + bool ProcessHeader(Ptr<Packet> p, uint16_t& param);
4.228 +
4.229 + /**
4.230 + * Start Sending a Packet Down the Wire.
4.231 + *
4.232 + * @returns true if success, false on failure
4.233 + */
4.234 + bool TransmitStart (Ptr<Packet> p);
4.235 +
4.236 + void NotifyLinkUp (void);
4.237 +
4.238 + /**
4.239 + * The Queue which this EmuNetDevice uses as a packet source.
4.240 + * Management of this Queue has been delegated to the EmuNetDevice
4.241 + * and it has the responsibility for deletion.
4.242 + * @see class Queue
4.243 + * @see class DropTailQueue
4.244 + */
4.245 + Ptr<Queue> m_queue;
4.246 +
4.247 + /**
4.248 + * The trace source for the packet reception events that the device can
4.249 + * fire.
4.250 + *
4.251 + * @see class CallBackTraceSource
4.252 + */
4.253 + TracedCallback<Ptr<const Packet> > m_rxTrace;
4.254 +
4.255 + /**
4.256 + * The trace source for the packet drop events that the device can
4.257 + * fire.
4.258 + *
4.259 + * @see class CallBackTraceSource
4.260 + */
4.261 + TracedCallback<Ptr<const Packet> > m_dropTrace;
4.262 +
4.263 + /**
4.264 + * Time to start spinning up the device
4.265 + */
4.266 + Time m_tStart;
4.267 +
4.268 + /**
4.269 + * Time to start tearing down the device
4.270 + */
4.271 + Time m_tStop;
4.272 +
4.273 + EventId m_startEvent;
4.274 + EventId m_stopEvent;
4.275 +
4.276 + int32_t m_sock;
4.277 +
4.278 + Ptr<SystemThread> m_readThread;
4.279 +
4.280 + /**
4.281 + * The Node to which this device is attached.
4.282 + */
4.283 + Ptr<Node> m_node;
4.284 +
4.285 + /**
4.286 + * The MAC address which has been assigned to this device.
4.287 + */
4.288 + Mac48Address m_address;
4.289 +
4.290 + /**
4.291 + * The callback used to notify higher layers that a packet has been received.
4.292 + */
4.293 + NetDevice::ReceiveCallback m_rxCallback;
4.294 +
4.295 + /**
4.296 + * The callback used to notify higher layers that a packet has been received in promiscuous mode.
4.297 + */
4.298 + NetDevice::PromiscReceiveCallback m_promiscRxCallback;
4.299 +
4.300 + /**
4.301 + * The ns-3 interface index (in the sense of net device index) that has been assigned to this network device.
4.302 + */
4.303 + uint32_t m_ifIndex;
4.304 +
4.305 + /**
4.306 + * The Unix interface index that we got from the system and which corresponds to the interface (e.g., "eth1")
4.307 + * we are using to talk to the network. Valid when m_sock is valid.
4.308 + */
4.309 + int32_t m_sll_ifindex;
4.310 +
4.311 + /**
4.312 + * The human readable name of this device.
4.313 + */
4.314 + std::string m_name;
4.315 +
4.316 + /**
4.317 + * Flag indicating whether or not the link is up. In this case,
4.318 + * whether or not the device is connected to a channel.
4.319 + */
4.320 + bool m_linkUp;
4.321 +
4.322 + /**
4.323 + * Callback to fire if the link changes state (up or down).
4.324 + */
4.325 + Callback<void> m_linkChangeCallback;
4.326 +
4.327 + /**
4.328 + * The unix/linux name of the underlying device (e.g., eth0)
4.329 + */
4.330 + std::string m_deviceName;
4.331 +};
4.332 +
4.333 +} // namespace ns3
4.334 +
4.335 +#endif // EMU_NET_DEVICE_H
4.336 +
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/src/devices/emu/emu-sock-creator.cc Wed Oct 29 22:39:36 2008 -0700
5.3 @@ -0,0 +1,246 @@
5.4 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
5.5 +/*
5.6 + * Copyright (c) University of Washington
5.7 + *
5.8 + * This program is free software; you can redistribute it and/or modify
5.9 + * it under the terms of the GNU General Public License version 2 as
5.10 + * published by the Free Software Foundation;
5.11 + *
5.12 + * This program is distributed in the hope that it will be useful,
5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.15 + * GNU General Public License for more details.
5.16 + *
5.17 + * You should have received a copy of the GNU General Public License
5.18 + * along with this program; if not, write to the Free Software
5.19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5.20 + */
5.21 +
5.22 +#include <unistd.h>
5.23 +#include <string>
5.24 +#include <iostream>
5.25 +#include <iomanip>
5.26 +#include <sstream>
5.27 +#include <stdlib.h>
5.28 +#include <errno.h>
5.29 +
5.30 +#include <sys/socket.h>
5.31 +#include <sys/un.h>
5.32 +#include <sys/ioctl.h>
5.33 +#include <net/ethernet.h>
5.34 +#include <net/if.h>
5.35 +#include <netinet/in.h>
5.36 +#include <netpacket/packet.h>
5.37 +#include <arpa/inet.h>
5.38 +
5.39 +#include "emu-encode-decode.h"
5.40 +
5.41 +#define EMU_MAGIC 65867
5.42 +
5.43 +static int gVerbose = 0;
5.44 +
5.45 +#define LOG(msg) \
5.46 + if (gVerbose) \
5.47 + { \
5.48 + std::cout << msg << std::endl; \
5.49 + }
5.50 +
5.51 +#define ABORT(msg) \
5.52 + std::cout << __FILE__ << __FUNCTION__ << ": fatal error at line " << __LINE__ << ": " << msg << std::endl; \
5.53 + exit (-1);
5.54 +
5.55 +#define ABORT_IF(cond, msg, printErrno) \
5.56 + if (cond) \
5.57 + { \
5.58 + std::cout << __FILE__ << __FUNCTION__ << ": fatal error at line " << __LINE__ << ": " << msg << std::endl; \
5.59 + if (printErrno) \
5.60 + { \
5.61 + std::cout << " errno = " << errno << "(" << strerror (errno) << ")" << std::endl; \
5.62 + } \
5.63 + exit (-1); \
5.64 + }
5.65 +
5.66 +/**
5.67 + * \brief Send the socket file descriptor we created back to the emu device,
5.68 + * which will read it as soon as we're done.
5.69 + *
5.70 + * \param path The socket address information from the Unix socket we use
5.71 + * to send the created socket back to.
5.72 + * \param fd The socket we're going to send.
5.73 + */
5.74 + static void
5.75 +SendSocket (const char *path, int fd)
5.76 +{
5.77 + //
5.78 + // Open a Unix (local interprocess) socket to call back to the emu net
5.79 + // device.
5.80 + //
5.81 + LOG ("SendSocket(): Create Unix socket");
5.82 + int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
5.83 + ABORT_IF (sock == -1, "SendSocket(): Unable to open socket", 1);
5.84 +
5.85 + //
5.86 + // We have this string called path, which is really a hex representation
5.87 + // of the endpoint that the net device created. It used a forward encoding
5.88 + // method (EmuBufferToString) to take the sockaddr_un it made and passed
5.89 + // the resulting string to us. So we need to take the inverse method
5.90 + // (EmuStringToBuffer) and build the same sockaddr_un over here.
5.91 + //
5.92 + socklen_t clientAddrLen;
5.93 + struct sockaddr_un clientAddr;
5.94 +
5.95 + LOG ("SendSocket(): Decode address");
5.96 + bool rc = ns3::EmuStringToBuffer (path, (uint8_t *)&clientAddr, &clientAddrLen);
5.97 + ABORT_IF (rc == false, "SendSocket(): Unable to decode path", 0);
5.98 +
5.99 + LOG ("SendSocket(): Connect");
5.100 + int status = connect (sock, (struct sockaddr*)&clientAddr, clientAddrLen);
5.101 + ABORT_IF (status != -1, "SendSocket(): Unable to connect to emu device", 1);
5.102 +
5.103 + LOG ("SendSocket(): Connected");
5.104 +
5.105 + //
5.106 + // This is arcane enough that a few words are worthwhile to explain what's
5.107 + // going on here.
5.108 + //
5.109 + // The interesting information (the socket FD) is going to go back to the
5.110 + // emu net device as an integer of ancillary data. Ancillary data is bits
5.111 + // that are not a part a socket payload (out-of-band data). We're also
5.112 + // going to send one integer back. It's just initialized to a magic number
5.113 + // we use to make sure that the emu device is talking to the emu socket
5.114 + // creator and not some other creator process.
5.115 + //
5.116 + // The struct iovec below is part of a scatter-gather list. It describes a
5.117 + // buffer. In this case, it describes a buffer (an integer) containing the
5.118 + // data that we're going to send back to the emu net device (that magic
5.119 + // number).
5.120 + //
5.121 + struct iovec iov;
5.122 + uint32_t magic = EMU_MAGIC;
5.123 + iov.iov_base = &magic;
5.124 + iov.iov_len = sizeof(magic);
5.125 +
5.126 + //
5.127 + // The CMSG macros you'll see below are used to create and access control
5.128 + // messages (which is another name for ancillary data). The ancillary
5.129 + // data is made up of pairs of struct cmsghdr structures and associated
5.130 + // data arrays.
5.131 + //
5.132 + // First, we're going to allocate a buffer on the stack to contain our
5.133 + // data array (that contains the socket). Sometimes you'll see this called
5.134 + // an "ancillary element" but the msghdr uses the control message termimology
5.135 + // so we call it "control."
5.136 + //
5.137 + size_t msg_size = sizeof(int);
5.138 + char control[CMSG_SPACE(msg_size)];
5.139 +
5.140 + //
5.141 + // There is a msghdr that is used to minimize the number of parameters
5.142 + // passed to sendmsg (which we will use to send our ancillary data). This
5.143 + // structure uses terminology corresponding to control messages, so you'll
5.144 + // see msg_control, which is the pointer to the ancillary data and controllen
5.145 + // which is the size of the ancillary data array.
5.146 + //
5.147 + // So, initialize the message header that describes our ancillary/control data
5.148 + // and point it to the control message/ancillary data we just allocated space
5.149 + // for.
5.150 + //
5.151 + struct msghdr msg;
5.152 + msg.msg_name = 0;
5.153 + msg.msg_namelen = 0;
5.154 + msg.msg_iov = &iov;
5.155 + msg.msg_iovlen = 1;
5.156 + msg.msg_control = control;
5.157 + msg.msg_controllen = sizeof (control);
5.158 + msg.msg_flags = 0;
5.159 +
5.160 + //
5.161 + // A cmsghdr contains a length field that is the length of the header and
5.162 + // the data. It has a cmsg_level field corresponding to the originating
5.163 + // protocol. This takes values which are legal levels for getsockopt and
5.164 + // setsockopt (here SOL_SOCKET). We're going to use the SCM_RIGHTS type of
5.165 + // cmsg, that indicates that the ancillary data array contains access rights
5.166 + // that we are sending back to the emu net device.
5.167 + //
5.168 + // We have to put together the first (and only) cmsghdr that will describe
5.169 + // the whole package we're sending.
5.170 + //
5.171 + struct cmsghdr *cmsg;
5.172 + cmsg = CMSG_FIRSTHDR(&msg);
5.173 + cmsg->cmsg_level = SOL_SOCKET;
5.174 + cmsg->cmsg_type = SCM_RIGHTS;
5.175 + cmsg->cmsg_len = CMSG_LEN(msg_size);
5.176 + //
5.177 + // We also have to update the controllen in case other stuff is actually
5.178 + // in there we may not be aware of (due to macros).
5.179 + //
5.180 + msg.msg_controllen = cmsg->cmsg_len;
5.181 +
5.182 + //
5.183 + // Finally, we get a pointer to the start of the ancillary data array and
5.184 + // put our file descriptor in.
5.185 + //
5.186 + int *fdptr = (int*) (CMSG_DATA(cmsg));
5.187 + *fdptr = fd; //
5.188 +
5.189 + //
5.190 + // Actually send the file descriptor back to the emulated net device.
5.191 + //
5.192 + ssize_t len = sendmsg(sock, &msg, 0);
5.193 + ABORT_IF (len == -1, "Could not send socket back to emu net device", 1);
5.194 +
5.195 + LOG ("SendSocket(): sendmsg complete");
5.196 +}
5.197 +
5.198 + int
5.199 +main (int argc, char *argv[])
5.200 +{
5.201 + int c;
5.202 + char *path = NULL;
5.203 +
5.204 + opterr = 0;
5.205 +
5.206 + while ((c = getopt (argc, argv, "vp:")) != -1)
5.207 + {
5.208 + switch (c)
5.209 + {
5.210 + case 'v':
5.211 + gVerbose = true;
5.212 + break;
5.213 + case 'p':
5.214 + path = optarg;
5.215 + break;
5.216 + }
5.217 + }
5.218 +
5.219 + //
5.220 + // This program is spawned by an emu net device running in a simulation. It
5.221 + // wants to create a raw socket as described below. We are going to do the
5.222 + // work here since we're running suid root. Once we create the raw socket,
5.223 + // we have to send it back to the emu net device. We do that over a Unix
5.224 + // (local interprocess) socket. The emu net device created a socket to
5.225 + // listen for our response on, and it is expected to have encoded the address
5.226 + // information as a string and to have passed that string as an argument to
5.227 + // us. We see it here as the "path" string. We can't do anything useful
5.228 + // unless we have that string.
5.229 + //
5.230 + ABORT_IF (path == NULL, "path is a required argument", 0);
5.231 +
5.232 + //
5.233 + // The whole reason for all of the hoops we went through to call out to this
5.234 + // program will pay off here. We created this program to run as suid root
5.235 + // in order to keep the main simulation program from having to be run with
5.236 + // root privileges. We need root privileges to be able to open a raw socket
5.237 + // though. So all of these hoops are to allow us to exeucte the following
5.238 + // single line of code:
5.239 + //
5.240 + int sock = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
5.241 + ABORT_IF (sock == -1, "CreateSocket(): Unable to open raw socket", 1);
5.242 +
5.243 + //
5.244 + // Send the socket back to the emu net device so it can go about its business
5.245 + //
5.246 + SendSocket (path, sock);
5.247 +
5.248 + return 0;
5.249 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/src/devices/emu/emu.h Wed Oct 29 22:39:36 2008 -0700
6.3 @@ -0,0 +1,10 @@
6.4 +/**
6.5 + * \ingroup devices
6.6 + * \defgroup Emulated Emulated Net Device Model
6.7 + *
6.8 + * \section Emulated Net Device Model
6.9 + *
6.10 + * This is a description of the emulated network device model.
6.11 + *
6.12 + * It is very detailed and comprehensive and answers all possible questions.
6.13 + */
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/src/devices/emu/waf Wed Oct 29 22:39:36 2008 -0700
7.3 @@ -0,0 +1,1 @@
7.4 +exec "`dirname "$0"`"/../../../waf "$@"
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/src/devices/emu/wscript Wed Oct 29 22:39:36 2008 -0700
8.3 @@ -0,0 +1,22 @@
8.4 +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
8.5 +
8.6 +
8.7 +def build(bld):
8.8 + obj = bld.create_suid_program('emu-sock-creator')
8.9 + obj.source = [
8.10 + 'emu-sock-creator.cc',
8.11 + 'emu-encode-decode.cc',
8.12 + ]
8.13 +
8.14 + module = bld.create_ns3_module('emu', ['node'])
8.15 + module.source = [
8.16 + 'emu-net-device.cc',
8.17 + 'emu-encode-decode.cc',
8.18 + ]
8.19 +
8.20 + headers = bld.create_obj('ns3header')
8.21 + headers.module = 'emu'
8.22 + headers.source = [
8.23 + 'emu-net-device.h',
8.24 + ]
8.25 +
9.1 --- a/src/devices/emulated/emulated-net-device.cc Wed Oct 29 11:49:21 2008 -0700
9.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
9.3 @@ -1,642 +0,0 @@
9.4 -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
9.5 -/*
9.6 - * Copyright (c) 2008 University of Washington
9.7 - *
9.8 - * This program is free software; you can redistribute it and/or modify
9.9 - * it under the terms of the GNU General Public License version 2 as
9.10 - * published by the Free Software Foundation;
9.11 - *
9.12 - * This program is distributed in the hope that it will be useful,
9.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
9.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9.15 - * GNU General Public License for more details.
9.16 - *
9.17 - * You should have received a copy of the GNU General Public License
9.18 - * along with this program; if not, write to the Free Software
9.19 - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
9.20 - */
9.21 -
9.22 -#include "emulated-net-device.h"
9.23 -
9.24 -#include "ns3/log.h"
9.25 -#include "ns3/queue.h"
9.26 -#include "ns3/simulator.h"
9.27 -#include "ns3/realtime-simulator-impl.h"
9.28 -#include "ns3/mac48-address.h"
9.29 -#include "ns3/ethernet-header.h"
9.30 -#include "ns3/ethernet-trailer.h"
9.31 -#include "ns3/llc-snap-header.h"
9.32 -#include "ns3/trace-source-accessor.h"
9.33 -#include "ns3/pointer.h"
9.34 -#include "ns3/channel.h"
9.35 -#include "ns3/system-thread.h"
9.36 -#include "ns3/string.h"
9.37 -#include "ns3/boolean.h"
9.38 -
9.39 -#include <sys/socket.h>
9.40 -#include <sys/ioctl.h>
9.41 -#include <net/ethernet.h>
9.42 -#include <net/if.h>
9.43 -#include <netinet/in.h>
9.44 -#include <netpacket/packet.h>
9.45 -#include <arpa/inet.h>
9.46 -
9.47 -NS_LOG_COMPONENT_DEFINE ("EmulatedNetDevice");
9.48 -
9.49 -namespace ns3 {
9.50 -
9.51 -NS_OBJECT_ENSURE_REGISTERED (EmulatedNetDevice);
9.52 -
9.53 -TypeId
9.54 -EmulatedNetDevice::GetTypeId (void)
9.55 -{
9.56 - static TypeId tid = TypeId ("ns3::EmulatedNetDevice")
9.57 - .SetParent<NetDevice> ()
9.58 - .AddConstructor<EmulatedNetDevice> ()
9.59 - .AddAttribute ("Address",
9.60 - "The ns-3 MAC address of this (virtual) device.",
9.61 - Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
9.62 - MakeMac48AddressAccessor (&EmulatedNetDevice::m_address),
9.63 - MakeMac48AddressChecker ())
9.64 - .AddAttribute ("DeviceName",
9.65 - "The name of the underlying real device (e.g. eth1).",
9.66 - StringValue ("eth1"),
9.67 - MakeStringAccessor (&EmulatedNetDevice::m_deviceName),
9.68 - MakeStringChecker ())
9.69 - .AddAttribute ("Start",
9.70 - "The simulation time at which to spin up the device thread.",
9.71 - TimeValue (Seconds (0.)),
9.72 - MakeTimeAccessor (&EmulatedNetDevice::m_tStart),
9.73 - MakeTimeChecker ())
9.74 - .AddAttribute ("Stop",
9.75 - "The simulation time at which to tear down the device thread.",
9.76 - TimeValue (Seconds (0.)),
9.77 - MakeTimeAccessor (&EmulatedNetDevice::m_tStop),
9.78 - MakeTimeChecker ())
9.79 - .AddAttribute ("TxQueue",
9.80 - "A queue to use as the transmit queue in the device.",
9.81 - PointerValue (),
9.82 - MakePointerAccessor (&EmulatedNetDevice::m_queue),
9.83 - MakePointerChecker<Queue> ())
9.84 - .AddTraceSource ("Rx",
9.85 - "Trace source to fire on reception of a MAC packet.",
9.86 - MakeTraceSourceAccessor (&EmulatedNetDevice::m_rxTrace))
9.87 - .AddTraceSource ("Drop",
9.88 - "Trace source to fire on when a MAC packet is dropped.",
9.89 - MakeTraceSourceAccessor (&EmulatedNetDevice::m_dropTrace))
9.90 - ;
9.91 - return tid;
9.92 -}
9.93 -
9.94 -
9.95 -EmulatedNetDevice::EmulatedNetDevice ()
9.96 -:
9.97 - m_startEvent (),
9.98 - m_stopEvent (),
9.99 - m_sock (-1),
9.100 - m_readThread (0),
9.101 - m_ifIndex (-1),
9.102 - m_sll_ifindex (-1),
9.103 - m_name ("Emulated NetDevice")
9.104 -{
9.105 - NS_LOG_FUNCTION (this);
9.106 - Start (m_tStart);
9.107 -}
9.108 -
9.109 -EmulatedNetDevice::~EmulatedNetDevice ()
9.110 -{
9.111 -}
9.112 -
9.113 -void
9.114 -EmulatedNetDevice::DoDispose()
9.115 -{
9.116 - NS_LOG_FUNCTION_NOARGS ();
9.117 - m_node = 0;
9.118 - NetDevice::DoDispose ();
9.119 -}
9.120 -
9.121 -void
9.122 -EmulatedNetDevice::Start (Time tStart)
9.123 -{
9.124 - NS_LOG_FUNCTION (tStart);
9.125 -
9.126 - //
9.127 - // Cancel any pending start event and schedule a new one at some relative time in the future.
9.128 - //
9.129 - Simulator::Cancel (m_startEvent);
9.130 - m_startEvent = Simulator::Schedule (tStart, &EmulatedNetDevice::StartDevice, this);
9.131 -}
9.132 -
9.133 - void
9.134 -EmulatedNetDevice::Stop (Time tStop)
9.135 -{
9.136 - NS_LOG_FUNCTION (tStop);
9.137 - //
9.138 - // Cancel any pending stop event and schedule a new one at some relative time in the future.
9.139 - //
9.140 - Simulator::Cancel (m_stopEvent);
9.141 - m_startEvent = Simulator::Schedule (tStop, &EmulatedNetDevice::StopDevice, this);
9.142 -}
9.143 -
9.144 - void
9.145 -EmulatedNetDevice::StartDevice (void)
9.146 -{
9.147 - NS_LOG_FUNCTION_NOARGS ();
9.148 -
9.149 - //
9.150 - // Spin up the emulated net device and start receiving packets.
9.151 - //
9.152 - NS_ASSERT_MSG (m_sock == -1, "EmulatedNetDevice::StartDevice(): Device is already started");
9.153 -
9.154 - NS_LOG_LOGIC ("Creating socket");
9.155 -
9.156 - m_sock = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
9.157 - // m_sock = socket (AF_INET, SOCK_PACKET, htons(ETH_P_ALL));
9.158 - NS_ASSERT_MSG (m_sock != -1, "EmulatedNetDevice::StartDevice(): Unable to open socket");
9.159 -
9.160 - //
9.161 - // Figure out which interface index corresponds to the device name in the corresponding attribute.
9.162 - //
9.163 - struct ifreq ifr;
9.164 - bzero (&ifr, sizeof(ifr));
9.165 - strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
9.166 -
9.167 - NS_LOG_LOGIC ("Getting interface index");
9.168 - int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
9.169 - NS_ASSERT_MSG (rc != -1, "EmulatedNetDevice::StartDevice(): Can't get interface index");
9.170 -
9.171 - //
9.172 - // Save the real interface index for later calls to sendto
9.173 - //
9.174 - m_sll_ifindex = ifr.ifr_ifindex;
9.175 -
9.176 - //
9.177 - // Bind the socket to the interface we just found.
9.178 - //
9.179 - struct sockaddr_ll ll;
9.180 - bzero (&ll, sizeof(ll));
9.181 -
9.182 - ll.sll_family = AF_PACKET;
9.183 - ll.sll_ifindex = m_sll_ifindex;
9.184 - ll.sll_protocol = htons(ETH_P_ALL);
9.185 -
9.186 - NS_LOG_LOGIC ("Binding socket to interface");
9.187 -
9.188 - rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
9.189 - NS_ASSERT_MSG (rc != -1, "EmulatedNetDevice::StartDevice(): Can't bind to specified interface");
9.190 -
9.191 - //
9.192 - // Now spin up a read thread to read packets.
9.193 - //
9.194 - NS_ASSERT_MSG (m_readThread == 0, "EmulatedNetDevice::StartDevice(): Receive thread is already running");
9.195 -
9.196 - NS_LOG_LOGIC ("Spinning up read thread");
9.197 -
9.198 - m_readThread = Create<SystemThread> (MakeCallback (&EmulatedNetDevice::ReadThread, this));
9.199 - m_readThread->Start ();
9.200 -
9.201 - NotifyLinkUp ();
9.202 -}
9.203 -
9.204 -void
9.205 -EmulatedNetDevice::StopDevice (void)
9.206 -{
9.207 - NS_LOG_FUNCTION_NOARGS ();
9.208 -
9.209 - close (m_sock);
9.210 - m_sock = -1;
9.211 -
9.212 - NS_ASSERT_MSG (m_readThread != 0, "EmulatedNetDevice::StopDevice(): Receive thread is not running");
9.213 -
9.214 - NS_LOG_LOGIC ("Joining read thread");
9.215 - m_readThread->Join ();
9.216 - m_readThread = 0;
9.217 -}
9.218 -
9.219 -void
9.220 -EmulatedNetDevice::ForwardUp (uint8_t *buf, uint32_t len)
9.221 -{
9.222 - NS_LOG_FUNCTION (buf << len);
9.223 -
9.224 - //
9.225 - // Create a packet out of the buffer we received and free that buffer.
9.226 - //
9.227 - Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
9.228 - free (buf);
9.229 - buf = 0;
9.230 -
9.231 - //
9.232 - // Trace sinks will expect complete packets, not packets without some of the
9.233 - // headers.
9.234 - //
9.235 - Ptr<Packet> originalPacket = packet->Copy ();
9.236 -
9.237 - //
9.238 - // Checksum the packet
9.239 - //
9.240 - EthernetTrailer trailer;
9.241 - packet->RemoveTrailer (trailer);
9.242 - trailer.CheckFcs (packet);
9.243 -
9.244 - EthernetHeader header (false);
9.245 - packet->RemoveHeader (header);
9.246 -
9.247 - NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
9.248 - NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
9.249 -
9.250 - //
9.251 - // An IP host group address is mapped to an Ethernet multicast address
9.252 - // by placing the low-order 23-bits of the IP address into the low-order
9.253 - // 23 bits of the Ethernet multicast address 01-00-5E-00-00-00 (hex).
9.254 - //
9.255 - // We are going to receive all packets destined to any multicast address,
9.256 - // which means clearing the low-order 23 bits the header destination
9.257 - //
9.258 - Mac48Address mcDest;
9.259 - uint8_t mcBuf[6];
9.260 -
9.261 - header.GetDestination ().CopyTo (mcBuf);
9.262 - mcBuf[3] &= 0x80;
9.263 - mcBuf[4] = 0;
9.264 - mcBuf[5] = 0;
9.265 - mcDest.CopyFrom (mcBuf);
9.266 -
9.267 - Mac48Address multicast = Mac48Address::ConvertFrom (GetMulticast ());
9.268 - Mac48Address broadcast = Mac48Address::ConvertFrom (GetBroadcast ());
9.269 - Mac48Address destination = Mac48Address::ConvertFrom (GetAddress ());
9.270 -
9.271 - LlcSnapHeader llc;
9.272 - packet->RemoveHeader (llc);
9.273 - uint16_t protocol = llc.GetType ();
9.274 -
9.275 - PacketType packetType;
9.276 -
9.277 - if (header.GetDestination () == broadcast)
9.278 - {
9.279 - NS_LOG_LOGIC ("Pkt destination is PACKET_BROADCAST");
9.280 - packetType = NS3_PACKET_BROADCAST;
9.281 - }
9.282 - else if (mcDest == multicast)
9.283 - {
9.284 - NS_LOG_LOGIC ("Pkt destination is PACKET_MULTICAST");
9.285 - packetType = NS3_PACKET_MULTICAST;
9.286 - }
9.287 - else if (header.GetDestination () == destination)
9.288 - {
9.289 - NS_LOG_LOGIC ("Pkt destination is PACKET_HOST");
9.290 - packetType = NS3_PACKET_HOST;
9.291 - }
9.292 - else
9.293 - {
9.294 - NS_LOG_LOGIC ("Pkt destination is PACKET_OTHERHOST");
9.295 - packetType = NS3_PACKET_OTHERHOST;
9.296 - }
9.297 -
9.298 - if (!m_promiscRxCallback.IsNull ())
9.299 - {
9.300 - NS_LOG_LOGIC ("calling m_promiscRxCallback");
9.301 - m_promiscRxCallback (this, packet->Copy (), protocol, header.GetSource (), header.GetDestination (), packetType);
9.302 - }
9.303 -
9.304 - if (packetType != NS3_PACKET_OTHERHOST)
9.305 - {
9.306 - m_rxTrace (originalPacket);
9.307 - NS_LOG_LOGIC ("calling m_rxCallback");
9.308 - m_rxCallback (this, packet, protocol, header.GetSource ());
9.309 - }
9.310 -}
9.311 -
9.312 -void
9.313 -EmulatedNetDevice::ReadThread (void)
9.314 -{
9.315 - NS_LOG_FUNCTION_NOARGS ();
9.316 -
9.317 - //
9.318 - // It's important to remember that we're in a completely different thread than the simulator is running in. We
9.319 - // need to synchronize with that other thread to get the packet up into ns-3. What we will need to do is to schedule
9.320 - // a method to forward up the packet using the multithreaded simulator we are most certainly running. However, I just
9.321 - // said it -- we are talking about two threads here, so it is very, very dangerous to do any kind of reference couning
9.322 - // 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
9.323 - // buffer into the ns-3 context thread where it will create the packet.
9.324 - //
9.325 -
9.326 - int32_t len = -1;
9.327 - struct sockaddr_ll addr;
9.328 - socklen_t addrSize = sizeof (addr);
9.329 -
9.330 - for (;;)
9.331 - {
9.332 - uint32_t bufferSize = 65536;
9.333 - uint8_t *buf = (uint8_t *)malloc (bufferSize);
9.334 - NS_ASSERT_MSG (buf, "EmulatedNetDevice::ReadThread(): malloc packet buffer failed");
9.335 - NS_LOG_LOGIC ("Calling recvfrom");
9.336 - len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr, &addrSize);
9.337 -
9.338 - if (len == -1)
9.339 - {
9.340 - free (buf);
9.341 - buf = 0;
9.342 - return;
9.343 - }
9.344 -
9.345 - NS_LOG_INFO ("EmulatedNetDevice::ReadThread(): Received packet");
9.346 - NS_LOG_INFO ("EmulatedNetDevice::ReadThread(): Scheduling handler");
9.347 - DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->ScheduleRealtimeNow (
9.348 - MakeEvent (&EmulatedNetDevice::ForwardUp, this, buf, len));
9.349 - buf = 0;
9.350 - }
9.351 -}
9.352 -
9.353 -bool
9.354 -EmulatedNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
9.355 -{
9.356 - NS_LOG_FUNCTION (packet << dest << protocolNumber);
9.357 - //
9.358 - // The immediate questions here are how are we going to encapsulate packets and what do we use as the MAC source and
9.359 - // destination (hardware) addresses?
9.360 - //
9.361 - // If we return false from EmulatedNetDevice::NeedsArp, the ArpIpv4Interface will pass the broadcast address as the
9.362 - // hardware (Ethernet) destination by default. If we return true from EmulatedNetDevice::NeedsArp, then the hardware
9.363 - // destination is actually meaningful, but we'll have an ns-3 ARP running on this device. There can also be an ARP
9.364 - // running on the underlying OS so we have to be very careful, both about multiple ARPs and also about TCP, UDP, etc.
9.365 - //
9.366 - // We are operating in promiscuous mode on the receive side (all ns-3 net devices are required to implement the
9.367 - // promiscuous callback in a meaningful way), so we have an option regarding the hardware addresses. We don't actually have
9.368 - // to use the real hardware addresses and IP addresses of the underlying system. We can completely use MAC-spoofing to
9.369 - // fake out the OS by using the ns-3 assigned MAC address (and also the ns-3 assigned IP addresses). Ns-3 starts its
9.370 - // MAC address allocation using the OUI (vendor-code) 00:00:00 which is unassigned to any organization and is a globally
9.371 - // administered address, so there shouldn't be any collisions with real hardware.
9.372 - //
9.373 - // So what we do is we return true from EmulatedNetDevice::NeedsArp which tells ns-3 to use its own ARP. We spoof the
9.374 - // MAC address of the device and use promiscuous mode to receive traffic destined to that address.
9.375 - //
9.376 - return SendFrom (packet, m_address, dest, protocolNumber);
9.377 -}
9.378 -
9.379 -bool
9.380 -EmulatedNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &dest, uint16_t protocolNumber)
9.381 -{
9.382 - NS_LOG_FUNCTION (packet << src << dest << protocolNumber);
9.383 -
9.384 - if (IsLinkUp () == false)
9.385 - {
9.386 - NS_LOG_LOGIC ("Link is down, returning");
9.387 - return false;
9.388 - }
9.389 -
9.390 - Mac48Address destination = Mac48Address::ConvertFrom (dest);
9.391 - Mac48Address source = Mac48Address::ConvertFrom (src);
9.392 -
9.393 - NS_LOG_LOGIC ("Transmit packet with UID " << packet->GetUid ());
9.394 - NS_LOG_LOGIC ("Transmit packet from " << source);
9.395 - NS_LOG_LOGIC ("Transmit packet to " << destination);
9.396 -
9.397 -#if 0
9.398 - {
9.399 - struct ifreq ifr;
9.400 - bzero (&ifr, sizeof(ifr));
9.401 - strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
9.402 -
9.403 - NS_LOG_LOGIC ("Getting MAC address");
9.404 - int32_t rc = ioctl (m_sock, SIOCGIFHWADDR, &ifr);
9.405 - NS_ASSERT_MSG (rc != -1, "EmulatedNetDevice::SendFrom(): Can't get MAC address");
9.406 -
9.407 - std::ostringstream oss;
9.408 - oss << std::hex <<
9.409 - (ifr.ifr_hwaddr.sa_data[0] & 0xff) << ":" <<
9.410 - (ifr.ifr_hwaddr.sa_data[1] & 0xff) << ":" <<
9.411 - (ifr.ifr_hwaddr.sa_data[2] & 0xff) << ":" <<
9.412 - (ifr.ifr_hwaddr.sa_data[3] & 0xff) << ":" <<
9.413 - (ifr.ifr_hwaddr.sa_data[4] & 0xff) << ":" <<
9.414 - (ifr.ifr_hwaddr.sa_data[5] & 0xff) << std::dec;
9.415 -
9.416 - NS_LOG_LOGIC ("Fixup source to HW MAC " << oss.str ());
9.417 - source = Mac48Address (oss.str ().c_str ());
9.418 - NS_LOG_LOGIC ("source now " << source);
9.419 - }
9.420 -#endif
9.421 -
9.422 - LlcSnapHeader llc;
9.423 - llc.SetType (protocolNumber);
9.424 - packet->AddHeader (llc);
9.425 -
9.426 - EthernetHeader header (false);
9.427 - header.SetSource (source);
9.428 - header.SetDestination (destination);
9.429 - header.SetLengthType (packet->GetSize ());
9.430 - packet->AddHeader (header);
9.431 -
9.432 - EthernetTrailer trailer;
9.433 - trailer.CalcFcs (packet);
9.434 - packet->AddTrailer (trailer);
9.435 -
9.436 - //
9.437 - // Enqueue and dequeue the packet to hit the tracing hooks.
9.438 - //
9.439 - m_queue->Enqueue (packet);
9.440 - packet = m_queue->Dequeue ();
9.441 -
9.442 - struct sockaddr_ll ll;
9.443 - bzero (&ll, sizeof (ll));
9.444 -
9.445 - ll.sll_family = AF_PACKET;
9.446 - ll.sll_ifindex = m_sll_ifindex;
9.447 - ll.sll_protocol = htons(ETH_P_ALL);
9.448 -
9.449 - NS_LOG_LOGIC ("calling sendto");
9.450 -
9.451 - int32_t rc;
9.452 - rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
9.453 -
9.454 - NS_LOG_LOGIC ("sendto returns " << rc);
9.455 -
9.456 - return rc == -1 ? false : true;
9.457 -}
9.458 -
9.459 -void
9.460 -EmulatedNetDevice::SetDataRate(DataRate bps)
9.461 -{
9.462 - NS_LOG_FUNCTION (this << bps);
9.463 - NS_ASSERT_MSG (false, "EmulatedNetDevice::SetDataRate(): Unable.");
9.464 -}
9.465 -
9.466 -void
9.467 -EmulatedNetDevice::SetQueue (Ptr<Queue> q)
9.468 -{
9.469 - NS_LOG_FUNCTION (this << q);
9.470 - m_queue = q;
9.471 -}
9.472 -
9.473 -Ptr<Queue>
9.474 -EmulatedNetDevice::GetQueue(void) const
9.475 -{
9.476 - NS_LOG_FUNCTION_NOARGS ();
9.477 - return m_queue;
9.478 -}
9.479 -
9.480 -void
9.481 -EmulatedNetDevice::NotifyLinkUp (void)
9.482 -{
9.483 - m_linkUp = true;
9.484 - if (!m_linkChangeCallback.IsNull ())
9.485 - {
9.486 - m_linkChangeCallback ();
9.487 - }
9.488 -}
9.489 -
9.490 -void
9.491 -EmulatedNetDevice::SetName(const std::string name)
9.492 -{
9.493 - m_name = name;
9.494 -}
9.495 -
9.496 -std::string
9.497 -EmulatedNetDevice::GetName(void) const
9.498 -{
9.499 - return m_name;
9.500 -}
9.501 -
9.502 -void
9.503 -EmulatedNetDevice::SetIfIndex(const uint32_t index)
9.504 -{
9.505 - m_ifIndex = index;
9.506 -}
9.507 -
9.508 -uint32_t
9.509 -EmulatedNetDevice::GetIfIndex(void) const
9.510 -{
9.511 - return m_ifIndex;
9.512 -}
9.513 -
9.514 -Ptr<Channel>
9.515 -EmulatedNetDevice::GetChannel (void) const
9.516 -{
9.517 - NS_ASSERT_MSG (false, "EmulatedNetDevice::GetChannel(): Unable.");
9.518 - return 0;
9.519 -}
9.520 -
9.521 -void
9.522 -EmulatedNetDevice::SetAddress (Mac48Address addr)
9.523 -{
9.524 - NS_LOG_FUNCTION (addr);
9.525 - m_address = addr;
9.526 -}
9.527 -
9.528 -Address
9.529 -EmulatedNetDevice::GetAddress (void) const
9.530 -{
9.531 - NS_LOG_FUNCTION_NOARGS ();
9.532 - return m_address;
9.533 -}
9.534 -
9.535 -bool
9.536 -EmulatedNetDevice::SetMtu (const uint16_t mtu)
9.537 -{
9.538 - NS_ASSERT_MSG (false, "EmulatedNetDevice::SetMtu(): Unable.");
9.539 - return false;
9.540 -}
9.541 -
9.542 -uint16_t
9.543 -EmulatedNetDevice::GetMtu (void) const
9.544 -{
9.545 - struct ifreq ifr;
9.546 - bzero (&ifr, sizeof (ifr));
9.547 - strcpy(ifr.ifr_name, m_deviceName.c_str ());
9.548 -
9.549 - int32_t fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
9.550 -
9.551 - int32_t rc = ioctl(fd, SIOCGIFMTU, &ifr);
9.552 - NS_ASSERT_MSG (rc != -1, "EmulatedNetDevice::GetMtu(): Can't ioctl SIOCGIFMTU");
9.553 -
9.554 - close (fd);
9.555 -
9.556 - return ifr.ifr_mtu;
9.557 -}
9.558 -
9.559 -bool
9.560 -EmulatedNetDevice::IsLinkUp (void) const
9.561 -{
9.562 - return m_linkUp;
9.563 -}
9.564 -
9.565 -void
9.566 -EmulatedNetDevice::SetLinkChangeCallback (Callback<void> callback)
9.567 -{
9.568 - m_linkChangeCallback = callback;
9.569 -}
9.570 -
9.571 -bool
9.572 -EmulatedNetDevice::IsBroadcast (void) const
9.573 -{
9.574 - return true;
9.575 -}
9.576 -
9.577 -Address
9.578 -EmulatedNetDevice::GetBroadcast (void) const
9.579 -{
9.580 - return Mac48Address ("ff:ff:ff:ff:ff:ff");
9.581 -}
9.582 -
9.583 -bool
9.584 -EmulatedNetDevice::IsMulticast (void) const
9.585 -{
9.586 - return false;
9.587 -}
9.588 -
9.589 -Address
9.590 -EmulatedNetDevice::GetMulticast (void) const
9.591 -{
9.592 - return Mac48Address ("01:00:5e:00:00:00");
9.593 -}
9.594 -
9.595 -Address
9.596 -EmulatedNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const
9.597 -{
9.598 - return Mac48Address ("01:00:5e:00:00:00");
9.599 -}
9.600 -
9.601 -bool
9.602 -EmulatedNetDevice::IsPointToPoint (void) const
9.603 -{
9.604 - return false;
9.605 -}
9.606 -
9.607 -void
9.608 -EmulatedNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
9.609 -{
9.610 - NS_ASSERT_MSG (false, "EmulatedNetDevice::SetPromiscReceiveCallback(): Not implemented");
9.611 -}
9.612 -
9.613 - bool
9.614 -EmulatedNetDevice::SupportsSendFrom () const
9.615 -{
9.616 - NS_LOG_FUNCTION_NOARGS ();
9.617 - return true;
9.618 -}
9.619 -
9.620 -
9.621 -Ptr<Node>
9.622 -EmulatedNetDevice::GetNode (void) const
9.623 -{
9.624 - return m_node;
9.625 -}
9.626 -
9.627 -void
9.628 -EmulatedNetDevice::SetNode (Ptr<Node> node)
9.629 -{
9.630 - m_node = node;
9.631 -}
9.632 -
9.633 -bool
9.634 -EmulatedNetDevice::NeedsArp (void) const
9.635 -{
9.636 - return true;
9.637 -}
9.638 -
9.639 -void
9.640 -EmulatedNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
9.641 -{
9.642 - m_rxCallback = cb;
9.643 -}
9.644 -
9.645 -} // namespace ns3
10.1 --- a/src/devices/emulated/emulated-net-device.h Wed Oct 29 11:49:21 2008 -0700
10.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
10.3 @@ -1,321 +0,0 @@
10.4 -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
10.5 -/*
10.6 - * Copyright (c) 2008 University of Washington
10.7 - *
10.8 - * This program is free software; you can redistribute it and/or modify
10.9 - * it under the terms of the GNU General Public License version 2 as
10.10 - * published by the Free Software Foundation;
10.11 - *
10.12 - * This program is distributed in the hope that it will be useful,
10.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
10.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10.15 - * GNU General Public License for more details.
10.16 - *
10.17 - * You should have received a copy of the GNU General Public License
10.18 - * along with this program; if not, write to the Free Software
10.19 - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
10.20 - */
10.21 -
10.22 -#ifndef EMULATED_NET_DEVICE_H
10.23 -#define EMULATED_NET_DEVICE_H
10.24 -
10.25 -#include <string.h>
10.26 -#include "ns3/address.h"
10.27 -#include "ns3/net-device.h"
10.28 -#include "ns3/node.h"
10.29 -#include "ns3/callback.h"
10.30 -#include "ns3/packet.h"
10.31 -#include "ns3/traced-callback.h"
10.32 -#include "ns3/event-id.h"
10.33 -#include "ns3/nstime.h"
10.34 -#include "ns3/data-rate.h"
10.35 -#include "ns3/ptr.h"
10.36 -#include "ns3/mac48-address.h"
10.37 -#include "ns3/system-thread.h"
10.38 -
10.39 -namespace ns3 {
10.40 -
10.41 -class Queue;
10.42 -
10.43 -/**
10.44 - * \class EmulatedNetDevice
10.45 - * \brief A Device for an Emulated Network Link.
10.46 - */
10.47 -class EmulatedNetDevice : public NetDevice
10.48 -{
10.49 -public:
10.50 - static TypeId GetTypeId (void);
10.51 -
10.52 - /**
10.53 - * Construct a EmulatedNetDevice
10.54 - *
10.55 - * This is the constructor for the EmulatedNetDevice. It takes as a
10.56 - */
10.57 - EmulatedNetDevice ();
10.58 -
10.59 - /**
10.60 - * Destroy a EmulatedNetDevice
10.61 - *
10.62 - * This is the destructor for the EmulatedNetDevice.
10.63 - */
10.64 - virtual ~EmulatedNetDevice ();
10.65 -
10.66 - /**
10.67 - * Set the Data Rate used for transmission of packets.
10.68 - *
10.69 - * @see Attach ()
10.70 - * @param bps the data rate at which this object operates
10.71 - */
10.72 - void SetDataRate (DataRate bps);
10.73 -
10.74 - /**
10.75 - * Set the inteframe gap used to separate packets. The interframe gap
10.76 - * defines the minimum space required between packets sent by this device.
10.77 - *
10.78 - * @param t the interframe gap time
10.79 - */
10.80 - void SetInterframeGap (Time t);
10.81 -
10.82 - /**
10.83 - * Set a start time for the device.
10.84 - *
10.85 - * @param tStart the start time
10.86 - */
10.87 - void Start (Time tStart);
10.88 -
10.89 - /**
10.90 - * Set a stop time for the device.
10.91 - *
10.92 - * @param tStop the stop time
10.93 - */
10.94 - void Stop (Time tStop);
10.95 -
10.96 - /**
10.97 - * Attach a queue to the EmulatedNetDevice.
10.98 - *
10.99 - * The EmulatedNetDevice "owns" a queue that implements a queueing
10.100 - * method such as DropTail or RED.
10.101 - *
10.102 - * @see Queue
10.103 - * @see DropTailQueue
10.104 - * @param queue Ptr to the new queue.
10.105 - */
10.106 - void SetQueue (Ptr<Queue> queue);
10.107 -
10.108 - /**
10.109 - * Receive a packet.
10.110 - *
10.111 - * The EmulatedNetDevice receives packets from its socket reader
10.112 - * and forwards them up the protocol stack. This is the public method
10.113 - * used by the reader to indicate that a packet has arrived at the device.
10.114 - *
10.115 - * @param p Ptr to the received packet.
10.116 - */
10.117 - void Receive (Ptr<Packet> p);
10.118 -
10.119 - /**
10.120 - * Assign a MAC address to this device.
10.121 - *
10.122 - * @see Mac48Address
10.123 - * @param addr The new address.
10.124 - */
10.125 - void SetAddress (Mac48Address addr);
10.126 -
10.127 -//
10.128 -// Pure virtual methods inherited from NetDevice we must implement.
10.129 -//
10.130 - virtual void SetName(const std::string name);
10.131 - virtual std::string GetName(void) const;
10.132 -
10.133 - virtual void SetIfIndex(const uint32_t index);
10.134 - virtual uint32_t GetIfIndex(void) const;
10.135 -
10.136 - virtual Ptr<Channel> GetChannel (void) const;
10.137 - virtual Address GetAddress (void) const;
10.138 -
10.139 - virtual bool SetMtu (const uint16_t mtu);
10.140 - virtual uint16_t GetMtu (void) const;
10.141 -
10.142 - virtual bool IsLinkUp (void) const;
10.143 -
10.144 - virtual void SetLinkChangeCallback (Callback<void> callback);
10.145 -
10.146 - virtual bool IsBroadcast (void) const;
10.147 - virtual Address GetBroadcast (void) const;
10.148 -
10.149 - virtual bool IsMulticast (void) const;
10.150 - virtual Address GetMulticast (void) const;
10.151 - virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
10.152 -
10.153 - virtual bool IsPointToPoint (void) const;
10.154 -
10.155 - virtual bool Send(Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber);
10.156 -
10.157 - virtual bool SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
10.158 -
10.159 - virtual Ptr<Node> GetNode (void) const;
10.160 - virtual void SetNode (Ptr<Node> node);
10.161 -
10.162 - virtual bool NeedsArp (void) const;
10.163 -
10.164 - virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
10.165 - virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb);
10.166 -
10.167 - virtual bool SupportsSendFrom (void) const;
10.168 -
10.169 -private:
10.170 -
10.171 - virtual void DoDispose (void);
10.172 -
10.173 - /**
10.174 - * Get a copy of the attached Queue.
10.175 - *
10.176 - * This method is provided for any derived class that may need to get
10.177 - * direct access to the underlying queue.
10.178 - *
10.179 - * @returns Ptr to the queue.
10.180 - */
10.181 - Ptr<Queue> GetQueue(void) const;
10.182 -
10.183 - /**
10.184 - * Spin up the device
10.185 - */
10.186 - void StartDevice (void);
10.187 -
10.188 - /**
10.189 - * Tear down the device
10.190 - */
10.191 - void StopDevice (void);
10.192 -
10.193 - /**
10.194 - * Loop to read and process packets
10.195 - */
10.196 - void ReadThread (void);
10.197 -
10.198 - /**
10.199 - * Method to handle received packets. Synchronized with simulator via ScheduleNow from ReadThread.
10.200 - */
10.201 - void ForwardUp (uint8_t *buf, uint32_t len);
10.202 -
10.203 - /**
10.204 - * Adds the necessary headers and trailers to a packet of data in order to
10.205 - * respect the protocol implemented by the agent.
10.206 - */
10.207 - void AddHeader(Ptr<Packet> p, uint16_t protocolNumber);
10.208 -
10.209 - /**
10.210 - * Removes, from a packet of data, all headers and trailers that
10.211 - * relate to the protocol implemented by the agent
10.212 - * \return Returns true if the packet should be forwarded up the
10.213 - * protocol stack.
10.214 - */
10.215 - bool ProcessHeader(Ptr<Packet> p, uint16_t& param);
10.216 -
10.217 - /**
10.218 - * Start Sending a Packet Down the Wire.
10.219 - *
10.220 - * @returns true if success, false on failure
10.221 - */
10.222 - bool TransmitStart (Ptr<Packet> p);
10.223 -
10.224 - void NotifyLinkUp (void);
10.225 -
10.226 - /**
10.227 - * The Queue which this EmulatedNetDevice uses as a packet source.
10.228 - * Management of this Queue has been delegated to the EmulatedNetDevice
10.229 - * and it has the responsibility for deletion.
10.230 - * @see class Queue
10.231 - * @see class DropTailQueue
10.232 - */
10.233 - Ptr<Queue> m_queue;
10.234 -
10.235 - /**
10.236 - * The trace source for the packet reception events that the device can
10.237 - * fire.
10.238 - *
10.239 - * @see class CallBackTraceSource
10.240 - */
10.241 - TracedCallback<Ptr<const Packet> > m_rxTrace;
10.242 -
10.243 - /**
10.244 - * The trace source for the packet drop events that the device can
10.245 - * fire.
10.246 - *
10.247 - * @see class CallBackTraceSource
10.248 - */
10.249 - TracedCallback<Ptr<const Packet> > m_dropTrace;
10.250 -
10.251 - /**
10.252 - * Time to start spinning up the device
10.253 - */
10.254 - Time m_tStart;
10.255 -
10.256 - /**
10.257 - * Time to start tearing down the device
10.258 - */
10.259 - Time m_tStop;
10.260 -
10.261 - EventId m_startEvent;
10.262 - EventId m_stopEvent;
10.263 -
10.264 - int32_t m_sock;
10.265 -
10.266 - Ptr<SystemThread> m_readThread;
10.267 -
10.268 - /**
10.269 - * The Node to which this device is attached.
10.270 - */
10.271 - Ptr<Node> m_node;
10.272 -
10.273 - /**
10.274 - * The MAC address which has been assigned to this device.
10.275 - */
10.276 - Mac48Address m_address;
10.277 -
10.278 - /**
10.279 - * The callback used to notify higher layers that a packet has been received.
10.280 - */
10.281 - NetDevice::ReceiveCallback m_rxCallback;
10.282 -
10.283 - /**
10.284 - * The callback used to notify higher layers that a packet has been received in promiscuous mode.
10.285 - */
10.286 - NetDevice::PromiscReceiveCallback m_promiscRxCallback;
10.287 -
10.288 - /**
10.289 - * The ns-3 interface index (in the sense of net device index) that has been assigned to this network device.
10.290 - */
10.291 - uint32_t m_ifIndex;
10.292 -
10.293 - /**
10.294 - * The Unix interface index that we got from the system and which corresponds to the interface (e.g., "eth1")
10.295 - * we are using to talk to the network. Valid when m_sock is valid.
10.296 - */
10.297 - int32_t m_sll_ifindex;
10.298 -
10.299 - /**
10.300 - * The human readable name of this device.
10.301 - */
10.302 - std::string m_name;
10.303 -
10.304 - /**
10.305 - * Flag indicating whether or not the link is up. In this case,
10.306 - * whether or not the device is connected to a channel.
10.307 - */
10.308 - bool m_linkUp;
10.309 -
10.310 - /**
10.311 - * Callback to fire if the link changes state (up or down).
10.312 - */
10.313 - Callback<void> m_linkChangeCallback;
10.314 -
10.315 - /**
10.316 - * The unix/linux name of the underlying device (e.g., eth0)
10.317 - */
10.318 - std::string m_deviceName;
10.319 -};
10.320 -
10.321 -} // namespace ns3
10.322 -
10.323 -#endif // EMULATED_NET_DEVICE_H
10.324 -
11.1 --- a/src/devices/emulated/emulated.h Wed Oct 29 11:49:21 2008 -0700
11.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
11.3 @@ -1,10 +0,0 @@
11.4 -/**
11.5 - * \ingroup devices
11.6 - * \defgroup Emulated Emulated Net Device Model
11.7 - *
11.8 - * \section Emulated Net Device Model
11.9 - *
11.10 - * This is a description of the emulated network device model.
11.11 - *
11.12 - * It is very detailed and comprehensive and answers all possible questions.
11.13 - */
12.1 --- a/src/devices/emulated/waf Wed Oct 29 11:49:21 2008 -0700
12.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
12.3 @@ -1,1 +0,0 @@
12.4 -exec "`dirname "$0"`"/../../../waf "$@"
13.1 --- a/src/devices/emulated/wscript Wed Oct 29 11:49:21 2008 -0700
13.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
13.3 @@ -1,14 +0,0 @@
13.4 -## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
13.5 -
13.6 -
13.7 -def build(bld):
13.8 - module = bld.create_ns3_module('emulated', ['node'])
13.9 - module.source = [
13.10 - 'emulated-net-device.cc',
13.11 - ]
13.12 - headers = bld.create_obj('ns3header')
13.13 - headers.module = 'emulated'
13.14 - headers.source = [
13.15 - 'emulated-net-device.h',
13.16 - ]
13.17 -
14.1 --- a/src/helper/emu-helper.cc Wed Oct 29 11:49:21 2008 -0700
14.2 +++ b/src/helper/emu-helper.cc Wed Oct 29 22:39:36 2008 -0700
14.3 @@ -22,7 +22,7 @@
14.4 #include "ns3/simulator.h"
14.5 #include "ns3/object-factory.h"
14.6 #include "ns3/queue.h"
14.7 -#include "ns3/emulated-net-device.h"
14.8 +#include "ns3/emu-net-device.h"
14.9 #include "ns3/pcap-writer.h"
14.10 #include "ns3/config.h"
14.11 #include "ns3/packet.h"
14.12 @@ -37,7 +37,7 @@
14.13 {
14.14 NS_LOG_FUNCTION_NOARGS ();
14.15 m_queueFactory.SetTypeId ("ns3::DropTailQueue");
14.16 - m_deviceFactory.SetTypeId ("ns3::EmulatedNetDevice");
14.17 + m_deviceFactory.SetTypeId ("ns3::EmuNetDevice");
14.18 }
14.19
14.20 void
14.21 @@ -78,13 +78,13 @@
14.22
14.23 oss.str ("");
14.24 oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
14.25 - "/$ns3::EmulatedNetDevice/Rx";
14.26 + "/$ns3::EmuNetDevice/Rx";
14.27 Config::ConnectWithoutContext (oss.str (),
14.28 MakeBoundCallback (&EmuHelper::RxEvent, pcap));
14.29
14.30 oss.str ("");
14.31 oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
14.32 - "/$ns3::EmulatedNetDevice/TxQueue/Enqueue";
14.33 + "/$ns3::EmuNetDevice/TxQueue/Enqueue";
14.34 Config::ConnectWithoutContext (oss.str (),
14.35 MakeBoundCallback (&EmuHelper::EnqueueEvent, pcap));
14.36 }
14.37 @@ -131,25 +131,25 @@
14.38 std::ostringstream oss;
14.39
14.40 oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
14.41 - "/$ns3::EmulatedNetDevice/Rx";
14.42 + "/$ns3::EmuNetDevice/Rx";
14.43 Config::Connect (oss.str (),
14.44 MakeBoundCallback (&EmuHelper::AsciiRxEvent, &os));
14.45
14.46 oss.str ("");
14.47 oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
14.48 - "/$ns3::EmulatedNetDevice/TxQueue/Enqueue";
14.49 + "/$ns3::EmuNetDevice/TxQueue/Enqueue";
14.50 Config::Connect (oss.str (),
14.51 MakeBoundCallback (&EmuHelper::AsciiEnqueueEvent, &os));
14.52
14.53 oss.str ("");
14.54 oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
14.55 - "/$ns3::EmulatedNetDevice/TxQueue/Dequeue";
14.56 + "/$ns3::EmuNetDevice/TxQueue/Dequeue";
14.57 Config::Connect (oss.str (),
14.58 MakeBoundCallback (&EmuHelper::AsciiDequeueEvent, &os));
14.59
14.60 oss.str ("");
14.61 oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid <<
14.62 - "/$ns3::EmulatedNetDevice/TxQueue/Drop";
14.63 + "/$ns3::EmuNetDevice/TxQueue/Drop";
14.64 Config::Connect (oss.str (),
14.65 MakeBoundCallback (&EmuHelper::AsciiDropEvent, &os));
14.66 }
14.67 @@ -197,7 +197,7 @@
14.68 {
14.69 Ptr<Node> node = *i;
14.70
14.71 - Ptr<EmulatedNetDevice> device = m_deviceFactory.Create<EmulatedNetDevice> ();
14.72 + Ptr<EmuNetDevice> device = m_deviceFactory.Create<EmuNetDevice> ();
14.73 //
14.74 // This is a mac address used for ns-3 internal things. It cannot override the real MAC address on the NIC in
14.75 // question.
15.1 --- a/src/helper/emu-helper.h Wed Oct 29 11:49:21 2008 -0700
15.2 +++ b/src/helper/emu-helper.h Wed Oct 29 22:39:36 2008 -0700
15.3 @@ -25,7 +25,7 @@
15.4 #include "ns3/object-factory.h"
15.5 #include "ns3/net-device-container.h"
15.6 #include "ns3/node-container.h"
15.7 -#include "ns3/emulated-net-device.h"
15.8 +#include "ns3/emu-net-device.h"
15.9
15.10 namespace ns3 {
15.11
16.1 --- a/src/wscript Wed Oct 29 11:49:21 2008 -0700
16.2 +++ b/src/wscript Wed Oct 29 22:39:36 2008 -0700
16.3 @@ -21,7 +21,7 @@
16.4 'devices/csma',
16.5 'devices/bridge',
16.6 'devices/tap',
16.7 - 'devices/emulated',
16.8 + 'devices/emu',
16.9 'applications/onoff',
16.10 'applications/packet-sink',
16.11 'applications/udp-echo',