--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/host-tap-net-device.cc Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,194 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "host-tap-net-device.h"
+#include "ns3/node.h"
+#include "ns3/tap-channel.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("HostTapNetDevice");
+
+namespace ns3 {
+
+TypeId
+HostTapNetDevice::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::HostTapNetDevice")
+ .SetParent<NetDevice> ()
+ .AddConstructor<HostTapNetDevice> ()
+ ;
+ return tid;
+}
+
+HostTapNetDevice::HostTapNetDevice ()
+ : m_node (0),
+ m_mtu (0xffff),
+ m_name (""),
+ m_ifIndex (0)
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+HostTapNetDevice::SetChannel (Ptr<TapChannel> channel)
+{
+ m_channel = channel;
+ m_channel->SetHostDevice (this);
+}
+
+void
+HostTapNetDevice::SetAddress (Mac48Address address)
+{
+ m_address = address;
+}
+
+Mac48Address
+HostTapNetDevice::GetMacAddress (void) const
+{
+ return m_address;
+}
+
+void
+HostTapNetDevice::SetName(const std::string name)
+{
+ m_name = name;
+}
+std::string
+HostTapNetDevice::GetName(void) const
+{
+ return m_name;
+}
+void
+HostTapNetDevice::SetIfIndex(const uint32_t index)
+{
+ m_ifIndex = index;
+}
+uint32_t
+HostTapNetDevice::GetIfIndex(void) const
+{
+ return m_ifIndex;
+}
+Ptr<Channel>
+HostTapNetDevice::GetChannel (void) const
+{
+ return m_channel;
+}
+Address
+HostTapNetDevice::GetAddress (void) const
+{
+ return m_address;
+}
+bool
+HostTapNetDevice::SetMtu (const uint16_t mtu)
+{
+ m_mtu = mtu;
+ return true;
+}
+uint16_t
+HostTapNetDevice::GetMtu (void) const
+{
+ return m_mtu;
+}
+bool
+HostTapNetDevice::IsLinkUp (void) const
+{
+ return true;
+}
+void
+HostTapNetDevice::SetLinkChangeCallback (Callback<void> callback)
+{}
+bool
+HostTapNetDevice::IsBroadcast (void) const
+{
+ return true;
+}
+Address
+HostTapNetDevice::GetBroadcast (void) const
+{
+ return Mac48Address ("ff:ff:ff:ff:ff:ff");
+}
+bool
+HostTapNetDevice::IsMulticast (void) const
+{
+ return true;
+}
+Address
+HostTapNetDevice::GetMulticast (void) const
+{
+ return Mac48Address::GetMulticastPrefix ();
+}
+Address
+HostTapNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const
+{
+ return Mac48Address::GetMulticast (multicastGroup);
+}
+bool
+HostTapNetDevice::IsPointToPoint (void) const
+{
+ return false;
+}
+bool
+HostTapNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
+{
+ return false;
+}
+bool
+HostTapNetDevice::SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber)
+{
+ return false;
+}
+Ptr<Node>
+HostTapNetDevice::GetNode (void) const
+{
+ return m_node;
+}
+void
+HostTapNetDevice::SetNode (Ptr<Node> node)
+{
+ m_node = node;
+}
+bool
+HostTapNetDevice::NeedsArp (void) const
+{
+ return false;
+}
+void
+HostTapNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
+{}
+
+void
+HostTapNetDevice::DoDispose (void)
+{
+ NS_LOG_FUNCTION (this);
+ m_node = 0;
+ m_channel = 0;
+ NetDevice::DoDispose ();
+}
+
+void
+HostTapNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
+{}
+
+bool
+HostTapNetDevice::SupportsSendFrom (void) const
+{
+ return false;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/host-tap-net-device.h Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,90 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef HOST_TAP_NET_DEVICE_H
+#define HOST_TAP_NET_DEVICE_H
+
+#include "ns3/net-device.h"
+#include "ns3/mac48-address.h"
+#include "ns3/traced-callback.h"
+#include <stdint.h>
+#include <string>
+
+namespace ns3 {
+
+class Node;
+class TapChannel;
+
+
+/**
+ * \ingroup netdevice
+ *
+ * \brief a NetDevice to get packets to and from a host tap device.
+ */
+class HostTapNetDevice : public NetDevice
+{
+public:
+ static TypeId GetTypeId (void);
+ HostTapNetDevice ();
+
+ void SetAddress (Mac48Address address);
+ void SetChannel (Ptr<TapChannel> channel);
+
+ Mac48Address GetMacAddress (void) const;
+
+ // inherited from NetDevice base class.
+ virtual void SetName(const std::string name);
+ virtual std::string GetName(void) const;
+ virtual void SetIfIndex(const uint32_t index);
+ virtual uint32_t GetIfIndex(void) const;
+ virtual Ptr<Channel> GetChannel (void) const;
+ virtual Address GetAddress (void) const;
+ virtual bool SetMtu (const uint16_t mtu);
+ virtual uint16_t GetMtu (void) const;
+ virtual bool IsLinkUp (void) const;
+ virtual void SetLinkChangeCallback (Callback<void> callback);
+ virtual bool IsBroadcast (void) const;
+ virtual Address GetBroadcast (void) const;
+ virtual bool IsMulticast (void) const;
+ virtual Address GetMulticast (void) const;
+ virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+ virtual bool IsPointToPoint (void) const;
+ virtual bool Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
+ virtual bool SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
+ virtual Ptr<Node> GetNode (void) const;
+ virtual void SetNode (Ptr<Node> node);
+ virtual bool NeedsArp (void) const;
+ virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
+ virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb);
+ virtual bool SupportsSendFrom (void) const;
+
+protected:
+ virtual void DoDispose (void);
+private:
+ Ptr<Node> m_node;
+ uint16_t m_mtu;
+ std::string m_name;
+ uint32_t m_ifIndex;
+ Mac48Address m_address;
+ Ptr<TapChannel> m_channel;
+};
+
+} // namespace ns3
+
+#endif /* HOST_TAP_NET_DEVICE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/tap-channel.cc Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,61 @@
+#include "tap-channel.h"
+#include "host-tap-net-device.h"
+#include "tap-net-device.h"
+
+namespace ns3 {
+
+
+TapChannel::TapChannel ()
+ : m_hostDevice (0),
+ m_device (0)
+{}
+
+void
+TapChannel::DoDispose (void)
+{
+ m_device = 0;
+ m_hostDevice = 0;
+ Channel::DoDispose ();
+}
+
+void
+TapChannel::SetDevice (Ptr<TapNetDevice> device)
+{
+ m_device = device;
+}
+
+void
+TapChannel::SetHostDevice (Ptr<HostTapNetDevice> device)
+{
+ m_hostDevice = device;
+}
+
+Ptr<HostTapNetDevice>
+TapChannel::GetHostDevice (void) const
+{
+ return m_hostDevice;
+}
+
+uint32_t
+TapChannel::GetNDevices (void) const
+{
+ return 2;
+}
+Ptr<NetDevice>
+TapChannel::GetDevice (uint32_t i) const
+{
+ if (i == 0)
+ {
+ return m_device;
+ }
+ else if (i == 1)
+ {
+ return m_hostDevice;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/tap-channel.h Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,36 @@
+#ifndef TAP_CHANNEL_H
+#define TAP_CHANNEL_H
+
+#include "ns3/channel.h"
+
+namespace ns3 {
+
+class HostTapNetDevice;
+class TapNetDevice;
+class NetDevice;
+
+
+class TapChannel : public Channel
+{
+public:
+ TapChannel ();
+
+ void SetHostDevice (Ptr<HostTapNetDevice> device);
+ void SetDevice (Ptr<TapNetDevice> device);
+
+ Ptr<HostTapNetDevice> GetHostDevice (void) const;
+
+ // overriden from Channel base class
+ virtual uint32_t GetNDevices (void) const;
+ virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
+
+private:
+ virtual void DoDispose (void);
+
+ Ptr<HostTapNetDevice> m_hostDevice;
+ Ptr<TapNetDevice> m_device;
+};
+
+} // namespace ns3
+
+#endif /* TAP_CHANNEL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/tap-manager-client.cc Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,180 @@
+#include "tap-manager-client.h"
+#include "ns3/log.h"
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <linux/un.h>
+#include <errno.h>
+#include <string.h>
+#include <iomanip>
+#include <iostream>
+#include <list>
+
+
+NS_LOG_COMPONENT_DEFINE("TapManagerClient");
+
+#define TAP_MANAGER "ns3-tap-manager"
+
+namespace ns3 {
+
+static std::string
+EncodeAsString (struct sockaddr_un un, int len)
+{
+ uint8_t *buffer = (uint8_t *)&un;
+ std::ostringstream oss;
+ oss.setf (std::ios::hex, std::ios::basefield);
+ oss.fill('0');
+ for (uint8_t i = 0; i < len; i++)
+ {
+ oss << ":" << std::setw (2) << (uint32_t)buffer[i];
+ }
+ return oss.str ();
+}
+
+bool
+TapManagerClient::Exists (std::string filename) const
+{
+ struct stat st;
+ int retval = ::stat (filename.c_str (), &st);
+ return retval == 0;
+}
+
+std::string
+TapManagerClient::FindManager (void) const
+{
+ std::list<std::string> locations;
+ locations.push_back ("./src/devices/tap");
+ locations.push_back ("./build/debug/src/devices/tap");
+ locations.push_back ("./build/optimized/src/devices/tap");
+ for (std::list<std::string>::const_iterator i = locations.begin (); i != locations.end (); ++i)
+ {
+ if (Exists (*i + "/" + TAP_MANAGER))
+ {
+ return *i + "/" + TAP_MANAGER;
+ }
+ }
+ NS_FATAL_ERROR ("Could not find manager");
+ return ""; // quiet compiler
+}
+
+int
+TapManagerClient::AllocateTap (Mac48Address host, Ipv4Address ad, Ipv4Mask mask, Ipv4Address gateway)
+{
+ NS_LOG_FUNCTION (host << ad << mask << gateway);
+ // create a socket to get information back from the tap manager.
+ int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
+ if (sock == -1)
+ {
+ NS_FATAL_ERROR ("Socket creation, errno=" << strerror (errno));
+ }
+
+ struct sockaddr_un un;
+ memset (&un, 0, sizeof (un));
+ un.sun_family = AF_UNIX;
+ int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t)); // let the kernel allocate an endpoint for us.
+ if (status == -1)
+ {
+ NS_FATAL_ERROR ("Could not bind: errno=" << strerror (errno));
+ }
+ socklen_t len = sizeof (un);
+ status = getsockname (sock, (struct sockaddr*)&un, &len);
+ if (status == -1)
+ {
+ NS_FATAL_ERROR ("Could not get socket address: errno=" << strerror (errno));
+ }
+ NS_LOG_DEBUG ("Allocated enpoint=" << EncodeAsString (un, len) << ", len=" << len);
+
+ pid_t pid = ::fork ();
+ if (pid == 0)
+ {
+ // child.
+ NS_LOG_DEBUG ("Child");
+
+ std::ostringstream oss;
+ oss << "--path=" << EncodeAsString (un, len);
+ std::string pathArg = oss.str ();
+ oss.str ("");
+ oss << "--mac-addr=" << host;
+ std::string hostArg = oss.str ();
+ oss.str ("");
+ oss << "--ip-addr=" << ad;
+ std::string ipArg = oss.str ();
+ oss.str ("");
+ oss << "--ip-gw=" << gateway;
+ std::string ipGw = oss.str ();
+ oss.str ("");
+ oss << "--ip-netmask=" << mask;
+ std::string ipMask = oss.str ();
+ oss.str ("");
+ status = ::execl (FindManager ().c_str (),
+ TAP_MANAGER,
+ pathArg.c_str (),
+ hostArg.c_str (),
+ ipArg.c_str (),
+ ipGw.c_str (),
+ ipMask.c_str (),
+ (char *)NULL);
+ if (status == -1)
+ {
+ NS_LOG_ERROR ("Cannot execl tap-manager, errno=" << ::strerror (errno));
+ }
+ ::_exit (-1);
+ }
+ else
+ {
+ // parent
+ NS_LOG_DEBUG ("Parent");
+ int st;
+ pid_t waited = waitpid (pid, &st, 0);
+ if (waited == -1)
+ {
+ NS_FATAL_ERROR ("Cannot wait for tap-manager, errno=" << strerror (errno));
+ }
+ NS_ASSERT (pid == waited);
+ if (!WIFEXITED (st))
+ {
+ // tap manager did not complete successfully
+ NS_FATAL_ERROR ("tap-manager did not exit correctly");
+ }
+ else if (WEXITSTATUS (st) != 0)
+ {
+ NS_FATAL_ERROR ("tap-manager did not complete successfully, err=" << WEXITSTATUS (st));
+ }
+ // the tap fd should be available on our unix socket now.
+ size_t msg_size = sizeof(int);
+ char control[CMSG_SPACE(msg_size)];
+ struct cmsghdr *cmsg;
+ uint8_t buffer;
+ struct iovec iov;
+ iov.iov_base = &buffer;
+ iov.iov_len = 1;
+ struct msghdr msg;
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control;
+ msg.msg_controllen = sizeof (control);
+ msg.msg_flags = 0;
+ ssize_t bytesRead = recvmsg (sock, &msg, 0);
+ if (bytesRead != 1)
+ {
+ NS_FATAL_ERROR ("Did not get byte from tap-manager");
+ }
+ NS_LOG_ERROR ("read bytes=" << bytesRead);
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS)
+ {
+ int *fd = (int*)CMSG_DATA (cmsg);
+ NS_LOG_ERROR ("got tap fd=" << *fd);
+ return *fd;
+ }
+ }
+ NS_FATAL_ERROR ("Did not get SCM_RIGHTS from tap-manager");
+ }
+ return -1;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/tap-manager-client.h Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,21 @@
+#ifndef TAP_MANAGER_CLIENT_H
+#define TAP_MANAGER_CLIENT_H
+
+#include "ns3/mac48-address.h"
+#include "ns3/ipv4-address.h"
+#include <string>
+
+namespace ns3 {
+
+class TapManagerClient
+{
+public:
+ int AllocateTap (Mac48Address host, Ipv4Address ad, Ipv4Mask mask, Ipv4Address gateway);
+private:
+ std::string FindManager (void) const;
+ bool Exists (std::string filename) const;
+};
+
+} // namespace ns3
+
+#endif /* TAP_MANAGER_CLIENT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/tap-manager.cc Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,339 @@
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/un.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/route.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#define noENABLE_LOG
+
+#define EXIT_ERROR(x, err) \
+ std::cout << __FILE__ << ":" << __LINE__ << ": Unrecoverable Error: " << x; \
+ std::cout << " errno=" << strerror (errno) << std::endl; \
+ exit (err)
+#ifdef ENABLE_LOG
+#define LOG(x) \
+ std::cout << x << std::endl;
+#else
+#define LOG(x)
+#endif
+
+
+#define CHECK_ARG(el,var) \
+ { \
+ char start[] = "--" el "="; \
+ if (strncmp (*argv, start, strlen (start)) == 0) \
+ { \
+ var = *argv + strlen (start); \
+ LOG ("--" << el << "=" << var); \
+ } \
+ }
+
+#define ASCII_DOT (0x2e)
+#define ASCII_ZERO (0x30)
+#define ASCII_a (0x41)
+#define ASCII_z (0x5a)
+#define ASCII_A (0x61)
+#define ASCII_Z (0x7a)
+#define ASCII_COLON (0x3a)
+#define ASCII_ZERO (0x30)
+static char
+AsciiToLowCase (char c)
+{
+ if (c >= ASCII_a && c <= ASCII_z) {
+ return c;
+ } else if (c >= ASCII_A && c <= ASCII_Z) {
+ return c + (ASCII_a - ASCII_A);
+ } else {
+ return c;
+ }
+}
+static uint32_t
+AsciiToIpv4 (const char *address)
+{
+ uint32_t host = 0;
+ while (true) {
+ uint8_t byte = 0;
+ while (*address != ASCII_DOT &&
+ *address != 0) {
+ byte *= 10;
+ byte += *address - ASCII_ZERO;
+ address++;
+ }
+ host <<= 8;
+ host |= byte;
+ if (*address == 0) {
+ break;
+ }
+ address++;
+ }
+ return host;
+}
+
+static void
+AsciiToMac48 (const char *str, uint8_t addr[6])
+{
+ int i = 0;
+ while (*str != 0 && i < 6)
+ {
+ uint8_t byte = 0;
+ while (*str != ASCII_COLON && *str != 0)
+ {
+ byte <<= 4;
+ char low = AsciiToLowCase (*str);
+ if (low >= ASCII_a)
+ {
+ byte |= low - ASCII_a + 10;
+ }
+ else
+ {
+ byte |= low - ASCII_ZERO;
+ }
+ str++;
+ }
+ addr[i] = byte;
+ i++;
+ if (*str == 0)
+ {
+ break;
+ }
+ str++;
+ }
+}
+
+static void
+SetInetAddress (sockaddr *ad, uint32_t networkOrder)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in*)ad;
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0; // unused
+ sin->sin_addr.s_addr = htonl (networkOrder);
+}
+
+
+static int
+CreateTap (const char *mac_addr, const char *ip,
+ const char *gw, const char *netmask)
+{
+ // opening the tun device usually requires root privs
+ int tap = open ("/dev/net/tun", O_RDWR);
+ if (tap == -1)
+ {
+ EXIT_ERROR ("Could not open /dev/net/tun", 1);
+ }
+ // now, crate a tap device.
+ struct ifreq ifr;
+ // make sure that the tap device will not send us the tun_pi header.
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ ifr.ifr_name[0] = 0; // allow the kernel to pick a device name.
+ int status = ioctl (tap, TUNSETIFF, (void *) &ifr);
+ if (status == -1)
+ {
+ EXIT_ERROR ("Could not allocate a tap device", 2);
+ }
+ std::string tapDeviceName = (char *)ifr.ifr_name;
+ LOG ("Allocated TAP device=" << tapDeviceName);
+
+ // set its hardware address to something we know will be unique within the simulation
+ ifr.ifr_hwaddr.sa_family = 1; // this is ARPHRD_ETHER from if_arp.h
+ AsciiToMac48 (mac_addr, (uint8_t*)ifr.ifr_hwaddr.sa_data);
+ status = ioctl (tap, SIOCSIFHWADDR, &ifr);
+ if (status == -1)
+ {
+ EXIT_ERROR ("Could not set hardware address=" << mac_addr << " for=" << (char *)ifr.ifr_name, 3);
+ }
+ LOG ("device=" << (char *)ifr.ifr_name << " addr=" << mac_addr);
+
+
+ // The ip address must be set using an AF_INET socket.
+ int fd = socket (AF_INET, SOCK_DGRAM, 0);
+
+ // set interface up.
+ status = ioctl (fd, SIOCGIFFLAGS, &ifr);
+ if (status == -1)
+ {
+ EXIT_ERROR ("Could not get flags for interface=" << (char *)ifr.ifr_name, 4);
+ }
+ ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+ status = ioctl (fd, SIOCSIFFLAGS, &ifr);
+ if (status == -1)
+ {
+ EXIT_ERROR ("Could not bring interface " << (char *)ifr.ifr_name << " up", 5);
+ }
+ LOG ("device=" << (char *)ifr.ifr_name << " is up");
+
+
+ // set its ip address.
+ SetInetAddress (&ifr.ifr_addr, AsciiToIpv4 (ip));
+ status = ioctl (fd, SIOCSIFADDR, &ifr);
+ if (status == -1)
+ {
+ EXIT_ERROR ("Could not set ip address=" << ip << " for=" << (char *)ifr.ifr_name, 6);
+ }
+ LOG ("device=" << (char *)ifr.ifr_name << " addr=" << ip);
+
+ // set its ip mask to be /32
+ SetInetAddress (&ifr.ifr_netmask, 0xffffffff);
+ status = ioctl (fd, SIOCSIFNETMASK, &ifr);
+ if (status == -1)
+ {
+ EXIT_ERROR ("Could not set ip mask=" << netmask << " for=" << (char *)ifr.ifr_name, 7);
+ }
+ LOG ("device=" << (char *)ifr.ifr_name << " mask=" << netmask);
+
+ // add routing entry for gateway.
+ struct rtentry rt;
+ SetInetAddress (&rt.rt_dst, AsciiToIpv4 (gw));
+ SetInetAddress (&rt.rt_genmask, 0xffffffff);
+ rt.rt_flags = RTF_UP;
+ rt.rt_metric = 2;
+ rt.rt_dev = (char*)tapDeviceName.c_str ();
+ status = ioctl (fd, SIOCADDRT, &rt);
+ if (status == -1)
+ {
+ EXIT_ERROR ("Could not add routing table entry", 8);
+ }
+ LOG ("added routing table entry for gw.");
+
+ // add routing entry for subnet through gateway.
+ uint32_t network = AsciiToIpv4 (ip) & AsciiToIpv4 (netmask);
+ SetInetAddress (&rt.rt_dst, network);
+ SetInetAddress (&rt.rt_gateway, AsciiToIpv4 (gw));
+ SetInetAddress (&rt.rt_genmask, AsciiToIpv4 (netmask));
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ rt.rt_metric = 2;
+ rt.rt_dev = (char*)tapDeviceName.c_str ();
+ status = ioctl (fd, SIOCADDRT, &rt);
+ if (status == -1)
+ {
+ EXIT_ERROR ("Could not add routing table entry", 9);
+ }
+ LOG ("added routing table entry for subnet.");
+
+ return tap;
+}
+
+static struct sockaddr_un
+DecodeFromString (const char *path, socklen_t *len)
+{
+ sockaddr_un un;
+ uint8_t *buffer = (uint8_t *)&un;
+ std::istringstream iss;
+ iss.str (path);
+ uint8_t n = 0;
+ while (!iss.bad () && !iss.eof () && !iss.fail ())
+ {
+ char c;
+ iss.read (&c, 1);
+ uint32_t tmp;
+ iss >> std::hex >> tmp;
+ //LOG (std::hex << tmp);
+ buffer[n] = tmp;
+ n++;
+ }
+ *len = n;
+ return un;
+}
+
+static void
+SendFd (const char *path, int fd)
+{
+ // send back configuration to caller.
+ int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
+ if (sock == -1)
+ {
+ EXIT_ERROR ("Socket creation", 10);
+ }
+ LOG ("Socket Created");
+
+ socklen_t local_len;
+ struct sockaddr_un local = DecodeFromString (path, &local_len);
+ LOG ("len=" << local_len);
+ int status = connect (sock, (struct sockaddr*)&local, local_len);
+ if (status == -1)
+ {
+ EXIT_ERROR ("Could not connect to caller", 11);
+ }
+ LOG ("Socket Connected");
+
+ // we send a single byte whose content is meaningless.
+ // we also return as ancillary data the tap file descriptor
+ struct cmsghdr *cmsg;
+ size_t msg_size = sizeof(int);
+ char control[CMSG_SPACE(msg_size)];
+ struct iovec iov;
+ struct msghdr msg;
+ char buffer = 0;
+ iov.iov_base = &buffer;
+ iov.iov_len = 1;
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control;
+ msg.msg_controllen = sizeof (control);
+ msg.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(msg_size);
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ int *fdptr = (int*) (CMSG_DATA(cmsg));
+ *fdptr = fd;
+
+ ssize_t len = sendmsg(sock, &msg, 0);
+ if (len == -1)
+ {
+ EXIT_ERROR ("Could not send SCM_RIGHTS", 12);
+ }
+ LOG ("Sent SCM_RIGHTS");
+}
+
+
+
+
+int main (int argc, char *argv[])
+{
+ char *path = 0;
+ char *mac_addr = 0;
+ char *ip_addr = 0;
+ char *ip_gw = 0;
+ char *ip_netmask = 0;
+ char *stop = 0;
+ argv++;
+ argc--;
+ while (argc > 0)
+ {
+ CHECK_ARG("path", path);
+ CHECK_ARG("mac-addr", mac_addr);
+ CHECK_ARG("ip-addr", ip_addr);
+ CHECK_ARG("ip-gw", ip_gw);
+ CHECK_ARG("ip-netmask", ip_netmask);
+ CHECK_ARG("stop", stop);
+ argv++;
+ argc--;
+ }
+
+ int tap = CreateTap (mac_addr, ip_addr, ip_gw, ip_netmask);
+
+ if (stop)
+ {
+ while (1) {}
+ }
+
+ SendFd (path, tap);
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/tap-net-device.cc Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,323 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "tap-net-device.h"
+#include "tap-manager-client.h"
+#include "ns3/node.h"
+#include "ns3/channel.h"
+#include "ns3/packet.h"
+#include "ns3/log.h"
+#include "ns3/system-thread.h"
+#include "ns3/realtime-simulator-impl.h"
+#include "ns3/make-event.h"
+#include "ns3/simulator.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/trace-source-accessor.h"
+#include "host-tap-net-device.h"
+#include "tap-channel.h"
+#include <errno.h>
+#include <stdlib.h>
+
+NS_LOG_COMPONENT_DEFINE ("TapNetDevice");
+
+namespace ns3 {
+
+TypeId
+TapNetDevice::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::TapNetDevice")
+ .SetParent<NetDevice> ()
+ .AddConstructor<TapNetDevice> ()
+ .AddTraceSource ("Rx", "A packet has been received",
+ MakeTraceSourceAccessor (&TapNetDevice::m_rxTrace))
+ .AddTraceSource ("Tx", "A packet has been sent",
+ MakeTraceSourceAccessor (&TapNetDevice::m_txTrace))
+ .AddTraceSource ("Drop", "A packet has been dropped",
+ MakeTraceSourceAccessor (&TapNetDevice::m_dropTrace))
+ ;
+ return tid;
+}
+
+TapNetDevice::TapNetDevice ()
+ : m_node (0),
+ m_mtu (0xffff),
+ m_name (""),
+ m_ifIndex (0),
+ m_tap (-1)
+{
+ NS_LOG_FUNCTION (this);
+}
+
+void
+TapNetDevice::SetChannel (Ptr<TapChannel> channel)
+{
+ m_channel = channel;
+ m_channel->SetDevice (this);
+}
+
+void
+TapNetDevice::SetupHost (Ipv4Address ad, Ipv4Mask mask, Ipv4Address gateway)
+{
+ NS_LOG_FUNCTION (this << ad << mask << gateway);
+ NS_ASSERT (m_tap == -1);
+
+ Mac48Address hostMacAddress = m_channel->GetHostDevice ()->GetMacAddress ();
+
+ TapManagerClient manager;
+ m_tap = manager.AllocateTap (hostMacAddress, ad, mask, gateway);
+
+ m_thread = Create<SystemThread> (MakeCallback (&TapNetDevice::ReadThread, this));
+ m_thread->Start ();
+}
+
+
+void
+TapNetDevice::ReadThread (void)
+{
+ NS_LOG_FUNCTION (this);
+
+ while (1)
+ {
+ uint8_t *buffer = (uint8_t *)malloc (0xffff);
+ ssize_t bytesRead = read (m_tap, buffer, 0xffff);
+ if (bytesRead == -1)
+ {
+ if (errno == EBADF || errno == EINTR)
+ {
+ // the device was closed from under us by ::DoDispose
+ return;
+ }
+ NS_FATAL_ERROR ("Error reading from tap device: errno=" << strerror (errno));
+ }
+ // Note: we purposedly don't use a smart pointer to manage this packet
+ // because the want to hand over ownership of this packet to the ForwardUp
+ // method.
+ DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->
+ ScheduleRealtimeNow (MakeEvent (&TapNetDevice::ForwardUp, this, buffer, (uint32_t)bytesRead));
+ }
+}
+
+void
+TapNetDevice::ForwardUp (uint8_t *buffer, uint32_t size)
+{
+ NS_LOG_FUNCTION (this << buffer << size);
+
+ // swallow packet reference in smart pointer.
+ Ptr<Packet> packet = Create<Packet> (buffer, size);
+ free (buffer);
+ Ptr<Packet> copy = packet->Copy ();
+
+ EthernetHeader header = EthernetHeader (false);
+ packet->RemoveHeader (header);
+
+ uint16_t protocol = header.GetLengthType ();
+ Mac48Address to = header.GetDestination ();
+ Mac48Address from = header.GetSource ();
+
+ NetDevice::PacketType packetType;
+ if (to == m_address)
+ {
+ packetType = NetDevice::PACKET_HOST;
+ }
+ else if (to.IsBroadcast ())
+ {
+ packetType = NetDevice::PACKET_HOST;
+ }
+ else if (to.IsMulticast ())
+ {
+ packetType = NetDevice::PACKET_MULTICAST;
+ }
+ else
+ {
+ packetType = NetDevice::PACKET_OTHERHOST;
+ }
+ m_rxTrace (copy, from, to);
+ if (packetType != NetDevice::PACKET_OTHERHOST)
+ {
+ m_rxCallback (this, packet, protocol, from);
+ }
+ if (!m_promiscCallback.IsNull ())
+ {
+ m_promiscCallback (this, packet, protocol, from, to, packetType);
+ }
+}
+
+void
+TapNetDevice::SetAddress (Mac48Address address)
+{
+ m_address = address;
+}
+
+void
+TapNetDevice::SetName(const std::string name)
+{
+ m_name = name;
+}
+std::string
+TapNetDevice::GetName(void) const
+{
+ return m_name;
+}
+void
+TapNetDevice::SetIfIndex(const uint32_t index)
+{
+ m_ifIndex = index;
+}
+uint32_t
+TapNetDevice::GetIfIndex(void) const
+{
+ return m_ifIndex;
+}
+Ptr<Channel>
+TapNetDevice::GetChannel (void) const
+{
+ return m_channel;
+}
+Address
+TapNetDevice::GetAddress (void) const
+{
+ return m_address;
+}
+bool
+TapNetDevice::SetMtu (const uint16_t mtu)
+{
+ m_mtu = mtu;
+ return true;
+}
+uint16_t
+TapNetDevice::GetMtu (void) const
+{
+ return m_mtu;
+}
+bool
+TapNetDevice::IsLinkUp (void) const
+{
+ return true;
+}
+void
+TapNetDevice::SetLinkChangeCallback (Callback<void> callback)
+{}
+bool
+TapNetDevice::IsBroadcast (void) const
+{
+ return true;
+}
+Address
+TapNetDevice::GetBroadcast (void) const
+{
+ return Mac48Address ("ff:ff:ff:ff:ff:ff");
+}
+bool
+TapNetDevice::IsMulticast (void) const
+{
+ return true;
+}
+Address
+TapNetDevice::GetMulticast (void) const
+{
+ return Mac48Address::GetMulticastPrefix ();
+}
+Address
+TapNetDevice::MakeMulticastAddress (Ipv4Address multicastGroup) const
+{
+ return Mac48Address::GetMulticast (multicastGroup);
+}
+bool
+TapNetDevice::IsPointToPoint (void) const
+{
+ return false;
+}
+bool
+TapNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
+{
+ NS_LOG_FUNCTION (this << packet << dest << protocolNumber);
+ return SendFrom (packet, m_address, dest, protocolNumber);
+}
+bool
+TapNetDevice::SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber)
+{
+ NS_LOG_FUNCTION (this << packet << source << dest << protocolNumber);
+ Mac48Address to = Mac48Address::ConvertFrom (dest);
+ Mac48Address from = Mac48Address::ConvertFrom (source);
+
+ EthernetHeader header = EthernetHeader (false);
+ header.SetSource (from);
+ header.SetDestination (to);
+ header.SetLengthType (protocolNumber);
+ packet->AddHeader (header);
+
+ ssize_t written = write (m_tap, packet->PeekData (), packet->GetSize ());
+ if (written == -1 || written != (ssize_t)packet->GetSize ())
+ {
+ m_dropTrace (packet, from, to);
+ return false;
+ }
+
+ m_txTrace (packet, from, to);
+
+ return true;
+}
+
+Ptr<Node>
+TapNetDevice::GetNode (void) const
+{
+ return m_node;
+}
+void
+TapNetDevice::SetNode (Ptr<Node> node)
+{
+ m_node = node;
+}
+bool
+TapNetDevice::NeedsArp (void) const
+{
+ return true;
+}
+void
+TapNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
+{
+ m_rxCallback = cb;
+}
+
+void
+TapNetDevice::DoDispose (void)
+{
+ NS_LOG_FUNCTION (this);
+ close (m_tap);
+ m_thread->Join ();
+ m_thread = 0;
+ m_node = 0;
+ m_channel = 0;
+ NetDevice::DoDispose ();
+}
+
+
+void
+TapNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
+{
+ m_promiscCallback = cb;
+}
+
+bool
+TapNetDevice::SupportsSendFrom (void) const
+{
+ return true;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/tap-net-device.h Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2008 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef TAP_NET_DEVICE_H
+#define TAP_NET_DEVICE_H
+
+#include "ns3/net-device.h"
+#include "ns3/mac48-address.h"
+#include "ns3/traced-callback.h"
+#include <stdint.h>
+#include <string>
+
+namespace ns3 {
+
+class Node;
+class SystemThread;
+class TapChannel;
+
+/**
+ * \ingroup netdevice
+ *
+ * \brief a NetDevice to get packets to and from a host tap device.
+ */
+class TapNetDevice : public NetDevice
+{
+public:
+ static TypeId GetTypeId (void);
+ TapNetDevice ();
+
+ void SetAddress (Mac48Address address);
+
+ void SetChannel (Ptr<TapChannel> channel);
+
+ void SetupHost (Ipv4Address ad, Ipv4Mask mask, Ipv4Address gateway);
+
+ // inherited from NetDevice base class.
+ virtual void SetName(const std::string name);
+ virtual std::string GetName(void) const;
+ virtual void SetIfIndex(const uint32_t index);
+ virtual uint32_t GetIfIndex(void) const;
+ virtual Ptr<Channel> GetChannel (void) const;
+ virtual Address GetAddress (void) const;
+ virtual bool SetMtu (const uint16_t mtu);
+ virtual uint16_t GetMtu (void) const;
+ virtual bool IsLinkUp (void) const;
+ virtual void SetLinkChangeCallback (Callback<void> callback);
+ virtual bool IsBroadcast (void) const;
+ virtual Address GetBroadcast (void) const;
+ virtual bool IsMulticast (void) const;
+ virtual Address GetMulticast (void) const;
+ virtual Address MakeMulticastAddress (Ipv4Address multicastGroup) const;
+ virtual bool IsPointToPoint (void) const;
+ virtual bool Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
+ virtual bool SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
+ virtual Ptr<Node> GetNode (void) const;
+ virtual void SetNode (Ptr<Node> node);
+ virtual bool NeedsArp (void) const;
+ virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
+ virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb);
+ virtual bool SupportsSendFrom (void) const;
+
+protected:
+ virtual void DoDispose (void);
+private:
+ void Receive (Ptr<Packet> packet, uint16_t protocol,
+ Mac48Address to, Mac48Address from);
+ void ForwardUp (uint8_t *buffer, uint32_t size);
+ void ReadThread (void);
+
+ NetDevice::ReceiveCallback m_rxCallback;
+ NetDevice::PromiscReceiveCallback m_promiscCallback;
+ Ptr<Node> m_node;
+ uint16_t m_mtu;
+ std::string m_name;
+ uint32_t m_ifIndex;
+ Mac48Address m_address;
+ int m_tap;
+ Ptr<SystemThread> m_thread;
+ TracedCallback<Ptr<const Packet>,Mac48Address,Mac48Address> m_rxTrace;
+ TracedCallback<Ptr<const Packet>,Mac48Address,Mac48Address> m_txTrace;
+ TracedCallback<Ptr<const Packet>,Mac48Address,Mac48Address> m_dropTrace;
+ Ptr<TapChannel> m_channel;
+};
+
+} // namespace ns3
+
+#endif /* TAP_NET_DEVICE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/emutap/wscript Mon Oct 27 13:01:28 2008 -0700
@@ -0,0 +1,26 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+
+def build(bld):
+ obj = bld.create_suid_program('ns3-tap-manager')
+ obj.source = [
+ 'tap-manager.cc',
+ ]
+
+ module = bld.create_ns3_module('emutap', ['node'])
+ module.uselib = 'CAP'
+ module.source = [
+ 'tap-net-device.cc',
+ 'tap-manager-client.cc',
+ 'tap-channel.cc',
+ 'host-tap-net-device.cc',
+ ]
+ headers = bld.create_obj('ns3header')
+ headers.module = 'emutap'
+ headers.source = [
+ 'tap-net-device.h',
+ 'host-tap-net-device.h',
+ 'tap-channel.h',
+ ]
+
+
--- a/src/wscript Mon Oct 27 16:40:03 2008 +0100
+++ b/src/wscript Mon Oct 27 13:01:28 2008 -0700
@@ -19,6 +19,8 @@
'internet-stack',
'devices/point-to-point',
'devices/csma',
+ 'devices/bridge',
+ 'devices/emutap',
'applications/onoff',
'applications/packet-sink',
'applications/udp-echo',
@@ -27,7 +29,6 @@
'mobility',
'devices/wifi',
'helper',
- 'devices/bridge',
'contrib/stats',
)
--- a/wscript Mon Oct 27 16:40:03 2008 +0100
+++ b/wscript Mon Oct 27 13:01:28 2008 -0700
@@ -12,6 +12,7 @@
import Params
import Object
import ccroot
+import Task
Params.g_autoconfig = 1
@@ -166,6 +167,10 @@
help=('For regression testing, only run/generate the indicated regression tests, '
'specified as a comma separated list of test names'),
dest='regression_tests', type="string")
+ opt.add_option('--disable-sudo',
+ help=('Do not attempt to use sudo to setup suid bits on ns3 executables.'),
+ dest='disable_sudo', action='store_true',
+ default=False)
# options provided in a script in a subdirectory named "src"
opt.sub_options('src')
@@ -275,6 +280,9 @@
# we cannot run regression tests without diff
conf.find_program('diff', var='DIFF')
+ # for suid bits
+ conf.find_program('sudo', var='SUDO')
+
# we cannot pull regression traces without mercurial
conf.find_program('hg', var='MERCURIAL')
@@ -288,6 +296,41 @@
print "%-30s: %s" % (caption, status)
+class SuidBuildTask(Task.TaskBase):
+ """task that makes a binary Suid
+ """
+ def __init__(self, bld, program):
+ self.m_display = 'build-suid'
+ self.prio = 1000 # build after the rest of ns-3
+ self.__program = program
+ self.__env = bld.env ()
+ super(SuidBuildTask, self).__init__()
+
+ def run(self):
+ try:
+ program_obj = _find_program(self.__program.target, self.__env)
+ except ValueError, ex:
+ Params.fatal(str(ex))
+
+ try:
+ program_node = program_obj.path.find_build(ccroot.get_target_name(program_obj))
+ except AttributeError:
+ Params.fatal("%s does not appear to be a program" % (program_name,))
+
+ filename = program_node.abspath(self.__env)
+ os.system ('sudo chown root ' + filename)
+ os.system ('sudo chmod u+s ' + filename)
+
+def create_suid_program(bld, name):
+ program = bld.create_obj('cpp', 'program')
+ program.is_ns3_program = True
+ program.module_deps = list()
+ program.name = name
+ program.target = name
+ if bld.env ()['SUDO'] and not Params.g_options.disable_sudo:
+ SuidBuildTask (bld, program)
+ return program
+
def create_ns3_program(bld, name, dependencies=('simulator',)):
program = bld.create_obj('cpp', 'program')
program.is_ns3_program = True
@@ -340,6 +383,7 @@
Params.g_cwd_launch = Params.g_build.m_curdirnode.abspath()
bld.create_ns3_program = types.MethodType(create_ns3_program, bld)
+ bld.create_suid_program = types.MethodType(create_suid_program, bld)
variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT']
variant_env = bld.env_of_name(variant_name)
bld.m_allenvs['default'] = variant_env # switch to the active variant