merge in tap device
This commit is contained in:
194
src/devices/emutap/host-tap-net-device.cc
Normal file
194
src/devices/emutap/host-tap-net-device.cc
Normal 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
|
||||
90
src/devices/emutap/host-tap-net-device.h
Normal file
90
src/devices/emutap/host-tap-net-device.h
Normal 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 */
|
||||
61
src/devices/emutap/tap-channel.cc
Normal file
61
src/devices/emutap/tap-channel.cc
Normal 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
|
||||
36
src/devices/emutap/tap-channel.h
Normal file
36
src/devices/emutap/tap-channel.h
Normal 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 */
|
||||
180
src/devices/emutap/tap-manager-client.cc
Normal file
180
src/devices/emutap/tap-manager-client.cc
Normal 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
|
||||
21
src/devices/emutap/tap-manager-client.h
Normal file
21
src/devices/emutap/tap-manager-client.h
Normal 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 */
|
||||
339
src/devices/emutap/tap-manager.cc
Normal file
339
src/devices/emutap/tap-manager.cc
Normal 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;
|
||||
}
|
||||
323
src/devices/emutap/tap-net-device.cc
Normal file
323
src/devices/emutap/tap-net-device.cc
Normal 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
|
||||
103
src/devices/emutap/tap-net-device.h
Normal file
103
src/devices/emutap/tap-net-device.h
Normal 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 */
|
||||
26
src/devices/emutap/wscript
Normal file
26
src/devices/emutap/wscript
Normal 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',
|
||||
]
|
||||
|
||||
|
||||
@@ -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
44
wscript
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user