EMANE  1.2.1
neighbormanager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013,2016 - Adjacent Link LLC, Bridgewater, New Jersey
3  * Copyright (c) 2010-2012 - 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 #include "neighbormanager.h"
35 #include "maclayer.h"
36 #include "utils.h"
37 #include "msgtypes.h"
38 
39 #include "emane/constants.h"
40 
41 #include <sstream>
42 
43 
44 namespace {
45  const char * pzLayerName {"NeighborManager"};
46 }
47 
48 
50  PlatformServiceProvider * pPlatformService,
51  MACLayer *pMACLayer):
52  id_{id},
53  pPlatformService_{pPlatformService},
54  pMACLayer_{pMACLayer},
55  wmmManager_{id, pPlatformService, pMACLayer},
56  nbrTimeOutMicroseconds_{},
57  lastOneHopNbrListTxTime_{},
58  RNDZeroToOne_{0.0f, 1.0f},
59  lastResetTime_{}
60 {
61  // reset counters
62  resetCounters_i();
63 
64  utilizationRatioVector_ = wmmManager_.getUtilizationRatios(Microseconds::zero());
65 }
66 
67 
68 
70 { }
71 
72 
73 void
75 {
76  wmmManager_.setNumCategories(u8NumCategories);
77 }
78 
79 
80 float
82 {
83  // find the src in the one hop nbr(s)
84  auto nbrEntry = oneHopNbrMap_.find(src);
85 
86  float fResult{};
87 
88  if(nbrEntry != oneHopNbrMap_.end())
89  {
90  fResult = nbrEntry->second.getHiddenChannelActivity();
91  }
92 
93  return fResult;
94 }
95 
96 
97 
98 float
100 {
101  // find the src
102  auto nbrEntry = oneHopNbrMap_.find(src);
103 
104  float fResult{};
105 
106  if(nbrEntry != oneHopNbrMap_.end())
107  {
108  fResult = nbrEntry->second.getEstimatedNumCommonNeighbors();
109  }
110 
111  return fResult;
112 }
113 
114 
115 float
117 {
118  // find the src
119  auto nbrEntry = oneHopNbrMap_.find(src);
120 
121  float fResult{};
122 
123  if(nbrEntry != oneHopNbrMap_.end())
124  {
125  // set result
126  fResult = fEstimatedNumOneHopNeighbors_ - nbrEntry->second.getEstimatedNumCommonNeighbors();
127  }
128 
129  // min allowed is 0
130  if(fResult < 0.0f)
131  {
132  fResult = 0.0f;
133  }
134 
135  return fResult;
136 }
137 
138 
139 
142 {
143  // find the src
144  auto nbrEntry = oneHopNbrMap_.find(src);
145 
146  if(nbrEntry != oneHopNbrMap_.end())
147  {
148  return nbrEntry->second.getUtilizationMicroseconds(MSG_TYPE_MASK_ALL_DATA);
149  }
150  else
151  {
152  return Microseconds::zero();
153  }
154 }
155 
156 
157 
158 float
160 {
161  return fEstimatedNumOneHopNeighbors_;
162 }
163 
164 
165 
166 float
168 {
169  return fEstimatedNumTwoHopNeighbors_;
170 }
171 
172 
173 
176 {
177  return totalOneHopUtilizationMicroseconds_;
178 }
179 
180 
181 
184 {
185  return totalTwoHopUtilizationMicroseconds_;
186 }
187 
188 
189 
192 {
193  return averageMessageDurationMicroseconds_;
194 }
195 
196 
197 
198 
199 float
201 {
202  return fLocalNodeTx_;
203 }
204 
205 
206 
207 size_t
209 {
210  return numTotalActiveOneHopNeighbors_;
211 }
212 
213 
214 
215 float
217 {
218  return fAverageRxPowerPerMessageMilliWatts_;
219 }
220 
221 
222 
223 float
225 {
226  if(sumHiddenPackets_ > 0)
227  {
228  return fHiddenRxPowerMilliWatts_ / sumHiddenPackets_;
229  }
230  else
231  {
232  return 0.0;
233  }
234 }
235 
236 
237 
238 float
240 {
241  if(sumCommonPackets_ > 0)
242  {
243  return fCommonRxPowerMilliWatts_ / sumCommonPackets_;
244  }
245  else
246  {
247  return 0.0;
248  }
249 }
250 
251 
252 
253 float
255 {
256  // get random probability
257  const float fRandom{RNDZeroToOne_()};
258 
259  // get result using common info
260  const float fResult{getRandomRxPowerMilliWatts_i(src, fRandom, commonProbabilityMapMap_, commonNbrAvgRxPowerMwMap_)};
261 
262  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
263  DEBUG_LEVEL,
264  "MACI %03hu %s::%s: src %hu, random %5.4f, result %5.4f",
265  id_,
266  pzLayerName,
267  __func__,
268  src,
269  fRandom,
270  fResult);
271 
272  return fResult;
273 }
274 
275 
276 
277 float
279 {
280  // get random probability
281  const float fRandom{RNDZeroToOne_()};
282 
283  // get result using hidden info
284  const float fResult{getRandomRxPowerMilliWatts_i(src,
285  fRandom,
286  hiddenProbabilityMapMap_,
287  hiddenNbrAvgRxPowerMwMap_)};
288 
289  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
290  DEBUG_LEVEL,
291  "MACI %03hu %s::%s: src %hu, random %5.4f, result %6.4f mW",
292  id_,
293  pzLayerName,
294  __func__,
295  src,
296  fRandom,
297  fResult);
298 
299  // return result
300  return fResult;
301 }
302 
303 
304 
305 float
306 EMANE::Models::IEEE80211ABG::NeighborManager::getRandomRxPowerMilliWatts_i(NEMId src,
307  float fRandom,
308  const ProbabilityPairMapMap & pmap,
309  const RxPowerMap & rmap) const
310 {
311  // result
312  float fResult{};
313 
314  // lookup probabilty pair map
315  auto pmmiter = pmap.find(src);
316 
317  // entry found
318  if(pmmiter != pmap.end())
319  {
320  // for each common probabilty entry
321  for(auto & piter : pmmiter->second)
322  {
323  // search probability ranges
324  if((fRandom >= piter.second.first) && (fRandom <= piter.second.second))
325  {
326  // lookup common nbr
327  auto riter = rmap.find(piter.first);
328 
329  // common nbr found
330  if(riter != rmap.end())
331  {
332  // set result
333  fResult = riter->second;
334  }
335 
336  // done
337  break;
338  }
339  }
340  }
341 
342  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
343  DEBUG_LEVEL,
344  "MACI %03hu %s::%s: src %hu, random %5.4f, result %6.4f",
345  id_,
346  pzLayerName,
347  __func__,
348  src,
349  fRandom,
350  fResult);
351 
352  return fResult;
353 }
354 
355 
356 
359 {
360  return lastOneHopNbrListTxTime_;
361 }
362 
363 
364 
365 void
367 {
368  nbrTimeOutMicroseconds_ = timeOutMicroseconds;
369 }
370 
371 void
373 {
374  lastResetTime_ = Clock::now();
375 }
376 
377 void
379 {
380  // current time
381  const TimePoint currentTime{Clock::now()};
382 
383  Microseconds deltaTMicroseconds{std::chrono::duration_cast<Microseconds>(currentTime - lastResetTime_)};
384 
385  // nbr timeout enabled
386  if(nbrTimeOutMicroseconds_ != Microseconds::zero())
387  {
388  // time out old one hop nbrs
389  if(flushOneHopNeighbors_i(currentTime, nbrTimeOutMicroseconds_) == true)
390  {
391  // nbr table changed, send event
392  sendOneHopNbrListEvent_i();
393  }
394 
395  // time out old two hop nbrs
396  if(flushTwoHopNeighbors_i(currentTime, nbrTimeOutMicroseconds_) == true)
397  {
398  // dont care
399  }
400  }
401 
402  // for each one hop nbr
403  for(auto & nbrEntry :oneHopNbrMap_)
404  {
405  // store history and reset all utilizations
406  nbrEntry.second.storeUtilization();
407  }
408 
409  // calculate bw utilization
410  calculateBwUtilization_i(deltaTMicroseconds);
411 
412  // for each two hop nbr
413  for(auto & nbr2Entry : twoHopNbrMap_)
414  {
415  // reset utilization
416  nbr2Entry.second.resetUtilization();
417  }
418 
419  // get wmm bandiwdth utilization ratio(s)
420  utilizationRatioVector_ = wmmManager_.getUtilizationRatios(deltaTMicroseconds);
421 
422  lastResetTime_ = currentTime;
423 }
424 
425 
426 
427 
428 
429 void
431  std::uint8_t type,
432  float fRxPowerMilliWatts,
433  const TimePoint & timePoint,
434  const Microseconds & durationMicroseconds,
435  std::uint8_t u8Category)
436 {
437  bool changed{false};
438 
439  // add/update one hop nbr
440  auto nbrResult = addOneHopNeighbor_i(src);
441 
442  // new nbr
443  if(nbrResult.second == true)
444  {
445  // one hop nbr table changed
446  changed = true;
447  }
448 
449  // udpate the duration, last activity time and rx power
450  nbrResult.first->second.updateChannelActivity(durationMicroseconds, type, timePoint, fRxPowerMilliWatts);
451 
452  if(src == id_)
453  {
454  wmmManager_.updateLocalActivity(u8Category, durationMicroseconds);
455  }
456  else
457  {
458  wmmManager_.updateTotalActivity(u8Category, durationMicroseconds);
459  }
460 
461 
462  // nbr table changed
463  if(changed == true)
464  {
465  // send one hop nbr list event
466  sendOneHopNbrListEvent_i();
467  }
468 }
469 
470 
471 
472 
473 void
475  NEMId origin,
476  std::uint8_t type,
477  float fRxPowerMilliWatts,
478  const TimePoint & timePoint,
479  const Microseconds & durationMicroseconds,
480  std::uint8_t u8Category)
481 {
482  bool changed{false};
483 
484  // check unicast rts/cts origin is not us
485  if(origin != id_)
486  {
487  // rts/cts origin not found
488  if(oneHopNbrMap_.find(origin) == oneHopNbrMap_.end())
489  {
490  // add two hop nbr
491  auto nbr2Result = addTwoHopNeighbor_i(origin);
492 
493  // udpate the duration (unicast msg), last activity time
494  nbr2Result.first->second.updateChannelActivity(durationMicroseconds, timePoint);
495  }
496  }
497 
498  // add/update one hop nbr
499  auto nbrResult = addOneHopNeighbor_i(src);
500 
501  // new nbr
502  if(nbrResult.second == true)
503  {
504  // one hop nbr table changed
505  changed = true;
506  }
507 
508  // do not include the duration, just set last activity time and rx power
509  nbrResult.first->second.updateChannelActivity(Microseconds::zero(), type, timePoint, fRxPowerMilliWatts);
510 
511  if(src == id_)
512  {
513  wmmManager_.updateLocalActivity(u8Category, durationMicroseconds);
514  }
515  else
516  {
517  wmmManager_.updateTotalActivity(u8Category, durationMicroseconds);
518  }
519 
520  // nbr table changed
521  if(changed == true)
522  {
523  // send one hop nbr list event
524  sendOneHopNbrListEvent_i();
525  }
526 }
527 
528 
529 
530 
531 void
533 {
534  try
535  {
536  OneHopNeighborsEvent event{serialization};
537 
538  NbrSet nbrSet{event.getNeighbors()};
539 
540  NEMId eventSource{event.getEventSource()};
541 
542  // bump num rx events
544 
545  // search for one hop nbr
546  auto nbrEntry = oneHopNbrMap_.find(eventSource);
547 
548  // src is an active one hop nbr
549  if(nbrEntry != oneHopNbrMap_.end())
550  {
551  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
552  DEBUG_LEVEL,
553  "MACI %03hu %s::%s: update 1hop_nbr_list for nbr %hu, %zd entries",
554  id_,
555  pzLayerName,
556  __func__,
557  eventSource,
558  nbrSet.size());
559 
560  // set one hop nbrs of this one hop nbr
561  nbrEntry->second.setOneHopNeighbors(nbrSet);
562  }
563  else
564  {
565  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
566  DEBUG_LEVEL,
567  "MACI %03hu %s::%s: unknown nbr %hu, 1hop_nbr_list with %zd entries will be cached",
568  id_,
569  pzLayerName,
570  __func__,
571  eventSource,
572  nbrSet.size());
573  }
574 
575  // we want to keep a cache of events in case of unknown or timed out nodes
576  // find src of this event in the one hop nbr list event cache
577  auto iter = cachedOneHopNbrSetMap_.find(eventSource);
578 
579  // not already cached
580  if(iter == cachedOneHopNbrSetMap_.end())
581  {
582  // insert into cache
583  cachedOneHopNbrSetMap_[eventSource] = nbrSet;
584 
585  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
586  DEBUG_LEVEL,
587  "MACI %03hu %s::%s: added event cache 1hop_nbr_list for nbr %hu, %zd entries",
588  id_,
589  pzLayerName,
590  __func__,
591  eventSource,
592  nbrSet.size());
593  }
594  else
595  {
596  // update cache
597  iter->second = nbrSet;
598 
599  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
600  DEBUG_LEVEL,
601  "MACI %03hu %s::%s: updated event cache 1hop_nbr_list for nbr %hu, %zd entries",
602  id_,
603  pzLayerName,
604  __func__,
605  eventSource,
606  nbrSet.size());
607  }
608 
609  }
610  catch(SerializationException &ex)
611  {
612  LOGGER_STANDARD_LOGGING(pPlatformService_->logService(),
613  ERROR_LEVEL,
614  "MACI %03hu %s::%s: 1hop neighbors event error %s",
615  id_,
616  pzLayerName,
617  __func__,
618  ex.what());
619 
620  // bump num rx invalid events
622  }
623 }
624 
625 
628 {
629  return utilizationRatioVector_;
630 }
631 
632 
633 
634 
635 void
636 EMANE::Models::IEEE80211ABG::NeighborManager::calculateBwUtilization_i(const Microseconds & deltaTMicroseconds)
637 {
638  // internal call
639 
640  // reset counters
641  resetCounters_i();
642 
643  // each one hop nbr
644  for(auto & nbrEntry : oneHopNbrMap_)
645  {
646  // get bandwidth utilization all DATA msg types
647  Microseconds utilizationMicroseconds{nbrEntry.second.getUtilizationMicroseconds(MSG_TYPE_MASK_ALL_DATA)};
648 
649  // check utilization
650  if(utilizationMicroseconds > Microseconds::zero())
651  {
652  // sum total one hop bandwidth utilization
653  totalOneHopUtilizationMicroseconds_ += utilizationMicroseconds;
654 
655  // store the one hop utilization
656  oneHopUtilizationMap_[nbrEntry.first] = utilizationMicroseconds;
657 
658  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
659  DEBUG_LEVEL,
660  "MACI %03hu %s::%s: 1hop_nbr %hu, 1hop_bw %lf, total_1hop_bw %lf",
661  id_,
662  pzLayerName,
663  __func__,
664  nbrEntry.first,
665  std::chrono::duration_cast<DoubleSeconds>(utilizationMicroseconds).count(),
666  std::chrono::duration_cast<DoubleSeconds>(totalOneHopUtilizationMicroseconds_).count());
667 
668  // this nem
669  if(nbrEntry.first == id_)
670  {
671  // set this nem bw utilization
672  utilizationThisNEMMicroseconds_ = utilizationMicroseconds;
673  }
674  // other nem(s)
675  else
676  {
677  // sum number of one hop packets all DATA msg types
678  totalOneHopNumPackets_ += nbrEntry.second.getNumberOfPackets(MSG_TYPE_MASK_ALL_DATA);
679 
680  // sum one hop rx power all DATA msg types
681  fTotalRxPowerMilliWatts_ += nbrEntry.second.getRxPowerMilliWatts(MSG_TYPE_MASK_ALL_DATA);
682  }
683  }
684  }
685 
686  // set the local node Tx value avoid / by 0
687  if(totalOneHopUtilizationMicroseconds_ != Microseconds::zero())
688  {
689  fLocalNodeTx_ = getRatio(utilizationThisNEMMicroseconds_, totalOneHopUtilizationMicroseconds_);
690  }
691  else
692  {
693  fLocalNodeTx_ = 0.0;
694  }
695 
696 #ifdef VERY_VERBOSE_LOGGING
697  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
698  DEBUG_LEVEL,
699  "MACI %03hu %s::%s: %zd active 1hop_nbrs, "
700  "1hop_total_bw %lf, total_1hop_pkts %zd, total_1hop_pwr %5.4f mW, local tx %5.4f",
701  id_,
702  pzLayerName,
703  __func__,
704  oneHopUtilizationMap_.size(),
705  std::chrono::duration_cast<DoubleSeconds>(totalOneHopUtilizationMicroseconds_).count(),
706  totalOneHopNumPackets_,
707  fTotalRxPowerMilliWatts_,
708  fLocalNodeTx_);
709 #endif
710 
711  // each two hop nbr
712  for(const auto & nbr2Entry : twoHopNbrMap_)
713  {
714  // get bandwidth utilization
715 
716  const Microseconds utilizationMicroseconds{nbr2Entry.second.getUtilizationMicroseconds()};
717 
718  // check any utilization
719  if(utilizationMicroseconds > Microseconds::zero())
720  {
721  // store the two hop utilization
722  twoHopUtilizationMap_[nbr2Entry.first] = utilizationMicroseconds;
723 
724  // sum total 2 hop bandwidth utilization
725  totalTwoHopUtilizationMicroseconds_ += utilizationMicroseconds;
726 
727  // sum number of 2 hop packets
728  totalTwoHopNumPackets_ += nbr2Entry.second.getNumberOfPackets();
729 
730  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
731  DEBUG_LEVEL,
732  "MACI %03hu %s::%s: 2hop_nbr %hu, 2hop_bw %lf, total_2hop_bw %lf",
733  id_,
734  pzLayerName,
735  __func__,
736  nbr2Entry.first,
737  std::chrono::duration_cast<DoubleSeconds>(utilizationMicroseconds).count(),
738  std::chrono::duration_cast<DoubleSeconds>(totalTwoHopUtilizationMicroseconds_).count());
739 
740  }
741  }
742 
743 #ifdef VERY_VERBOSE_LOGGING
744  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
745  DEBUG_LEVEL,
746  "MACI %03hu %s::%s: %zd active 2hop_nbrs, total_2hop_bw %lf, total_pkts %zd",
747  id_,
748  pzLayerName,
749  __func__,
750  twoHopUtilizationMap_.size(),
751  std::chrono::duration_cast<DoubleSeconds>(totalTwoHopUtilizationMicroseconds_).count(),
752  totalTwoHopNumPackets_);
753 #endif
754 
755  // check two hop packet count, prevents / by 0
756  if(totalTwoHopNumPackets_ > 0)
757  {
758  // sum B
759  float B{};
760 
761  // average bandwidth utilization per active two hop nbr
762  averageUtilizationPerTwoHopNbrMicroseconds_ =
763  std::chrono::duration_cast<Microseconds>(DoubleSeconds{((totalTwoHopUtilizationMicroseconds_.count() *
764  (1.0f / twoHopUtilizationMap_.size())) / USEC_PER_SEC_F)});
765 
766  // each two hop utilization entry
767  for(const auto & twoHopUtilization : twoHopUtilizationMap_)
768  {
769  // get A
770  const float A = getA_i(twoHopUtilization.second, averageUtilizationPerTwoHopNbrMicroseconds_);
771 
772  // sum A^2
773  B += powf(A, 2.0f);
774 
775  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
776  DEBUG_LEVEL,
777  "MACI %03hu %s::%s: 2hop A = %5.4f, B = %5.4f",
778  id_,
779  pzLayerName,
780  __func__,
781  A, B);
782  }
783 
784  // calculate the total estimated number of two hop nbrs
785  fEstimatedNumTwoHopNeighbors_ = round(B);
786  }
787 
788 
789  // check one hop packet count, prevents / by 0
790  if(totalOneHopNumPackets_ > 0)
791  {
792  // set num active nbrs, may include us
793  numTotalActiveOneHopNeighbors_ = oneHopUtilizationMap_.size();
794 
795  // average bandwidth utilization per active one hop nbr
796  averageUtilizationPerOneHopNbrMicroseconds_ =
797  std::chrono::duration_cast<Microseconds>(DoubleSeconds{((totalOneHopUtilizationMicroseconds_.count() *
798  (1.0f / numTotalActiveOneHopNeighbors_)) / USEC_PER_SEC_F)});
799 
800  // average rx power per packet
801  fAverageRxPowerPerMessageMilliWatts_ = fTotalRxPowerMilliWatts_ / totalOneHopNumPackets_;
802 
803  // average message duration (not including this nem)
804  averageMessageDurationMicroseconds_ =
805  std::chrono::duration_cast<Microseconds>(DoubleSeconds{(((totalOneHopUtilizationMicroseconds_.count() -
806  utilizationThisNEMMicroseconds_.count()) * (1.0f / totalOneHopNumPackets_)) / USEC_PER_SEC_F)});
807 
808  float A1{}, A2{}, B1{};
809 
810  // each one hop nbr
811  for(auto & nbrEntry1 : oneHopNbrMap_)
812  {
813  // check nbr activity all DATA msg types
814  if(nbrEntry1.second.getNumberOfPackets(MSG_TYPE_MASK_ALL_DATA) > 0)
815  {
816  // get A
817  A1 = getA_i(nbrEntry1.second.getUtilizationMicroseconds(MSG_TYPE_MASK_ALL_DATA),
818  averageUtilizationPerOneHopNbrMicroseconds_);
819 
820  B1 += powf(A1, 2.0f);
821 
822  // check nbr is not us
823  if(nbrEntry1.first != id_)
824  {
825  float B2{};
826 
827  // the sum of hidden bandwidth utilization
828  Microseconds hiddenUtilizationMicroseconds{};
829 
830  // the sum of common rx power in mW
831  float fCommonRxPowerMilliWatts{};
832 
833  // the sum of hidden rx power in mW
834  float fHiddenRxPowerMilliWatts{};
835 
836  // the sum of common tx pkts
837  size_t numCommonPackets{};
838 
839  // the sum of hidden tx pkts
840  size_t numHiddenPackets{};
841 
842  // get the one hop nbrs of this nbr
843  const NbrSet nbrOneHopNbrSet = nbrEntry1.second.getOneHopNeighbors();
844 
845 #ifdef VERBOSE_LOGGIN
846  std::stringstream ss;
847 
848  // list the nbrs of this nbr
849  for(auto & nbr : nbrOneHopNbrSet)
850  {
851  if(nbr == nbrOneHopNbrSet.begin())
852  {
853  ss << *nbr;
854  }
855  else
856  {
857  ss << ", " << *nbr;
858  }
859  }
860 
861  LOGGER_VERBOSE_LOGGING(pPlatformService_,
862  DEBUG_LEVEL,
863  "MACI %03hu %s::%s: nbr %hu has %zu 1hop_nbrs: %s",
864  id_,
865  pzLayerName,
866  __func__,
867  nbrEntry1.first,
868  nbrOneHopNbrSet.size(),
869  ss.str().c_str());
870 #endif
871 
872  // nbrs hidden from this nbr
873  NbrSet hiddenNbrs;
874 
875  // nbrs common with this nbr
876  NbrSet commonNbrs;
877 
878  // each one hop nbr (again)
879  for(auto & nbrEntry2 : oneHopNbrMap_)
880  {
881  // does the nbr's one hop nbr set include our nbr
882  if(nbrOneHopNbrSet.find(nbrEntry2.first) != nbrOneHopNbrSet.end())
883  {
884  // get all DATA msg types
885  const int typeMask{MSG_TYPE_MASK_ALL_DATA};
886 
887  A2 = getA_i(nbrEntry2.second.getUtilizationMicroseconds(typeMask),
888  averageUtilizationPerOneHopNbrMicroseconds_);
889 
890  B2 +=powf(A2, 2.0f);
891 
892  // get common rx power
893  const float fRxPowermW{nbrEntry2.second.getRxPowerMilliWatts(typeMask)};
894 
895  // get the common number of packets
896  const size_t numPackets{nbrEntry2.second.getNumberOfPackets(typeMask)};
897 
898  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
899  DEBUG_LEVEL,
900  "MACI %03hu %s::%s: our nbr %hu is common with nbr %hu, pkts %zd, rxpwr %6.4f mW",
901  id_,
902  pzLayerName,
903  __func__,
904  nbrEntry2.first,
905  nbrEntry1.first,
906  numPackets,
907  fRxPowermW);
908 
909  // add to common nbrs
910  commonNbrs.insert(nbrEntry2.first);
911 
912  // save common rx power avoid / by 0
913  commonNbrAvgRxPowerMwMap_[nbrEntry2.first] = numPackets > 0 ? fRxPowermW / numPackets : 0;
914 
915  // sum the common rx power
916  fCommonRxPowerMilliWatts += fRxPowermW;
917 
918  // sum the common number of packets
919  numCommonPackets += numPackets;
920  }
921  // hidden from this nbr
922  else
923  {
924  // get all unicast and broadcast msg types
925  const int typeMask {MSG_TYPE_MASK_UNICAST | MSG_TYPE_MASK_BROADCAST};
926 
927  // sum the hidden bandwidth utilization
928  hiddenUtilizationMicroseconds += nbrEntry2.second.getUtilizationMicroseconds(typeMask);
929 
930  // get hidden rx power
931  const float fRxPowermW{nbrEntry2.second.getRxPowerMilliWatts(typeMask)};
932 
933  // get the hidden number of packets
934  const size_t numPackets{nbrEntry2.second.getNumberOfPackets(typeMask)};
935 
936  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
937  DEBUG_LEVEL,
938  "MACI %03hu %s::%s: nbr %hu is hidden from nbr %hu, pkts %zd, rxpwr %6.4f mW",
939  id_,
940  pzLayerName,
941  __func__,
942  nbrEntry2.first,
943  nbrEntry1.first,
944  numPackets,
945  fRxPowermW);
946 
947  // add to hidden nbrs
948  hiddenNbrs.insert(nbrEntry2.first);
949 
950  // save hidden rx power avoid / by 0
951  hiddenNbrAvgRxPowerMwMap_[nbrEntry2.first] = numPackets > 0 ? fRxPowermW / numPackets : 0;
952 
953  // sum the hidden rx power
954  fHiddenRxPowerMilliWatts += fRxPowermW;
955 
956  // sum the hidden number of packets
957  numHiddenPackets += numPackets;
958  }
959  }
960 
961  // set the common nbrs
962  nbrEntry1.second.setCommonNeighbors(commonNbrs);
963 
964  // set the hidden nbrs
965  nbrEntry1.second.setHiddenNeighbors(hiddenNbrs);
966 
967  // get the hidden channel activity
968  const float H{getH_i(hiddenUtilizationMicroseconds, deltaTMicroseconds)};
969 
970  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
971  DEBUG_LEVEL,
972  "MACI %03hu %s::%s: 1hop_nbr %hu, A1 = %5.4f, A2 = %5.4f, B1 = %5.4f, B2 = %5.4f, H = %5.4f",
973  id_,
974  pzLayerName,
975  __func__,
976  nbrEntry1.first,
977  A1, A2, B1, B2, H);
978 
979  // set the estimated number of common nbrs this nbr
980  nbrEntry1.second.setEstimatedNumCommonNeighbors(round(B2));
981 
982  // set the avg common rx power this nbr, avoid / by 0
983  nbrEntry1.second.setAverageCommonRxPowerMilliWatts(numCommonPackets > 0.0f ?
984  fCommonRxPowerMilliWatts / numCommonPackets : 0.0f);
985 
986  // set the hidden channel activity this nbr
987  nbrEntry1.second.setHiddenChannelActivity(H);
988 
989  // set the avg hidden rx power this nbr, avoid / by 0
990  nbrEntry1.second.setAverageHiddenRxPowerMilliWatts(numHiddenPackets > 0.0f ?
991  fHiddenRxPowerMilliWatts / numHiddenPackets : 0.0f);
992 
993  // set the overall sum of common pkts
994  sumCommonPackets_ += numCommonPackets;
995 
996  // set the overall sum of hidden pkts
997  sumHiddenPackets_ += numHiddenPackets;
998 
999  // set the overall pwr of common pkts
1000  fCommonRxPowerMilliWatts_ += fCommonRxPowerMilliWatts;
1001 
1002  // set the overall pwr of hidden pkts
1003  fHiddenRxPowerMilliWatts_ += fHiddenRxPowerMilliWatts;
1004  }
1005  }
1006  }
1007 
1008  // set common and hidden probability
1009  setCommonAndHiddenProbability_i();
1010 
1011  // calculate the total estimated number of one hop nbrs
1012  fEstimatedNumOneHopNeighbors_ = round(B1);
1013 
1014  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1015  DEBUG_LEVEL,
1016  "MACI %03hu %s::%s: est nbrs [1hop %5.4f, 2hop %5.4f], active nbrs %zd, elapsed time %lf",
1017  id_,
1018  pzLayerName,
1019  __func__,
1020  fEstimatedNumOneHopNeighbors_,
1021  fEstimatedNumTwoHopNeighbors_,
1022  numTotalActiveOneHopNeighbors_,
1023  std::chrono::duration_cast<DoubleSeconds>(deltaTMicroseconds).count());
1024  }
1025 }
1026 
1027 
1028 
1029 void
1030 EMANE::Models::IEEE80211ABG::NeighborManager::resetCounters_i()
1031 {
1032  // internal call
1033 
1034  fLocalNodeTx_ = 0.0f;
1035 
1036  totalOneHopNumPackets_ = 0;
1037 
1038  totalTwoHopNumPackets_ = 0;
1039 
1040  sumCommonPackets_ = 0;
1041 
1042  sumHiddenPackets_ = 0;
1043 
1044  numTotalActiveOneHopNeighbors_ = 0;
1045 
1046  fTotalRxPowerMilliWatts_ = 0.0f;
1047 
1048  fEstimatedNumOneHopNeighbors_ = 0.0f;
1049 
1050  fEstimatedNumTwoHopNeighbors_ = 0.0f;
1051 
1052  fAverageRxPowerPerMessageMilliWatts_ = 0.0f;
1053 
1054  fHiddenRxPowerMilliWatts_ = 0.0f;
1055 
1056  fCommonRxPowerMilliWatts_ = 0.0f;
1057 
1058  averageMessageDurationMicroseconds_ = Microseconds::zero();
1059 
1060  totalOneHopUtilizationMicroseconds_ = Microseconds::zero();
1061 
1062  totalTwoHopUtilizationMicroseconds_ = Microseconds::zero();
1063 
1064  averageUtilizationPerOneHopNbrMicroseconds_ = Microseconds::zero();
1065 
1066  averageUtilizationPerTwoHopNbrMicroseconds_ = Microseconds::zero();
1067 
1068  utilizationThisNEMMicroseconds_ = Microseconds::zero();
1069 
1070  oneHopUtilizationMap_.clear();
1071 
1072  twoHopUtilizationMap_.clear();
1073 }
1074 
1075 
1076 
1077 bool
1078 EMANE::Models::IEEE80211ABG::NeighborManager::flushOneHopNeighbors_i(const TimePoint & currentTime,
1079  const Microseconds & timeOutMicroseconds)
1080 {
1081  // internal call
1082 
1083  // number of expired entries
1084  size_t numExpired{};
1085 
1086  for(NeighborEntryMap::iterator iter = oneHopNbrMap_.begin(); iter != oneHopNbrMap_.end(); /* bump/erase below */)
1087  {
1088  // nbr age
1089  const Microseconds ageMicroseconds =
1090  std::chrono::duration_cast<Microseconds>(currentTime - iter->second.getLastActivityTime());
1091 
1092  // nbr timed out
1093  if(ageMicroseconds > timeOutMicroseconds)
1094  {
1095  // log first, then remove
1096  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1097  DEBUG_LEVEL,
1098  "MACI %03hu %s::%s: remove 1hop_nbr %hu, age %lf, %zd nbrs remaining",
1099  id_,
1100  pzLayerName,
1101  __func__,
1102  iter->first,
1103  std::chrono::duration_cast<DoubleSeconds>(ageMicroseconds).count(),
1104  oneHopNbrMap_.size() - 1);
1105 
1106  pStatisticOneHopNbrTable_->deleteRow(iter->first);
1107 
1108  // remove entry and bump
1109  oneHopNbrMap_.erase(iter++);
1110 
1111  // bump num expired
1112  ++numExpired;
1113  }
1114  else
1115  {
1116  // bump
1117  ++iter;
1118  }
1119  }
1120 
1121  // return expired status
1122  return numExpired != 0;
1123 }
1124 
1125 
1126 
1127 bool
1128 EMANE::Models::IEEE80211ABG::NeighborManager::flushTwoHopNeighbors_i(const TimePoint & currentTime,
1129  const Microseconds & timeOutMicroseconds)
1130 {
1131  // internal call
1132 
1133  // number of expired entries
1134  size_t numExpired{};
1135 
1136  // each two hop nbr
1137  for(Neighbor2HopEntryMap::iterator iter = twoHopNbrMap_.begin(); iter != twoHopNbrMap_.end(); /* bump/erase below */)
1138  {
1139  // nbr age
1140  const Microseconds ageMicroseconds =
1141  std::chrono::duration_cast<Microseconds>(currentTime - iter->second.getLastActivityTime());
1142 
1143  // nbr timed out
1144  if(ageMicroseconds > timeOutMicroseconds)
1145  {
1146  // log first, then remove
1147  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1148  DEBUG_LEVEL,
1149  "MACI %03hu %s::%s: remove 2hop_nbr %hu, age %lf, %zd nbrs remaining",
1150  id_,
1151  pzLayerName,
1152  __func__,
1153  iter->first,
1154  std::chrono::duration_cast<DoubleSeconds>(ageMicroseconds).count(),
1155  twoHopNbrMap_.size() - 1);
1156 
1157  pStatisticTwoHopNbrTable_->deleteRow(iter->first);
1158 
1159  // remove entry and bump
1160  twoHopNbrMap_.erase(iter++);
1161 
1162  // bump num expired
1163  ++numExpired;
1164 
1165  }
1166  else
1167  {
1168  // bump
1169  ++iter;
1170  }
1171  }
1172 
1173  // return expired status
1174  return numExpired != 0;
1175 }
1176 
1177 
1178 
1179 
1180 void
1181 EMANE::Models::IEEE80211ABG::NeighborManager::sendOneHopNbrListEvent_i()
1182 {
1183  // internal call
1184 
1185  NbrSet nbrSet;
1186 
1187  // each one hop nbr
1188  for(auto & nbrEntry : oneHopNbrMap_)
1189  {
1190  nbrSet.insert(nbrEntry.first);
1191  }
1192 
1193  OneHopNeighborsEvent event(id_, nbrSet);
1194 
1195  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1196  DEBUG_LEVEL,
1197  "MACI %03hu %s::%s: sending list of %zd 1hop_nbrs",
1198  id_,
1199  pzLayerName,
1200  __func__,
1201  nbrSet.size());
1202 
1203  // send event
1204  pPlatformService_->eventService().sendEvent(0, // nem id
1205  event); // the event
1206 
1207  // bump tx events
1209 
1210  // update last event tx time
1211  lastOneHopNbrListTxTime_ = Clock::now();
1212 }
1213 
1214 
1215 
1216 
1217 
1218 
1219 EMANE::Models::IEEE80211ABG::NeighborManager::NeighborEntryInsertResult
1220 EMANE::Models::IEEE80211ABG::NeighborManager::addOneHopNeighbor_i(NEMId src)
1221 {
1222  // internal call
1223 
1224  // try to add one hop nbr
1225  auto nbrResult = oneHopNbrMap_.insert(std::make_pair(src, NeighborEntry()));
1226 
1227  if(nbrResult.second == true)
1228  {
1229  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1230  DEBUG_LEVEL,
1231  "MACI %03hu %s::%s: added 1hop_nbr %hu, %zd total nbrs",
1232  id_,
1233  pzLayerName,
1234  __func__,
1235  src,
1236  oneHopNbrMap_.size());
1237 
1238  pStatisticOneHopNbrTable_->addRow(src,{Any{src}});
1239 
1240  // set high water
1241  pMACLayer_->getStatistics().updateOneHopNbrHighWaterMark(oneHopNbrMap_.size());
1242 
1243  // check one hop nbr list event cache
1244  auto iter = cachedOneHopNbrSetMap_.find(src);
1245 
1246  if(iter != cachedOneHopNbrSetMap_.end())
1247  {
1248  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1249  DEBUG_LEVEL,
1250  "MACI %03hu %s::%s: copied 1hop_nbr_list from cache for nbr %hu, has %zd total nbrs",
1251  id_,
1252  pzLayerName,
1253  __func__,
1254  src,
1255  iter->second.size());
1256 
1257  // set one hop nbrs of this one hop nbr from the cache
1258  nbrResult.first->second.setOneHopNeighbors(iter->second);
1259  }
1260  else
1261  {
1262  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1263  DEBUG_LEVEL,
1264  "MACI %03hu %s::%s: no 1hop_nbr_list cache for nbr %hu, must wait for event update",
1265  id_,
1266  pzLayerName,
1267  __func__,
1268  src);
1269  }
1270  }
1271  else
1272  {
1273  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1274  DEBUG_LEVEL,
1275  "MACI %03hu %s::%s: existing 1hop_nbr %hu, keep existing 1hop_nbr_list",
1276  id_,
1277  pzLayerName,
1278  __func__,
1279  src);
1280  }
1281 
1282  return nbrResult;
1283 }
1284 
1285 
1286 
1287 EMANE::Models::IEEE80211ABG::NeighborManager::Neighbor2HopEntryInsertResult
1288 EMANE::Models::IEEE80211ABG::NeighborManager::addTwoHopNeighbor_i(NEMId src)
1289 {
1290  // internal call
1291 
1292  // add 2 hop nbr
1293  auto nbr2Result = twoHopNbrMap_.insert(std::make_pair(src, Neighbor2HopEntry()));
1294 
1295  if(nbr2Result.second == true)
1296  {
1297  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1298  DEBUG_LEVEL,
1299  "MACI %03hu %s::%s: added 2hop_nbr %hu, %zd total nbrs",
1300  id_,
1301  pzLayerName,
1302  __func__,
1303  src,
1304  twoHopNbrMap_.size());
1305 
1306  pStatisticTwoHopNbrTable_->addRow(src,{Any{src}});
1307 
1308  // set high water
1309  pMACLayer_->getStatistics().updateTwoHopNbrHighWaterMark(twoHopNbrMap_.size());
1310  }
1311  else
1312  {
1313  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1314  DEBUG_LEVEL,
1315  "MACI %03hu %s::%s: existing 2hop_nbr %hu, %zd total nbrs",
1316  id_,
1317  pzLayerName,
1318  __func__,
1319  src,
1320  twoHopNbrMap_.size());
1321  }
1322 
1323  return nbr2Result;
1324  }
1325 
1326 
1327 
1328 
1329 float
1330 EMANE::Models::IEEE80211ABG::NeighborManager::getA_i(const Microseconds & utilizationMicroseconds,
1331  const Microseconds & avgUtilizationMicroseconds) const
1332 {
1333  // internal call
1334 
1335  const float A{getChannelActivity_i(utilizationMicroseconds, avgUtilizationMicroseconds)};
1336 
1337  // cap at 1.0
1338  if(A > 1.0f)
1339  {
1340  return 1.0f;
1341  }
1342  else
1343  {
1344  return A;
1345  }
1346 }
1347 
1348 
1349 
1350 float
1351 EMANE::Models::IEEE80211ABG::NeighborManager::getC_i(const Microseconds & utilizationMicroseconds,
1352  const Microseconds & deltaTMicroseconds) const
1353 {
1354  // internal call
1355 
1356  const float C{getChannelActivity_i(utilizationMicroseconds, deltaTMicroseconds)};
1357 
1358  // cap to 1.0
1359  if(C > 1.0f)
1360  {
1361  return 1.0f;
1362  }
1363  else
1364  {
1365  return C;
1366  }
1367 }
1368 
1369 
1370 
1371 float
1372 EMANE::Models::IEEE80211ABG::NeighborManager::getH_i(const Microseconds & utilizationMicroseconds,
1373  const Microseconds & deltaTMicroseconds) const
1374 {
1375  // internal call
1376 
1377  const float H{getChannelActivity_i(utilizationMicroseconds, deltaTMicroseconds)};
1378 
1379  // cap at 1.0
1380  if(H > 1.0f)
1381  {
1382  return 1.0f;
1383  }
1384  else
1385  {
1386  return H;
1387  }
1388 }
1389 
1390 
1391 
1392 float
1393 EMANE::Models::IEEE80211ABG::NeighborManager::getChannelActivity_i(const Microseconds & utilizationMicroseconds,
1394  const Microseconds & deltaTMicroseconds) const
1395 {
1396  // internal call
1397 
1398  // check divide by zero
1399  if(deltaTMicroseconds == Microseconds::zero())
1400  {
1401  return 0.0f;
1402  }
1403  else
1404  {
1405  return getRatio(utilizationMicroseconds, deltaTMicroseconds);
1406  }
1407 }
1408 
1409 
1410 void
1411 EMANE::Models::IEEE80211ABG::NeighborManager::setCommonAndHiddenProbability_i()
1412 {
1413  // for each one hop utilization
1414  for(auto & oneHopUtilization : oneHopUtilizationMap_)
1415  {
1416  // exclude ourself
1417  if(oneHopUtilization.first != id_)
1418  {
1419  // remove local and src utilization from total one hop utilization
1420  Microseconds adjustedUtililizationMicroseconds{
1421  totalOneHopUtilizationMicroseconds_ -
1422  utilizationThisNEMMicroseconds_ -
1423  oneHopUtilization.second};
1424 
1425  // check remaining utlzation
1426  if(adjustedUtililizationMicroseconds > Microseconds::zero())
1427  {
1428  // lookup nbr
1429  auto niter = oneHopNbrMap_.find(oneHopUtilization.first);
1430 
1431  if(niter != oneHopNbrMap_.end())
1432  {
1433  // get common nbrs
1434  const NbrSet commonNbrs = niter->second.getCommonNeighbors();
1435 
1436  // get hidden nbrs
1437  const NbrSet hiddenNbrs = niter->second.getHiddenNeighbors();
1438 
1439  // get one hop utilzation
1440  NbrUtilizationMap adjustedUtilzationMap = oneHopUtilizationMap_;
1441 
1442  // remove local node from utilization
1443  adjustedUtilzationMap.erase(id_);
1444 
1445  // remove src from utilization
1446  adjustedUtilzationMap.erase(oneHopUtilization.first);
1447 
1448  // get and store common probability using adjusted one hop utilization for this src
1449  commonProbabilityMapMap_[oneHopUtilization.first] = setProbability_i(oneHopUtilization.first,
1450  adjustedUtilzationMap,
1451  adjustedUtililizationMicroseconds,
1452  commonNbrs,
1453  "common");
1454 
1455  // get and store hidden probability using adjusted one hop utilization for this src
1456  hiddenProbabilityMapMap_[oneHopUtilization.first] = setProbability_i(oneHopUtilization.first,
1457  adjustedUtilzationMap,
1458  adjustedUtililizationMicroseconds,
1459  hiddenNbrs,
1460  "hidden");
1461  }
1462  }
1463  }
1464  }
1465 }
1466 
1467 
1468 
1469 EMANE::Models::IEEE80211ABG::NeighborManager::ProbabilityPairMap
1470 EMANE::Models::IEEE80211ABG::NeighborManager::setProbability_i(NEMId src __attribute__((unused)),
1471  const NbrUtilizationMap & map,
1472  const Microseconds & rUtilizationMicroseconds,
1473  const NbrSet & nbrSet,
1474  const char *str __attribute__((unused))) const
1475 {
1476  ProbabilityPairMap probabilityMap;
1477 
1478  NbrUtilizationMap adjustedUtilizationMap;
1479 
1480  Microseconds utilizationMicroseconds{rUtilizationMicroseconds};
1481 
1482  for(auto & utilization : map)
1483  {
1484  if(nbrSet.find(utilization.first) != nbrSet.end())
1485  {
1486  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1487  DEBUG_LEVEL,
1488  "MACI %03hu %s::%s_%s: src %hu, is %s w/r to nbr %hu",
1489  id_,
1490  pzLayerName,
1491  __func__,
1492  str,
1493  src,
1494  str,
1495  utilization.first);
1496 
1497  // add entry
1498  adjustedUtilizationMap[utilization.first] = utilization.second;
1499  }
1500  else
1501  {
1502  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1503  DEBUG_LEVEL,
1504  "MACI %03hu %s::%s_%s: src %hu, is not %s w/r to nbr %hu, ignore",
1505  id_,
1506  pzLayerName,
1507  __func__,
1508  str,
1509  src,
1510  str,
1511  utilization.first);
1512 
1513  // subtract utilization
1514  utilizationMicroseconds -= utilization.second;
1515  }
1516  }
1517 
1518  // check remaining utilization
1519  if(utilizationMicroseconds > Microseconds::zero())
1520  {
1521  // initial values
1522  float p1{}, p2{};
1523 
1524  size_t num{adjustedUtilizationMap.size()};
1525 
1526  // for each utilization
1527  for(NbrUtilizationMap::iterator iter = adjustedUtilizationMap.begin(); iter != adjustedUtilizationMap.end(); ++iter, --num)
1528  {
1529  // not last entry
1530  if(num != 1)
1531  {
1532  // get ratio
1533  p2 += getRatio(iter->second, utilizationMicroseconds);
1534  }
1535  // last entry
1536  else
1537  {
1538  // set to 1
1539  p2 = 1.0f;
1540  }
1541 
1542  LOGGER_VERBOSE_LOGGING(pPlatformService_->logService(),
1543  DEBUG_LEVEL,
1544  "MACI %03hu %s::%s_%s: src %hu, nbr %hu, p1 %5.4f, p2 %5.4f",
1545  id_,
1546  pzLayerName,
1547  __func__,
1548  str,
1549  src,
1550  iter->first,
1551  p1,
1552  p2);
1553 
1554  // insert range
1555  probabilityMap[iter->first] = ProbabilityPair(p1, p2);
1556 
1557  // bump range
1558  p1 = p2;
1559  }
1560  }
1561 
1562  return probabilityMap;
1563 }
1564 
1565 
1566 void
1568 {
1569  pStatisticOneHopNbrTable_ = statisticRegistrar.registerTable<NEMId>("OneHopNeighborTable",
1570  {"NEM Id"},
1572  "Current One Hop Neighbors");
1573 
1574  pStatisticTwoHopNbrTable_ = statisticRegistrar.registerTable<NEMId>("TwoHopNeighborTable",
1575  {"NEM Id"},
1577  "Current Two Hop Neighbors");
1578 
1579 }
void updateTwoHopNbrHighWaterMark(size_t num)
set the two hop nbr high water mark
std::string Serialization
Definition: serializable.h:42
void incrementRxOneHopNbrListEventCount()
increment number rx one hop nbr list events
void handleOneHopNeighborsEvent(const Serialization &serialization)
SerializationException is thrown when an exception occurs during serialization or deserialization of ...
UtilizationRatioVector getUtilizationRatios(const Microseconds &deltaTMicroseconds)
Definition: wmmmanager.cc:180
#define LOGGER_VERBOSE_LOGGING(logger, level, fmt, args...)
void registerStatistics(StatisticRegistrar &statisticRegistrar)
void setNeighborTimeoutMicroseconds(const Microseconds &timeOutMicroseconds)
void incrementTxOneHopNbrListEventCount()
increment number tx one hop nbr list events
Defines a 1 hop nbr and its bandwidth utilization.
Definition: neighborentry.h:59
std::vector< UtilizationRatioPair > UtilizationRatioVector
Definition: wmmmanager.h:61
Microseconds getAllUtilizationMicroseconds(NEMId src) const
const std::uint8_t MSG_TYPE_MASK_BROADCAST
Definition: msgtypes.h:50
const std::uint8_t MSG_TYPE_MASK_ALL_DATA
Definition: msgtypes.h:52
void updateLocalActivity(std::uint8_t u8Category, const Microseconds &durationMicroseconds)
Definition: wmmmanager.cc:97
The PlatformServiceProvider interface provides access to emulator services.
EMANE::NetworkAdapterException __attribute__
float getNumberOfEstimatedCommonNeighbors(NEMId src) const
virtual EventServiceProvider & eventService()=0
void updateCtrlChannelActivity(NEMId src, NEMId origin, std::uint8_t type, float fRxPowerMilliWatts, const TimePoint &tvTime, const Microseconds &duration, std::uint8_t u8Category)
const char * what() const
Definition: exception.h:62
The StatisticRegistrar allows NEM layers to register statistics and statistic tables. Statistics and Statistic tables are owned by the emulator framework and a borrowed reference is returned to the registering NEM layer.
StatisticTable< Key, Compare, scolumn > * registerTable(const std::string &sName, const StatisticTableLabels &labels, const StatisticProperties &properties=StatisticProperties::NONE, const std::string &sDescription="")
void updateOneHopNbrHighWaterMark(size_t num)
set the one hop nbr high water mark
void setCategories(std::uint8_t u8NumCategories)
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
Microseconds getTotalOneHopUtilizationMicroseconds() const
NeighborManager(NEMId id, PlatformServiceProvider *pPlatformService, MACLayer *pMgr)
float getRatio(const EMANE::Microseconds &d1, const EMANE::Microseconds d2)
Definition: utils.h:65
float getNumberOfEstimatedHiddenNeighbors(NEMId src) const
void setNumCategories(const std::uint8_t u8NumCategories)
Definition: wmmmanager.cc:136
const float USEC_PER_SEC_F
Definition: constants.h:61
std::set< EMANE::NEMId > NbrSet
Definition: neighbortype.h:47
void addRow(const Key &key, const std::vector< Any > &anys={})
virtual LogServiceProvider & logService()=0
Microseconds getTotalTwoHopUtilizationMicroseconds() const
void deleteRow(const Key &key)
const std::uint8_t MSG_TYPE_MASK_UNICAST
Definition: msgtypes.h:51
union EtherAddr src
Definition: netutils.h:391
Defines a 2 hop nbr and its bandwidth utilization.
Microseconds getAverageMessageDurationMicroseconds() const
Clock::time_point TimePoint
Definition: types.h:50
void updateDataChannelActivity(NEMId src, std::uint8_t type, float fRxPowerMilliWatts, const TimePoint &timePoint, const Microseconds &duration, std::uint8_t u8Category)
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
The Any class can contain an instance of one of any type in its support type set. ...
Definition: any.h:49
virtual void sendEvent(NEMId nemId, const Event &event)=0
void incrementRxOneHopNbrListInvalidEventCount()
increment number rx one hop nbr list invalid events
void updateTotalActivity(std::uint8_t u8Category, const Microseconds &durationMicroseconds)
Definition: wmmmanager.cc:61
WMMManager::UtilizationRatioVector getUtilizationRatios()