Update README and add contrib dir

This commit is contained in:
2025-12-01 15:56:02 +01:00
parent 1b80de2153
commit cd9ba93d58
150 changed files with 25563 additions and 0 deletions

View 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;
}
}

View 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 */

View 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;
}
}

View 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 */

View 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;
}
}

View 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 */

View 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

View 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 */

View 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

View 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 */