34 #define _GLIBCXX_USE_NANOSLEEP 57 const char * pzLayerName{
"RFPipeMACLayer"};
59 const std::uint16_t DROP_CODE_SINR = 1;
60 const std::uint16_t DROP_CODE_REGISTRATION_ID = 2;
61 const std::uint16_t DROP_CODE_DST_MAC = 3;
62 const std::uint16_t DROP_CODE_QUEUE_OVERFLOW = 4;
63 const std::uint16_t DROP_CODE_BAD_CONTROL_INFO = 5;
64 const std::uint16_t DROP_CODE_BAD_SPECTRUM_QUERY = 6;
65 const std::uint16_t DROP_CODE_FLOW_CONTROL_ERROR = 7;
83 u64TxSequenceNumber_{},
84 flowControlManager_{*
this},
86 neighborMetricManager_(
id),
87 queueMetricManager_(
id),
88 radioMetricTimedEventId_{},
89 commonLayerStatistics_{STATISTIC_TABLE_LABELS,{},
"0"},
90 RNDZeroToOne_{0.0f, 1.0f},
93 pNumDownstreamQueueDelay_{},
94 downstreamQueueTimedEventId_{},
95 bHasPendingDownstreamQueueEntry_{},
96 pendingDownstreamQueueEntry_{},
97 currentEndOfTransmissionTime_{},
121 "Defines whether promiscuous mode is enabled or not." 122 " If promiscuous mode is enabled, all received packets" 123 " (intended for the given node or not) that pass the" 124 " probability of reception check are sent upstream to" 127 configRegistrar.registerNumeric<std::uint64_t>(
"datarate",
131 "Defines the transmit datarate in bps." 132 " The datarate is used by the transmitter" 133 " to compute the transmit delay (packet size/datarate)" 134 " between successive transmissions.",
139 configRegistrar.registerNumeric<
float>(
"jitter",
143 "Defines delay jitter in seconds applied to each transmitted packet." 144 " The jitter is added to the configured delay based on a uniform" 145 " random distribution between +/- the configured jitter value.",
148 configRegistrar.registerNumeric<
float>(
"delay",
152 "Defines an additional fixed delay in seconds applied to each" 153 " transmitted packet.",
156 configRegistrar.registerNumeric<
bool>(
"flowcontrolenable",
159 "Defines whether flow control is enabled. Flow control only works" 160 " with the virtual transport and the setting must match the setting" 161 " within the virtual transport configuration.");
163 configRegistrar.registerNumeric<std::uint16_t>(
"flowcontroltokens",
166 "Defines the maximum number of flow control tokens" 167 " (packet transmission units) that can be processed from the" 168 " virtual transport without being refreshed. The number of" 169 " available tokens at any given time is coordinated with the" 170 " virtual transport and when the token count reaches zero, no" 171 " further packets are transmitted causing application socket" 172 " queues to backup.");
176 configRegistrar.registerNonNumeric<std::string>(
"pcrcurveuri",
179 "Defines the URI of the Packet Completion Rate (PCR) curve" 180 " file. The PCR curve file contains probability of reception curves" 181 " as a function of Signal to Interference plus Noise Ratio (SINR).");
184 configRegistrar.registerNumeric<
bool>(
"radiometricenable",
187 "Defines if radio metrics will be reported up via the Radio to Router Interface" 191 configRegistrar.registerNumeric<
float>(
"radiometricreportinterval",
194 "Defines the metric report interval in seconds in support of the R2RI feature.",
198 configRegistrar.registerNumeric<
float>(
"neighbormetricdeletetime",
199 ConfigurationProperties::DEFAULT |
202 "Defines the time in seconds of no RF receptions from a given neighbor" 203 " before it is removed from the neighbor table.",
214 pNumDownstreamQueueDelay_ =
215 statisticRegistrar.registerNumeric<std::uint64_t>(
"numDownstreamQueueDelay",
219 statisticRegistrar.registerNumeric<
float>(
"avgDownstreamQueueDelay",
235 for(
const auto & item : update)
237 if(item.first ==
"enablepromiscuousmode")
240 bPromiscuousMode_ = item.second[0].asBool();
244 "MACI %03hu %s::%s %s = %s",
249 bPromiscuousMode_ ?
"on" :
"off");
252 else if(item.first ==
"datarate")
254 u64DataRatebps_ = item.second[0].asUINT64();
258 "MACI %03hu %s::%s %s = %ju",
265 else if(item.first ==
"jitter")
267 fJitterSeconds_ = item.second[0].asFloat();
269 if(fJitterSeconds_ > 0.0f)
273 std::uniform_real_distribution<float>>
274 (-fJitterSeconds_ / 2.0f, fJitterSeconds_ / 2.0));
279 "MACI %03hu %s::%s %s = %f",
286 else if(item.first ==
"delay")
293 "MACI %03hu %s::%s %s = %lf",
298 std::chrono::duration_cast<
DoubleSeconds>(delayMicroseconds_).count());
301 else if(item.first ==
"flowcontrolenable")
303 bFlowControlEnable_ = item.second[0].asBool();
307 "MACI %03hu %s::%s %s = %s",
312 bFlowControlEnable_ ?
"on" :
"off");
314 else if(item.first ==
"flowcontroltokens")
316 u16FlowControlTokens_ = item.second[0].asUINT16();
320 "MACI %03hu %s::%s %s = %hu",
325 u16FlowControlTokens_);
327 else if(item.first ==
"pcrcurveuri")
329 sPCRCurveURI_ = item.second[0].asString();
333 "MACI %03hu %s::%s %s = %s",
338 sPCRCurveURI_.c_str());
340 else if(item.first ==
"radiometricenable")
342 bRadioMetricEnable_ = item.second[0].asBool();
346 "MACI %03hu %s::%s %s = %s",
351 bRadioMetricEnable_ ?
"on" :
"off");
353 else if(item.first ==
"radiometricreportinterval")
355 radioMetricReportIntervalMicroseconds_ =
360 "MACI %03hu %s::%s %s = %lf",
365 std::chrono::duration_cast<
DoubleSeconds>(radioMetricReportIntervalMicroseconds_).count());
367 else if(item.first ==
"neighbormetricdeletetime")
369 neighborMetricDeleteTimeMicroseconds_ =
374 "MACI %03hu %s::%s %s = %lf",
379 std::chrono::duration_cast<
DoubleSeconds>(neighborMetricDeleteTimeMicroseconds_).count());
383 throw makeException<ConfigureException>(
"RFPipe::MACLayer: " 384 "Unexpected configuration item %s",
402 pcrManager_.
load(sPCRCurveURI_);
423 if(bFlowControlEnable_)
426 flowControlManager_.
start(u16FlowControlTokens_);
430 "MACI %03hu %s::%s sent a flow control token update," 431 " a handshake response is required to process packets",
439 radioMetricTimedEventId_ =
445 if(!bRadioMetricEnable_)
454 radioMetricReportIntervalMicroseconds_),
461 Clock::now() + radioMetricReportIntervalMicroseconds_,
462 radioMetricReportIntervalMicroseconds_);
467 "MACI %03hu %s::%s: added radio metric timed eventId %zu",
471 radioMetricTimedEventId_);
485 for(
const auto & item : update)
487 if(item.first ==
"enablepromiscuousmode")
489 bPromiscuousMode_ = item.second[0].asBool();
493 "MACI %03hu %s::%s %s = %s",
498 bPromiscuousMode_ ?
"on" :
"off");
501 else if(item.first ==
"datarate")
503 u64DataRatebps_ = item.second[0].asUINT64();
507 "MACI %03hu %s::%s %s = %ju",
514 else if(item.first ==
"jitter")
516 fJitterSeconds_ = item.second[0].asFloat();
518 if(fJitterSeconds_ > 0.0f)
522 std::uniform_real_distribution<float>>
523 (-fJitterSeconds_ / 2.0f, fJitterSeconds_ / 2.0));
528 "MACI %03hu %s::%s %s = %f",
535 else if(item.first ==
"delay")
542 "MACI %03hu %s::%s %s = %lf",
547 std::chrono::duration_cast<
DoubleSeconds>(delayMicroseconds_).count());
550 else if(item.first ==
"neighbormetricdeletetime")
552 neighborMetricDeleteTimeMicroseconds_ =
560 "MACI %03hu %s::%s %s = %lf",
565 std::chrono::duration_cast<
DoubleSeconds>(neighborMetricDeleteTimeMicroseconds_).count());
569 throw makeException<ConfigureException>(
"RFPipe::MACLayer: " 570 "Unexpected configuration item %s",
592 downstreamQueueTimedEventId_ = 0;
595 if(bFlowControlEnable_)
598 flowControlManager_.
stop();
624 for(
const auto & pMessage : msgs)
628 "MACI %03hu %s::%s downstream control message id %hu",
634 switch(pMessage->getId())
638 const auto pFlowControlControlMessage =
641 if(bFlowControlEnable_)
645 "MACI %03hu %s::%s received a flow control token request/response",
656 "MACI %03hu %s::%s received a flow control token request but" 657 " flow control is not enabled",
668 const auto pSerializedControlMessage =
671 switch(pSerializedControlMessage->getSerializedId())
675 std::unique_ptr<Controls::FlowControlControlMessage>
676 pFlowControlControlMessage{
679 if(bFlowControlEnable_)
687 "MACI %03hu %s::%s received a flow control token request but" 688 " flow control is not enabled",
717 "MACI %03hu %s::%s: MAC Registration Id %hu does not match our Id %hu, drop.",
725 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
726 DROP_CODE_REGISTRATION_ID);
736 if(len && pkt.
length() >= len)
746 for(
auto & pControlMessage : msgs)
748 switch(pControlMessage->getId())
753 pReceivePropertiesControlMessage =
759 "MACI %03hu RFPipe::%s Receiver Properties Control Message",
768 pFrequencyControlMessage =
774 "MACI %03hu RFPipe::%s Frequency Control Message",
785 if(!pReceivePropertiesControlMessage || !pFrequencyControlMessage ||
786 pFrequencyControlMessage->getFrequencySegments().empty())
790 "MACI %03hu %s::%s: phy control " 791 "message not provided from src %hu, drop",
795 pktInfo.getSource());
798 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
799 DROP_CODE_BAD_CONTROL_INFO);
806 const auto & frequencySegments = pFrequencyControlMessage->getFrequencySegments();
809 TimePoint startOfReception{pReceivePropertiesControlMessage->getTxTime() +
810 pReceivePropertiesControlMessage->getPropagationDelay() +
811 frequencySegments.begin()->getOffset()};
814 Microseconds span{pReceivePropertiesControlMessage->getSpan()};
822 std::uint64_t u64SequenceNumber,
823 std::uint64_t u64DataRate)
831 "MACI %03hu %s upstream EOR processing: src %hu, dst %hu," 832 " len %zu, freq %ju, offset %ju, duration %ju, mac sequence %ju",
836 pktInfo.getDestination(),
838 frequencySegment.getFrequencyHz(),
839 frequencySegment.getOffset().count(),
840 frequencySegment.getDuration().count(),
846 double dNoiseFloordB{};
865 bool bSignalInNoise{};
867 std::tie(dNoiseFloordB,bSignalInNoise) =
870 dSINR = frequencySegment.getRxPowerdBm() - dNoiseFloordB;
875 "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, max noise %f, signal in noise %s, SINR %f",
879 pktInfo.getDestination(),
881 bSignalInNoise ?
"yes" :
"no",
888 "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, sor %ju, span %ju spectrum service request error: %s",
892 pktInfo.getDestination(),
893 std::chrono::duration_cast<
Microseconds>(startOfReception.time_since_epoch()).count(),
898 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
899 DROP_CODE_BAD_SPECTRUM_QUERY);
904 const Microseconds & durationMicroseconds{frequencySegment.getDuration()};
907 if(!checkPOR(dSINR, pkt.
length()))
911 "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, " 912 "rxpwr %3.2f dBm, drop",
916 pktInfo.getDestination(),
917 frequencySegment.getRxPowerdBm());
920 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
934 durationMicroseconds,
938 if(bPromiscuousMode_ ||
939 (pktInfo.getDestination() ==
id_) ||
944 "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, forward upstream",
948 pktInfo.getDestination());
951 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime));
963 "MACI %03hu %s upstream EOR processing: not for this nem, " 964 "ignore pkt src %hu, dst %hu, drop",
968 pktInfo.getDestination());
971 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
980 auto eor = startOfReception + frequencySegments.begin()->getDuration();
1008 if(bFlowControlEnable_)
1012 if(status.second ==
false)
1016 "MACI %03hu %s::%s: failed to remove token, drop packet (tokens:%hu)",
1023 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
1024 DROP_CODE_FLOW_CONTROL_ERROR);
1036 durationMicroseconds,
1039 if(bHasPendingDownstreamQueueEntry_)
1041 std::vector<DownstreamQueueEntry> result{downstreamQueue_.
enqueue(entry)};
1044 for(
auto & iter : result)
1047 std::chrono::duration_cast<Microseconds>(Clock::now() - iter.acquireTime_),
1048 DROP_CODE_QUEUE_OVERFLOW);
1051 if(bFlowControlEnable_)
1053 auto status = flowControlManager_.
addToken();
1059 "MACI %03hu %s::%s: failed to add token (tokens:%hu)",
1069 auto now = Clock::now();
1071 if(currentEndOfTransmissionTime_ <= now)
1073 handleDownstreamQueueEntry(now,u64TxSequenceNumber_);
1078 bHasPendingDownstreamQueueEntry_ =
true;
1080 pendingDownstreamQueueEntry_ = std::move(entry);
1082 auto now = Clock::now();
1084 if(currentEndOfTransmissionTime_ - currentDelay_ <= now)
1086 currentDelay_ = delayMicroseconds_ + getJitter();
1088 if(currentDelay_ > Microseconds::zero())
1090 currentEndOfTransmissionTime_ = now + currentDelay_;
1092 downstreamQueueTimedEventId_ =
1094 schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1096 currentEndOfTransmissionTime_,
1097 u64TxSequenceNumber_),
1098 currentEndOfTransmissionTime_);
1102 handleDownstreamQueueEntry(now,u64TxSequenceNumber_);
1108 downstreamQueueTimedEventId_ =
1110 schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1112 currentEndOfTransmissionTime_,
1113 u64TxSequenceNumber_),
1114 currentEndOfTransmissionTime_);
1124 EMANE::Models::RFPipe::MACLayer::handleDownstreamQueueEntry(
TimePoint sot,
1125 std::uint64_t u64TxSequenceNumber)
1127 auto now = Clock::now();
1132 if(u64TxSequenceNumber == u64TxSequenceNumber_ ||
1133 (bHasPendingDownstreamQueueEntry_ && currentEndOfTransmissionTime_ <= now))
1138 if(u64TxSequenceNumber != u64TxSequenceNumber_)
1143 if(bHasPendingDownstreamQueueEntry_)
1145 if(bFlowControlEnable_)
1147 auto status = flowControlManager_.
addToken();
1153 "MACI %03hu %s::%s: failed to add token (tokens:%hu)",
1166 auto & pkt = pendingDownstreamQueueEntry_.
pkt_;
1169 pkt.
prepend(serialization.c_str(), serialization.size());
1172 pkt.prependLengthPrefixFraming(serialization.size());
1175 std::chrono::duration_cast<Microseconds>(now - pendingDownstreamQueueEntry_.
acquireTime_));
1189 *pNumDownstreamQueueDelay_ += queueDelayMicroseconds.count();
1191 avgDownstreamQueueDelay_.
update(queueDelayMicroseconds.count());
1197 queueDelayMicroseconds);
1203 currentDelay_ = delayMicroseconds_ + getJitter();
1206 currentEndOfTransmissionTime_ =
1209 std::tie(pendingDownstreamQueueEntry_,
1210 bHasPendingDownstreamQueueEntry_) =
1213 if(bHasPendingDownstreamQueueEntry_)
1215 if(currentEndOfTransmissionTime_ > now)
1217 downstreamQueueTimedEventId_ =
1219 schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1221 currentEndOfTransmissionTime_,
1222 u64TxSequenceNumber_),
1223 currentEndOfTransmissionTime_);
1227 handleDownstreamQueueEntry(currentEndOfTransmissionTime_,u64TxSequenceNumber_);
1237 EMANE::Models::RFPipe::MACLayer::getDurationMicroseconds(
size_t lengthInBytes)
1239 if(u64DataRatebps_ > 0)
1241 float fSeconds{((lengthInBytes * 8.0f) / u64DataRatebps_)};
1253 EMANE::Models::RFPipe::MACLayer::getJitter()
1255 if(fJitterSeconds_ > 0.0f)
1267 EMANE::Models::RFPipe::MACLayer::checkPOR(
float fSINR,
size_t packetSize)
1270 float fPCR{pcrManager_.
getPCR(fSINR, packetSize)};
1273 float fRandomValue{RNDZeroToOne_()};
1276 bool bResult{fPCR >= fRandomValue};
1280 "MACI %03hu %s::%s: sinr %3.2f, pcr %3.2f %s rand %3.3f",
1286 bResult ?
">=" :
"<",
std::pair< DownstreamQueueEntry, bool > dequeue()
removes an element from the queue
std::string Serialization
A Packet class that allows upstream processing to strip layer headers as the packet travels up the st...
const PacketInfo & getPacketInfo() const
void updateNeighborStatus()
The Registrar interface provides access to all of the emulator registrars.
A Serialized Control Message is used to encapsulate Serializable control messages as they traverse pr...
virtual ConfigurationRegistrar & configurationRegistrar()=0
void updateNeighborRxMetric(NEMId src, std::uint64_t u64SeqNum, const uuid_t &uuid, const TimePoint &rxTime)
void postStart() override
#define LOGGER_VERBOSE_LOGGING(logger, level, fmt, args...)
Controls::R2RIQueueMetrics getQueueMetrics()
Controls::R2RINeighborMetrics getNeighborMetrics()
virtual StatisticRegistrar & statisticRegistrar()=0
Recieve Properties Control Message is sent from the emulator physical layer with every upstream packe...
void processOutbound(const UpstreamPacket &pkt, Microseconds delay, size_t dropCode={})
Holds the frequency, offset and duration of a frequency segment.
std::list< const ControlMessage * > ControlMessages
std::pair< std::uint16_t, bool > addToken(std::uint16_t u16Tokens=1)
void processDownstreamControl(const ControlMessages &msgs) override
static TimeStampControlMessage * create(const TimePoint ×tamp)
void initialize(Registrar ®istrar) override
std::vector< DownstreamQueueEntry > enqueue(DownstreamQueueEntry &entry)
Adds an element to the queue.
NEMId getDestination() const
std::uint16_t stripLengthPrefixFraming()
constexpr NEMId NEM_BROADCAST_MAC_ADDRESS
size_t strip(size_t size)
RFPipe MAC downstream queue entry definition.
SpectrumServiceException is thrown when an exception occurs during spectrum service processing...
void prepend(const void *buf, size_t size)
void start(std::uint16_t u16TotalTokensAvailable)
float getPCR(float fSinr, size_t size)
RadioServiceProvider * pRadioService_
static FlowControlControlMessage * create(const Serialization &serialization)
void registerStatistics(StatisticRegistrar &statisticRegistrar)
void updateNeighborTxMetric(NEMId dst, std::uint64_t u64DataRatebps, const TimePoint &txTime)
Store source, destination, creation time and priority information for a packet.
static FrequencyControlMessage * create(std::uint64_t u64BandwidthHz, const FrequencySegments &frequencySegments)
size_t getNumDiscards(bool bClear)
Returns the number of discards.
void processDownstreamPacket(DownstreamPacket &pkt, const ControlMessages &msgs) override
const char * what() const
The Frequency Control Message is sent to the emulator physical layer to specify the frequency segment...
void processUpstreamControl(const ControlMessages &msgs) override
void processFlowControlMessage(const Controls::FlowControlControlMessage *pMsg)
#define LOGGER_VERBOSE_LOGGING_FN_VARGS(logger, level, fn, fmt, args...)
std::vector< std::string > StatisticTableLabels
const PacketInfo & getPacketInfo() const
Specialized packet the allows downstream processing to add layer specific headers as the packet trave...
void processConfiguration(const ConfigurationUpdate &update) override
void registerStatistics(StatisticRegistrar &statisticRegistrar)
MACLayer(NEMId id, PlatformServiceProvider *pPlatformServiceProvider, RadioServiceProvider *pRadioServiceProvider)
std::chrono::microseconds Microseconds
std::chrono::duration< double > DoubleSeconds
static R2RISelfMetricControlMessage * create(const Serialization &serialization)
Flow Control Control Messages are sent between a MAC layer and a transport in order to communicate da...
Microseconds durationMicroseconds_
void updateQueueMetric(std::uint16_t u16QueueId, std::uint32_t u32QueueSize, std::uint32_t u32QueueDepth, std::uint32_t u32NumDiscards, const Microseconds &queueDelay)
void configure(const ConfigurationUpdate &update) override
The RadioServiceProvider interface provides access to radio (RF) model specific services.
std::pair< double, bool > maxBinNoiseFloor(const SpectrumWindow &window, double dRxPowerdBm, const TimePoint &startTime=TimePoint::min())
void sendDownstreamPacket(const CommonMACHeader &hdr, DownstreamPacket &pkt, const ControlMessages &msgs=DownstreamTransport::empty)
std::uint64_t u64DataRatebps_
TimerEventId schedule(Function fn, const TimePoint &timePoint, const Duration &interval=Duration::zero())
void sendUpstreamControl(const ControlMessages &msgs)
void registerStatistics(StatisticRegistrar &statisticRegistrar)
void setNeighborDeleteTimeMicroseconds(const Microseconds &ageMicroseconds)
DECLARE_MAC_LAYER(EMANE::Models::RFPipe::MACLayer)
std::vector< ConfigurationNameAnyValues > ConfigurationUpdate
static R2RINeighborMetricControlMessage * create(const Serialization &serialization)
std::pair< std::uint16_t, bool > removeToken()
void processUpstreamPacket(const CommonMACHeader &hdr, UpstreamPacket &pkt, const ControlMessages &msgs) override
void registerNumeric(const std::string &sName, const ConfigurationProperties &properties=ConfigurationProperties::NONE, const std::initializer_list< T > &values={}, const std::string &sUsage="", T minValue=std::numeric_limits< T >::lowest(), T maxValue=std::numeric_limits< T >::max(), std::size_t minOccurs=1, std::size_t maxOccurs=1, const std::string &sRegexPattern={})
Clock::time_point TimePoint
size_t getMaxCapacity()
Returns the max size of the queue.
Implementation of the rf pipe mac layer.
virtual bool cancelTimedEvent(TimerEventId eventId)=0
size_t getCurrentDepth()
Returns the current size of the queue.
void sendUpstreamPacket(UpstreamPacket &pkt, const ControlMessages &msgs=empty)
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
virtual SpectrumServiceProvider & spectrumService()=0
virtual SpectrumWindow request(std::uint64_t u64FrequencyHz, const Microseconds &duration=Microseconds::zero(), const TimePoint &startTime=TimePoint::min()) const =0
void processInbound(const UpstreamPacket &pkt)
void registerStatistic(StatisticNumeric< T > *p)
A utility wrapper around a generator and a distribution.
static R2RIQueueMetricControlMessage * create(const Serialization &serialization)
void load(const std::string &uri)
bool addQueueMetric(std::uint16_t u16QueueId, std::uint32_t u32QueueSize)
Interface used to create a MAC layer plugin implementation.