Update README and add contrib dir
This commit is contained in:
137
contrib/ethernet/model/ethernet-channel.cc
Normal file
137
contrib/ethernet/model/ethernet-channel.cc
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "ethernet-channel.h"
|
||||
#include "ethernet-net-device.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("EthernetChannel");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(EthernetChannel);
|
||||
|
||||
TypeId
|
||||
EthernetChannel::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::EthernetChannel")
|
||||
.SetParent<Channel>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<EthernetChannel>()
|
||||
.AddAttribute("Delay",
|
||||
"Propagation delay through the channel",
|
||||
TimeValue(NanoSeconds(25)),
|
||||
MakeTimeAccessor(&EthernetChannel::m_delay),
|
||||
MakeTimeChecker())
|
||||
.AddTraceSource("TxRxEthernet",
|
||||
"Trace source indicating transmission of packet "
|
||||
"from the EthernetChannel, used by the Animation "
|
||||
"interface.",
|
||||
MakeTraceSourceAccessor(&EthernetChannel::m_txrxEthernet),
|
||||
"ns3::EthernetChannel::TxRxAnimationCallback");
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
EthernetChannel::EthernetChannel()
|
||||
: Channel(),
|
||||
m_nDevices(0)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetChannel::Attach(Ptr<EthernetNetDevice> device)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << device);
|
||||
NS_ASSERT_MSG(m_nDevices < N_DEVICES, "Only two devices permitted");
|
||||
NS_ASSERT(device);
|
||||
|
||||
m_wire[m_nDevices++].m_src = device;
|
||||
//
|
||||
// If we have both devices connected to the channel, then finish introducing
|
||||
// the two halves and set the links to IDLE.
|
||||
//
|
||||
if (m_nDevices == N_DEVICES)
|
||||
{
|
||||
m_wire[0].m_dst = m_wire[1].m_src;
|
||||
m_wire[1].m_dst = m_wire[0].m_src;
|
||||
m_wire[0].m_state = IDLE;
|
||||
m_wire[1].m_state = IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetChannel::TransmitStart(Ptr<const Packet> p, Ptr<EthernetNetDevice> src, Time txTime)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << p << src);
|
||||
NS_LOG_LOGIC("UID is " << p->GetUid() << ")");
|
||||
|
||||
NS_ASSERT(m_wire[0].m_state != INITIALIZING);
|
||||
NS_ASSERT(m_wire[1].m_state != INITIALIZING);
|
||||
|
||||
uint32_t wire = src == m_wire[0].m_src ? 0 : 1;
|
||||
|
||||
Simulator::ScheduleWithContext(m_wire[wire].m_dst->GetNode()->GetId(),
|
||||
txTime + m_delay,
|
||||
&EthernetNetDevice::Receive,
|
||||
m_wire[wire].m_dst,
|
||||
p->Copy());
|
||||
|
||||
// Call the tx anim callback on the net device
|
||||
m_txrxEthernet(p, src, m_wire[wire].m_dst, txTime, txTime + m_delay);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
EthernetChannel::GetNDevices() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_nDevices;
|
||||
}
|
||||
|
||||
Ptr<EthernetNetDevice>
|
||||
EthernetChannel::GetEthernetDevice(std::size_t i) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
NS_ASSERT(i < 2);
|
||||
return m_wire[i].m_src;
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
EthernetChannel::GetDevice(std::size_t i) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return GetEthernetDevice(i);
|
||||
}
|
||||
|
||||
Time
|
||||
EthernetChannel::GetDelay() const
|
||||
{
|
||||
return m_delay;
|
||||
}
|
||||
|
||||
Ptr<EthernetNetDevice>
|
||||
EthernetChannel::GetSource(uint32_t i) const
|
||||
{
|
||||
return m_wire[i].m_src;
|
||||
}
|
||||
|
||||
Ptr<EthernetNetDevice>
|
||||
EthernetChannel::GetDestination(uint32_t i) const
|
||||
{
|
||||
return m_wire[i].m_dst;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetChannel::IsInitialized() const
|
||||
{
|
||||
NS_ASSERT(m_wire[0].m_state != INITIALIZING);
|
||||
NS_ASSERT(m_wire[1].m_state != INITIALIZING);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
207
contrib/ethernet/model/ethernet-channel.h
Normal file
207
contrib/ethernet/model/ethernet-channel.h
Normal file
@@ -0,0 +1,207 @@
|
||||
#ifndef ETHERNET_CHANNEL_H
|
||||
#define ETHERNET_CHANNEL_H
|
||||
|
||||
#include "ns3/channel.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
// Add a doxygen group for this module.
|
||||
// If you have more than one file, this should be in only one of them.
|
||||
/**
|
||||
* \defgroup ethernet Description of the ethernet
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class EthernetNetDevice;
|
||||
class Packet;
|
||||
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* \brief Simple Ethernet Channel.
|
||||
*
|
||||
* This class represents a very simple full duplex Ethernet channel. It is
|
||||
* largely inspired by the PointToPointChannel. There is no multi-drop
|
||||
* capability on this channel -- there can be a maximum of two Ethernet
|
||||
* net devices connected.
|
||||
*
|
||||
* There are two "wires" in the channel. The first device connected gets the
|
||||
* [0] wire to transmit on. The second device gets the [1] wire. There is a
|
||||
* state (IDLE, TRANSMITTING) associated with each wire.
|
||||
*
|
||||
* \see Attach
|
||||
* \see TransmitStart
|
||||
*/
|
||||
|
||||
class EthernetChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a EthernetChannel
|
||||
*
|
||||
* By default, you get a channel that has a 25ns delay.
|
||||
*/
|
||||
EthernetChannel();
|
||||
|
||||
/**
|
||||
* \brief Attach a given netdevice to this channel
|
||||
* \param device pointer to the netdevice to attach to the channel
|
||||
*/
|
||||
void Attach(Ptr<EthernetNetDevice> device);
|
||||
|
||||
/**
|
||||
* \brief Transmit a packet over this channel
|
||||
* \param p Packet to transmit
|
||||
* \param src Source EthernetNetDevice
|
||||
* \param txTime Transmit time to apply
|
||||
* \returns true if successful (currently always true)
|
||||
*/
|
||||
virtual bool TransmitStart(Ptr<const Packet> p, Ptr<EthernetNetDevice> src, Time txTime);
|
||||
|
||||
/**
|
||||
* \brief Get number of devices on this channel
|
||||
* \returns number of devices on this channel
|
||||
*/
|
||||
std::size_t GetNDevices() const override;
|
||||
|
||||
/**
|
||||
* \brief Get EthernetNetDevice corresponding to index i on this channel
|
||||
* \param i Index number of the device requested
|
||||
* \returns Ptr to EthernetNetDevice requested
|
||||
*/
|
||||
Ptr<EthernetNetDevice> GetEthernetDevice(std::size_t i) const;
|
||||
|
||||
/**
|
||||
* \brief Get NetDevice corresponding to index i on this channel
|
||||
* \param i Index number of the device requested
|
||||
* \returns Ptr to NetDevice requested
|
||||
*/
|
||||
Ptr<NetDevice> GetDevice(std::size_t i) const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Get the delay associated with this channel
|
||||
* \returns Time delay
|
||||
*/
|
||||
Time GetDelay() const;
|
||||
|
||||
/**
|
||||
* \brief Check to make sure the wire is initialized
|
||||
* \returns true if initialized, asserts otherwise
|
||||
*/
|
||||
bool IsInitialized() const;
|
||||
|
||||
/**
|
||||
* \brief Get the net-device source
|
||||
* \param i the wire requested
|
||||
* \returns Ptr to EthernetNetDevice source for the
|
||||
* specified wire
|
||||
*/
|
||||
Ptr<EthernetNetDevice> GetSource(uint32_t i) const;
|
||||
|
||||
/**
|
||||
* \brief Get the net-device destination
|
||||
* \param i the wire requested
|
||||
* \returns Ptr to EthernetNetDevice destination for
|
||||
* the specified wire
|
||||
*/
|
||||
Ptr<EthernetNetDevice> GetDestination(uint32_t i) const;
|
||||
|
||||
/**
|
||||
* TracedCallback signature for packet transmission animation events.
|
||||
*
|
||||
* \param [in] packet The packet being transmitted.
|
||||
* \param [in] txDevice the TransmitTing NetDevice.
|
||||
* \param [in] rxDevice the Receiving NetDevice.
|
||||
* \param [in] duration The amount of time to transmit the packet.
|
||||
* \param [in] lastBitTime Last bit receive time (relative to now)
|
||||
* \deprecated The non-const \c Ptr<NetDevice> argument is deprecated
|
||||
* and will be changed to \c Ptr<const NetDevice> in a future release.
|
||||
*/
|
||||
typedef void (*TxRxAnimationCallback)(Ptr<const Packet> packet,
|
||||
Ptr<NetDevice> txDevice,
|
||||
Ptr<NetDevice> rxDevice,
|
||||
Time duration,
|
||||
Time lastBitTime);
|
||||
|
||||
private:
|
||||
/** Each ethernet full duplex wire has exactly two net devices. */
|
||||
static const std::size_t N_DEVICES = 2;
|
||||
|
||||
Time m_delay; //!< Propagation delay
|
||||
std::size_t m_nDevices; //!< Devices of this channel
|
||||
|
||||
/**
|
||||
* The trace source for the packet transmission animation events that the
|
||||
* device can fire.
|
||||
* Arguments to the callback are the packet, transmitting
|
||||
* net device, receiving net device, transmission time and
|
||||
* packet receipt time.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
* \deprecated The non-const \c Ptr<NetDevice> argument is deprecated
|
||||
* and will be changed to \c Ptr<const NetDevice> in a future release.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>, // Packet being transmitted
|
||||
Ptr<NetDevice>, // Transmitting NetDevice
|
||||
Ptr<NetDevice>, // Receiving NetDevice
|
||||
Time, // Amount of time to transmit the pkt
|
||||
Time // Last bit receive time (relative to now)
|
||||
>
|
||||
m_txrxEthernet;
|
||||
|
||||
/** \brief Wire states
|
||||
*
|
||||
*/
|
||||
enum WireState
|
||||
{
|
||||
/** Initializing state */
|
||||
INITIALIZING,
|
||||
/** Idle state (no transmission from NetDevice) */
|
||||
IDLE,
|
||||
/** Transmitting state (data being transmitted from NetDevice. */
|
||||
TRANSMITTING,
|
||||
/** Propagating state (data is being propagated in the channel. */
|
||||
PROPAGATING
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Wire model for the EthernetChannel
|
||||
*/
|
||||
class Wire
|
||||
{
|
||||
public:
|
||||
/** \brief Create the wire, it will be in INITIALIZING state
|
||||
*
|
||||
*/
|
||||
Wire()
|
||||
: m_state(INITIALIZING),
|
||||
m_src(nullptr),
|
||||
m_dst(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
WireState m_state; //!< State of the wire
|
||||
Ptr<EthernetNetDevice> m_src; //!< First NetDevice
|
||||
Ptr<EthernetNetDevice> m_dst; //!< Second NetDevice
|
||||
};
|
||||
|
||||
Wire m_wire[N_DEVICES]; //!< Wire model
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ETHERNET_CHANNEL_H */
|
||||
277
contrib/ethernet/model/ethernet-header2.cc
Normal file
277
contrib/ethernet/model/ethernet-header2.cc
Normal file
@@ -0,0 +1,277 @@
|
||||
#include "ethernet-header2.h"
|
||||
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/header.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
#include "ns3/address-utils.h"
|
||||
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("EthernetHeader2");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(EthernetHeader2);
|
||||
|
||||
EthernetHeader2::EthernetHeader2()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
EthernetHeader2::~EthernetHeader2()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
TypeId
|
||||
EthernetHeader2::GetTypeId()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
static TypeId tid = TypeId("ns3::EthernetHeader2")
|
||||
.SetParent<Header>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<EthernetHeader2>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
EthernetHeader2::GetInstanceTypeId() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return GetTypeId();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::Print(std::ostream& os) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
std::string proto;
|
||||
|
||||
os << m_src << "->" << m_dest << " with ";
|
||||
for(int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == VLAN)
|
||||
{
|
||||
os <<"vlan_id=" << (m_QTagList[i].TCI & 0xFFF) << " ";
|
||||
}
|
||||
if(m_QTagList[i].Type == REDUNDANCY)
|
||||
{
|
||||
os <<"RTAG=True ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EthernetHeader2::GetSerializedSize() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
int tagSize = 0;
|
||||
for (int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type==VLAN)
|
||||
{
|
||||
tagSize += 4;
|
||||
}
|
||||
else if(m_QTagList[i].Type==REDUNDANCY)
|
||||
{
|
||||
tagSize += 6;
|
||||
}
|
||||
}
|
||||
return 6 + 6 + tagSize + 2;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::Serialize(Buffer::Iterator start) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
Buffer::Iterator i = start;
|
||||
WriteTo(i, m_dest);
|
||||
WriteTo(i, m_src);
|
||||
|
||||
for (int j=0; j<(int)m_QTagList.size() ; j++)
|
||||
{
|
||||
i.WriteHtonU16(m_QTagList[j].TPID);
|
||||
if(m_QTagList[j].Type == VLAN)
|
||||
{
|
||||
i.WriteHtonU16(m_QTagList[j].TCI);
|
||||
}
|
||||
else if(m_QTagList[j].Type == REDUNDANCY)
|
||||
{
|
||||
i.WriteHtonU32(m_QTagList[j].TCI);
|
||||
}
|
||||
}
|
||||
i.WriteHtonU16(m_ethertype);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EthernetHeader2::Deserialize(Buffer::Iterator start)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
Buffer::Iterator i = start;
|
||||
ReadFrom(i, m_dest);
|
||||
ReadFrom(i, m_src);
|
||||
uint16_t tmp = i.ReadNtohU16();
|
||||
while (tmp==0x8100 or tmp==0xf1c1){
|
||||
TagType type = VLAN;
|
||||
uint32_t tci = 0;
|
||||
|
||||
if (tmp==0x8100){
|
||||
type = VLAN;
|
||||
tci = i.ReadNtohU16();
|
||||
}
|
||||
else if (tmp==0xf1c1){
|
||||
type = REDUNDANCY;
|
||||
tci = i.ReadNtohU32();
|
||||
}
|
||||
Qtag entry = {tmp, tci, type};
|
||||
m_QTagList.insert(m_QTagList.end(), entry);
|
||||
tmp = i.ReadNtohU16();
|
||||
}
|
||||
m_ethertype = tmp;
|
||||
|
||||
// NS_LOG_INFO("m_QTagList size = " << m_QTagList.size());
|
||||
return GetSerializedSize();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EthernetHeader2::SetDest(Mac48Address addr)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_dest = addr;
|
||||
}
|
||||
|
||||
Mac48Address
|
||||
EthernetHeader2::GetDest()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_dest;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::SetSrc(Mac48Address addr)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_src = addr;
|
||||
}
|
||||
|
||||
Mac48Address
|
||||
EthernetHeader2::GetSrc()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_src;
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
EthernetHeader2::GetPcp()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for(int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == VLAN)
|
||||
{
|
||||
return (m_QTagList[i].TCI >> 13) & 0x7;
|
||||
}
|
||||
}
|
||||
NS_ASSERT_MSG(true, "Can't find a Vlan QTag in this header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
EthernetHeader2::GetDei()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for(int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == VLAN)
|
||||
{
|
||||
return uint8_t((m_QTagList[i].TCI >> 12) & 0x1);
|
||||
}
|
||||
}
|
||||
NS_ASSERT_MSG(true, "Can't find a Vlan QTag in this header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
EthernetHeader2::GetVid()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for(int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == VLAN)
|
||||
{
|
||||
return (m_QTagList[i].TCI & 0xFFF);
|
||||
}
|
||||
}
|
||||
NS_ASSERT_MSG(true, "Can't find a Vlan QTag in this header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::SetEthertype(uint16_t ethertype)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_ethertype = ethertype;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
EthernetHeader2::GetEthertype()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_ethertype;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::SetVlanTag(uint8_t pcp, uint8_t dei, uint16_t vid)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(vid < 4096 , "Vlan id must be between 0 and 4095");
|
||||
NS_ASSERT_MSG(dei < 2 , "DEI must be between 0 and 1");
|
||||
NS_ASSERT_MSG(pcp < 8 , "PCP must be between 0 and 7");
|
||||
|
||||
uint16_t tpid = 0x8100;
|
||||
uint32_t tci = (pcp << 13) | (dei << 12) | vid;
|
||||
Qtag entry = {tpid, tci, VLAN};
|
||||
m_QTagList.insert(m_QTagList.begin(), entry);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::SetRedundancyTag(uint16_t seqNum)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
uint16_t tpid = 0xf1c1;
|
||||
uint32_t tci = (0 << 16) | seqNum;
|
||||
Qtag entry = {tpid, tci, REDUNDANCY};
|
||||
m_QTagList.insert(m_QTagList.begin(), entry);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
EthernetHeader2::RemoveRedundancyTag()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for (int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == REDUNDANCY)
|
||||
{
|
||||
uint16_t seqNum = m_QTagList[i].TCI & 0xFFFF;
|
||||
m_QTagList.erase(m_QTagList.begin() + i);
|
||||
return seqNum;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERT_MSG(true, "Can't find a Redundancy QTag in this header");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
86
contrib/ethernet/model/ethernet-header2.h
Normal file
86
contrib/ethernet/model/ethernet-header2.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef ETHERNET_HEADER2_H
|
||||
#define ETHERNET_HEADER2_H
|
||||
|
||||
#include "ns3/header.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* \brief Packet header for Ethernet
|
||||
*
|
||||
* This class can be used to add a header to Ethernet packet.
|
||||
*/
|
||||
|
||||
class EthernetHeader2 : public Header
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Construct a Ethernet header.
|
||||
*/
|
||||
EthernetHeader2();
|
||||
|
||||
/**
|
||||
* \brief Destroy a Ethernet header.
|
||||
*/
|
||||
~EthernetHeader2() override;
|
||||
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Get the TypeId of the instance
|
||||
*
|
||||
* \return The TypeId for this instance
|
||||
*/
|
||||
TypeId GetInstanceTypeId() const override;
|
||||
|
||||
void Print(std::ostream& os) const override;
|
||||
void Serialize(Buffer::Iterator start) const override;
|
||||
uint32_t Deserialize(Buffer::Iterator start) override;
|
||||
uint32_t GetSerializedSize() const override;
|
||||
|
||||
void SetDest(Mac48Address addr);
|
||||
Mac48Address GetDest();
|
||||
void SetSrc(Mac48Address addr);
|
||||
Mac48Address GetSrc();
|
||||
uint8_t GetPcp();
|
||||
uint8_t GetDei();
|
||||
uint16_t GetVid();
|
||||
void SetEthertype(uint16_t ethertype);
|
||||
uint16_t GetEthertype();
|
||||
|
||||
void SetVlanTag(uint8_t pcp, uint8_t dei, uint16_t vid);
|
||||
void SetRedundancyTag(uint16_t seqNum);
|
||||
uint16_t RemoveRedundancyTag();
|
||||
|
||||
|
||||
private:
|
||||
Mac48Address m_dest;
|
||||
Mac48Address m_src;
|
||||
|
||||
//QTag (VlanTag, RedundancyTag ...)
|
||||
enum TagType
|
||||
{
|
||||
VLAN,
|
||||
REDUNDANCY,
|
||||
};
|
||||
struct Qtag
|
||||
{
|
||||
uint16_t TPID; //Tag Protocol Identifier
|
||||
uint32_t TCI; //Tag Control Information
|
||||
TagType Type;
|
||||
};
|
||||
|
||||
std::vector<Qtag> m_QTagList;
|
||||
|
||||
uint16_t m_ethertype;
|
||||
};
|
||||
|
||||
} // namespace eden
|
||||
#endif /* ETHERNET_HEADER2_H */
|
||||
769
contrib/ethernet/model/ethernet-net-device.cc
Normal file
769
contrib/ethernet/model/ethernet-net-device.cc
Normal file
@@ -0,0 +1,769 @@
|
||||
#include "ethernet-net-device.h"
|
||||
|
||||
#include "ethernet-channel.h"
|
||||
#include "ethernet-header2.h"
|
||||
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/llc-snap-header.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/queue.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/ethernet-trailer.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
#include "ns3/names.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("EthernetNetDevice");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(EthernetNetDevice);
|
||||
|
||||
TypeId
|
||||
EthernetNetDevice::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::EthernetNetDevice")
|
||||
.SetParent<NetDevice>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<EthernetNetDevice>()
|
||||
.AddAttribute("Mtu",
|
||||
"The MAC-level Maximum Transmission Unit",
|
||||
UintegerValue(DEFAULT_MTU),
|
||||
MakeUintegerAccessor(&EthernetNetDevice::SetMtu,
|
||||
&EthernetNetDevice::GetMtu),
|
||||
MakeUintegerChecker<uint16_t>())
|
||||
.AddAttribute("Address",
|
||||
"The MAC address of this device.",
|
||||
Mac48AddressValue(Mac48Address("00:00:00:00:ED:E1")),
|
||||
MakeMac48AddressAccessor(&EthernetNetDevice::m_address),
|
||||
MakeMac48AddressChecker())
|
||||
.AddAttribute("DataRate",
|
||||
"The default data rate for point to point links",
|
||||
DataRateValue(DataRate("1Gb/s")),
|
||||
MakeDataRateAccessor(&EthernetNetDevice::m_bps),
|
||||
MakeDataRateChecker())
|
||||
.AddAttribute("ReceiveErrorModel",
|
||||
"The receiver error model used to simulate packet loss",
|
||||
PointerValue(),
|
||||
MakePointerAccessor(&EthernetNetDevice::m_receiveErrorModel),
|
||||
MakePointerChecker<ErrorModel>())
|
||||
.AddAttribute("preambleAndSFDGap",
|
||||
"Number of byte for the preamble and start of frame delimiter gap",
|
||||
UintegerValue(8),
|
||||
MakeUintegerAccessor(&EthernetNetDevice::m_preambleAndSFDGap),
|
||||
MakeUintegerChecker<uint8_t>())
|
||||
.AddAttribute("InterframeGap",
|
||||
"Number of byte for the interframe gap",
|
||||
UintegerValue(12),
|
||||
MakeUintegerAccessor(&EthernetNetDevice::m_interframeGap),
|
||||
MakeUintegerChecker<uint8_t>())
|
||||
|
||||
//
|
||||
// Trace sources at the "top" of the net device, where packets transition
|
||||
// to/from higher layers.
|
||||
//
|
||||
.AddTraceSource("MacTx",
|
||||
"Trace source indicating a packet has arrived "
|
||||
"for transmission by this device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macTxTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("MacTxAnimation",
|
||||
"Trace source indicating a packet has arrived "
|
||||
"for transmission by this device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macTxAnimationTrace),
|
||||
"ns3::EthernetNetDevice::MacTxAnimationCallback")
|
||||
.AddTraceSource("MacTxDrop",
|
||||
"Trace source indicating a packet has been dropped "
|
||||
"by the device before transmission",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macTxDropTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("MacPromiscRx",
|
||||
"A packet has been received by this device, "
|
||||
"has been passed up from the physical layer "
|
||||
"and is being forwarded up the local protocol stack. "
|
||||
"This is a promiscuous trace,",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macPromiscRxTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("MacRx",
|
||||
"A packet has been received by this device, "
|
||||
"has been passed up from the physical layer "
|
||||
"and is being forwarded up the local protocol stack. "
|
||||
"This is a non-promiscuous trace,",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macRxTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("MacRxAnimation",
|
||||
"Trace source indicating a packet has arrived "
|
||||
"in this device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macRxAnimationTrace),
|
||||
"ns3::EthernetNetDevice::MacRxAnimationCallback")
|
||||
#if 0
|
||||
// Not currently implemented for this device
|
||||
.AddTraceSource ("MacRxDrop",
|
||||
"Trace source indicating a packet was dropped "
|
||||
"before being forwarded up the stack",
|
||||
MakeTraceSourceAccessor (&EthernetNetDevice::m_macRxDropTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
#endif
|
||||
//
|
||||
// Trace sources at the "bottom" of the net device, where packets transition
|
||||
// to/from the channel.
|
||||
//
|
||||
.AddTraceSource("PhyTxBegin",
|
||||
"Trace source indicating a packet has begun "
|
||||
"transmitting over the channel",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyTxBeginTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("PhyTxEnd",
|
||||
"Trace source indicating a packet has been "
|
||||
"completely transmitted over the channel",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyTxEndTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("PhyTxDrop",
|
||||
"Trace source indicating a packet has been "
|
||||
"dropped by the device during transmission",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyTxDropTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("Latency",
|
||||
"Trace source to compute network latency ",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_latencyTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("FIFOState",
|
||||
"Trace source to study the FIFO state ",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_FIFOStateSnifferTrace),
|
||||
"ns3::EthernetNetDevice::m_FIFOStateSnifferTrace")
|
||||
#if 0
|
||||
// Not currently implemented for this device
|
||||
.AddTraceSource ("PhyRxBegin",
|
||||
"Trace source indicating a packet has begun "
|
||||
"being received by the device",
|
||||
MakeTraceSourceAccessor (&EthernetNetDevice::m_phyRxBeginTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
#endif
|
||||
.AddTraceSource("PhyRxEnd",
|
||||
"Trace source indicating a packet has been "
|
||||
"completely received by the device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyRxEndTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("PhyRxDrop",
|
||||
"Trace source indicating a packet has been "
|
||||
"dropped by the device during reception",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyRxDropTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
|
||||
//
|
||||
// Trace sources designed to simulate a packet sniffer facility (tcpdump).
|
||||
// Note that there is really no difference between promiscuous and
|
||||
// non-promiscuous traces in a point-to-point link.
|
||||
//
|
||||
.AddTraceSource("Sniffer",
|
||||
"Trace source simulating a non-promiscuous packet sniffer "
|
||||
"attached to the device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_snifferTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("PromiscSniffer",
|
||||
"Trace source simulating a promiscuous packet sniffer "
|
||||
"attached to the device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_promiscSnifferTrace),
|
||||
"ns3::Packet::TracedCallback");
|
||||
return tid;
|
||||
}
|
||||
|
||||
EthernetNetDevice::EthernetNetDevice()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_txMachineState = READY;
|
||||
m_channel = nullptr;
|
||||
m_linkUp = false;
|
||||
m_currentPkt = nullptr;
|
||||
}
|
||||
|
||||
EthernetNetDevice::~EthernetNetDevice()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::AddHeader(Ptr<Packet> p, Mac48Address dst, Mac48Address src, uint16_t ethertype)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
EthernetHeader2 ethHeader;
|
||||
ethHeader.SetDest(dst);
|
||||
ethHeader.SetSrc(src);
|
||||
ethHeader.SetEthertype(ethertype);
|
||||
p->AddHeader(ethHeader);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::AddHeader(Ptr<Packet> p, Mac48Address dst, Mac48Address src, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
EthernetHeader2 ethHeader;
|
||||
ethHeader.SetDest(dst);
|
||||
ethHeader.SetSrc(src);
|
||||
ethHeader.SetEthertype(ethertype);
|
||||
ethHeader.SetVlanTag(pcp, dei, vid);
|
||||
p->AddHeader(ethHeader);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_node = nullptr;
|
||||
m_channel = nullptr;
|
||||
m_receiveErrorModel = nullptr;
|
||||
m_currentPkt = nullptr;
|
||||
m_queues.clear();
|
||||
NetDevice::DoDispose();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetDataRate(DataRate bps)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_bps = bps;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::TransmitStart(Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << p);
|
||||
NS_ASSERT_MSG(m_channel != nullptr, "Channel ptr is null");
|
||||
|
||||
NS_LOG_INFO(Names::FindName(this) << " PKT #" << p->GetUid() << " at " << Simulator::Now().GetNanoSeconds()<<" Transmit started ");
|
||||
|
||||
//Add a tag to compute delay between reception(or FIFO enter if first
|
||||
//emission port) and transmission start
|
||||
TimestampTag tag(Simulator::Now());
|
||||
p->AddByteTag(tag);
|
||||
|
||||
//
|
||||
// This function is called to start the process of transmitting a packet.
|
||||
// We need to tell the channel that we've started wiggling the wire and
|
||||
// schedule an event that will be executed when the transmission is complete.
|
||||
//
|
||||
NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
|
||||
m_txMachineState = BUSY;
|
||||
m_currentPkt = p;
|
||||
m_phyTxBeginTrace(m_currentPkt);
|
||||
|
||||
Time preambleAndSFDGapTime = m_bps.CalculateBytesTxTime(m_preambleAndSFDGap);
|
||||
Time txTime = m_bps.CalculateBytesTxTime(p->GetSize());
|
||||
Time interpacketGapTime = m_bps.CalculateBytesTxTime(m_interframeGap);
|
||||
Time txCompleteTime = preambleAndSFDGapTime + txTime + interpacketGapTime;
|
||||
|
||||
//NS_LOG_INFO(Names::FindName(this) << " "<< Simulator::Now().GetNanoSeconds()<<" Transmit pkt #"<<p->GetUid());
|
||||
//NS_LOG_LOGIC(Names::FindName(this) << " Schedule TransmitCompleteEvent in " << txCompleteTime.As(Time::S) << " for PKT #" << p->GetUid());
|
||||
Simulator::Schedule(txCompleteTime, &EthernetNetDevice::TransmitComplete, this);
|
||||
|
||||
bool result = m_channel->TransmitStart(p, this, txCompleteTime-interpacketGapTime); //Pkt don't need to wait for the end of Interpacket gap to be considered as receive on the other end of the link
|
||||
if (!result)
|
||||
{
|
||||
m_phyTxDropTrace(p);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::TransmitComplete()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
NS_LOG_INFO(Names::FindName(this) << " PKT #" << m_currentPkt->GetUid() << " at " << Simulator::Now().GetNanoSeconds()<<" Transmit completed ");
|
||||
// NS_LOG_INFO(Names::FindName(this) << " "<< Simulator::Now().GetNanoSeconds()<<" Transmit completed pkt ");
|
||||
//
|
||||
// This function is called to when we're all done transmitting a packet.
|
||||
// We try and pull another packet off of the transmit queue. If the queue
|
||||
// is empty, we are done, otherwise we need to start transmitting the
|
||||
// next packet.
|
||||
//
|
||||
NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
|
||||
m_txMachineState = READY;
|
||||
|
||||
NS_ASSERT_MSG(m_currentPkt, "EthernetNetDevice::TransmitComplete(): m_currentPkt zero");
|
||||
|
||||
m_phyTxEndTrace(m_currentPkt);
|
||||
|
||||
m_currentPkt = nullptr;
|
||||
|
||||
//Add the event after all the already present at this exact instant to avoid
|
||||
//the beginning of a transmission if a packet will be ready at the event just
|
||||
//after but at the same time instant.
|
||||
Simulator::Schedule(Time(0), &EthernetNetDevice::CheckForReadyPacket, this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EthernetNetDevice::CheckForReadyPacket()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
if (m_txMachineState != READY){
|
||||
return;
|
||||
}
|
||||
|
||||
int next_queue_id = TransmitSelection();
|
||||
if(next_queue_id==-1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Ptr<Packet> p = m_queues[next_queue_id]->Dequeue();
|
||||
//
|
||||
// Got another packet off of the queue, so start the transmit process again.
|
||||
//
|
||||
m_snifferTrace(p);
|
||||
m_promiscSnifferTrace(p);
|
||||
TransmitStart(p);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
EthernetNetDevice::TransmitSelection()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
//For now simple Static Priority Algo
|
||||
for (int i = m_queues.size(); i --> 0; )
|
||||
{
|
||||
if(!m_queues[i]->IsEmpty())
|
||||
{
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EthernetNetDevice::Attach(Ptr<EthernetChannel> ch)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << &ch);
|
||||
|
||||
m_channel = ch;
|
||||
|
||||
m_channel->Attach(this);
|
||||
|
||||
//
|
||||
// This device is up whenever it is attached to a channel. A better plan
|
||||
// would be to have the link come up when both devices are attached, but this
|
||||
// is not done for now.
|
||||
//
|
||||
NotifyLinkUp();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetQueue(Ptr<Queue<Packet>> q)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << q);
|
||||
m_queues.insert(m_queues.end(),q);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetReceiveErrorModel(Ptr<ErrorModel> em)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << em);
|
||||
m_receiveErrorModel = em;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::Receive(Ptr<Packet> packet)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << packet);
|
||||
NS_LOG_LOGIC("UID is " << packet->GetUid());
|
||||
if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt(packet))
|
||||
{
|
||||
//
|
||||
// If we have an error model and it indicates that it is time to lose a
|
||||
// corrupted packet, don't forward this packet up, let it go.
|
||||
//
|
||||
NS_LOG_LOGIC("Dropping pkt due to error model ");
|
||||
m_phyRxDropTrace(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Add timestamp to measure delay in the switches
|
||||
TimestampTag tag(Simulator::Now());
|
||||
packet->AddByteTag(tag);
|
||||
//
|
||||
// Hit the trace hooks. All of these hooks are in the same place in this
|
||||
// device because it is so simple, but this is not usually the case in
|
||||
// more complicated devices.
|
||||
//
|
||||
m_snifferTrace(packet);
|
||||
m_promiscSnifferTrace(packet);
|
||||
m_phyRxEndTrace(packet);
|
||||
|
||||
//
|
||||
// Trace sinks will expect complete packets, not packets without some of the
|
||||
// headers.
|
||||
//
|
||||
Ptr<Packet> originalPacket = packet->Copy();
|
||||
|
||||
EthernetTrailer trailer;
|
||||
packet->RemoveTrailer(trailer);
|
||||
if (Node::ChecksumEnabled())
|
||||
{
|
||||
trailer.EnableFcs(true);
|
||||
}
|
||||
|
||||
bool crcGood = trailer.CheckFcs(packet);
|
||||
if (!crcGood)
|
||||
{
|
||||
NS_LOG_INFO("CRC error on Packet " << packet);
|
||||
m_phyRxDropTrace(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Strip off the ethernet protocol header and forward this packet
|
||||
// up the protocol stack. Since this is a simple point-to-point link,
|
||||
// there is no difference in what the promisc callback sees and what the
|
||||
// normal receive callback sees.
|
||||
//
|
||||
EthernetHeader2 header;
|
||||
packet->RemoveHeader(header);
|
||||
|
||||
uint16_t protocol;
|
||||
protocol = header.GetEthertype();
|
||||
|
||||
//
|
||||
// Classify the packet based on its destination.
|
||||
//
|
||||
PacketType packetType;
|
||||
|
||||
if (header.GetDest() == m_address)
|
||||
{
|
||||
packetType = PACKET_HOST;
|
||||
}
|
||||
else if (header.GetDest().IsGroup())
|
||||
{
|
||||
packetType = PACKET_MULTICAST;
|
||||
}
|
||||
else if (header.GetDest().IsBroadcast())
|
||||
{
|
||||
packetType = PACKET_BROADCAST;
|
||||
}
|
||||
else
|
||||
{
|
||||
packetType = PACKET_OTHERHOST;
|
||||
}
|
||||
|
||||
if (!m_promiscCallback.IsNull())
|
||||
{
|
||||
m_macPromiscRxTrace(originalPacket->Copy());
|
||||
m_promiscCallback(this,
|
||||
originalPacket,
|
||||
protocol,
|
||||
header.GetSrc(),
|
||||
header.GetDest(),
|
||||
packetType);
|
||||
}
|
||||
//
|
||||
// If this packet is not destined for some other host, it must be for us
|
||||
// as either a broadcast, multicast or unicast. We need to hit the mac
|
||||
// packet received trace hook and forward the packet up the stack.
|
||||
//
|
||||
if (packetType != PACKET_OTHERHOST)
|
||||
{
|
||||
//NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << Names::FindName(m_node) << "/" << Names::FindName(this) <<" : Pkt #" << originalPacket->GetUid() <<" received by the netDevice ! " << originalPacket->ToString());
|
||||
m_macRxTrace(originalPacket);
|
||||
m_macRxAnimationTrace(originalPacket, this);
|
||||
m_rxCallback(this, packet, protocol, header.GetSrc());
|
||||
m_latencyTrace(originalPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Queue<Packet>>
|
||||
EthernetNetDevice::GetQueue(uint8_t index) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_queues[index];
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::NotifyLinkUp()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_linkUp = true;
|
||||
m_linkChangeCallbacks();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetIfIndex(const uint32_t index)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_ifIndex = index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EthernetNetDevice::GetIfIndex() const
|
||||
{
|
||||
return m_ifIndex;
|
||||
}
|
||||
|
||||
Ptr<Channel>
|
||||
EthernetNetDevice::GetChannel() const
|
||||
{
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetAddress(Address address)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << address);
|
||||
m_address = Mac48Address::ConvertFrom(address);
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetAddress() const
|
||||
{
|
||||
return m_address;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EthernetNetDevice::IsLinkUp() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_linkUp;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::AddLinkChangeCallback(Callback<void> callback)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_linkChangeCallbacks.ConnectWithoutContext(callback);
|
||||
}
|
||||
|
||||
//
|
||||
// This is a ethernet device, so every transmission is a broadcast to
|
||||
// all of the devices on the channel.
|
||||
//
|
||||
bool
|
||||
EthernetNetDevice::IsBroadcast() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetBroadcast() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return Mac48Address("ff:ff:ff:ff:ff:ff");
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::IsMulticast() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetMulticast(Ipv4Address multicastGroup) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return Mac48Address("01:00:5e:00:00:00");
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetMulticast(Ipv6Address addr) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << addr);
|
||||
return Mac48Address("33:33:00:00:00:00");
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::IsPointToPoint() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::IsBridge() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EthernetNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t ethertype)
|
||||
{
|
||||
uint16_t vid = 65535;
|
||||
uint8_t pcp = 0;
|
||||
uint8_t dei = 0;
|
||||
return SendFrom(packet, GetAddress(), dest, ethertype, vid, pcp, dei);
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei)
|
||||
{
|
||||
return SendFrom(packet, GetAddress(), dest, ethertype, vid, pcp, dei);
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t ethertype)
|
||||
{
|
||||
//Call by the switch net device with a packet with a EhternetHeader2 and EthernetTrailer
|
||||
//Or by another SendFrom function that have already have a packet with header and trailer
|
||||
// /!\ source, dest, and ethertype are not use in this function but are needed in
|
||||
// the callback define by the netDevice class
|
||||
//
|
||||
// If IsLinkUp() is false it means there is no channel to send any packet
|
||||
// over so we just hit the drop trace on the packet and return an error.
|
||||
//
|
||||
if (!IsLinkUp())
|
||||
{
|
||||
m_macTxDropTrace(packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Add timestamp if first emission
|
||||
TimestampTag tag(Simulator::Now());
|
||||
if (!packet->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
packet->AddByteTag(tag);
|
||||
}
|
||||
m_macTxTrace(packet);
|
||||
m_macTxAnimationTrace(packet, this);
|
||||
|
||||
Ptr<Packet> pCopy = packet->Copy();
|
||||
EthernetHeader2 header;
|
||||
pCopy->RemoveHeader(header);
|
||||
uint8_t pcp = header.GetPcp();
|
||||
|
||||
NS_ASSERT_MSG(m_queues.size() > pcp, "Not enough fifos ( 0 to "<< m_queues.size()-1 <<") to handle this pcp priority ("<< unsigned(pcp) <<") on Node " <<Names::FindName(GetNode()));
|
||||
|
||||
|
||||
m_FIFOStateSnifferTrace(m_queues, m_txMachineState==BUSY, packet);
|
||||
//
|
||||
// We should enqueue and dequeue the packet to hit the tracing hooks.
|
||||
//
|
||||
if (m_queues[pcp]->Enqueue(packet))
|
||||
{
|
||||
NS_LOG_INFO(Names::FindName(this) << " Enqueue pkt #"<<packet->GetUid() << " OK !");
|
||||
//Add the event after all the already present at this exact instant to avoid
|
||||
//the beginning of a transmission if a packet will be ready at the event just
|
||||
//after but at the same time instant.
|
||||
Simulator::Schedule(Time(0), &EthernetNetDevice::CheckForReadyPacket, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Enqueue may fail (overflow)
|
||||
m_macTxDropTrace(packet);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << packet << dest << ethertype);
|
||||
NS_LOG_LOGIC(Names::FindName(this) << " p=" << packet->GetUid() << ", dest=" << &dest);
|
||||
|
||||
// NS_LOG_INFO(Names::FindName(this) << " SendFrom : p=" << packet->GetUid() << ", dest=" << &dest << " at " << Simulator::Now());
|
||||
|
||||
|
||||
if (vid == 65535){
|
||||
AddHeader(packet, Mac48Address::ConvertFrom(dest), Mac48Address::ConvertFrom(source), ethertype);
|
||||
}
|
||||
else{
|
||||
AddHeader(packet, Mac48Address::ConvertFrom(dest), Mac48Address::ConvertFrom(source), ethertype, vid, pcp, dei);
|
||||
}
|
||||
|
||||
EthernetTrailer trailer;
|
||||
trailer.EnableFcs(true);
|
||||
trailer.CalcFcs(packet);
|
||||
packet->AddTrailer(trailer);
|
||||
|
||||
|
||||
return SendFrom(packet, source, dest, ethertype);
|
||||
}
|
||||
|
||||
Ptr<Node>
|
||||
EthernetNetDevice::GetNode() const
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetNode(Ptr<Node> node)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_node = node;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::NeedsArp() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetReceiveCallback(NetDevice::ReceiveCallback cb)
|
||||
{
|
||||
m_rxCallback = cb;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb)
|
||||
{
|
||||
m_promiscCallback = cb;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::SupportsSendFrom() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetRemote() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT(m_channel->GetNDevices() == 2);
|
||||
for (std::size_t i = 0; i < m_channel->GetNDevices(); ++i)
|
||||
{
|
||||
Ptr<NetDevice> tmp = m_channel->GetDevice(i);
|
||||
if (tmp != this)
|
||||
{
|
||||
return tmp->GetAddress();
|
||||
}
|
||||
}
|
||||
NS_ASSERT(false);
|
||||
// quiet compiler.
|
||||
return Address();
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::SetMtu(uint16_t mtu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << mtu);
|
||||
m_mtu = mtu;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
EthernetNetDevice::GetMtu() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_mtu;
|
||||
}
|
||||
|
||||
}
|
||||
464
contrib/ethernet/model/ethernet-net-device.h
Normal file
464
contrib/ethernet/model/ethernet-net-device.h
Normal file
@@ -0,0 +1,464 @@
|
||||
#ifndef ETHERNET_NET_DEVICE_H
|
||||
#define ETHERNET_NET_DEVICE_H
|
||||
|
||||
#include "ns3/address.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/queue-fwd.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
|
||||
#include "ns3/net-device.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class EthernetChannel;
|
||||
class ErrorModel;
|
||||
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* \class EthernetNetDevice
|
||||
* \brief A Device for a Ethernet full duplex Link.
|
||||
*
|
||||
* This EthernetNetDevice class specializes the NetDevice abstract
|
||||
* base class. Together with a EthernetChannel (and a peer
|
||||
* EthernetNetDevice), the class models, with some level of
|
||||
* abstraction, a full duplex ethernet link.
|
||||
* Key parameters or objects that can be specified for this device
|
||||
* include a queue, data rate, and interframe transmission gap (the
|
||||
* propagation delay is set in the EthernetChannel).
|
||||
*/
|
||||
|
||||
class EthernetNetDevice : public NetDevice
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* Construct a EthernetNetDevice
|
||||
*
|
||||
* This is the constructor for the EthernetNetDevice. It takes as a
|
||||
* parameter a pointer to the Node to which this device is connected,
|
||||
* as well as an optional DataRate object.
|
||||
*/
|
||||
EthernetNetDevice();
|
||||
|
||||
/**
|
||||
* Destroy a EthernetNetDevice
|
||||
*
|
||||
* This is the destructor for the EthernetNetDevice.
|
||||
*/
|
||||
~EthernetNetDevice() override;
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
EthernetNetDevice& operator=(const EthernetNetDevice&) = delete;
|
||||
EthernetNetDevice(const EthernetNetDevice&) = delete;
|
||||
|
||||
/**
|
||||
* Set the Data Rate used for transmission of packets. The data rate is
|
||||
* set in the Attach () method from the corresponding field in the channel
|
||||
* to which the device is attached. It can be overridden using this method.
|
||||
*
|
||||
* \param bps the data rate at which this object operates
|
||||
*/
|
||||
void SetDataRate(DataRate bps);
|
||||
|
||||
/**
|
||||
* Attach the device to a channel.
|
||||
*
|
||||
* \param ch Ptr to the channel to which this object is being attached.
|
||||
* \return true if the operation was successful (always true actually)
|
||||
*/
|
||||
bool Attach(Ptr<EthernetChannel> ch);
|
||||
|
||||
/**
|
||||
* Attach a queue to the EthernetNetDevice.
|
||||
*
|
||||
* The EthernetNetDevice "owns" a queue that implements a queueing
|
||||
* method such as DropTailQueue or RedQueue
|
||||
*
|
||||
* \param queue Ptr to the new queue.
|
||||
*/
|
||||
void SetQueue(Ptr<Queue<Packet>> queue);
|
||||
|
||||
/**
|
||||
* Get a copy of the attached Queue.
|
||||
*
|
||||
* \param index Queue index
|
||||
* \returns Ptr to the queue.
|
||||
*/
|
||||
Ptr<Queue<Packet>> GetQueue(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* Attach a receive ErrorModel to the EthernetNetDevice.
|
||||
*
|
||||
* The EthernetNetDevice may optionally include an ErrorModel in
|
||||
* the packet receive chain.
|
||||
*
|
||||
* \param em Ptr to the ErrorModel.
|
||||
*/
|
||||
void SetReceiveErrorModel(Ptr<ErrorModel> em);
|
||||
|
||||
/**
|
||||
* Receive a packet from a connected EthernetNetDevice.
|
||||
*
|
||||
* The EthernetNetDevice receives packets from its connected channel
|
||||
* and forwards them up the protocol stack. This is the public method
|
||||
* used by the channel to indicate that the last bit of a packet has
|
||||
* arrived at the device.
|
||||
*
|
||||
* \param p Ptr to the received packet.
|
||||
*/
|
||||
virtual void Receive(Ptr<Packet> p);
|
||||
|
||||
// The remaining methods are documented in ns3::NetDevice*
|
||||
|
||||
void SetIfIndex(const uint32_t index) override;
|
||||
uint32_t GetIfIndex() const override;
|
||||
|
||||
Ptr<Channel> GetChannel() const override;
|
||||
|
||||
void SetAddress(Address address) override;
|
||||
Address GetAddress() const override;
|
||||
|
||||
bool SetMtu(const uint16_t mtu) override;
|
||||
uint16_t GetMtu() const override;
|
||||
|
||||
bool IsLinkUp() const override;
|
||||
|
||||
void AddLinkChangeCallback(Callback<void> callback) override;
|
||||
|
||||
bool IsBroadcast() const override;
|
||||
Address GetBroadcast() const override;
|
||||
|
||||
bool IsMulticast() const override;
|
||||
Address GetMulticast(Ipv4Address multicastGroup) const override;
|
||||
|
||||
bool IsPointToPoint() const override;
|
||||
bool IsBridge() const override;
|
||||
|
||||
bool Send(Ptr<Packet> packet, const Address& dest, uint16_t ethertype) override;
|
||||
bool Send(Ptr<Packet> packet, const Address& dest, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei);
|
||||
virtual bool SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t ethertype) override;
|
||||
bool SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t ethertype,
|
||||
uint16_t vid,
|
||||
uint8_t pcp,
|
||||
uint8_t dei);
|
||||
|
||||
Ptr<Node> GetNode() const override;
|
||||
void SetNode(Ptr<Node> node) override;
|
||||
|
||||
bool NeedsArp() const override;
|
||||
|
||||
void SetReceiveCallback(NetDevice::ReceiveCallback cb) override;
|
||||
|
||||
Address GetMulticast(Ipv6Address addr) const override;
|
||||
|
||||
void SetPromiscReceiveCallback(PromiscReceiveCallback cb) override;
|
||||
bool SupportsSendFrom() const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Dispose of the object
|
||||
*/
|
||||
void DoDispose() override;
|
||||
|
||||
/**
|
||||
* \returns the address of the remote device connected to this device
|
||||
* through the ethernet channel.
|
||||
*/
|
||||
Address GetRemote() const;
|
||||
|
||||
/**
|
||||
* Adds the necessary headers and trailers to a packet of data in order to
|
||||
* respect the protocol implemented by the agent.
|
||||
* \param p packet
|
||||
* \param dst Dst mac address
|
||||
* \param src Src mac address
|
||||
* \param ethertype ethertype
|
||||
*/
|
||||
void AddHeader(Ptr<Packet> p, Mac48Address dst, Mac48Address src, uint16_t ethertype);
|
||||
|
||||
/**
|
||||
* Adds the necessary headers to a packet of data in order to
|
||||
* respect the protocol implemented by the agent.
|
||||
* \param p packet
|
||||
* \param dst Dst mac address
|
||||
* \param src Src mac address
|
||||
* \param ethertype ethertype
|
||||
* \param vid vlain id
|
||||
* \param pcp pcp field
|
||||
* \param dei dei bit
|
||||
*/
|
||||
void AddHeader(Ptr<Packet> p, Mac48Address dst, Mac48Address src, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei);
|
||||
|
||||
/**
|
||||
* Start Sending a Packet Down the Wire.
|
||||
*
|
||||
* The TransmitStart method is the method that is used internally in the
|
||||
* EthernetNetDevice to begin the process of sending a packet out on
|
||||
* the channel. The corresponding method is called on the channel to let
|
||||
* it know that the physical device this class represents has virtually
|
||||
* started sending signals. An event is scheduled for the time at which
|
||||
* the bits have been completely transmitted.
|
||||
*
|
||||
* \see EthernetChannel::TransmitStart ()
|
||||
* \see TransmitComplete()
|
||||
* \param p a reference to the packet to send
|
||||
* \returns true if success, false on failure
|
||||
*/
|
||||
bool TransmitStart(Ptr<Packet> p);
|
||||
|
||||
/**
|
||||
* Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
|
||||
*
|
||||
* The TransmitComplete method is used internally to finish the process
|
||||
* of sending a packet out on the channel.
|
||||
*/
|
||||
void TransmitComplete();
|
||||
|
||||
/**
|
||||
* Find the nextEligible Queue for transimission
|
||||
*
|
||||
* \returns Int id to the queue.
|
||||
*/
|
||||
virtual int TransmitSelection();
|
||||
|
||||
virtual void CheckForReadyPacket();
|
||||
|
||||
|
||||
/**
|
||||
* \brief Make the link up and running
|
||||
*
|
||||
* It calls also the linkChange callback.
|
||||
*/
|
||||
void NotifyLinkUp();
|
||||
|
||||
/**
|
||||
* Enumeration of the states of the transmit machine of the net device.
|
||||
*/
|
||||
enum TxMachineState
|
||||
{
|
||||
READY, /**< The transmitter is ready to begin transmission of a packet */
|
||||
BUSY /**< The transmitter is busy transmitting a packet */
|
||||
};
|
||||
|
||||
/**
|
||||
* The state of the Net Device transmit state machine.
|
||||
*/
|
||||
TxMachineState m_txMachineState;
|
||||
|
||||
/**
|
||||
* The data rate that the Net Device uses to simulate packet transmission
|
||||
* timing.
|
||||
*/
|
||||
DataRate m_bps;
|
||||
|
||||
/**
|
||||
* The preamble and start of frame delimiter gap that the Net Device uses to throttle packet
|
||||
* transmission in bytes
|
||||
*/
|
||||
uint8_t m_preambleAndSFDGap;
|
||||
|
||||
/**
|
||||
* The interframe gap that the Net Device uses to throttle packet
|
||||
* transmission in bytes
|
||||
*/
|
||||
uint8_t m_interframeGap;
|
||||
|
||||
/**
|
||||
* The EthernetChannel to which this EthernetNetDevice has been
|
||||
* attached.
|
||||
*/
|
||||
Ptr<EthernetChannel> m_channel;
|
||||
|
||||
/**
|
||||
* The Queues which this EthernetNetDevice uses as a packet source.
|
||||
* Management of this Queues has been delegated to the EthernetNetDevice
|
||||
* and it has the responsibility for deletion.
|
||||
* \see class DropTailQueue
|
||||
*/
|
||||
std::vector<Ptr<Queue<Packet>>> m_queues;
|
||||
|
||||
/**
|
||||
* Error model for receive packet events
|
||||
*/
|
||||
Ptr<ErrorModel> m_receiveErrorModel;
|
||||
|
||||
/**
|
||||
* The trace source fired when packets come into the "top" of the device
|
||||
* at the L3/L2 transition, before being queued for transmission.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macTxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when packets coming into the "top" of the device
|
||||
* at the L3/L2 transition are dropped before being queued for transmission.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macTxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired for packets successfully received by the device
|
||||
* immediately before being forwarded up to higher layers (at the L2/L3
|
||||
* transition). This is a promiscuous trace (which doesn't mean a lot here
|
||||
* in the point-to-point device).
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macPromiscRxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired for packets successfully received by the device
|
||||
* immediately before being forwarded up to higher layers (at the L2/L3
|
||||
* transition). This is a non-promiscuous trace (which doesn't mean a lot
|
||||
* here in the point-to-point device).
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macRxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired for packets successfully received by the device
|
||||
* but are dropped before being forwarded up to higher layers (at the L2/L3
|
||||
* transition).
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macRxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet begins the transmission process on
|
||||
* the medium.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyTxBeginTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet ends the transmission process on
|
||||
* the medium.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyTxEndTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when the phy layer drops a packet before it tries
|
||||
* to transmit it.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyTxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet begins the reception process from
|
||||
* the medium -- when the simulated first bit(s) arrive.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyRxBeginTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet ends the reception process from
|
||||
* the medium.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyRxEndTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when the phy layer drops a packet it has received.
|
||||
* This happens if the receiver is not enabled or the error model is active
|
||||
* and indicates that the packet is corrupt.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyRxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when the packet is receive to compute latency.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_latencyTrace;
|
||||
|
||||
/**
|
||||
* TracedCallback signature for packet transmission/reception events
|
||||
* (for external visualyzer).
|
||||
*
|
||||
* \param [in] packet The packet being transmitted.
|
||||
* \param [in] tx or rx NetDevice.
|
||||
*/
|
||||
typedef void (*MacTxAnimationCallback)(Ptr<const Packet> packet,
|
||||
Ptr<NetDevice> device);
|
||||
|
||||
TracedCallback<Ptr<const Packet>, Ptr<NetDevice>> m_macTxAnimationTrace;
|
||||
TracedCallback<Ptr<const Packet>, Ptr<NetDevice>> m_macRxAnimationTrace;
|
||||
/**
|
||||
* A trace source that emulates a non-promiscuous protocol sniffer connected
|
||||
* to the device. Unlike your average everyday sniffer, this trace source
|
||||
* will not fire on PACKET_OTHERHOST events.
|
||||
*
|
||||
* On the transmit size, this trace hook will fire after a packet is dequeued
|
||||
* from the device queue for transmission. In Linux, for example, this would
|
||||
* correspond to the point just before a device \c hard_start_xmit where
|
||||
* \c dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET
|
||||
* ETH_P_ALL handlers.
|
||||
*
|
||||
* On the receive side, this trace hook will fire when a packet is received,
|
||||
* just before the receive callback is executed. In Linux, for example,
|
||||
* this would correspond to the point at which the packet is dispatched to
|
||||
* packet sniffers in \c netif_receive_skb.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_snifferTrace;
|
||||
|
||||
/**
|
||||
* A trace source that emulates a promiscuous mode protocol sniffer connected
|
||||
* to the device. This trace source fire on packets destined for any host
|
||||
* just like your average everyday packet sniffer.
|
||||
*
|
||||
* On the transmit size, this trace hook will fire after a packet is dequeued
|
||||
* from the device queue for transmission. In Linux, for example, this would
|
||||
* correspond to the point just before a device \c hard_start_xmit where
|
||||
* \c dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET
|
||||
* ETH_P_ALL handlers.
|
||||
*
|
||||
* On the receive side, this trace hook will fire when a packet is received,
|
||||
* just before the receive callback is executed. In Linux, for example,
|
||||
* this would correspond to the point at which the packet is dispatched to
|
||||
* packet sniffers in \c netif_receive_skb.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_promiscSnifferTrace;
|
||||
|
||||
|
||||
TracedCallback<std::vector<Ptr<Queue<Packet>>>,
|
||||
bool,
|
||||
Ptr<const Packet>> m_FIFOStateSnifferTrace;
|
||||
|
||||
|
||||
Ptr<Node> m_node; //!< Node owning this NetDevice
|
||||
Mac48Address m_address; //!< Mac48Address of this NetDevice
|
||||
NetDevice::ReceiveCallback m_rxCallback; //!< Receive callback
|
||||
NetDevice::PromiscReceiveCallback m_promiscCallback; //!< Receive callback
|
||||
// (promisc data)
|
||||
uint32_t m_ifIndex; //!< Index of the interface
|
||||
bool m_linkUp; //!< Identify if the link is up or not
|
||||
TracedCallback<> m_linkChangeCallbacks; //!< Callback for the link change event
|
||||
|
||||
static const uint16_t DEFAULT_MTU = 1500; //!< Default MTU
|
||||
|
||||
/**
|
||||
* \brief The Maximum Transmission Unit
|
||||
*
|
||||
* This corresponds to the maximum
|
||||
* number of bytes that can be transmitted as seen from higher layers.
|
||||
* This corresponds to the 1500 byte MTU size often seen on IP over
|
||||
* Ethernet.
|
||||
*/
|
||||
uint32_t m_mtu;
|
||||
|
||||
Ptr<Packet> m_currentPkt; //!< Current packet processed
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ETHERNET_NET_DEVICE_H */
|
||||
77
contrib/ethernet/model/switch-channel.cc
Normal file
77
contrib/ethernet/model/switch-channel.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "switch-channel.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup ethernet
|
||||
* ns3::SwitchChannel implementation.
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("SwitchChannel");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(SwitchChannel);
|
||||
|
||||
TypeId
|
||||
SwitchChannel::GetTypeId()
|
||||
{
|
||||
static TypeId tid = TypeId("ns3::SwitchChannel")
|
||||
.SetParent<Channel>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<SwitchChannel>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
SwitchChannel::SwitchChannel()
|
||||
: Channel()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
SwitchChannel::~SwitchChannel()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
|
||||
for (auto iter = m_switchedChannels.begin(); iter != m_switchedChannels.end(); iter++)
|
||||
{
|
||||
*iter = nullptr;
|
||||
}
|
||||
m_switchedChannels.clear();
|
||||
}
|
||||
|
||||
void
|
||||
SwitchChannel::AddChannel(Ptr<Channel> switchedChannel)
|
||||
{
|
||||
m_switchedChannels.push_back(switchedChannel);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
SwitchChannel::GetNDevices() const
|
||||
{
|
||||
uint32_t ndevices = 0;
|
||||
for (auto iter = m_switchedChannels.begin(); iter != m_switchedChannels.end(); iter++)
|
||||
{
|
||||
ndevices += (*iter)->GetNDevices();
|
||||
}
|
||||
return ndevices;
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
SwitchChannel::GetDevice(std::size_t i) const
|
||||
{
|
||||
std::size_t ndevices = 0;
|
||||
for (auto iter = m_switchedChannels.begin(); iter != m_switchedChannels.end(); iter++)
|
||||
{
|
||||
if ((i - ndevices) < (*iter)->GetNDevices())
|
||||
{
|
||||
return (*iter)->GetDevice(i - ndevices);
|
||||
}
|
||||
ndevices += (*iter)->GetNDevices();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
59
contrib/ethernet/model/switch-channel.h
Normal file
59
contrib/ethernet/model/switch-channel.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef SWITCH_CHANNEL_H
|
||||
#define SWITCH_CHANNEL_H
|
||||
|
||||
#include "ns3/channel.h"
|
||||
#include "ns3/net-device.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup ethernet
|
||||
* ns3::SwitchChannel declaration.
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
/**
|
||||
* \ingroup bridge
|
||||
*
|
||||
* \brief Virtual channel implementation for bridges (BridgeNetDevice).
|
||||
*
|
||||
* Just like SwitchNetDevice aggregates multiple NetDevices,
|
||||
* SwitchChannel aggregates multiple channels and make them appear as
|
||||
* a single channel to upper layers.
|
||||
* This class is greatly inspire form BridgeChannel
|
||||
*/
|
||||
class SwitchChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
SwitchChannel();
|
||||
~SwitchChannel() override;
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
SwitchChannel(const SwitchChannel&) = delete;
|
||||
SwitchChannel& operator=(const SwitchChannel&) = delete;
|
||||
|
||||
/**
|
||||
* Adds a channel to the bridged pool
|
||||
* \param bridgedChannel the channel to add to the pool
|
||||
*/
|
||||
void AddChannel(Ptr<Channel> bridgedChannel);
|
||||
|
||||
// virtual methods implementation, from Channel
|
||||
std::size_t GetNDevices() const override;
|
||||
Ptr<NetDevice> GetDevice(std::size_t i) const override;
|
||||
|
||||
private:
|
||||
std::vector<Ptr<Channel>> m_switchedChannels; //!< pool of switched channels
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* SWITCH_CHANNEL_H */
|
||||
427
contrib/ethernet/model/switch-net-device.cc
Normal file
427
contrib/ethernet/model/switch-net-device.cc
Normal file
@@ -0,0 +1,427 @@
|
||||
#include "switch-net-device.h"
|
||||
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/channel.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/names.h"
|
||||
#include "ns3/random-variable-stream.h"
|
||||
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/net-device.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup ethernet
|
||||
* ns3::SwitchNetDevice implementation.
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("SwitchNetDevice");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(SwitchNetDevice);
|
||||
|
||||
TypeId
|
||||
SwitchNetDevice::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::SwitchNetDevice")
|
||||
.SetParent<NetDevice>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<SwitchNetDevice>()
|
||||
.AddAttribute("Mtu",
|
||||
"The MAC-level Maximum Transmission Unit",
|
||||
UintegerValue(1500),
|
||||
MakeUintegerAccessor(&SwitchNetDevice::SetMtu, &SwitchNetDevice::GetMtu),
|
||||
MakeUintegerChecker<uint16_t>())
|
||||
.AddAttribute("MinForwardingLatency",
|
||||
"The minimum latency experienced by the packet during forwarding",
|
||||
TimeValue(Seconds(0)),
|
||||
MakeTimeAccessor(&SwitchNetDevice::m_minForwardingLatency),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("MaxForwardingLatency",
|
||||
"The maximun latency experienced by the packet during forwarding",
|
||||
TimeValue(Seconds(0)),
|
||||
MakeTimeAccessor(&SwitchNetDevice::m_maxForwardingLatency),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("MaxPortNumber",
|
||||
"The maximum number of port",
|
||||
UintegerValue(65535),
|
||||
MakeUintegerAccessor(&SwitchNetDevice::m_maxPortNumber),
|
||||
MakeUintegerChecker<uint16_t>())
|
||||
.AddAttribute("MaxFdbEntryNumber",
|
||||
"The maximum number of entry in the forwarding database",
|
||||
UintegerValue(65535),
|
||||
MakeUintegerAccessor(&SwitchNetDevice::m_maxFdbEntryNumber),
|
||||
MakeUintegerChecker<uint16_t>());
|
||||
return tid;
|
||||
}
|
||||
|
||||
SwitchNetDevice::SwitchNetDevice()
|
||||
: m_node(nullptr),
|
||||
m_ifIndex(0)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_channel = CreateObject<SwitchChannel>();
|
||||
}
|
||||
|
||||
SwitchNetDevice::~SwitchNetDevice()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
for (auto iter = m_ports.begin(); iter != m_ports.end(); iter++)
|
||||
{
|
||||
*iter = nullptr;
|
||||
}
|
||||
m_ports.clear();
|
||||
m_forwardingTable.clear();
|
||||
m_channel = nullptr;
|
||||
m_node = nullptr;
|
||||
NetDevice::DoDispose();
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::ReceiveFromDevice(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
const Address& src,
|
||||
const Address& dst,
|
||||
PacketType packetType)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
NS_LOG_DEBUG("UID is " << packet->GetUid());
|
||||
|
||||
Mac48Address src48 = Mac48Address::ConvertFrom(src);
|
||||
Mac48Address dst48 = Mac48Address::ConvertFrom(dst);
|
||||
|
||||
if (!m_promiscRxCallback.IsNull())
|
||||
{
|
||||
m_promiscRxCallback(this, packet, protocol, src, dst, packetType);
|
||||
}
|
||||
switch (packetType)
|
||||
{
|
||||
case PACKET_HOST:
|
||||
if (dst48 == m_address)
|
||||
{
|
||||
m_rxCallback(this, packet, protocol, src);
|
||||
}
|
||||
break;
|
||||
case PACKET_MULTICAST:
|
||||
case PACKET_BROADCAST:
|
||||
m_rxCallback(this, packet, protocol, src);
|
||||
ForwardBroadcast(incomingPort, packet, protocol, src48, dst48);
|
||||
break;
|
||||
|
||||
case PACKET_OTHERHOST:
|
||||
if (dst48 == m_address)
|
||||
{
|
||||
m_rxCallback(this, packet, protocol, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
Forward(incomingPort, packet, protocol, src48, dst48);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::Forward(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
Mac48Address src,
|
||||
Mac48Address dst)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
Ptr<Packet> originalPacket = packet->Copy();
|
||||
EthernetHeader2 header;
|
||||
originalPacket->RemoveHeader(header);
|
||||
uint16_t vid = header.GetVid();
|
||||
//NS_LOG_INFO(Names::FindName(this) << " Look in forwarding table for Pkt #" << packet->GetUid());
|
||||
std::vector<Ptr<NetDevice>> outPorts = GetOutputPortsFromForwardingTable(dst, vid);
|
||||
EventId e;
|
||||
int s = outPorts.size();
|
||||
for(int i=0; i < s; i++){
|
||||
//Avoid sending on the incomingPort
|
||||
if(outPorts[i] != incomingPort){
|
||||
Ptr<UniformRandomVariable> randVar = CreateObject<UniformRandomVariable>();
|
||||
Time forwardingLatency = NanoSeconds(randVar->GetValue(m_minForwardingLatency.GetNanoSeconds(), m_maxForwardingLatency.GetNanoSeconds()));
|
||||
Simulator::Schedule(forwardingLatency, &NetDevice::SendFrom, outPorts[i], packet->Copy(), src, dst, protocol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::ForwardBroadcast(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
Mac48Address src,
|
||||
Mac48Address dst)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
|
||||
Forward(incomingPort, packet, protocol, src, dst);
|
||||
}
|
||||
|
||||
std::vector<Ptr<NetDevice>>
|
||||
SwitchNetDevice::GetOutputPortsFromForwardingTable(Mac48Address dest, uint16_t vid)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
int s = m_forwardingTable.size();
|
||||
for(int i=0; i < s; i++){
|
||||
if(m_forwardingTable[i].dest == dest and m_forwardingTable[i].vid==vid){
|
||||
// NS_LOG_INFO(Names::FindName(this) << " Forwarding Table : Match on vid "<< vid << " for " << m_forwardingTable[i].associatedPorts.size() << " output port(s) ");
|
||||
return m_forwardingTable[i].associatedPorts;
|
||||
}
|
||||
}
|
||||
// NS_LOG_INFO(Names::FindName(this) << " Forwarding Table : No Match on vid "<< vid);
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::AddForwardingTableEntry(Mac48Address dest, uint16_t vid, std::vector<Ptr<NetDevice>> outPorts)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(m_forwardingTable.size() < m_maxFdbEntryNumber, "Trying to add more forwarding database entry than the " << m_maxFdbEntryNumber << " available.");
|
||||
PortsToVidAssociation entry = {dest, vid, outPorts};
|
||||
m_forwardingTable.insert(m_forwardingTable.end(), entry);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SwitchNetDevice::GetNSwitchPorts() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_ports.size();
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
SwitchNetDevice::GetSwitchPort(uint32_t n) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_ports[n];
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::AddSwitchPort(Ptr<NetDevice> switchPort)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
NS_ASSERT_MSG(m_ports.size() < m_maxPortNumber, "Trying to add more switch port than the " << m_maxPortNumber << " available.");
|
||||
//NS_ASSERT(switchPort != this);
|
||||
if (!Mac48Address::IsMatchingType(switchPort->GetAddress()))
|
||||
{
|
||||
NS_FATAL_ERROR("Device does not support eui 48 addresses: cannot be added to switch.");
|
||||
}
|
||||
if (!switchPort->SupportsSendFrom())
|
||||
{
|
||||
NS_FATAL_ERROR("Device does not support SendFrom: cannot be added to switch.");
|
||||
}
|
||||
if (m_address == Mac48Address())
|
||||
{
|
||||
m_address = Mac48Address::ConvertFrom(switchPort->GetAddress());
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG("RegisterProtocolHandler for " << switchPort->GetInstanceTypeId().GetName());
|
||||
m_node->RegisterProtocolHandler(MakeCallback(&SwitchNetDevice::ReceiveFromDevice, this),
|
||||
0,
|
||||
switchPort,
|
||||
true);
|
||||
m_ports.push_back(switchPort);
|
||||
m_channel->AddChannel(switchPort->GetChannel());
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetIfIndex(const uint32_t index)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_ifIndex = index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SwitchNetDevice::GetIfIndex() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_ifIndex;
|
||||
}
|
||||
|
||||
Ptr<Channel>
|
||||
SwitchNetDevice::GetChannel() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetAddress(Address address)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_address = Mac48Address::ConvertFrom(address);
|
||||
}
|
||||
|
||||
Address
|
||||
SwitchNetDevice::GetAddress() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_address;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::SetMtu(const uint16_t mtu)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_mtu = mtu;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
SwitchNetDevice::GetMtu() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_mtu;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsLinkUp() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::AddLinkChangeCallback(Callback<void> callback)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsBroadcast() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
SwitchNetDevice::GetBroadcast() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return Mac48Address("ff:ff:ff:ff:ff:ff");
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsMulticast() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
SwitchNetDevice::GetMulticast(Ipv4Address multicastGroup) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << multicastGroup);
|
||||
Mac48Address multicast = Mac48Address::GetMulticast(multicastGroup);
|
||||
return multicast;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsPointToPoint() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsBridge() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return SendFrom(packet, m_address, dest, protocolNumber);
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t protocolNumber)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
Mac48Address src = Mac48Address::ConvertFrom(source);
|
||||
Mac48Address dst = Mac48Address::ConvertFrom(dest);
|
||||
|
||||
|
||||
Ptr<Packet> originalPacket = packet->Copy();
|
||||
EthernetHeader2 header;
|
||||
originalPacket->RemoveHeader(header);
|
||||
uint16_t vid = header.GetVid();
|
||||
|
||||
std::vector<Ptr<NetDevice>> outPorts = GetOutputPortsFromForwardingTable(dst, vid);
|
||||
int s = outPorts.size();
|
||||
for(int i=0; i < s; i++){
|
||||
outPorts[i]->SendFrom(packet->Copy(), src, dst, protocolNumber);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Ptr<Node>
|
||||
SwitchNetDevice::GetNode() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_node;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetNode(Ptr<Node> node)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_node = node;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::NeedsArp() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetReceiveCallback(NetDevice::ReceiveCallback cb)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_rxCallback = cb;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_promiscRxCallback = cb;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::SupportsSendFrom() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
SwitchNetDevice::GetMulticast(Ipv6Address addr) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << addr);
|
||||
return Mac48Address::GetMulticast(addr);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
220
contrib/ethernet/model/switch-net-device.h
Normal file
220
contrib/ethernet/model/switch-net-device.h
Normal file
@@ -0,0 +1,220 @@
|
||||
#ifndef SWITCH_NET_DEVICE_H
|
||||
#define SWITCH_NET_DEVICE_H
|
||||
|
||||
#include "switch-channel.h"
|
||||
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup ethernet
|
||||
* ns3::SwitchNetDevice declaration.
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* \brief a virtual net device that bridges multiple LAN segments
|
||||
*
|
||||
* The SwitchNetDevice object is a "virtual" netdevice that aggregates
|
||||
* multiple "real" netdevices and implements the data plane forwarding
|
||||
* part of IEEE 802.1D. By adding a SwitchNetDevice to a Node, it
|
||||
* will act as a "switch" to multiple LAN segments.
|
||||
*
|
||||
* \attention The switch netdevice don't implement a "Learning bridge" algorithm
|
||||
* or Spanning Tree Protocol as described in 802.1D
|
||||
*
|
||||
* \attention Switching is designed to work only with Ethernet NetDevices
|
||||
* modelling IEEE 802-style technologies, such as EthernetNetDevice
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* \brief a virtual net device that bridges multiple LAN segments
|
||||
*/
|
||||
class SwitchNetDevice : public NetDevice
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
SwitchNetDevice();
|
||||
~SwitchNetDevice() override;
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
SwitchNetDevice(const SwitchNetDevice&) = delete;
|
||||
SwitchNetDevice& operator=(const SwitchNetDevice&) = delete;
|
||||
|
||||
/**
|
||||
* \brief Add a 'port' to a switch device
|
||||
* \param switchPort the NetDevice to add
|
||||
*
|
||||
* This method adds a new switch port to a SwitchNetDevice, so that
|
||||
* the new switch port NetDevice becomes part of the switch and L2
|
||||
* frames start being forwarded to/from this NetDevice.
|
||||
*
|
||||
* \attention The netdevice that is being added as switch port must
|
||||
* _not_ have an IP address. In order to add IP connectivity to a
|
||||
* bridging node you must enable IP on the SwitchNetDevice itself,
|
||||
* never on its port netdevices.
|
||||
*/
|
||||
void AddSwitchPort(Ptr<NetDevice> switchPort);
|
||||
|
||||
/**
|
||||
* \brief Gets the number of switched 'ports', i.e., the NetDevices currently switched.
|
||||
*
|
||||
* \return the number of switched ports.
|
||||
*/
|
||||
uint32_t GetNSwitchPorts() const;
|
||||
|
||||
/**
|
||||
* \brief Gets the n-th switched port.
|
||||
* \param n the port index
|
||||
* \return the n-th switched NetDevice
|
||||
*/
|
||||
Ptr<NetDevice> GetSwitchPort(uint32_t n) const;
|
||||
|
||||
// inherited from NetDevice base class.
|
||||
void SetIfIndex(const uint32_t index) override;
|
||||
uint32_t GetIfIndex() const override;
|
||||
Ptr<Channel> GetChannel() const override;
|
||||
void SetAddress(Address address) override;
|
||||
Address GetAddress() const override;
|
||||
bool SetMtu(const uint16_t mtu) override;
|
||||
uint16_t GetMtu() const override;
|
||||
bool IsLinkUp() const override;
|
||||
void AddLinkChangeCallback(Callback<void> callback) override;
|
||||
bool IsBroadcast() const override;
|
||||
Address GetBroadcast() const override;
|
||||
bool IsMulticast() const override;
|
||||
Address GetMulticast(Ipv4Address multicastGroup) const override;
|
||||
bool IsPointToPoint() const override;
|
||||
bool IsBridge() const override;
|
||||
bool Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber) override;
|
||||
bool SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t protocolNumber) override;
|
||||
Ptr<Node> GetNode() const override;
|
||||
void SetNode(Ptr<Node> node) override;
|
||||
bool NeedsArp() const override;
|
||||
void SetReceiveCallback(NetDevice::ReceiveCallback cb) override;
|
||||
void SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb) override;
|
||||
bool SupportsSendFrom() const override;
|
||||
Address GetMulticast(Ipv6Address addr) const override;
|
||||
|
||||
/**
|
||||
* \brief Add a entry to the forwarding table
|
||||
* \param dest destination mac
|
||||
* \param vid Vlan ID
|
||||
* \param outPorts vector of output port
|
||||
*/
|
||||
void AddForwardingTableEntry(Mac48Address dest,
|
||||
uint16_t vid,
|
||||
std::vector<Ptr<NetDevice>> outPorts);
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
|
||||
/**
|
||||
* \brief Receives a packet from one switched port.
|
||||
* \param device the originating port
|
||||
* \param packet the received packet
|
||||
* \param protocol the packet protocol (e.g., Ethertype)
|
||||
* \param source the packet source
|
||||
* \param destination the packet destination
|
||||
* \param packetType the packet type (e.g., host, broadcast, etc.)
|
||||
*/
|
||||
void ReceiveFromDevice(Ptr<NetDevice> device,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
const Address& source,
|
||||
const Address& destination,
|
||||
PacketType packetType);
|
||||
|
||||
/**
|
||||
* \brief Forwards a packet
|
||||
* \param incomingPort the packet incoming port
|
||||
* \param packet the packet
|
||||
* \param protocol the packet protocol (e.g., Ethertype)
|
||||
* \param src the packet source
|
||||
* \param dst the packet destination
|
||||
*/
|
||||
void Forward(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
Mac48Address src,
|
||||
Mac48Address dst);
|
||||
|
||||
/**
|
||||
* \brief Forwards a broadcast or a multicast packet
|
||||
* \param incomingPort the packet incoming port
|
||||
* \param packet the packet
|
||||
* \param protocol the packet protocol (e.g., Ethertype)
|
||||
* \param src the packet source
|
||||
* \param dst the packet destination
|
||||
*/
|
||||
void ForwardBroadcast(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
Mac48Address src,
|
||||
Mac48Address dst);
|
||||
|
||||
/**
|
||||
* \brief Get the output ports from the forwarding table
|
||||
* \param dest destination mac
|
||||
* \param vid Vlan ID
|
||||
* \return output ports
|
||||
*/
|
||||
std::vector<Ptr<NetDevice>> GetOutputPortsFromForwardingTable(Mac48Address dest,
|
||||
uint16_t vid);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
NetDevice::ReceiveCallback m_rxCallback; //!< receive callback
|
||||
NetDevice::PromiscReceiveCallback m_promiscRxCallback; //!< promiscuous receive callback
|
||||
|
||||
Mac48Address m_address; //!< MAC address of the NetDevice
|
||||
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* Structure holding the association between ports and vid for a mac destination address
|
||||
*/
|
||||
struct PortsToVidAssociation
|
||||
{
|
||||
Mac48Address dest;
|
||||
uint16_t vid;
|
||||
std::vector<Ptr<NetDevice>> associatedPorts;
|
||||
};
|
||||
|
||||
std::vector<PortsToVidAssociation> m_forwardingTable; //!< Container for forwarding table
|
||||
Ptr<Node> m_node; //!< node owning this NetDevice
|
||||
Ptr<SwitchChannel> m_channel; //!< virtual bridged channel
|
||||
std::vector<Ptr<NetDevice>> m_ports; //!< switched ports
|
||||
uint32_t m_ifIndex; //!< Interface index
|
||||
uint16_t m_mtu; //!< MTU of the switched NetDevice
|
||||
|
||||
Time m_minForwardingLatency;
|
||||
Time m_maxForwardingLatency;
|
||||
|
||||
uint16_t m_maxPortNumber;
|
||||
uint16_t m_maxFdbEntryNumber;
|
||||
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* SWITCH_NET_DEVICE_H */
|
||||
Reference in New Issue
Block a user