759 lines
24 KiB
C++
759 lines
24 KiB
C++
|
|
#include "tsn-multidrop-net-device.h"
|
||
|
|
|
||
|
|
#include "ns3/tsn-net-device.h"
|
||
|
|
#include "ns3/tsn-multidrop-channel.h"
|
||
|
|
#include "ns3/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/timestamp-tag.h"
|
||
|
|
#include "ns3/ethernet-trailer.h"
|
||
|
|
#include "ns3/names.h"
|
||
|
|
|
||
|
|
|
||
|
|
namespace ns3
|
||
|
|
{
|
||
|
|
|
||
|
|
NS_LOG_COMPONENT_DEFINE("TsnMultidropNetDevice");
|
||
|
|
|
||
|
|
NS_OBJECT_ENSURE_REGISTERED(TsnMultidropNetDevice);
|
||
|
|
|
||
|
|
TypeId
|
||
|
|
TsnMultidropNetDevice::GetTypeId()
|
||
|
|
{
|
||
|
|
static TypeId tid =
|
||
|
|
TypeId("ns3::TsnMultidropNetDevice")
|
||
|
|
.SetParent<TsnNetDevice>()
|
||
|
|
.SetGroupName("Tsn")
|
||
|
|
.AddConstructor<TsnMultidropNetDevice>()
|
||
|
|
.AddAttribute("PLCALocalNodeId",
|
||
|
|
"Local node ID for PLCA",
|
||
|
|
UintegerValue(0),
|
||
|
|
MakeUintegerAccessor(&TsnMultidropNetDevice::m_PLCALocalNodeId),
|
||
|
|
MakeUintegerChecker<uint8_t>())
|
||
|
|
.AddAttribute("PLCANodeCount",
|
||
|
|
"Number of node in the collision domain",
|
||
|
|
UintegerValue(8),
|
||
|
|
MakeUintegerAccessor(&TsnMultidropNetDevice::m_PLCANodeCount),
|
||
|
|
MakeUintegerChecker<uint8_t>())
|
||
|
|
.AddAttribute("PLCATransmitOpportunityTimer",
|
||
|
|
"Max number of bit time between transmit opportunity",
|
||
|
|
UintegerValue(32),
|
||
|
|
MakeUintegerAccessor(&TsnMultidropNetDevice::m_PLCATransmitOpportunityTimer),
|
||
|
|
MakeUintegerChecker<uint8_t>())
|
||
|
|
.AddAttribute("PLCAMaxBurstCount",
|
||
|
|
"Max number of additional packet that can be transmit in a single opportunity",
|
||
|
|
UintegerValue(0),
|
||
|
|
MakeUintegerAccessor(&TsnMultidropNetDevice::m_PLCAMaxBurstCount),
|
||
|
|
MakeUintegerChecker<uint8_t>())
|
||
|
|
.AddAttribute("PLCABurstTimer",
|
||
|
|
"Max number of bit time PLCA waits for the mac to send a "
|
||
|
|
"new packet before yielding the transmission opportunity",
|
||
|
|
UintegerValue(128),
|
||
|
|
MakeUintegerAccessor(&TsnMultidropNetDevice::m_PLCABurstTimer),
|
||
|
|
MakeUintegerChecker<uint8_t>())
|
||
|
|
|
||
|
|
.AddTraceSource("PLCAState",
|
||
|
|
"PLCA State trace",
|
||
|
|
MakeTraceSourceAccessor(&TsnMultidropNetDevice::m_PLCAStateTrace),
|
||
|
|
"ns3::TsnMultidropNetDevice::m_PLCAState");
|
||
|
|
return tid;
|
||
|
|
}
|
||
|
|
|
||
|
|
TsnMultidropNetDevice::TsnMultidropNetDevice()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
TsnMultidropNetDevice::~TsnMultidropNetDevice()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::DoDispose()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
NetDevice::DoDispose();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool
|
||
|
|
TsnMultidropNetDevice::Attach(Ptr<TsnMultidropChannel> 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();
|
||
|
|
//Init PLCA
|
||
|
|
PLCA();
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
bool
|
||
|
|
TsnMultidropNetDevice::TransmitStart(Ptr<Packet> p, int queue_id)
|
||
|
|
{
|
||
|
|
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 ");
|
||
|
|
|
||
|
|
//Timestamping at last bits emission
|
||
|
|
NS_ASSERT_MSG(m_node != nullptr, "m_node was not set using void TsnNetDevice::SetNode(Ptr<TsnNode> node)");
|
||
|
|
Time txTimestamp = m_node->GetTime();
|
||
|
|
|
||
|
|
//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");
|
||
|
|
NS_ASSERT_MSG(m_PLCAState == COMMIT, "Must be COMMIT to transmit with PLCA");
|
||
|
|
m_txMachineState = BUSY;
|
||
|
|
m_PLCAState = TRANSMIT;
|
||
|
|
m_txHardwareLatencyExperienced = false;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
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, &TsnTransmissionSelectionAlgo::TransmitComplete, m_transmissionSelectionAlgos[queue_id], p);
|
||
|
|
m_transmissionSelectionAlgos[queue_id]->TransmitStart(p, txTime);
|
||
|
|
|
||
|
|
Simulator::Schedule(txCompleteTime, &TsnMultidropNetDevice::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);
|
||
|
|
}
|
||
|
|
if(!m_rxCallbackWithTimestamp.IsNull()){
|
||
|
|
m_txCallbackWithTimestamp(p, txTimestamp);
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool
|
||
|
|
TsnMultidropNetDevice::isPacketPending()
|
||
|
|
{
|
||
|
|
int next_queue_id = TransmitSelection();
|
||
|
|
if(next_queue_id==-1)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::Send1Packet()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
NS_ASSERT(m_PLCAState == COMMIT);
|
||
|
|
|
||
|
|
int next_queue_id = TransmitSelection();
|
||
|
|
NS_ASSERT_MSG(next_queue_id!=-1, "No packet available");
|
||
|
|
NS_LOG_INFO("Send 1 pkt from queue " << (next_queue_id));
|
||
|
|
|
||
|
|
Ptr<Packet> p = m_queues[next_queue_id]->Dequeue();
|
||
|
|
m_snifferTrace(p);
|
||
|
|
m_promiscSnifferTrace(p);
|
||
|
|
TransmitStart(p, next_queue_id);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::TransmitComplete()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
// 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");
|
||
|
|
NS_ASSERT_MSG(m_PLCAState == TRANSMIT, "Must be COMMIT if transmitting with PLCA");
|
||
|
|
NS_LOG_INFO(Names::FindName(this) << " PKT #" << m_currentPkt->GetUid() << " at " << Simulator::Now().GetNanoSeconds()<<" Transmit end ");
|
||
|
|
m_txMachineState = READY;
|
||
|
|
|
||
|
|
NS_ASSERT_MSG(m_currentPkt, "TsnMultidropNetDevice::TransmitComplete(): m_currentPkt zero");
|
||
|
|
|
||
|
|
m_phyTxEndTrace(m_currentPkt);
|
||
|
|
|
||
|
|
//m_transmissionSelectionAlgos[queue_id]->TransmitComplete(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), &TsnMultidropNetDevice::PLCA, this);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::PLCA()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
NS_LOG_INFO(Names::FindName(this) << " : Current PLCA state = " << m_PLCAState);
|
||
|
|
|
||
|
|
if(m_PLCAState == DISABLE)
|
||
|
|
{
|
||
|
|
//We can't really turn on or off PLCA but we don't need this functionnality
|
||
|
|
//for our work
|
||
|
|
|
||
|
|
if(m_PLCALocalNodeId == 0)
|
||
|
|
{
|
||
|
|
m_PLCAactive = false;
|
||
|
|
m_PLCAState = RECOVER;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_PLCAactive = false;
|
||
|
|
m_PLCAState = RESYNC;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if(m_PLCAState == RECOVER)
|
||
|
|
{
|
||
|
|
m_PLCAState = WAIT_TO;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
else if(m_PLCAState == RESYNC)
|
||
|
|
{
|
||
|
|
if(m_PLCALocalNodeId == 0)
|
||
|
|
{
|
||
|
|
m_PLCAactive = true;
|
||
|
|
m_PLCAState = SEND_BEACON;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (m_PLCAState == SYNCING)
|
||
|
|
{
|
||
|
|
m_PLCACurID = 0;
|
||
|
|
m_PLCAState = WAIT_TO;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
else if(m_PLCAState == SEND_BEACON)
|
||
|
|
{
|
||
|
|
m_PLCAactive = true;
|
||
|
|
m_channel->StartBeaconTransmission();
|
||
|
|
Simulator::Schedule(m_bps.CalculateBytesTxTime(m_PLCABeaconTimer), &TsnMultidropNetDevice::BeaconTimerDone, this);
|
||
|
|
}
|
||
|
|
else if(m_PLCAState == WAIT_TO)
|
||
|
|
{
|
||
|
|
m_PLCAToTimerEvent = Simulator::Schedule(m_bps.CalculateBytesTxTime(m_PLCATransmitOpportunityTimer), &TsnMultidropNetDevice::ToTimerDone, this);
|
||
|
|
if(m_PLCALocalNodeId == m_PLCACurID)
|
||
|
|
{
|
||
|
|
if (isPacketPending())
|
||
|
|
{
|
||
|
|
m_PLCAState = COMMIT;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_PLCAState = YIELD;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (m_PLCAState == COMMIT)
|
||
|
|
{
|
||
|
|
Simulator::Cancel(m_PLCAToTimerEvent);
|
||
|
|
m_PLCABurstCount = 0;
|
||
|
|
Simulator::Schedule(Time(0), &TsnMultidropNetDevice::Send1Packet, this); //Schedule in 0 to put this at the end of the event list
|
||
|
|
}
|
||
|
|
else if (m_PLCAState == TRANSMIT)
|
||
|
|
{
|
||
|
|
//At least one pkt is ready to be sent
|
||
|
|
if(m_txMachineState == READY)
|
||
|
|
{
|
||
|
|
if (m_PLCABurstCount >= m_PLCAMaxBurstCount)
|
||
|
|
{
|
||
|
|
m_PLCAState = NEXT_TX_OPPORTUNITY;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_PLCAState = BURST;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
NS_ASSERT_MSG(false, "PLCA burst mode not implemented");
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (m_PLCAState == BURST)
|
||
|
|
{
|
||
|
|
m_PLCABurstCount = m_PLCABurstCount + 1;
|
||
|
|
if (isPacketPending())
|
||
|
|
{
|
||
|
|
Send1Packet();
|
||
|
|
m_PLCAState = TRANSMIT;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//TODO burst timer ! How does it work ????
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else if (m_PLCAState == YIELD)
|
||
|
|
{
|
||
|
|
//Do nothing
|
||
|
|
}
|
||
|
|
else if (m_PLCAState == NEXT_TX_OPPORTUNITY)
|
||
|
|
{
|
||
|
|
m_PLCACurID = m_PLCACurID + 1;
|
||
|
|
NS_LOG_INFO(Names::FindName(this) << " : New PLCACurId = " << (uint16_t) m_PLCACurID);
|
||
|
|
|
||
|
|
if (m_PLCALocalNodeId == 0 && m_PLCACurID >= m_PLCANodeCount)
|
||
|
|
{
|
||
|
|
m_PLCAState = RESYNC;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
m_PLCAState = WAIT_TO;
|
||
|
|
}
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::ToTimerDone()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
m_PLCAState = NEXT_TX_OPPORTUNITY;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::BeaconTimerDone()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
m_PLCAState = SYNCING;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
m_channel->StopBeaconTransmission();
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::BeaconDetTimerDone()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
m_PLCAState = RESYNC;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::StartBeaconReception()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
if (m_PLCALocalNodeId != 0)
|
||
|
|
{
|
||
|
|
m_PLCAState = EARLY_RECEIVE;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
Simulator::Cancel(m_PLCAToTimerEvent);
|
||
|
|
m_PLCABeaconDetTimerEvent = Simulator::Schedule(m_bps.CalculateBytesTxTime(m_PLCABeaconDetTimer), &TsnMultidropNetDevice::BeaconDetTimerDone, this);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::StopBeaconReception()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
if (m_PLCALocalNodeId != 0)
|
||
|
|
{
|
||
|
|
if (m_PLCABeaconDetTimerEvent.IsRunning())
|
||
|
|
{
|
||
|
|
Simulator::Cancel(m_PLCABeaconDetTimerEvent);
|
||
|
|
m_PLCAState = SYNCING;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::StartReception()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
NS_ASSERT_MSG(m_PLCAState == WAIT_TO || m_PLCAState == RECEIVE, "m_PLCAState = " << m_PLCAState);
|
||
|
|
if(m_PLCAState == WAIT_TO)
|
||
|
|
{
|
||
|
|
m_PLCAState = EARLY_RECEIVE;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
Simulator::Cancel(m_PLCAToTimerEvent);
|
||
|
|
m_PLCAState = RECEIVE; //The early receive state is jump because we don't simulate the phy layer
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::EndReception()
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
m_PLCAState = NEXT_TX_OPPORTUNITY;
|
||
|
|
m_PLCAStateTrace(m_PLCAState);
|
||
|
|
PLCA();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TsnMultidropNetDevice::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 = header.GetEthertype();
|
||
|
|
int8_t priority = header.GetPcp();
|
||
|
|
|
||
|
|
|
||
|
|
// Stream identification out-facing input
|
||
|
|
std::vector<Ptr<StreamIdEntry>> streamIdentityTable = GetNode()->GetStreamIdentityTable();
|
||
|
|
for (uint32_t i = 0; i < streamIdentityTable.size(); i++){
|
||
|
|
if (streamIdentityTable[i]->Match(this, false, true, originalPacket)){
|
||
|
|
uint32_t streamHandle = streamIdentityTable[i]->GetStreamHandle();
|
||
|
|
|
||
|
|
//PSFP
|
||
|
|
std::vector<Ptr<StreamFilterInstance>> streamFilterInstanceTable = GetNode()->GetStreamFilterInstanceTable();
|
||
|
|
for (uint16_t i = 0; i < streamFilterInstanceTable.size(); i++){
|
||
|
|
if (streamFilterInstanceTable[i]->Match(streamHandle, priority)){
|
||
|
|
//MaxSDUSizeFilter
|
||
|
|
if (streamFilterInstanceTable[i]->MaxSDUSizeFilter(originalPacket)){
|
||
|
|
m_maxSDUSizeFilterDropTrace(originalPacket);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
//TODO Stream Gate
|
||
|
|
|
||
|
|
//Flow Meter
|
||
|
|
std::vector<uint16_t> fmids = streamFilterInstanceTable[i]->GetFlowMeterIds();
|
||
|
|
std::vector<Ptr<FlowMeterInstance>> flowMeterInstanceTable = GetNode()->GetFlowMeterInstanceTable();
|
||
|
|
bool pass = true;
|
||
|
|
for (uint16_t j = 0; j < fmids.size(); j++){
|
||
|
|
if(flowMeterInstanceTable[fmids[j]]->Test(originalPacket)){
|
||
|
|
pass = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (not pass){
|
||
|
|
streamFilterInstanceTable[i]->increaseRedFrameCount();
|
||
|
|
m_REDFrameDropTrace(originalPacket);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//FRER
|
||
|
|
// NS_LOG_INFO( "Stream handle of Pkt #"<<packet->GetUid() << " on input : " << streamHandle);
|
||
|
|
bool isSeqNumber = false;
|
||
|
|
uint16_t seqNumber = 0;
|
||
|
|
//Sequence decode => extract RTAG if this function is enable for this stream handle
|
||
|
|
//TODO
|
||
|
|
|
||
|
|
//Individual Recovery if this function is enable for this stream handle
|
||
|
|
//TODO
|
||
|
|
|
||
|
|
//Sequence Recovery if this function is enable for this stream handle
|
||
|
|
//TODO
|
||
|
|
|
||
|
|
//Stream Transfert Function
|
||
|
|
//Nothing to implement in the simulator
|
||
|
|
|
||
|
|
//Sequence Generation if this function is enable for this stream handle
|
||
|
|
std::vector<Ptr<SequenceGenerationFunction>> seqGenTable = GetNode()->GetSequenceGenerationTable();
|
||
|
|
for (uint32_t i = 0; i < seqGenTable.size(); i++)
|
||
|
|
{
|
||
|
|
if(seqGenTable[i]->IsApplicable(streamHandle))
|
||
|
|
{
|
||
|
|
isSeqNumber = true;
|
||
|
|
seqNumber = seqGenTable[i]->GetSequenceNumber();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//Stream splitting if this function is enable for this stream handle
|
||
|
|
//TODO
|
||
|
|
//Sequence encode => encode RTAG if this function is enable for this stream handle
|
||
|
|
if (isSeqNumber)
|
||
|
|
{
|
||
|
|
std::vector<Ptr<SequenceEncodeDecodeFunction>> seqEncTable = GetNode()->GetSequenceEncodeDecodeTable();
|
||
|
|
for (uint32_t i = 0; i < seqEncTable.size(); i++)
|
||
|
|
{
|
||
|
|
if(seqEncTable[i]->IsApplicable(streamHandle, this, false))
|
||
|
|
{
|
||
|
|
seqEncTable[i]->Encode(originalPacket, seqNumber);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// 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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Simulator::Schedule(m_bps.CalculateBytesTxTime(m_interframeGap), &TsnMultidropNetDevice::EndReception, this);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
bool
|
||
|
|
TsnMultidropNetDevice::IsPointToPoint() const
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool
|
||
|
|
TsnMultidropNetDevice::SendFrom(Ptr<Packet> packet,
|
||
|
|
const Address& source,
|
||
|
|
const Address& dest,
|
||
|
|
uint16_t ethertype)
|
||
|
|
{
|
||
|
|
NS_LOG_FUNCTION(this);
|
||
|
|
|
||
|
|
// Stream identification in-facing output
|
||
|
|
std::vector<Ptr<StreamIdEntry>> streamIdentityTable = GetNode()->GetStreamIdentityTable();
|
||
|
|
for (uint16_t i = 0; i < streamIdentityTable.size(); i++){
|
||
|
|
if (streamIdentityTable[i]->Match(this, true, false, packet)){
|
||
|
|
uint32_t streamHandle = streamIdentityTable[i]->GetStreamHandle();
|
||
|
|
|
||
|
|
//FRER
|
||
|
|
// NS_LOG_INFO( "Stream handle of Pkt #"<<packet->GetUid() << " on output : " << streamHandle);
|
||
|
|
bool isSeqNumber = false;
|
||
|
|
uint16_t seqNumber = 0;
|
||
|
|
//Sequence decode => extract RTAG if this function is enable for this stream handle
|
||
|
|
std::vector<Ptr<SequenceEncodeDecodeFunction>> seqEncTable = GetNode()->GetSequenceEncodeDecodeTable();
|
||
|
|
for (uint32_t i = 0; i < seqEncTable.size(); i++)
|
||
|
|
{
|
||
|
|
if(seqEncTable[i]->IsApplicable(streamHandle, this, false))
|
||
|
|
{
|
||
|
|
isSeqNumber = true;
|
||
|
|
seqNumber = seqEncTable[i]->Decode(packet);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//Individual Recovery if this function is enable for this stream handle
|
||
|
|
//TODO
|
||
|
|
//Sequence Recovery if this function is enable for this stream handle
|
||
|
|
std::vector<Ptr<SequenceRecoveryFunction>> seqRcvyTable = GetNode()->GetSequenceRecoveryTable();
|
||
|
|
for (uint32_t i = 0; i < seqRcvyTable.size(); i++)
|
||
|
|
{
|
||
|
|
bool IsApplicable(uint32_t streamHandle, Ptr<TsnNetDevice> port, bool direction, bool hasSeqNumber, bool individualRecovery);
|
||
|
|
if(seqRcvyTable[i]->IsApplicable(streamHandle, this, false, isSeqNumber, false))
|
||
|
|
{
|
||
|
|
if(!seqRcvyTable[i]->Recovery(seqNumber))
|
||
|
|
{
|
||
|
|
//Duplicate FRER packet detected ! ==> Drop
|
||
|
|
m_frerDropTrace(packet);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
//Stream Transfert Function
|
||
|
|
//Nothing to implement in the simulator
|
||
|
|
//Sequence Generation if this function is enable for this stream handle
|
||
|
|
//TODO
|
||
|
|
//Stream splitting if this function is enable for this stream handle
|
||
|
|
//TODO
|
||
|
|
//Sequence encode => encode RTAG if this function is enable for this stream handle
|
||
|
|
//TODO
|
||
|
|
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//Stream identification out-facing output (active)
|
||
|
|
for (uint16_t i = 0; i < streamIdentityTable.size(); i++){
|
||
|
|
if (streamIdentityTable[i]->Match(this, false, false, packet)){
|
||
|
|
streamIdentityTable[i]->DoActiveUpdate(packet);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
//
|
||
|
|
// 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();
|
||
|
|
|
||
|
|
m_FIFOStateSnifferTrace(m_queues, m_txMachineState==BUSY, packet);
|
||
|
|
//NS_LOG_INFO(Names::FindName(this) << " "<< Simulator::Now().GetNanoSeconds()<<" Enqueue pkt #"<<packet->GetUid() << " (Vid : " << vid << ") in FIFO #" << unsigned(pcp));
|
||
|
|
//
|
||
|
|
// 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), &TsnNetDevice::CheckForReadyPacket, this);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Enqueue may fail (overflow)
|
||
|
|
m_macTxDropTrace(packet);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|