merge in tap device
authorCraig Dowell <craigdo@ee.washington.edu>
Mon, 27 Oct 2008 13:01:28 -0700
changeset 3826 40c5841b616d
parent 3817 4ed410f69d36
child 3827 4b603cd4ee42
merge in tap device
src/devices/emutap/host-tap-net-device.cc
src/devices/emutap/host-tap-net-device.h
src/devices/emutap/tap-channel.cc
src/devices/emutap/tap-channel.h
src/devices/emutap/tap-manager-client.cc
src/devices/emutap/tap-manager-client.h
src/devices/emutap/tap-manager.cc
src/devices/emutap/tap-net-device.cc
src/devices/emutap/tap-net-device.h
src/devices/emutap/wscript
src/wscript
wscript
--- /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