checkpoint tap development
This commit is contained in:
157
examples/csma-tap-bridge.cc
Normal file
157
examples/csma-tap-bridge.cc
Normal file
@@ -0,0 +1,157 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// Network topology
|
||||
//
|
||||
// +----------+ +----------+
|
||||
// | external | | external |
|
||||
// | Linux | | Linux |
|
||||
// | Host | | Host |
|
||||
// +----------+ +----------+
|
||||
// | n0 n3 |
|
||||
// | +--------+ +--------+ |
|
||||
// +-------| tap | | tap |-------+
|
||||
// | bridge | ... | bridge |
|
||||
// +--------+ +--------+
|
||||
// | CSMA | | CSMA |
|
||||
// +--------+ +--------+
|
||||
// | |
|
||||
// | |
|
||||
// | n1 n2 |
|
||||
// | | | |
|
||||
// ================
|
||||
// LAN
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "ns3/simulator-module.h"
|
||||
#include "ns3/node-module.h"
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/helper-module.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("CsmaTapBridgeExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
//
|
||||
// Users may find it convenient to turn on explicit debugging
|
||||
// for selected modules; the below lines suggest how to do this
|
||||
//
|
||||
#if 0
|
||||
LogComponentEnable ("CsmaOneSubnetExample", LOG_LEVEL_INFO);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Make the random number generators generate reproducible results.
|
||||
//
|
||||
RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
|
||||
|
||||
//
|
||||
// Allow the user to override any of the defaults and the above Bind() at
|
||||
// run-time, via command-line arguments
|
||||
//
|
||||
CommandLine cmd;
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
//
|
||||
// Create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer nodes;
|
||||
nodes.Create (4);
|
||||
|
||||
//
|
||||
// Create and install the network.
|
||||
//
|
||||
NS_LOG_INFO ("Build Topology");
|
||||
CsmaHelper csma;
|
||||
csma.SetChannelAttribute ("DataRate", DataRateValue (5000000));
|
||||
csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
|
||||
|
||||
NetDeviceContainer devices = csma.Install (nodes);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (nodes);
|
||||
|
||||
//
|
||||
// Add the tap bridges to nodes zero and one to enable external Linux
|
||||
// processes to talk to the CSMA devices.
|
||||
//
|
||||
TapBridgeHelper bridge;
|
||||
NetDeviceContainer bridgeDevices;
|
||||
bridgeDevices.Add (bridge.Install (nodes.Get (0), devices.Get (0)));
|
||||
bridgeDevices.Add (bridge.Install (nodes.Get (3), devices.Get (3)));
|
||||
|
||||
//
|
||||
// We've got the "hardware" in place. Now add IP addresses. We mjust not
|
||||
// add IP addresses to the devices that we bridged using the TapBridgeHelper
|
||||
// above. The IP addresses are added to the bridge itself and are propagated
|
||||
// to the tap device on the host. We do need to add IP addresses to the CSMA
|
||||
// devices that are attached to the nodes that are entirely contained within
|
||||
// the simulation (not connected to any other external host).
|
||||
//
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
NetDeviceContainer ndc;
|
||||
ndc.Add (bridgeDevices.Get (0));
|
||||
ndc.Add (devices.Get (1));
|
||||
ndc.Add (devices.Get (2));
|
||||
ndc.Add (bridgeDevices.Get (0));
|
||||
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer interfaces = ipv4.Assign (ndc);
|
||||
|
||||
#if 1
|
||||
//
|
||||
// Testing only -- send a packet from an internal node to an external node
|
||||
//
|
||||
uint32_t packetSize = 1024;
|
||||
uint32_t maxPacketCount = 100;
|
||||
Time interPacketInterval = Seconds (1.);
|
||||
UdpEchoClientHelper client (interfaces.GetAddress (0), 9);
|
||||
client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
|
||||
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
|
||||
client.SetAttribute ("PacketSize", UintegerValue (packetSize));
|
||||
ApplicationContainer apps = client.Install (nodes.Get (1));
|
||||
apps.Start (Seconds (2.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
#endif
|
||||
|
||||
//
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
|
||||
//
|
||||
#if 0
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
std::ofstream ascii;
|
||||
ascii.open ("csma-tap-bridge.tr");
|
||||
CsmaHelper::EnableAsciiAll (ascii);
|
||||
CsmaHelper::EnablePcapAll ("csma-tap-bridge");
|
||||
#endif
|
||||
|
||||
//
|
||||
// Now, do the actual simulation. Run for a few minutes to allow the user a chance
|
||||
// to run some applications on the Linux hosts.
|
||||
//
|
||||
Simulator::Stop (Seconds (3. * 60.));
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -48,6 +48,10 @@ def build(bld):
|
||||
['csma', 'internet-stack'])
|
||||
obj.source = 'csma-one-subnet.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-tap-bridge',
|
||||
['csma', 'tap-bridge', 'internet-stack'])
|
||||
obj.source = 'csma-tap-bridge.cc'
|
||||
|
||||
obj = bld.create_ns3_program('csma-bridge',
|
||||
['bridge', 'csma', 'internet-stack'])
|
||||
obj.source = 'csma-bridge.cc'
|
||||
|
||||
292
src/devices/tap-bridge/tap-bridge.cc
Normal file
292
src/devices/tap-bridge/tap-bridge.cc
Normal file
@@ -0,0 +1,292 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "tap-bridge.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/channel.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TapBridge");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (TapBridge);
|
||||
|
||||
TypeId
|
||||
TapBridge::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::TapBridge")
|
||||
.SetParent<NetDevice> ()
|
||||
.AddConstructor<TapBridge> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
TapBridge::TapBridge ()
|
||||
: m_node (0),
|
||||
m_ifIndex (0)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
TapBridge::~TapBridge()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::DoDispose ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
NetDevice::DoDispose ();
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::SetBridgedDevice (Ptr<NetDevice> bridgedDevice)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
NS_ASSERT_MSG (m_node != 0, "TapBridge::SetBridgedDevice: Bridge not installed in a node");
|
||||
NS_ASSERT_MSG (bridgedDevice != this, "TapBridge::SetBridgedDevice: Cannot bridge to self");
|
||||
NS_ASSERT_MSG (m_bridgedDevice == 0, "TapBridge::SetBridgedDevice: Already bridged");
|
||||
|
||||
if (!Mac48Address::IsMatchingType (bridgedDevice->GetAddress ()))
|
||||
{
|
||||
NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support eui 48 addresses: cannot be added to bridge.");
|
||||
}
|
||||
|
||||
if (!bridgedDevice->SupportsSendFrom ())
|
||||
{
|
||||
NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support SendFrom: cannot be added to bridge.");
|
||||
}
|
||||
|
||||
//
|
||||
// Tell the bridged device to forward its received packets here.
|
||||
//
|
||||
m_node->RegisterProtocolHandler (MakeCallback (&TapBridge::ReceiveFromBridgedDevice, this), 0, bridgedDevice, true);
|
||||
m_bridgedDevice = bridgedDevice;
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::ReceiveFromBridgedDevice (
|
||||
Ptr<NetDevice> device,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
Address const &src,
|
||||
Address const &dst,
|
||||
PacketType packetType)
|
||||
{
|
||||
NS_LOG_FUNCTION (device << packet << protocol << src << dst << packetType);
|
||||
NS_ASSERT_MSG (device == m_bridgedDevice, "TapBridge::SetBridgedDevice: Received packet from unexpected device");
|
||||
|
||||
NS_LOG_DEBUG ("Packet UID is " << packet->GetUid ());
|
||||
|
||||
Mac48Address src48 = Mac48Address::ConvertFrom (src);
|
||||
Mac48Address dst48 = Mac48Address::ConvertFrom (dst);
|
||||
|
||||
//
|
||||
// We have received a packet from the ns-3 net device that has been associated
|
||||
// with this bridge. We want to take these bits and send them off to the
|
||||
// Tap device on the Linux host.
|
||||
//
|
||||
NS_LOG_LOGIC ("TapBridge::ReceiveFromDevice: Not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::SetName(const std::string name)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
std::string
|
||||
TapBridge::GetName(void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::SetIfIndex(const uint32_t index)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_ifIndex = index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
TapBridge::GetIfIndex(void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_ifIndex;
|
||||
}
|
||||
|
||||
Ptr<Channel>
|
||||
TapBridge::GetChannel (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Address
|
||||
TapBridge::GetAddress (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_address;
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::SetMtu (const uint16_t mtu)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_mtu = mtu;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
TapBridge::GetMtu (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_mtu;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TapBridge::IsLinkUp (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::SetLinkChangeCallback (Callback<void> callback)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::IsBroadcast (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
TapBridge::GetBroadcast (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return Mac48Address ("ff:ff:ff:ff:ff:ff");
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::IsMulticast (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
TapBridge::GetMulticast (Ipv4Address multicastGroup) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << multicastGroup);
|
||||
Mac48Address multicast = Mac48Address::GetMulticast (multicastGroup);
|
||||
return multicast;
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::IsPointToPoint (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::IsBridge (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::Send (Ptr<Packet> packet, const Address& dst, uint16_t protocol)
|
||||
{
|
||||
NS_LOG_FUNCTION (packet << dst << protocol);
|
||||
NS_FATAL_ERROR ("TapBridge::Send: You may not call Send on a TapBridge directly");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dst, uint16_t protocol)
|
||||
{
|
||||
NS_LOG_FUNCTION (packet << src << dst << protocol);
|
||||
NS_FATAL_ERROR ("TapBridge::Send: You may not call SendFrom on a TapBridge directly");
|
||||
return false;
|
||||
}
|
||||
|
||||
Ptr<Node>
|
||||
TapBridge::GetNode (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return m_node;
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::SetNode (Ptr<Node> node)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_node = node;
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::NeedsArp (void) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::SetReceiveCallback (NetDevice::ReceiveCallback cb)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_rxCallback = cb;
|
||||
}
|
||||
|
||||
void
|
||||
TapBridge::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_promiscRxCallback = cb;
|
||||
}
|
||||
|
||||
bool
|
||||
TapBridge::SupportsSendFrom () const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
return true;
|
||||
}
|
||||
|
||||
Address TapBridge::GetMulticast (Ipv6Address addr) const
|
||||
{
|
||||
NS_LOG_FUNCTION (this << addr);
|
||||
return Mac48Address::GetMulticast (addr);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
128
src/devices/tap-bridge/tap-bridge.h
Normal file
128
src/devices/tap-bridge/tap-bridge.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef TAP_BRIDGE_H
|
||||
#define TAP_BRIDGE_H
|
||||
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* \ingroup devices
|
||||
* \defgroup tap-bridge TapBridge
|
||||
*
|
||||
* \brief A bridge to make it appear that a host is connected to an ns-3 net device.
|
||||
*
|
||||
* The Tap Bridge lives in a kind of a gray world somewhere between a Linux host and
|
||||
* an ns-3 bridge device. From the Linux perspective, this code appears as the user
|
||||
* mode handler for a Tap net device. That is, when the Linux host writes to the
|
||||
* /dev/tapx device that we create for it, the write is redirected into the TapBridge
|
||||
* and from that perspective, becomes a read. The TapBridge then redirects the data
|
||||
* written (by the Linux host) to the tap device on out the ns-3 net device to which
|
||||
* we are bridged. When a packet comes in from the ns-3 world to the ns-3 net device
|
||||
* we are bridging, it appears via a callback from that net device. Our job is to
|
||||
* take those bits and write them back to the host using the user mode handler for
|
||||
* /dev/tapx. This write to the device will then appear to the Linux host as if a
|
||||
* packet has arrived on its device.
|
||||
*
|
||||
* The upshot is that the Tap Bridge appears to bridge a tap device on a Linux host
|
||||
* in the "real world" to an ns-3 net device in the simulation. In order to do this
|
||||
* we need a "ghost node" in the simulation to hold the bridged ns-3 net device and
|
||||
* this Tap Bridge. It won't actually do anything else in the simulation. You will
|
||||
* be able to perform typical ns-3 operations on that node, but they will have no
|
||||
* effect other than to set up, tear down and configure the net devices and bridges
|
||||
* mentioned above.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup tap-bridge
|
||||
* \brief A bridge to make it appear that a host is connected to an ns-3 net device.
|
||||
*/
|
||||
|
||||
class TapBridge : public NetDevice
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
TapBridge ();
|
||||
virtual ~TapBridge ();
|
||||
|
||||
/** \brief Set the device to bridge.
|
||||
*
|
||||
* This method tells the bridge which ns-3 net device it should use to connect
|
||||
* the simulation side of the bridge.
|
||||
*
|
||||
* \attention The ns-3 net device that is being set as the device must not
|
||||
* have an IP address. This address is a property of the host Linux device.
|
||||
*/
|
||||
void SetBridgedDevice (Ptr<NetDevice> bridgedDevice);
|
||||
|
||||
// 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 (Ipv4Address multicastGroup) const;
|
||||
virtual bool IsPointToPoint (void) const;
|
||||
virtual bool IsBridge (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 (NetDevice::PromiscReceiveCallback cb);
|
||||
virtual bool SupportsSendFrom () const;
|
||||
virtual Address GetMulticast (Ipv6Address addr) const;
|
||||
|
||||
protected:
|
||||
virtual void DoDispose (void);
|
||||
|
||||
void ReceiveFromBridgedDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
|
||||
Address const &src, Address const &dst, PacketType packetType);
|
||||
|
||||
private:
|
||||
NetDevice::ReceiveCallback m_rxCallback;
|
||||
NetDevice::PromiscReceiveCallback m_promiscRxCallback;
|
||||
|
||||
Mac48Address m_address;
|
||||
Ptr<Node> m_node;
|
||||
std::string m_name;
|
||||
uint32_t m_ifIndex;
|
||||
uint16_t m_mtu;
|
||||
|
||||
Ptr<NetDevice> m_bridgedDevice;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* TAP_BRIDGE_H */
|
||||
110
src/devices/tap-bridge/tap-encode-decode.cc
Normal file
110
src/devices/tap-bridge/tap-encode-decode.cc
Normal file
@@ -0,0 +1,110 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Convert a byte buffer to a string containing a hex representation
|
||||
* of the buffer. Make the string pretty by adding a colon (':') between
|
||||
* the hex.
|
||||
*
|
||||
* \param buffer The input buffer to be converted.
|
||||
* \param len The length of the input buffer.
|
||||
* \returns A string containing a hex representation of the data in buffer.
|
||||
*/
|
||||
std::string
|
||||
TapBufferToString (uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
//
|
||||
// Tell the stream to make hex characters, zero-filled
|
||||
//
|
||||
oss.setf (std::ios::hex, std::ios::basefield);
|
||||
oss.fill('0');
|
||||
|
||||
//
|
||||
// Loop through the buffer, separating the two-digit-wide hex bytes
|
||||
// with a colon.
|
||||
//
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
{
|
||||
oss << ":" << std::setw (2) << (uint32_t)buffer[i];
|
||||
}
|
||||
return oss.str ();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Convert string encoded by the inverse function (TapBufferToString)
|
||||
* back into a byte buffer.
|
||||
*
|
||||
* \param s The input string.
|
||||
* \param buffer The buffer to initialize with the converted bits.
|
||||
* \param len The length of the data that is valid in the buffer.
|
||||
* \returns True indicates a successful conversion.
|
||||
*/
|
||||
bool
|
||||
TapStringToBuffer (std::string s, uint8_t *buffer, uint32_t *len)
|
||||
{
|
||||
//
|
||||
// If the string was made by our inverse function, the string length must
|
||||
// be a multiple of three characters in length. Use this fact to do a
|
||||
// quick reasonableness test.
|
||||
//
|
||||
if ((s.length () % 3) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::istringstream iss;
|
||||
iss.str (s);
|
||||
|
||||
uint8_t n = 0;
|
||||
|
||||
while (iss.good ())
|
||||
{
|
||||
//
|
||||
// The first character in the "triplet" we're working on is always the
|
||||
// the ':' separator. Read that into a char and make sure we're skipping
|
||||
// what we think we're skipping.
|
||||
//
|
||||
char c;
|
||||
iss.read (&c, 1);
|
||||
if (c != ':')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// And then read in the real bits and convert them.
|
||||
//
|
||||
uint32_t tmp;
|
||||
iss >> std::hex >> tmp;
|
||||
buffer[n] = tmp;
|
||||
n++;
|
||||
}
|
||||
|
||||
*len = n;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
33
src/devices/tap-bridge/tap-encode-decode.h
Normal file
33
src/devices/tap-bridge/tap-encode-decode.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef TAP_ENCODE_DECODE_H
|
||||
#define TAP_ENCODE_DECODE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
std::string TapBufferToString (uint8_t *buffer, uint32_t len);
|
||||
bool TapStringToBuffer (std::string s, uint8_t *buffer, uint32_t *len);
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif // TAP_ENCODE_DECODE_H
|
||||
|
||||
456
src/devices/tap-bridge/tap-sock-creator.cc
Normal file
456
src/devices/tap-bridge/tap-sock-creator.cc
Normal file
@@ -0,0 +1,456 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#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 "tap-encode-decode.h"
|
||||
|
||||
#define TAP_MAGIC 95549
|
||||
|
||||
static int gVerbose = 0;
|
||||
|
||||
#define LOG(msg) \
|
||||
if (gVerbose) \
|
||||
{ \
|
||||
std::cout << __FUNCTION__ << "(): " << msg << std::endl; \
|
||||
}
|
||||
|
||||
#define ABORT(msg, printErrno) \
|
||||
std::cout << __FILE__ << ": fatal error at line " << __LINE__ << ": " << __FUNCTION__ << "(): " << msg << std::endl; \
|
||||
if (printErrno) \
|
||||
{ \
|
||||
std::cout << " errno = " << errno << " (" << strerror (errno) << ")" << std::endl; \
|
||||
} \
|
||||
exit (-1);
|
||||
|
||||
#define ABORT_IF(cond, msg, printErrno) \
|
||||
if (cond) \
|
||||
{ \
|
||||
ABORT(msg, printErrno); \
|
||||
}
|
||||
|
||||
//
|
||||
// Thanks, Mathieu, for the beginning of these functions
|
||||
//
|
||||
#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);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Send the socket file descriptor we created back to the tap bridge,
|
||||
* which will read it as soon as we're done.
|
||||
*
|
||||
* \param path The socket address information from the Unix socket we use
|
||||
* to send the created socket back to.
|
||||
* \param fd The socket we're going to send.
|
||||
*/
|
||||
static void
|
||||
SendSocket (const char *path, int fd)
|
||||
{
|
||||
//
|
||||
// Open a Unix (local interprocess) socket to call back to the tap bridge
|
||||
//
|
||||
LOG ("Create Unix socket");
|
||||
int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
|
||||
ABORT_IF (sock == -1, "Unable to open socket", 1);
|
||||
|
||||
//
|
||||
// We have this string called path, which is really a hex representation
|
||||
// of the endpoint that the tap bridge created. It used a forward encoding
|
||||
// method (TapBufferToString) to take the sockaddr_un it made and passed
|
||||
// the resulting string to us. So we need to take the inverse method
|
||||
// (TapStringToBuffer) and build the same sockaddr_un over here.
|
||||
//
|
||||
socklen_t clientAddrLen;
|
||||
struct sockaddr_un clientAddr;
|
||||
|
||||
LOG ("Decode address " << path);
|
||||
bool rc = ns3::TapStringToBuffer (path, (uint8_t *)&clientAddr, &clientAddrLen);
|
||||
ABORT_IF (rc == false, "Unable to decode path", 0);
|
||||
|
||||
LOG ("Connect");
|
||||
int status = connect (sock, (struct sockaddr*)&clientAddr, clientAddrLen);
|
||||
ABORT_IF (status == -1, "Unable to connect to tap bridge", 1);
|
||||
|
||||
LOG ("Connected");
|
||||
|
||||
//
|
||||
// This is arcane enough that a few words are worthwhile to explain what's
|
||||
// going on here.
|
||||
//
|
||||
// The interesting information (the socket FD) is going to go back to the
|
||||
// tap bridge as an integer of ancillary data. Ancillary data is bits
|
||||
// that are not a part a socket payload (out-of-band data). We're also
|
||||
// going to send one integer back. It's just initialized to a magic number
|
||||
// we use to make sure that the tap bridge is talking to the tap socket
|
||||
// creator and not some other creator process (emu, specifically)
|
||||
//
|
||||
// The struct iovec below is part of a scatter-gather list. It describes a
|
||||
// buffer. In this case, it describes a buffer (an integer) containing the
|
||||
// data that we're going to send back to the tap bridge (that magic number).
|
||||
//
|
||||
struct iovec iov;
|
||||
uint32_t magic = TAP_MAGIC;
|
||||
iov.iov_base = &magic;
|
||||
iov.iov_len = sizeof(magic);
|
||||
|
||||
//
|
||||
// The CMSG macros you'll see below are used to create and access control
|
||||
// messages (which is another name for ancillary data). The ancillary
|
||||
// data is made up of pairs of struct cmsghdr structures and associated
|
||||
// data arrays.
|
||||
//
|
||||
// First, we're going to allocate a buffer on the stack to contain our
|
||||
// data array (that contains the socket). Sometimes you'll see this called
|
||||
// an "ancillary element" but the msghdr uses the control message termimology
|
||||
// so we call it "control."
|
||||
//
|
||||
size_t msg_size = sizeof(int);
|
||||
char control[CMSG_SPACE(msg_size)];
|
||||
|
||||
//
|
||||
// There is a msghdr that is used to minimize the number of parameters
|
||||
// passed to sendmsg (which we will use to send our ancillary data). This
|
||||
// structure uses terminology corresponding to control messages, so you'll
|
||||
// see msg_control, which is the pointer to the ancillary data and controllen
|
||||
// which is the size of the ancillary data array.
|
||||
//
|
||||
// So, initialize the message header that describes our ancillary/control data
|
||||
// and point it to the control message/ancillary data we just allocated space
|
||||
// for.
|
||||
//
|
||||
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;
|
||||
|
||||
//
|
||||
// A cmsghdr contains a length field that is the length of the header and
|
||||
// the data. It has a cmsg_level field corresponding to the originating
|
||||
// protocol. This takes values which are legal levels for getsockopt and
|
||||
// setsockopt (here SOL_SOCKET). We're going to use the SCM_RIGHTS type of
|
||||
// cmsg, that indicates that the ancillary data array contains access rights
|
||||
// that we are sending back to the tap bridge.
|
||||
//
|
||||
// We have to put together the first (and only) cmsghdr that will describe
|
||||
// the whole package we're sending.
|
||||
//
|
||||
struct cmsghdr *cmsg;
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(msg_size);
|
||||
//
|
||||
// We also have to update the controllen in case other stuff is actually
|
||||
// in there we may not be aware of (due to macros).
|
||||
//
|
||||
msg.msg_controllen = cmsg->cmsg_len;
|
||||
|
||||
//
|
||||
// Finally, we get a pointer to the start of the ancillary data array and
|
||||
// put our file descriptor in.
|
||||
//
|
||||
int *fdptr = (int*) (CMSG_DATA(cmsg));
|
||||
*fdptr = fd; //
|
||||
|
||||
//
|
||||
// Actually send the file descriptor back to the tap bridge.
|
||||
//
|
||||
ssize_t len = sendmsg(sock, &msg, 0);
|
||||
ABORT_IF (len == -1, "Could not send socket back to tap bridge", 1);
|
||||
|
||||
LOG ("sendmsg complete");
|
||||
}
|
||||
|
||||
static int
|
||||
CreateTap (const char *dev, const char *gw, const char *ip, const char *netmask, const char *mac)
|
||||
{
|
||||
//
|
||||
// Creation and management of Tap devices is done via the tun device
|
||||
//
|
||||
int tap = open ("/dev/net/tun", O_RDWR);
|
||||
ABORT_IF (tap == -1, "Could not open /dev/net/tun", true);
|
||||
|
||||
//
|
||||
// Allocate a tap device, making sure that it will not send the tun_pi header.
|
||||
// If we provide a null name to the ifr.ifr_name, we tell the kernel to pick
|
||||
// a name for us (i.e., tapn where n = 0..255
|
||||
//
|
||||
struct ifreq ifr;
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strcpy (ifr.ifr_name, dev);
|
||||
int status = ioctl (tap, TUNSETIFF, (void *) &ifr);
|
||||
ABORT_IF (status == -1, "Could not allocate tap device", true);
|
||||
|
||||
std::string tapDeviceName = (char *)ifr.ifr_name;
|
||||
LOG ("Allocated TAP device " << tapDeviceName);
|
||||
|
||||
//
|
||||
// Set the hardware (MAC) address of the new device
|
||||
//
|
||||
ifr.ifr_hwaddr.sa_family = 1; // this is ARPHRD_ETHER from if_arp.h
|
||||
AsciiToMac48 (mac, (uint8_t*)ifr.ifr_hwaddr.sa_data);
|
||||
status = ioctl (tap, SIOCSIFHWADDR, &ifr);
|
||||
ABORT_IF (status == -1, "Could not set MAC address", true);
|
||||
LOG ("Set device MAC address to " << mac);
|
||||
|
||||
int fd = socket (AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
//
|
||||
// Bring the interface up.
|
||||
//
|
||||
status = ioctl (fd, SIOCGIFFLAGS, &ifr);
|
||||
ABORT_IF (status == -1, "Could not get flags for interface", true);
|
||||
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
|
||||
status = ioctl (fd, SIOCSIFFLAGS, &ifr);
|
||||
ABORT_IF (status == -1, "Could not bring interface up", true);
|
||||
LOG ("Device is up");
|
||||
|
||||
//
|
||||
// Set the IP address of the new interface/device.
|
||||
//
|
||||
SetInetAddress (&ifr.ifr_addr, AsciiToIpv4 (ip));
|
||||
status = ioctl (fd, SIOCSIFADDR, &ifr);
|
||||
ABORT_IF (status == -1, "Could not set IP address", true);
|
||||
LOG ("Set device IP address to " << ip);
|
||||
|
||||
//
|
||||
// Set the net mask of the new interface/device
|
||||
//
|
||||
SetInetAddress (&ifr.ifr_netmask, AsciiToIpv4 (netmask));
|
||||
status = ioctl (fd, SIOCSIFNETMASK, &ifr);
|
||||
ABORT_IF (status == -1, "Could not set net mask", true);
|
||||
LOG ("Set device Net Mask to " << netmask);
|
||||
|
||||
return tap;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
char *dev = NULL;
|
||||
char *gw = NULL;
|
||||
char *ip = NULL;
|
||||
char *mac = NULL;
|
||||
char *netmask = NULL;
|
||||
char *path = NULL;
|
||||
|
||||
opterr = 0;
|
||||
|
||||
while ((c = getopt (argc, argv, "vd:g:i:m:n:p:")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'v':
|
||||
gVerbose = true;
|
||||
break;
|
||||
case 'd':
|
||||
dev = optarg; // name of the new tap device
|
||||
break;
|
||||
case 'g':
|
||||
gw = optarg; // gateway address for the new device
|
||||
break;
|
||||
case 'i':
|
||||
ip = optarg; // ip address of the new device
|
||||
break;
|
||||
case 'm':
|
||||
mac = optarg; // mac address of the new device
|
||||
break;
|
||||
case 'n':
|
||||
netmask = optarg; // net mask for the new device
|
||||
break;
|
||||
case 'p':
|
||||
path = optarg; // path back to the tap bridge
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// We have got to be able to coordinate the name of the tap device we are
|
||||
// going to create and or open with the device that an external Linux host
|
||||
// will use. THis name is given in dev
|
||||
//
|
||||
ABORT_IF (dev == NULL, "Device Name is a required argument", 0);
|
||||
LOG ("Provided Device Name is \"" << dev << "\"");
|
||||
|
||||
//
|
||||
// We have got to be able to provide a gateway to the external Linux host
|
||||
// so it can talk to the ns-3 network. This ip address is provided in
|
||||
// gw.
|
||||
//
|
||||
ABORT_IF (gw == NULL, "Gateway Address is a required argument", 0);
|
||||
LOG ("Provided Gateway Address is \"" << dev << "\"");
|
||||
|
||||
//
|
||||
// We have got to be able to assign an IP address to the tap device we are
|
||||
// allocating. This address is allocated in the simulation and assigned to
|
||||
// the tap bridge. This address is given in ip.
|
||||
//
|
||||
ABORT_IF (ip == NULL, "IP Address is a required argument", 0);
|
||||
LOG ("Provided IP Address is \"" << ip << "\"");
|
||||
|
||||
//
|
||||
// We have got to be able to assign a Mac address to the tap device we are
|
||||
// allocating. This address is allocated in the simulation and assigned to
|
||||
// the bridged device. This allows packets addressed to the bridged device
|
||||
// to appear in the Linux host as if they were received there.
|
||||
//
|
||||
ABORT_IF (mac == NULL, "MAC Address is a required argument", 0);
|
||||
LOG ("Provided MAC Address is \"" << mac << "\"");
|
||||
|
||||
//
|
||||
// We have got to be able to assign a net mask to the tap device we are
|
||||
// allocating. This mask is allocated in the simulation and given to
|
||||
// the bridged device.
|
||||
//
|
||||
ABORT_IF (netmask == NULL, "Net Mask is a required argument", 0);
|
||||
LOG ("Provided Net Mask is \"" << netmask << "\"");
|
||||
|
||||
//
|
||||
// This program is spawned by a tap bridge running in a simulation. It
|
||||
// wants to create a socket as described below. We are going to do the
|
||||
// work here since we're running suid root. Once we create the socket,
|
||||
// we have to send it back to the tap bridge. We do that over a Unix
|
||||
// (local interprocess) socket. The tap bridge created a socket to
|
||||
// listen for our response on, and it is expected to have encoded the address
|
||||
// information as a string and to have passed that string as an argument to
|
||||
// us. We see it here as the "path" string. We can't do anything useful
|
||||
// unless we have that string.
|
||||
//
|
||||
ABORT_IF (path == NULL, "path is a required argument", 0);
|
||||
LOG ("Provided path is \"" << path << "\"");
|
||||
|
||||
//
|
||||
// The whole reason for all of the hoops we went through to call out to this
|
||||
// program will pay off here. We created this program to run as suid root
|
||||
// in order to keep the main simulation program from having to be run with
|
||||
// root privileges. We need root privileges to be able to futz with the
|
||||
// Tap device underlying all of this. So all of these hoops are to allow
|
||||
// us to exeucte the following code:
|
||||
//
|
||||
LOG ("Creating Tap");
|
||||
int sock = CreateTap (dev, gw, ip, mac, netmask);
|
||||
ABORT_IF (sock == -1, "main(): Unable to create tap socket", 1);
|
||||
|
||||
//
|
||||
// Send the socket back to the tap net device so it can go about its business
|
||||
//
|
||||
SendSocket (path, sock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
8
src/devices/tap-bridge/tap.h
Normal file
8
src/devices/tap-bridge/tap.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* \ingroup devices
|
||||
* \defgroup TapBridgeModel Tap Bridge Model
|
||||
*
|
||||
* \section TapBridgeModelOverview TapBridge Model Overview
|
||||
*
|
||||
* The tap bridge ...
|
||||
*/
|
||||
1
src/devices/tap-bridge/waf
vendored
Executable file
1
src/devices/tap-bridge/waf
vendored
Executable file
@@ -0,0 +1 @@
|
||||
exec "`dirname "$0"`"/../../../waf "$@"
|
||||
41
src/devices/tap-bridge/wscript
Normal file
41
src/devices/tap-bridge/wscript
Normal file
@@ -0,0 +1,41 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def configure(conf):
|
||||
if conf.env['ENABLE_THREADING']:
|
||||
conf.env['ENABLE_TAP'] = conf.check(header_name='linux/if_ether.h',
|
||||
define_name='HAVE_IF_ETHER_H')
|
||||
conf.report_optional_feature("TapBridge", "Tap Bridge",
|
||||
conf.env['ENABLE_TAP'],
|
||||
"<linux/if_ether.h> include not detected")
|
||||
else:
|
||||
conf.report_optional_feature("TapBridge", "Tap Bridge",
|
||||
False,
|
||||
"needs threading support which is not available")
|
||||
|
||||
def build(bld):
|
||||
module = bld.create_ns3_module('tap-bridge', ['node'])
|
||||
module.source = [
|
||||
]
|
||||
headers = bld.new_task_gen('ns3header')
|
||||
headers.module = 'tap-bridge'
|
||||
headers.source = [
|
||||
'tap.h',
|
||||
]
|
||||
|
||||
env = bld.env_of_name('default')
|
||||
if env['ENABLE_TAP']:
|
||||
module.source.extend([
|
||||
'tap-bridge.cc',
|
||||
'tap-encode-decode.cc',
|
||||
])
|
||||
headers.source.extend([
|
||||
'tap-bridge.h',
|
||||
])
|
||||
|
||||
obj = bld.create_suid_program('tap-sock-creator')
|
||||
obj.source = [
|
||||
'tap-sock-creator.cc',
|
||||
'tap-encode-decode.cc',
|
||||
]
|
||||
|
||||
|
||||
54
src/helper/tap-bridge-helper.cc
Normal file
54
src/helper/tap-bridge-helper.cc
Normal file
@@ -0,0 +1,54 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/tap-bridge.h"
|
||||
#include "tap-bridge-helper.h"
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("TapBridgeHelper");
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
TapBridgeHelper::TapBridgeHelper ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_deviceFactory.SetTypeId ("ns3::TapBridge");
|
||||
}
|
||||
|
||||
void
|
||||
TapBridgeHelper::SetDeviceAttribute (std::string n1, const AttributeValue &v1)
|
||||
{
|
||||
NS_LOG_FUNCTION (n1 << &v1);
|
||||
m_deviceFactory.Set (n1, v1);
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
TapBridgeHelper::Install (Ptr<Node> node, Ptr<NetDevice> nd)
|
||||
{
|
||||
NS_LOG_FUNCTION (node << nd);
|
||||
NS_LOG_LOGIC ("Install TapBridge on node " << node->GetId () << " bridging net device " << nd);
|
||||
|
||||
Ptr<TapBridge> bridge = m_deviceFactory.Create<TapBridge> ();
|
||||
node->AddDevice (bridge);
|
||||
bridge->SetBridgedDevice (nd);
|
||||
|
||||
return bridge;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
44
src/helper/tap-bridge-helper.h
Normal file
44
src/helper/tap-bridge-helper.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 University of Washington
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef TAP_BRIDGE_HELPER_H
|
||||
#define TAP_BRIDGE_HELPER_H
|
||||
|
||||
#include "net-device-container.h"
|
||||
#include "ns3/object-factory.h"
|
||||
#include <string>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Node;
|
||||
class AttributeValue;
|
||||
|
||||
class TapBridgeHelper
|
||||
{
|
||||
public:
|
||||
TapBridgeHelper ();
|
||||
void SetDeviceAttribute (std::string n1, const AttributeValue &v1);
|
||||
Ptr<NetDevice> Install (Ptr<Node> node, Ptr<NetDevice> nd);
|
||||
private:
|
||||
ObjectFactory m_deviceFactory;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
#endif /* TAP_BRIDGE_HELPER_H */
|
||||
@@ -21,6 +21,7 @@ def build(bld):
|
||||
'ipv4-interface-container.cc',
|
||||
'udp-echo-helper.cc',
|
||||
'bridge-helper.cc',
|
||||
'tap-bridge-helper.cc',
|
||||
'yans-wifi-helper.cc',
|
||||
'v4ping-helper.cc',
|
||||
]
|
||||
@@ -46,6 +47,7 @@ def build(bld):
|
||||
'ipv4-interface-container.h',
|
||||
'udp-echo-helper.h',
|
||||
'bridge-helper.h',
|
||||
'tap-bridge-helper.h',
|
||||
'yans-wifi-helper.h',
|
||||
'v4ping-helper.h',
|
||||
]
|
||||
|
||||
@@ -23,6 +23,7 @@ all_modules = (
|
||||
'devices/csma',
|
||||
'devices/emu',
|
||||
'devices/bridge',
|
||||
'devices/tap-bridge',
|
||||
'applications/onoff',
|
||||
'applications/packet-sink',
|
||||
'applications/udp-echo',
|
||||
@@ -54,6 +55,7 @@ def configure(conf):
|
||||
conf.sub_config('core')
|
||||
conf.sub_config('simulator')
|
||||
conf.sub_config('devices/emu')
|
||||
conf.sub_config('devices/tap-bridge')
|
||||
conf.sub_config('contrib')
|
||||
conf.sub_config('internet-stack')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user