EMANE  1.0.1
models/mac/rfpipe/maclayer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2016 - Adjacent Link LLC, Bridgewater, New Jersey
3  * Copyright (c) 2008-2009 - DRS CenGen, LLC, Columbia, Maryland
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * * Neither the name of DRS CenGen, LLC nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #define _GLIBCXX_USE_NANOSLEEP
35 
36 #include "maclayer.h"
37 #include "rfpipemacheadermessage.h"
38 
47 
52 
53 #include <sstream>
54 
55 namespace
56 {
57  const char * pzLayerName{"RFPipeMACLayer"};
58 
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;
66 
67  EMANE::StatisticTableLabels STATISTIC_TABLE_LABELS
68  {
69  "SINR",
70  "Reg Id",
71  "Dst MAC",
72  "Queue Overflow",
73  "Bad Control",
74  "Bad Spectrum Query",
75  "Flow Control"
76  };
77 }
78 
80  PlatformServiceProvider * pPlatformServiceProvider,
81  RadioServiceProvider * pRadioServiceProvider):
82  MACLayerImplementor{id, pPlatformServiceProvider, pRadioServiceProvider},
83  u64TxSequenceNumber_{},
84  flowControlManager_{*this},
85  pcrManager_(id, pPlatformService_),
86  neighborMetricManager_(id),
87  queueMetricManager_(id),
88  radioMetricTimedEventId_{},
89  commonLayerStatistics_{STATISTIC_TABLE_LABELS,{},"0"},
90  RNDZeroToOne_{0.0f, 1.0f},
91  pRNDJitter_{},
92  fJitterSeconds_{},
93  pNumDownstreamQueueDelay_{},
94  downstreamQueueTimedEventId_{},
95  bHasPendingDownstreamQueueEntry_{},
96  pendingDownstreamQueueEntry_{},
97  currentEndOfTransmissionTime_{},
98  currentDelay_{}
99 {}
100 
102 
103 
104 void
106 {
108  DEBUG_LEVEL,
109  "MACI %03hu %s::%s",
110  id_,
111  pzLayerName,
112  __func__);
113 
114 
115  auto & configRegistrar = registrar.configurationRegistrar();
116 
117  configRegistrar.registerNumeric<bool>("enablepromiscuousmode",
120  {false},
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"
125  " the transport.");
126 
127  configRegistrar.registerNumeric<std::uint64_t>("datarate",
130  {1000000},
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.",
135  1);
136 
139  configRegistrar.registerNumeric<float>("jitter",
142  {0},
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.",
146  0.0f);
147 
148  configRegistrar.registerNumeric<float>("delay",
151  {0},
152  "Defines an additional fixed delay in seconds applied to each"
153  " transmitted packet.",
154  0.0f);
155 
156  configRegistrar.registerNumeric<bool>("flowcontrolenable",
158  {false},
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.");
162 
163  configRegistrar.registerNumeric<std::uint16_t>("flowcontroltokens",
165  {10},
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",
178  {},
179  "Defines the absolute 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",
186  {false},
187  "Defines if radio metrics will be reported up via the Radio to Router Interface"
188  " (R2RI).");
189 
190 
191  configRegistrar.registerNumeric<float>("radiometricreportinterval",
193  {1.0f},
194  "Defines the metric report interval in seconds in support of the R2RI feature.",
195  0.1f,
196  60.0f);
197 
198  configRegistrar.registerNumeric<float>("neighbormetricdeletetime",
199  ConfigurationProperties::DEFAULT |
201  {60.0f},
202  "Defines the time in seconds of no RF receptions from a given neighbor"
203  " before it is removed from the neighbor table.",
204  1.0f,
205  3660.0f);
206 
207 
208  auto & statisticRegistrar = registrar.statisticRegistrar();
209 
210  commonLayerStatistics_.registerStatistics(statisticRegistrar);
211 
212  downstreamQueue_.registerStatistics(statisticRegistrar);
213 
214  pNumDownstreamQueueDelay_ =
215  statisticRegistrar.registerNumeric<std::uint64_t>("numDownstreamQueueDelay",
217 
218  avgDownstreamQueueDelay_.registerStatistic(
219  statisticRegistrar.registerNumeric<float>("avgDownstreamQueueDelay",
221 
222  neighborMetricManager_.registerStatistics(statisticRegistrar);
223 }
224 
225 void
227 {
229  DEBUG_LEVEL,
230  "MACI %03hu %s::%s",
231  id_,
232  pzLayerName,
233  __func__);
234 
235  for(const auto & item : update)
236  {
237  if(item.first == "enablepromiscuousmode")
238  {
240  bPromiscuousMode_ = item.second[0].asBool();
241 
243  INFO_LEVEL,
244  "MACI %03hu %s::%s %s = %s",
245  id_,
246  pzLayerName,
247  __func__,
248  item.first.c_str(),
249  bPromiscuousMode_ ? "on" : "off");
251  }
252  else if(item.first == "datarate")
253  {
254  u64DataRatebps_ = item.second[0].asUINT64();
255 
257  INFO_LEVEL,
258  "MACI %03hu %s::%s %s = %ju",
259  id_,
260  pzLayerName,
261  __func__,
262  item.first.c_str(),
263  u64DataRatebps_);
264  }
265  else if(item.first == "jitter")
266  {
267  fJitterSeconds_ = item.second[0].asFloat();
268 
269  if(fJitterSeconds_ > 0.0f)
270  {
271  // create a random mumber distrubtion +- the jitter range
272  pRNDJitter_.reset(new Utils::RandomNumberDistribution<std::mt19937,
273  std::uniform_real_distribution<float>>
274  (-fJitterSeconds_ / 2.0f, fJitterSeconds_ / 2.0));
275  }
276 
278  INFO_LEVEL,
279  "MACI %03hu %s::%s %s = %f",
280  id_,
281  pzLayerName,
282  __func__,
283  item.first.c_str(),
284  fJitterSeconds_);
285  }
286  else if(item.first == "delay")
287  {
288  delayMicroseconds_ =
289  std::chrono::duration_cast<Microseconds>(DoubleSeconds{item.second[0].asFloat()});
290 
292  INFO_LEVEL,
293  "MACI %03hu %s::%s %s = %lf",
294  id_,
295  pzLayerName,
296  __func__,
297  item.first.c_str(),
298  std::chrono::duration_cast<DoubleSeconds>(delayMicroseconds_).count());
299 
300  }
301  else if(item.first == "flowcontrolenable")
302  {
303  bFlowControlEnable_ = item.second[0].asBool();
304 
306  INFO_LEVEL,
307  "MACI %03hu %s::%s %s = %s",
308  id_,
309  pzLayerName,
310  __func__,
311  item.first.c_str(),
312  bFlowControlEnable_ ? "on" : "off");
313  }
314  else if(item.first == "flowcontroltokens")
315  {
316  u16FlowControlTokens_ = item.second[0].asUINT16();
317 
319  INFO_LEVEL,
320  "MACI %03hu %s::%s %s = %hu",
321  id_,
322  pzLayerName,
323  __func__,
324  item.first.c_str(),
325  u16FlowControlTokens_);
326  }
327  else if(item.first == "pcrcurveuri")
328  {
329  sPCRCurveURI_ = item.second[0].asString();
330 
332  INFO_LEVEL,
333  "MACI %03hu %s::%s %s = %s",
334  id_,
335  pzLayerName,
336  __func__,
337  item.first.c_str(),
338  sPCRCurveURI_.c_str());
339  }
340  else if(item.first == "radiometricenable")
341  {
342  bRadioMetricEnable_ = item.second[0].asBool();
343 
345  INFO_LEVEL,
346  "MACI %03hu %s::%s %s = %s",
347  id_,
348  pzLayerName,
349  __func__,
350  item.first.c_str(),
351  bRadioMetricEnable_ ? "on" : "off");
352  }
353  else if(item.first == "radiometricreportinterval")
354  {
355  radioMetricReportIntervalMicroseconds_ =
356  std::chrono::duration_cast<Microseconds>(DoubleSeconds{item.second[0].asFloat()});
357 
359  INFO_LEVEL,
360  "MACI %03hu %s::%s %s = %lf",
361  id_,
362  pzLayerName,
363  __func__,
364  item.first.c_str(),
365  std::chrono::duration_cast<DoubleSeconds>(radioMetricReportIntervalMicroseconds_).count());
366  }
367  else if(item.first == "neighbormetricdeletetime")
368  {
369  neighborMetricDeleteTimeMicroseconds_ =
370  std::chrono::duration_cast<Microseconds>(DoubleSeconds{item.second[0].asFloat()});
371 
373  INFO_LEVEL,
374  "MACI %03hu %s::%s %s = %lf",
375  id_,
376  pzLayerName,
377  __func__,
378  item.first.c_str(),
379  std::chrono::duration_cast<DoubleSeconds>(neighborMetricDeleteTimeMicroseconds_).count());
380  }
381  else
382  {
383  throw makeException<ConfigureException>("RFPipe::MACLayer: "
384  "Unexpected configuration item %s",
385  item.first.c_str());
386  }
387  }
388 }
389 
390 
391 void
393 {
395  DEBUG_LEVEL,
396  "MACI %03hu %s::%s",
397  id_,
398  pzLayerName,
399  __func__);
400 
401  // load pcr curve
402  pcrManager_.load(sPCRCurveURI_);
403 
404  // set the neighbor delete time
405  neighborMetricManager_.setNeighborDeleteTimeMicroseconds(neighborMetricDeleteTimeMicroseconds_);
406 
407  // add downstream queue to be tracked
408  queueMetricManager_.addQueueMetric(0, downstreamQueue_.getMaxCapacity());
409 }
410 
411 
412 void
414 {
416  DEBUG_LEVEL,
417  "MACI %03hu %s::%s",
418  id_,
419  pzLayerName,
420  __func__);
421 
422  // check flow control enabled
423  if(bFlowControlEnable_)
424  {
425  // start flow control
426  flowControlManager_.start(u16FlowControlTokens_);
427 
429  DEBUG_LEVEL,
430  "MACI %03hu %s::%s sent a flow control token update,"
431  " a handshake response is required to process packets",
432  id_,
433  pzLayerName,
434  __func__);
435  }
436 
437  // set the timer timeout (absolute time), arg, interval
439  radioMetricTimedEventId_ =
441  schedule([this](const TimePoint &,
442  const TimePoint &,
443  const TimePoint &)
444  {
445  if(!bRadioMetricEnable_)
446  {
447  neighborMetricManager_.updateNeighborStatus();
448  }
449  else
450  {
451  ControlMessages msgs{
453  u64DataRatebps_,
454  radioMetricReportIntervalMicroseconds_),
457 
458  sendUpstreamControl(msgs);
459  }
460  },
461  Clock::now() + radioMetricReportIntervalMicroseconds_,
462  radioMetricReportIntervalMicroseconds_);
466  DEBUG_LEVEL,
467  "MACI %03hu %s::%s: added radio metric timed eventId %zu",
468  id_,
469  pzLayerName,
470  __func__,
471  radioMetricTimedEventId_);
472 }
473 
474 
475 void
477 {
479  DEBUG_LEVEL,
480  "MACI %03hu %s::%s",
481  id_,
482  pzLayerName,
483  __func__);
484 
485  for(const auto & item : update)
486  {
487  if(item.first == "enablepromiscuousmode")
488  {
489  bPromiscuousMode_ = item.second[0].asBool();
490 
492  INFO_LEVEL,
493  "MACI %03hu %s::%s %s = %s",
494  id_,
495  pzLayerName,
496  __func__,
497  item.first.c_str(),
498  bPromiscuousMode_ ? "on" : "off");
499 
500  }
501  else if(item.first == "datarate")
502  {
503  u64DataRatebps_ = item.second[0].asUINT64();
504 
506  INFO_LEVEL,
507  "MACI %03hu %s::%s %s = %ju",
508  id_,
509  pzLayerName,
510  __func__,
511  item.first.c_str(),
512  u64DataRatebps_);
513  }
514  else if(item.first == "jitter")
515  {
516  fJitterSeconds_ = item.second[0].asFloat();
517 
518  if(fJitterSeconds_ > 0.0f)
519  {
520  // create a random mumber distrubtion +- the jitter range
521  pRNDJitter_.reset(new Utils::RandomNumberDistribution<std::mt19937,
522  std::uniform_real_distribution<float>>
523  (-fJitterSeconds_ / 2.0f, fJitterSeconds_ / 2.0));
524  }
525 
527  INFO_LEVEL,
528  "MACI %03hu %s::%s %s = %f",
529  id_,
530  pzLayerName,
531  __func__,
532  item.first.c_str(),
533  fJitterSeconds_);
534  }
535  else if(item.first == "delay")
536  {
537  delayMicroseconds_ =
538  std::chrono::duration_cast<Microseconds>(DoubleSeconds{item.second[0].asFloat()});
539 
541  INFO_LEVEL,
542  "MACI %03hu %s::%s %s = %lf",
543  id_,
544  pzLayerName,
545  __func__,
546  item.first.c_str(),
547  std::chrono::duration_cast<DoubleSeconds>(delayMicroseconds_).count());
548 
549  }
550  else if(item.first == "neighbormetricdeletetime")
551  {
552  neighborMetricDeleteTimeMicroseconds_ =
553  std::chrono::duration_cast<Microseconds>(DoubleSeconds{item.second[0].asFloat()});
554 
555  // set the neighbor delete time
556  neighborMetricManager_.setNeighborDeleteTimeMicroseconds(neighborMetricDeleteTimeMicroseconds_);
557 
559  INFO_LEVEL,
560  "MACI %03hu %s::%s %s = %lf",
561  id_,
562  pzLayerName,
563  __func__,
564  item.first.c_str(),
565  std::chrono::duration_cast<DoubleSeconds>(neighborMetricDeleteTimeMicroseconds_).count());
566  }
567  else
568  {
569  throw makeException<ConfigureException>("RFPipe::MACLayer: "
570  "Unexpected configuration item %s",
571  item.first.c_str());
572  }
573  }
574 }
575 
576 
577 
578 void
580 {
582  DEBUG_LEVEL,
583  "MACI %03hu %s::%s",
584  id_,
585  pzLayerName,
586  __func__);
587 
589  pPlatformService_->timerService().cancelTimedEvent(downstreamQueueTimedEventId_);
592  downstreamQueueTimedEventId_ = 0;
593 
594  // check flow control enabled
595  if(bFlowControlEnable_)
596  {
597  // stop the flow control manager
598  flowControlManager_.stop();
599  }
600 }
601 
602 
603 
604 void
606  throw()
607 {
609  DEBUG_LEVEL,
610  "MACI %03hu %s::%s",
611  id_,
612  pzLayerName,
613  __func__);
614 }
615 
616 
617 void
619 
620 
621 void
623 {
624  for(const auto & pMessage : msgs)
625  {
627  DEBUG_LEVEL,
628  "MACI %03hu %s::%s downstream control message id %hu",
629  id_,
630  pzLayerName,
631  __func__,
632  pMessage->getId());
633 
634  switch(pMessage->getId())
635  {
637  {
638  const auto pFlowControlControlMessage =
639  static_cast<const Controls::FlowControlControlMessage *>(pMessage);
640 
641  if(bFlowControlEnable_)
642  {
644  DEBUG_LEVEL,
645  "MACI %03hu %s::%s received a flow control token request/response",
646  id_,
647  pzLayerName,
648  __func__);
649 
650  flowControlManager_.processFlowControlMessage(pFlowControlControlMessage);
651  }
652  else
653  {
655  ERROR_LEVEL,
656  "MACI %03hu %s::%s received a flow control token request but"
657  " flow control is not enabled",
658  id_,
659  pzLayerName,
660  __func__);
661  }
662  }
663  break;
664 
667  {
668  const auto pSerializedControlMessage =
669  static_cast<const Controls::SerializedControlMessage *>(pMessage);
670 
671  switch(pSerializedControlMessage->getSerializedId())
672  {
674  {
675  std::unique_ptr<Controls::FlowControlControlMessage>
676  pFlowControlControlMessage{
677  Controls::FlowControlControlMessage::create(pSerializedControlMessage->getSerialization())};
678 
679  if(bFlowControlEnable_)
680  {
681  flowControlManager_.processFlowControlMessage(pFlowControlControlMessage.get());
682  }
683  else
684  {
686  ERROR_LEVEL,
687  "MACI %03hu %s::%s received a flow control token request but"
688  " flow control is not enabled",
689  id_,
690  pzLayerName,
691  __func__);
692  }
693  }
694  break;
695  }
696  }
698  }
699  }
700 }
701 
702 
703 void
705  UpstreamPacket & pkt,
706  const ControlMessages & msgs)
707 {
708  // get current time
709  TimePoint beginTime{Clock::now()};
710 
711  commonLayerStatistics_.processInbound(pkt);
712 
713  if(commonMACHeader.getRegistrationId() != type_)
714  {
716  ERROR_LEVEL,
717  "MACI %03hu %s::%s: MAC Registration Id %hu does not match our Id %hu, drop.",
718  id_,
719  pzLayerName,
720  __func__,
721  commonMACHeader.getRegistrationId(),
722  type_);
723 
724  commonLayerStatistics_.processOutbound(pkt,
725  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
726  DROP_CODE_REGISTRATION_ID);
727 
728  // drop
729  return;
730  }
731 
732  size_t len{pkt.stripLengthPrefixFraming()};
733 
734  const PacketInfo & pktInfo{pkt.getPacketInfo()};
735 
736  if(len && pkt.length() >= len)
737  {
738  MACHeaderMessage rfpipeMACHeader{pkt.get(), len};
739 
740  pkt.strip(len);
741 
742  const Controls::ReceivePropertiesControlMessage * pReceivePropertiesControlMessage{};
743 
744  const Controls::FrequencyControlMessage * pFrequencyControlMessage{};
745 
746  for(auto & pControlMessage : msgs)
747  {
748  switch(pControlMessage->getId())
749  {
751  {
753  pReceivePropertiesControlMessage =
754  static_cast<const Controls::ReceivePropertiesControlMessage *>(pControlMessage);
755 
757  DEBUG_LEVEL,
758  Controls::ReceivePropertiesControlMessageFormatter(pReceivePropertiesControlMessage),
759  "MACI %03hu RFPipe::%s Receiver Properties Control Message",
760  id_,
761  __func__);
763  }
764  break;
765 
767  {
768  pFrequencyControlMessage =
769  static_cast<const Controls::FrequencyControlMessage *>(pControlMessage);
770 
772  DEBUG_LEVEL,
773  Controls::FrequencyControlMessageFormatter(pFrequencyControlMessage),
774  "MACI %03hu RFPipe::%s Frequency Control Message",
775  id_,
776  __func__);
777 
778  }
779 
780  break;
781  }
782  }
783 
784 
785  if(!pReceivePropertiesControlMessage || !pFrequencyControlMessage ||
786  pFrequencyControlMessage->getFrequencySegments().empty())
787  {
789  ERROR_LEVEL,
790  "MACI %03hu %s::%s: phy control "
791  "message not provided from src %hu, drop",
792  id_,
793  pzLayerName,
794  __func__,
795  pktInfo.getSource());
796 
797  commonLayerStatistics_.processOutbound(pkt,
798  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
799  DROP_CODE_BAD_CONTROL_INFO);
800 
801  // drop
802  return;
803  }
804  else
805  {
806  const auto & frequencySegments = pFrequencyControlMessage->getFrequencySegments();
807 
809  TimePoint startOfReception{pReceivePropertiesControlMessage->getTxTime() +
810  pReceivePropertiesControlMessage->getPropagationDelay() +
811  frequencySegments.begin()->getOffset()};
814  Microseconds span{pReceivePropertiesControlMessage->getSpan()};
815 
816  auto callback =
817  std::bind([this,
818  startOfReception,
819  frequencySegments,
820  span,
821  beginTime](UpstreamPacket & pkt,
822  std::uint64_t u64SequenceNumber,
823  std::uint64_t u64DataRate)
824  {
825  const PacketInfo & pktInfo{pkt.getPacketInfo()};
826 
827  const FrequencySegment & frequencySegment{*frequencySegments.begin()};
828 
830  DEBUG_LEVEL,
831  "MACI %03hu %s upstream EOR processing: src %hu, dst %hu,"
832  " len %zu, freq %ju, offset %ju, duration %ju, mac sequence %ju",
833  id_,
834  pzLayerName,
835  pktInfo.getSource(),
836  pktInfo.getDestination(),
837  pkt.length(),
838  frequencySegment.getFrequencyHz(),
839  frequencySegment.getOffset().count(),
840  frequencySegment.getDuration().count(),
841  u64SequenceNumber);
842 
843 
844  double dSINR{};
845 
846  double dNoiseFloordB{};
847 
848 
849  try
850  {
852  // get the spectrum info for the entire span, where a span
853  // is the total time between the start of the signal of the
854  // earliest segment and the end of the signal of the latest
855  // segment. This is not necessarily the signal duration.
856  auto window = pRadioService_->spectrumService().request(frequencySegment.getFrequencyHz(),
857  span,
858  startOfReception);
859 
860  // since we only have a single segment the span will equal the segment duration.
861  // For simple noise processing we will just pull out the max noise segment, we can
862  // use the maxBinNoiseFloor utility function for this. More elaborate noise window analysis
863  // will require a more complex algorithm, although you should get a lot of mileage out of
864  // this utility function.
865  bool bSignalInNoise{};
866 
867  std::tie(dNoiseFloordB,bSignalInNoise) =
868  Utils::maxBinNoiseFloor(window,frequencySegment.getRxPowerdBm());
869 
870  dSINR = frequencySegment.getRxPowerdBm() - dNoiseFloordB;
874  DEBUG_LEVEL,
875  "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, max noise %f, signal in noise %s, SINR %f",
876  id_,
877  pzLayerName,
878  pktInfo.getSource(),
879  pktInfo.getDestination(),
880  dNoiseFloordB,
881  bSignalInNoise ? "yes" : "no",
882  dSINR);
883  }
884  catch(SpectrumServiceException & exp)
885  {
887  ERROR_LEVEL,
888  "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, sor %ju, span %ju spectrum service request error: %s",
889  id_,
890  pzLayerName,
891  pktInfo.getSource(),
892  pktInfo.getDestination(),
893  std::chrono::duration_cast<Microseconds>(startOfReception.time_since_epoch()).count(),
894  span.count(),
895  exp.what());
896 
897  commonLayerStatistics_.processOutbound(pkt,
898  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
899  DROP_CODE_BAD_SPECTRUM_QUERY);
900  // drop
901  return;
902  }
903 
904  const Microseconds & durationMicroseconds{frequencySegment.getDuration()};
905 
906  // check sinr
907  if(!checkPOR(dSINR, pkt.length()))
908  {
910  DEBUG_LEVEL,
911  "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, "
912  "rxpwr %3.2f dBm, drop",
913  id_,
914  pzLayerName,
915  pktInfo.getSource(),
916  pktInfo.getDestination(),
917  frequencySegment.getRxPowerdBm());
918 
919  commonLayerStatistics_.processOutbound(pkt,
920  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
921  DROP_CODE_SINR);
922 
923  // drop
924  return;
925  }
926 
927  // update neighbor metrics
928  neighborMetricManager_.updateNeighborRxMetric(pktInfo.getSource(), // nbr (src)
929  u64SequenceNumber, // sequence number
930  pktInfo.getUUID(),
931  dSINR, // sinr in dBm
932  dNoiseFloordB, // noise floor in dB
933  startOfReception, // rx time
934  durationMicroseconds, // duration
935  u64DataRate); // data rate bps
936 
937  // check promiscuous mode, destination is this nem or to all nem's
938  if(bPromiscuousMode_ ||
939  (pktInfo.getDestination() == id_) ||
940  (pktInfo.getDestination() == NEM_BROADCAST_MAC_ADDRESS))
941  {
943  DEBUG_LEVEL,
944  "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, forward upstream",
945  id_,
946  pzLayerName,
947  pktInfo.getSource(),
948  pktInfo.getDestination());
949 
950  commonLayerStatistics_.processOutbound(pkt,
951  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime));
952 
953 
954  sendUpstreamPacket(pkt);
955 
956  // done
957  return;
958  }
959  else
960  {
962  DEBUG_LEVEL,
963  "MACI %03hu %s upstream EOR processing: not for this nem, "
964  "ignore pkt src %hu, dst %hu, drop",
965  id_,
966  pzLayerName,
967  pktInfo.getSource(),
968  pktInfo.getDestination());
969 
970  commonLayerStatistics_.processOutbound(pkt,
971  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
972  DROP_CODE_DST_MAC);
973 
974  // drop
975  return;
976  }
977  },pkt,commonMACHeader.getSequenceNumber(),rfpipeMACHeader.getDataRate());
978 
979 
980  auto eor = startOfReception + frequencySegments.begin()->getDuration();
981 
982  if(eor > beginTime)
983  {
984  // wait for end of reception to complete processing
985  pPlatformService_->timerService().schedule(callback,eor);
986  }
987  else
988  {
989  // we can process now, end of reception has past
990  callback();
991  }
992  }
993  }
994 }
995 
996 
997 
998 
999 void
1001  const ControlMessages &)
1002 {
1003  TimePoint beginTime{Clock::now()};
1004 
1005  commonLayerStatistics_.processInbound(pkt);
1006 
1007  // check flow control
1008  if(bFlowControlEnable_)
1009  {
1010  auto status = flowControlManager_.removeToken();
1011 
1012  if(status.second == false)
1013  {
1015  ERROR_LEVEL,
1016  "MACI %03hu %s::%s: failed to remove token, drop packet (tokens:%hu)",
1017  id_,
1018  pzLayerName,
1019  __func__,
1020  status.first);
1021 
1022  commonLayerStatistics_.processOutbound(pkt,
1023  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
1024  DROP_CODE_FLOW_CONTROL_ERROR);
1025 
1026  // drop
1027  return;
1028  }
1029  }
1030 
1031  // get duration
1032  Microseconds durationMicroseconds{getDurationMicroseconds(pkt.length())};
1033 
1034  DownstreamQueueEntry entry{pkt, // pkt
1035  beginTime, // acquire time
1036  durationMicroseconds, // duration
1037  u64DataRatebps_}; // data rate
1038 
1039  if(bHasPendingDownstreamQueueEntry_)
1040  {
1041  std::vector<DownstreamQueueEntry> result{downstreamQueue_.enqueue(entry)};
1042 
1043  // check for discarded, update stats
1044  for(auto & iter : result)
1045  {
1046  commonLayerStatistics_.processOutbound(iter.pkt_,
1047  std::chrono::duration_cast<Microseconds>(Clock::now() - iter.acquireTime_),
1048  DROP_CODE_QUEUE_OVERFLOW);
1049 
1050  // drop, replace token
1051  if(bFlowControlEnable_)
1052  {
1053  auto status = flowControlManager_.addToken();
1054 
1055  if(!status.second)
1056  {
1058  ERROR_LEVEL,
1059  "MACI %03hu %s::%s: failed to add token (tokens:%hu)",
1060  id_,
1061  pzLayerName,
1062  __func__,
1063  status.first);
1064  }
1065  }
1066  }
1067 
1068  // check to see if a packet can be sent
1069  auto now = Clock::now();
1070 
1071  if(currentEndOfTransmissionTime_ <= now)
1072  {
1073  handleDownstreamQueueEntry(now,u64TxSequenceNumber_);
1074  }
1075  }
1076  else
1077  {
1078  bHasPendingDownstreamQueueEntry_ = true;
1079 
1080  pendingDownstreamQueueEntry_ = std::move(entry);
1081 
1082  auto now = Clock::now();
1083 
1084  if(currentEndOfTransmissionTime_ - currentDelay_ <= now)
1085  {
1086  currentDelay_ = delayMicroseconds_ + getJitter();
1087 
1088  if(currentDelay_ > Microseconds::zero())
1089  {
1090  currentEndOfTransmissionTime_ = now + currentDelay_;
1091 
1092  downstreamQueueTimedEventId_ =
1094  schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1095  this,
1096  currentEndOfTransmissionTime_,
1097  u64TxSequenceNumber_),
1098  currentEndOfTransmissionTime_);
1099  }
1100  else
1101  {
1102  handleDownstreamQueueEntry(now,u64TxSequenceNumber_);
1103  }
1104  }
1105  else
1106  {
1108  downstreamQueueTimedEventId_ =
1110  schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1111  this,
1112  currentEndOfTransmissionTime_,
1113  u64TxSequenceNumber_),
1114  currentEndOfTransmissionTime_);
1116  }
1117  }
1118 }
1119 
1120 
1121 
1122 
1123 void
1124 EMANE::Models::RFPipe::MACLayer::handleDownstreamQueueEntry(TimePoint sot,
1125  std::uint64_t u64TxSequenceNumber)
1126 {
1127  auto now = Clock::now();
1128 
1129  // cached sequence number and next sequence number equality
1130  // guarantees sending the next packet, if available - even if an
1131  // early wakeup happens
1132  if(u64TxSequenceNumber == u64TxSequenceNumber_ ||
1133  (bHasPendingDownstreamQueueEntry_ && currentEndOfTransmissionTime_ <= now))
1134  {
1135  // the packet that was scheduled to be handled, has been but
1136  // there is another packet pending transmission and current packet
1137  // end of transmission has past - so send that one instead
1138  if(u64TxSequenceNumber != u64TxSequenceNumber_)
1139  {
1140  sot = now;
1141  }
1142 
1143  if(bHasPendingDownstreamQueueEntry_)
1144  {
1145  if(bFlowControlEnable_)
1146  {
1147  auto status = flowControlManager_.addToken();
1148 
1149  if(!status.second)
1150  {
1152  ERROR_LEVEL,
1153  "MACI %03hu %s::%s: failed to add token (tokens:%hu)",
1154  id_,
1155  pzLayerName,
1156  __func__,
1157  status.first);
1158 
1159  }
1160  }
1161 
1162  MACHeaderMessage rfpipeMACHeader{pendingDownstreamQueueEntry_.u64DataRatebps_};
1163 
1164  Serialization serialization{rfpipeMACHeader.serialize()};
1165 
1166  auto & pkt = pendingDownstreamQueueEntry_.pkt_;
1167 
1168  // prepend mac header to outgoing packet
1169  pkt.prepend(serialization.c_str(), serialization.size());
1170 
1171  // next prepend the serialization length
1172  pkt.prependLengthPrefixFraming(serialization.size());
1173 
1174  commonLayerStatistics_.processOutbound(pkt,
1175  std::chrono::duration_cast<Microseconds>(now - pendingDownstreamQueueEntry_.acquireTime_));
1176 
1179  sendDownstreamPacket(CommonMACHeader(type_, u64TxSequenceNumber_++),
1180  pkt,
1181  {Controls::FrequencyControlMessage::create(0, // bandwidth (0 means use phy default)
1182  {{0, pendingDownstreamQueueEntry_.durationMicroseconds_}}), // freq (0 means use phy default)
1184 
1186  // queue delay
1187  Microseconds queueDelayMicroseconds{std::chrono::duration_cast<Microseconds>(now - pendingDownstreamQueueEntry_.acquireTime_)};
1188 
1189  *pNumDownstreamQueueDelay_ += queueDelayMicroseconds.count();
1190 
1191  avgDownstreamQueueDelay_.update(queueDelayMicroseconds.count());
1192 
1193  queueMetricManager_.updateQueueMetric(0, // queue id, (we only have 1 queue)
1194  downstreamQueue_.getMaxCapacity(), // queue size
1195  downstreamQueue_.getCurrentDepth(), // queue depth
1196  downstreamQueue_.getNumDiscards(true), // get queue discards and clear counter
1197  queueDelayMicroseconds); // queue delay
1198 
1199  neighborMetricManager_.updateNeighborTxMetric(pendingDownstreamQueueEntry_.pkt_.getPacketInfo().getDestination(),
1200  pendingDownstreamQueueEntry_.u64DataRatebps_,
1201  now);
1202 
1203  currentDelay_ = delayMicroseconds_ + getJitter();
1204 
1205  // earliest you can send the next packet
1206  currentEndOfTransmissionTime_ =
1207  sot + pendingDownstreamQueueEntry_.durationMicroseconds_ + currentDelay_;
1208 
1209  std::tie(pendingDownstreamQueueEntry_,
1210  bHasPendingDownstreamQueueEntry_) =
1211  downstreamQueue_.dequeue();
1212 
1213  if(bHasPendingDownstreamQueueEntry_)
1214  {
1215  if(currentEndOfTransmissionTime_ > now)
1216  {
1217  downstreamQueueTimedEventId_ =
1219  schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1220  this,
1221  currentEndOfTransmissionTime_,
1222  u64TxSequenceNumber_),
1223  currentEndOfTransmissionTime_);
1224  }
1225  else
1226  {
1227  handleDownstreamQueueEntry(currentEndOfTransmissionTime_,u64TxSequenceNumber_);
1228  }
1229  }
1230  }
1231  }
1232 }
1233 
1234 
1235 
1237 EMANE::Models::RFPipe::MACLayer::getDurationMicroseconds(size_t lengthInBytes)
1238 {
1239  if(u64DataRatebps_ > 0)
1240  {
1241  float fSeconds{((lengthInBytes * 8.0f) / u64DataRatebps_)};
1242 
1243  return std::chrono::duration_cast<Microseconds>(DoubleSeconds{fSeconds});
1244  }
1245  else
1246  {
1247  return Microseconds{};
1248  }
1249 }
1250 
1251 
1253 EMANE::Models::RFPipe::MACLayer::getJitter()
1254 {
1255  if(fJitterSeconds_ > 0.0f)
1256  {
1257  return std::chrono::duration_cast<Microseconds>(DoubleSeconds{(*pRNDJitter_)()});
1258  }
1259  else
1260  {
1261  return Microseconds{};
1262  }
1263 }
1264 
1265 
1266 bool
1267 EMANE::Models::RFPipe::MACLayer::checkPOR(float fSINR, size_t packetSize)
1268 {
1269  // find por
1270  float fPCR{pcrManager_.getPCR(fSINR, packetSize)};
1271 
1272  // get random value [0.0, 1.0]
1273  float fRandomValue{RNDZeroToOne_()};
1274 
1275  // pcr >= random value
1276  bool bResult{fPCR >= fRandomValue};
1277 
1279  DEBUG_LEVEL,
1280  "MACI %03hu %s::%s: sinr %3.2f, pcr %3.2f %s rand %3.3f",
1281  id_,
1282  pzLayerName,
1283  __func__,
1284  fSINR,
1285  fPCR,
1286  bResult ? ">=" : "<",
1287  fRandomValue);
1288 
1289  return bResult;
1290 }
1291 
std::pair< DownstreamQueueEntry, bool > dequeue()
removes an element from the queue
std::string Serialization
Definition: serializable.h:42
A Packet class that allows upstream processing to strip layer headers as the packet travels up the st...
const PacketInfo & getPacketInfo() const
The Registrar interface provides access to all of the emulator registrars.
Definition: registrar.h:50
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)
#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 &timestamp)
RegistrationId getRegistrationId() const
void initialize(Registrar &registrar) override
std::vector< DownstreamQueueEntry > enqueue(DownstreamQueueEntry &entry)
Adds an element to the queue.
NEMId getDestination() const
Definition: packetinfo.inl:70
std::uint16_t stripLengthPrefixFraming()
constexpr NEMId NEM_BROADCAST_MAC_ADDRESS
Definition: types.h:69
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_
The PlatformServiceProvider interface provides access to emulator services.
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.
Definition: packetinfo.h:50
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
Definition: exception.h:62
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
Definition: types.h:45
std::chrono::duration< double > DoubleSeconds
Definition: types.h:47
std::uint16_t NEMId
Definition: types.h:52
Callable formatter object for ReceivePropertiesControlMessage instances.
static R2RISelfMetricControlMessage * create(const Serialization &serialization)
Flow Control Control Messages are sent between a MAC layer and a transport in order to communicate da...
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
PlatformServiceProvider * pPlatformService_
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)
TimerEventId schedule(Function fn, const TimePoint &timePoint, const Duration &interval=Duration::zero())
void sendUpstreamControl(const ControlMessages &msgs)
std::uint64_t getSequenceNumber() const
void registerStatistics(StatisticRegistrar &statisticRegistrar)
void setNeighborDeleteTimeMicroseconds(const Microseconds &ageMicroseconds)
const void * get() const
virtual LogServiceProvider & logService()=0
DECLARE_MAC_LAYER(EMANE::Models::RFPipe::MACLayer)
Callable formatter object for FrequencyControlMessage instances.
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
Definition: types.h:50
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.
Definition: maclayerimpl.h:48
virtual TimerServiceProvider & timerService()=0