merge in tap device

This commit is contained in:
Craig Dowell
2008-10-27 13:01:28 -07:00
parent 767b622b76
commit 622ced4462
12 changed files with 1419 additions and 1 deletions

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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 */

View File

@@ -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',
]

View File

@@ -19,6 +19,8 @@ all_modules = (
'internet-stack',
'devices/point-to-point',
'devices/csma',
'devices/bridge',
'devices/emutap',
'applications/onoff',
'applications/packet-sink',
'applications/udp-echo',
@@ -27,7 +29,6 @@ all_modules = (
'mobility',
'devices/wifi',
'helper',
'devices/bridge',
'contrib/stats',
)

44
wscript
View File

@@ -12,6 +12,7 @@ import pproc as subprocess
import Params
import Object
import ccroot
import Task
Params.g_autoconfig = 1
@@ -166,6 +167,10 @@ def set_options(opt):
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 @@ def configure(conf):
# 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 @@ def configure(conf):
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 @@ def build(bld):
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