cleanup, doxygen, prepare for review
This commit is contained in:
@@ -1,177 +0,0 @@
|
||||
/* -*- 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 |
|
||||
// | "left" | | "right" |
|
||||
// +----------+ +----------+
|
||||
// | 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);
|
||||
|
||||
//
|
||||
// We need to enable the real-time simulator since we are going to be
|
||||
// talking to the "real world."
|
||||
GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl"));
|
||||
|
||||
//
|
||||
// Also, since the whole point of this exercise is to exchange packets
|
||||
// with hosts running in the real world, we are going to need to enable
|
||||
// checksums.
|
||||
//
|
||||
Config::SetDefault ("ns3::Ipv4L3Protocol::CalcChecksum", BooleanValue (true));
|
||||
Config::SetDefault ("ns3::Icmpv4L4Protocol::CalcChecksum", BooleanValue (true));
|
||||
Config::SetDefault ("ns3::TcpL4Protocol::CalcChecksum", BooleanValue (true));
|
||||
Config::SetDefault ("ns3::UdpL4Protocol::CalcChecksum", BooleanValue (true));
|
||||
|
||||
//
|
||||
// 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);
|
||||
|
||||
//
|
||||
// We've got the "hardware" in place. Now add IP addresses.
|
||||
//
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
|
||||
|
||||
//
|
||||
// The Tap bridge is going to use the address information we just created
|
||||
// when it makes a Tap device on the Linux host. This actually happens
|
||||
// when the simulation is started, so there is no dependence on ordering
|
||||
// of the IP and MAC address assignment in the initialization phase of
|
||||
// the simulation.
|
||||
//
|
||||
// The Tap bridge will suck the MAC address out of the bridged device, and
|
||||
// the IP address and net mask out of the Ipv4Interface which is associated
|
||||
// with the bridged device. It will use these found values unless we
|
||||
// configure Attribute to provide alternate values. There are two
|
||||
// configuration Attributes we always need to pay some attention to.
|
||||
//
|
||||
// The "Gateway" Attribute is the IP address of the default gateway that
|
||||
// will be set on the newly created Tap devices on the Linux hosts. We
|
||||
// can't derive this address, so it must be set. Following standard
|
||||
// practice in helpers, this Attribute is a construction parameter for
|
||||
// the Helper. Here, we pick the interface corresponding to the
|
||||
// CSMA device on node one as the default gateway. You can change this
|
||||
// at a later time by setting the "Gateway" Attribute in the helper.
|
||||
//
|
||||
TapBridgeHelper bridge (interfaces.GetAddress (1));
|
||||
|
||||
//
|
||||
// The "DeviceName" is the name of the Tap device that will be created on
|
||||
// the Linux host. If we leave this Attribute set to the default value,
|
||||
// the Linux system will create on of the name /dev/tapx where x will be
|
||||
// a number from 0 to 255. In a simulation where you have some number of
|
||||
// Tap devices, it is convenient to assign a name. Referring back to the
|
||||
// topology illustration, we assign the name "left" to the tap device on
|
||||
// the host to the left of the diagram, and "right" to the host on the right.
|
||||
//
|
||||
// Create a tap-bridge on node zero, create a Tap device called "left" on the
|
||||
// Linux host and bridge that Linux device to the CSMA device on node zero.
|
||||
//
|
||||
bridge.SetAttribute ("DeviceName", StringValue ("left"));
|
||||
bridge.Install (nodes.Get (0), devices.Get (0));
|
||||
|
||||
//
|
||||
// Create a tap-bridge on node three, create a Tap device called "right" on the
|
||||
// Linux host and bridge that Linux device to the CSMA device on node three.
|
||||
//
|
||||
bridge.SetAttribute ("DeviceName", StringValue ("right"));
|
||||
bridge.Install (nodes.Get (3), devices.Get (3));
|
||||
|
||||
//
|
||||
// Configure tracing of all enqueue, dequeue, and NetDevice receive events.
|
||||
//
|
||||
NS_LOG_INFO ("Configure Tracing.");
|
||||
CsmaHelper::EnablePcapAll ("csma-tap-bridge");
|
||||
|
||||
//
|
||||
// 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 (60.));
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -48,10 +48,6 @@ 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('tap-dumbbell',
|
||||
['csma', 'point-to-point', 'tap-bridge', 'internet-stack'])
|
||||
obj.source = 'tap-dumbbell.cc'
|
||||
|
||||
@@ -46,7 +46,7 @@ class Node;
|
||||
* 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
|
||||
* /dev/tap 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
|
||||
@@ -78,6 +78,9 @@ public:
|
||||
virtual ~TapBridge ();
|
||||
|
||||
/** \brief Get the bridged net device.
|
||||
*
|
||||
* The bridged net device is the ns-3 device to which this bridge is connected,
|
||||
*
|
||||
* \returns the bridged net device.
|
||||
*/
|
||||
Ptr<NetDevice> GetBridgedNetDevice (void);
|
||||
@@ -93,9 +96,16 @@ public:
|
||||
void SetBridgedNetDevice (Ptr<NetDevice> bridgedDevice);
|
||||
|
||||
/**
|
||||
* Set a start time for the device.
|
||||
* \brief Set a start time for the device.
|
||||
*
|
||||
* @param tStart the start time
|
||||
* The tap bridge consumes a non-trivial amount of time to start. It starts
|
||||
* up in the context of a scheduled event to ensure that all configuration
|
||||
* has been completed before extracting the configuration (IP addresses, etc.)
|
||||
* In order to allow a more reasonable start-up sequence than a thundering
|
||||
* herd of devices, the time at which each device starts is also configurable
|
||||
* bot via the Attribute system and via this call.
|
||||
*
|
||||
* \param tStart the start time
|
||||
*/
|
||||
void Start (Time tStart);
|
||||
|
||||
@@ -103,10 +113,15 @@ public:
|
||||
* Set a stop time for the device.
|
||||
*
|
||||
* @param tStop the stop time
|
||||
*
|
||||
* \see TapBridge::Start
|
||||
*/
|
||||
void Stop (Time tStop);
|
||||
|
||||
// inherited from NetDevice base class.
|
||||
//
|
||||
// The following methods are inherited from NetDevice base class and are
|
||||
// documented there.
|
||||
//
|
||||
virtual void SetName(const std::string name);
|
||||
virtual std::string GetName(void) const;
|
||||
virtual void SetIfIndex(const uint32_t index);
|
||||
@@ -134,6 +149,14 @@ public:
|
||||
virtual Address GetMulticast (Ipv6Address addr) const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Call out to a separate process running as suid root in order to get our
|
||||
* tap device created. We do this to avoid having the entire simulation
|
||||
* running as root. If this method returns, we'll have a socket waiting
|
||||
* for us in m_sock that we can use to talk to the tap device.
|
||||
*/
|
||||
virtual void DoDispose (void);
|
||||
|
||||
void ReceiveFromBridgedDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
|
||||
@@ -141,6 +164,8 @@ protected:
|
||||
private:
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Call out to a separate process running as suid root in order to get our
|
||||
* tap device created. We do this to avoid having the entire simulation
|
||||
* running as root. If this method returns, we'll have a socket waiting
|
||||
@@ -149,67 +174,218 @@ private:
|
||||
void CreateTap (void);
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Figure out where the tap creation program lives on the system.
|
||||
*
|
||||
* \param creatorName The name of the program used to create the Tap.
|
||||
* \returns A path name to use when you want to create a Tap.
|
||||
*/
|
||||
std::string FindCreator (std::string creatorName);
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Spin up the device
|
||||
*/
|
||||
void StartTapDevice (void);
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Tear down the device
|
||||
*/
|
||||
void StopTapDevice (void);
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Loop to read and process packets
|
||||
*/
|
||||
void ReadThread (void);
|
||||
|
||||
/*
|
||||
* \internal
|
||||
*
|
||||
* Forward a packet received from the tap device to the bridged ns-3
|
||||
* device
|
||||
*
|
||||
* \param buf A character buffer containing the actaul packet bits that were
|
||||
* received from the host.
|
||||
* \param buf The length of the buffer.
|
||||
*/
|
||||
void ForwardToBridgedDevice (uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The host we are bridged to is in the evil real world. Do some sanity
|
||||
* checking on a received packet to make sure it isn't too evil for our
|
||||
* poor naive virginal simulator to handle.
|
||||
*/
|
||||
*
|
||||
* \param packet The packet we received from the host, and which we need
|
||||
* to check.
|
||||
* \param src A pointer to the data structure that will get the source
|
||||
* MAC address of the packet (extracted from the packet Ethernet
|
||||
* header).
|
||||
* \param dst A pointer to the data structure that will get the destination
|
||||
* MAC address of the packet (extracted from the packet Ethernet
|
||||
* header).
|
||||
* \param type A pointer to the variable that will get the packet type from
|
||||
* either the Ethernet header in the case of type interpretation
|
||||
* (DIX framing) or from the 802.2 LLC header in the case of
|
||||
* length interpretation (802.3 framing).
|
||||
*/
|
||||
Ptr<Packet> Filter (Ptr<Packet> packet, Address *src, Address *dst, uint16_t *type);
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Callback used to hook the standard packet receive callback of the TapBridge
|
||||
* ns-3 net device. This is never called, and therefore no packets will ever
|
||||
* be received forwarded up the IP stack on the ghost node through this device.
|
||||
*/
|
||||
NetDevice::ReceiveCallback m_rxCallback;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Callback used to hook the promiscuous packet receive callback of the TapBridge
|
||||
* ns-3 net device. This is never called, and therefore no packets will ever
|
||||
* be received forwarded up the IP stack on the ghost node through this device.
|
||||
*
|
||||
* Note that we intercept the similar callback in the bridged device in order to
|
||||
* do the actual bridging between the bridged ns-3 net device and the Tap device
|
||||
* on the host.
|
||||
*/
|
||||
NetDevice::PromiscReceiveCallback m_promiscRxCallback;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Pointer to the (ghost) Node to which we are connected.
|
||||
*/
|
||||
Ptr<Node> m_node;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* A possible name for the (ghost) Node to which we are connected.
|
||||
*/
|
||||
std::string m_name;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The ns-3 interface index of this TapBridge net device.
|
||||
*/
|
||||
uint32_t m_ifIndex;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The common mtu to use for the net devices
|
||||
*/
|
||||
uint16_t m_mtu;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The socket (actually interpreted as fd) to use to talk to the Tap device on
|
||||
* the real internet host.
|
||||
*/
|
||||
int32_t m_sock;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The ID of the ns-3 event used to schedule the start up of the underlying
|
||||
* host Tap device and ns-3 read thread.
|
||||
*/
|
||||
EventId m_startEvent;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The ID of the ns-3 event used to schedule the tear down of the underlying
|
||||
* host Tap device and ns-3 read thread.
|
||||
*/
|
||||
EventId m_stopEvent;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Used to identify the ns-3 read thread used to do blocking reads on the
|
||||
* socket (fd) corresponding to the host device.
|
||||
*/
|
||||
Ptr<SystemThread> m_readThread;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The (unused) MAC address of the TapBridge net device. Since the TapBridge
|
||||
* is implemented as a ns-3 net device, it is required to implement certain
|
||||
* functionality. In this case, the TapBridge is automatically assigned a
|
||||
* MAC address, but it is not used. The MAC address assigned to the internet
|
||||
* host actually comes from the bridged (N.B. the "ed") device and not from
|
||||
* the bridge device.
|
||||
*/
|
||||
Mac48Address m_address;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Time to start spinning up the device
|
||||
*/
|
||||
Time m_tStart;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Time to start tearing down the device
|
||||
*/
|
||||
Time m_tStop;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The name of the device to create on the host. If the device name is the
|
||||
* empty string, we allow the host kernel to choose a name.
|
||||
*/
|
||||
std::string m_tapDeviceName;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The IP address to use as the device default gateway on the host.
|
||||
*/
|
||||
Ipv4Address m_tapGateway;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The IP address to use as the device IP on the host.
|
||||
*/
|
||||
Ipv4Address m_tapIp;
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The MAC address to use as the hardware address on the host.
|
||||
*/
|
||||
Mac48Address m_tapMac;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The network mask to assign to the device created on the host.
|
||||
*/
|
||||
Ipv4Mask m_tapNetmask;
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The ns-3 net device to which we are bridging.
|
||||
*/
|
||||
Ptr<NetDevice> m_bridgedDevice;
|
||||
};
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ static int gVerbose = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Thanks, Mathieu, for the beginning of these functions
|
||||
// Lots of the following helper code taken from corresponding functions in src/node.
|
||||
//
|
||||
#define ASCII_DOT (0x2e)
|
||||
#define ASCII_ZERO (0x30)
|
||||
@@ -146,14 +146,6 @@ SetInetAddress (sockaddr *ad, uint32_t networkOrder)
|
||||
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)
|
||||
{
|
||||
@@ -447,14 +439,6 @@ main (int argc, char *argv[])
|
||||
int sock = CreateTap (dev, gw, ip, mac, netmask);
|
||||
ABORT_IF (sock == -1, "main(): Unable to create tap socket", 1);
|
||||
|
||||
#if 0
|
||||
for (;;)
|
||||
{
|
||||
LOG ("z");
|
||||
sleep (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Send the socket back to the tap net device so it can go about its business
|
||||
//
|
||||
|
||||
@@ -4,5 +4,65 @@
|
||||
*
|
||||
* \section TapBridgeModelOverview TapBridge Model Overview
|
||||
*
|
||||
* The tap bridge ...
|
||||
* The Tap Bridge is designed to integrate "real" internet hosts (or more
|
||||
* precisely, hosts that support Tun/Tap devices) into ns-3 simulations. The
|
||||
* goal is to make it appear to the host host node in question that it has an
|
||||
* ns-3 net device as a local device. The concept of a "real host" is a bit
|
||||
* slippery the "real host" may actually be virtualized using readily avialable
|
||||
* technologies such as VMware or OpenVZ.
|
||||
*
|
||||
* Since we are, in essence, connecting the inputs and outputs of an ns-3 net
|
||||
* device to the inputs and outputs of a Linux Tap net device, we call this
|
||||
* arrangement a Tap Bridge.
|
||||
*
|
||||
* The TapBridge appears to the Linux host computer as a network device just
|
||||
* like any arbitrary "eth0" or "ath0" might appear. The creation and
|
||||
* configuration of the device is done by the ns-3 simulation, however. You
|
||||
* should not expect to be able to configure a net device via, for example,
|
||||
* wlanconfig. The IP addresses, MAC addresses, gateway, etc., for the given
|
||||
* Tap device are also set up by the ns-3 simulation. If you change the
|
||||
* or manipulate the configuration manually, you will almost certainly break
|
||||
* the simulation.
|
||||
*
|
||||
* The TapBridge appears to an ns-3 simulation as a channel-less net device.
|
||||
* This device, however, must _not_ have an IP address associated with it.
|
||||
* Be aware that this is the inverse situation of an ns-3 BridgeNetDevice
|
||||
* which demands that its bridge ports not have IP addresses, but allows the
|
||||
* bridge to have an IP address.
|
||||
*
|
||||
* The host computer will appear in a simulation as a "ghost" node that contains
|
||||
* pairs of net devices and Tap bridges that represent the host devices. From
|
||||
* the perspective of a simulation, the only difference between a ghost node and
|
||||
* another node will be the presence of the TapBridge devices that connect to
|
||||
* the hosts. Configuration of address information and the ns-3 devices is
|
||||
* not changed in any way. A TapBridge will pick up the addressing info from
|
||||
* the ns-3 net device to which it is connected (its "bridged" net device) and
|
||||
* use that information to configure the device on the real host.
|
||||
*
|
||||
* The end result of this is a situation where one can, for example, use the
|
||||
* standard ping utility on a real host to ping a simulated ns-3 net device. If
|
||||
* correct routes are added to the internet host, the routing systems in ns-3
|
||||
* will enable correct routing of the packets across simulated ns-3 networks.
|
||||
* For an example of this, see the example program, tap-dumbbell.cc in the
|
||||
* ns-3 distribution.
|
||||
*
|
||||
* \section TapBridgeChannelModel Tap Bridge Channel Model
|
||||
*
|
||||
* There is no channel model associated with the Tap Bridge. In fact, the
|
||||
* intention is make it appear that the real internet host is connected to
|
||||
* the channel of the bridged net device.
|
||||
*
|
||||
* \section TapBridgeTracingModel Tap Bridge Tracing Model
|
||||
*
|
||||
* Unlike most ns-3 devices, the TapBridge does not provide any standard trace
|
||||
* sources. This is because the bridge is an intermediary that is essentially
|
||||
* one function call away from the bridged device. We expect that the trace
|
||||
* hooks in the bridged device will be sufficient for most users,
|
||||
*
|
||||
* \section TapBridgeUsage Using the Tap Bridge
|
||||
*
|
||||
* We expect that most users will interact with the TapBridge device through
|
||||
* the TapBridgeHelper. Users of other helper classes, such as CSMA or Wifi,
|
||||
* should be comfortable with the idioms used.
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user