EMANE  1.2.1
virtualtransport.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2016 - Adjacent Link LLC, Bridgewater, New Jersey
3  * Copyright (c) 2008-2010 - 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 "virtualtransport.h"
35 
36 #include "emane/downstreampacket.h"
39 #include "emane/startexception.h"
40 
41 #include "emane/utils/netutils.h"
43 
46 
49 
52 
55 
56 #include <sstream>
57 
58 namespace {
59  const std::uint16_t DROP_CODE_WRITE_ERROR = 1;
60  const std::uint16_t DROP_CODE_FRAME_ERROR = 2;
61 
62  EMANE::StatisticTableLabels STATISTIC_TABLE_LABELS {"Write Error",
63  "Frame Error"};
64 }
65 
66 
68  PlatformServiceProvider * pPlatformService):
69  EthernetTransport(id, pPlatformService),
70  pTunTap_{},
71  pBitPool_{},
72  thread_{},
73  bCanceled_{},
74  flowControlClient_{*this},
75  bFlowControlEnable_{},
76  commonLayerStatistics_{STATISTIC_TABLE_LABELS}
77 {}
78 
80 {
81  if(pTunTap_)
82  {
83  delete pTunTap_;
84 
85  pTunTap_ = nullptr;
86  }
87 
88  if(pBitPool_)
89  {
90  delete pBitPool_;
91 
92  pBitPool_ = nullptr;
93  }
94 }
95 
97 {
98  pTunTap_ = new TunTap{pPlatformService_};
99 
100  pBitPool_ = new Utils::BitPool{pPlatformService_, id_};
101 
102  auto & configRegistrar = registrar.configurationRegistrar();
103 
104  configRegistrar.registerNonNumeric<std::string>("device",
106  {"emane0"},
107  "Virtual device name.");
108 
109 
110  configRegistrar.registerNonNumeric<std::string>("devicepath",
113  "Path to the tuntap device.");
114 
115  configRegistrar.registerNumeric<std::uint64_t>("bitrate",
117  {0},
118  "Transport bitrate in bps. This is the total allowable"
119  " throughput for the transport combined in both directions"
120  " (upstream and downstream). A value of 0 disables the"
121  " bitrate feature.");
122 
123  configRegistrar.registerNumeric<bool>("broadcastmodeenable",
125  {false},
126  "Broadcast all packets to all NEMs.");
127 
128 
129  configRegistrar.registerNumeric<bool>("arpcacheenable",
131  {true},
132  "Enable ARP request/reply monitoring to map Ethernet address to NEM.");
133 
134 
135  configRegistrar.registerNumeric<bool>("arpmodeenable",
137  {true},
138  "Enable ARP on the virtual device.");
139 
140  configRegistrar.registerNumeric<bool>("flowcontrolenable",
142  {false},
143  "Enables downstream traffic flow control with a corresponding flow"
144  " control capable NEM layer.");
145 
146  configRegistrar.registerNonNumeric<INETAddr>("address",
148  {},
149  "IPv4 or IPv6 virutal device address.");
150 
151  configRegistrar.registerNonNumeric<INETAddr>("mask",
153  {},
154  "IPv4 or IPv6 virutal device addres network mask.");
155 
156  auto & statisticRegistrar = registrar.statisticRegistrar();
157 
158  commonLayerStatistics_.registerStatistics(statisticRegistrar);
159 
160 }
161 
162 
164 {
165  for(const auto & item : update)
166  {
167  if(item.first == "bitrate")
168  {
169  u64BitRate_ = item.second[0].asUINT64();
170 
172  INFO_LEVEL,
173  "TRANSPORTI %03hu VirtualTransport::%s %s: %ju",
174  id_,
175  __func__,
176  item.first.c_str(),
177  u64BitRate_);
178  }
179  else if(item.first == "devicepath")
180  {
181  sDevicePath_ = item.second[0].asString();
182 
184  INFO_LEVEL,
185  "TRANSPORTI %03hu VirtualTransport::%s %s: %s",
186  id_,
187  __func__,
188  item.first.c_str(),
189  sDevicePath_.c_str());
190  }
191  else if(item.first == "device")
192  {
193  sDeviceName_ = item.second[0].asString();
194 
196  INFO_LEVEL,
197  "TRANSPORTI %03hu VirtualTransport::%s %s: %s",
198  id_,
199  __func__,
200  item.first.c_str(),
201  sDeviceName_.c_str());
202  }
203  else if(item.first == "mask")
204  {
205  mask_ = item.second[0].asINETAddr();
206 
208  INFO_LEVEL,
209  "TRANSPORTI %03hu VirtualTransport::%s %s: %s",
210  id_,
211  __func__,
212  item.first.c_str(),
213  mask_.str(false).c_str());
214  }
215  else if(item.first == "address")
216  {
217  address_ = item.second[0].asINETAddr();
218 
220  INFO_LEVEL,
221  "TRANSPORTI %03hu VirtualTransport::%s %s: %s",
222  id_,
223  __func__,
224  item.first.c_str(),
225  address_.str(false).c_str());
226  }
227  else if(item.first == "arpmodeenable")
228  {
229  bARPMode_ = item.second[0].asBool();
230 
232  INFO_LEVEL,
233  "TRANSPORTI %03hu VirtualTransport::%s %s: %d",
234  id_,
235  __func__,
236  item.first.c_str(),
237  bARPMode_);
238  }
239  else if(item.first == "broadcastmodeenable")
240  {
241  bBroadcastMode_ = item.second[0].asBool();
242 
244  INFO_LEVEL,
245  "TRANSPORTI %03hu VirtualTransport::%s %s: %d",
246  id_,
247  __func__,
248  item.first.c_str(),
250  }
251  else if(item.first == "arpcacheenable")
252  {
253  bArpCacheMode_ = item.second[0].asBool();
254 
256  INFO_LEVEL,
257  "TRANSPORTI %03hu VirtualTransport::%s %s: %d",
258  id_,
259  __func__,
260  item.first.c_str(),
262  }
263  else if(item.first == "flowcontrolenable")
264  {
265  bFlowControlEnable_ = item.second[0].asBool();
266 
268  INFO_LEVEL,
269  "TRANSPORTI %03hu VirtualTransport::%s %s: %d",
270  id_,
271  __func__,
272  item.first.c_str(),
273  bFlowControlEnable_);
274  }
275  else
276  {
277  throw makeException<ConfigureException>("VirtualTransport: "
278  "Unexpected configuration item %s",
279  item.first.c_str());
280 
281  }
282  }
283 }
284 
285 
287 {
288  if(pTunTap_->open(sDevicePath_.c_str(), sDeviceName_.c_str()) < 0)
289  {
290  std::stringstream ssDescription;
291  ssDescription << "could not open tuntap device path "
292  << sDevicePath_
293  << " name "
294  << sDeviceName_
295  << std::ends;
296  throw StartException(ssDescription.str());
297  }
298 
299  if(pTunTap_->set_ethaddr (id_) < 0)
300  {
301  std::stringstream ssDescription;
302  ssDescription << "could not set tuntap eth address "
303  << id_
304  << std::ends;
305  throw StartException(ssDescription.str());
306  }
307 
308  if(pTunTap_->activate(bARPMode_) < 0)
309  {
310  std::stringstream ssDescription;
311  ssDescription << "could not activate tuntap arp mode "
312  << bARPMode_
313  << std::ends;
314  throw StartException(ssDescription.str());
315  }
316 
317  // was an interface address provided
318  if(!address_.isAny())
319  {
320  // set tuntap address/mask
321  if(pTunTap_->set_addr(address_, mask_) < 0)
322  {
323  std::stringstream ssDescription;
324  ssDescription << "could not set tuntap address "
325  << address_.str();
326  ssDescription << " mask "
327  << mask_.str()
328  << std::ends;
329  throw StartException(ssDescription.str());
330  }
331  }
332 
333  bCanceled_ = false;
334 
335  pBitPool_->setMaxSize(u64BitRate_);
336 
337  // start tuntap read thread
338  thread_ = std::thread{&VirtualTransport::readDevice,this};
339 }
340 
342 {
343  if(bFlowControlEnable_)
344  {
345  flowControlClient_.start();
346 
348  DEBUG_LEVEL,
349  "TRANSPORTI %03hu VirtualTransport::%s sent a flow control"
350  " token request, a handshake response is required to process"
351  " packets",
352  id_,
353  __func__);
354 
355  }
356 }
357 
359 {
360  if(thread_.joinable())
361  {
362  if(bFlowControlEnable_)
363  {
364  flowControlClient_.stop();
365  }
366 
367  bCanceled_ = true;
368 
369  ThreadUtils::cancel(thread_);
370 
371  thread_.join();
372  }
373 
374  pTunTap_->deactivate();
375 
376  pTunTap_->close();
377 }
378 
379 
381  throw()
382 {}
383 
384 
386  const ControlMessages & msgs)
387 {
388  const TimePoint beginTime{Clock::now()};
389 
390  // frame sanity check
391  if(verifyFrame(pkt.get(), pkt.length()) < 0)
392  {
394  ERROR_LEVEL,
395  "TRANSPORTI %03hu VirtualTransport::%s frame error",
396  id_,
397  __func__);
398  }
399 
400  handleUpstreamControl(msgs);
401 
402  commonLayerStatistics_.processInbound(pkt);
403 
404  const PacketInfo & pktInfo{pkt.getPacketInfo()};
405 
406  const Utils::EtherHeader * pEtherHeader {reinterpret_cast<const Utils::EtherHeader*>(pkt.get())};
407 
408  // update arp cache
409  updateArpCache(pEtherHeader, pktInfo.getSource());
410 
411  iovec iov;
412 
413  iov.iov_base = const_cast<char*>(reinterpret_cast<const char*>(pkt.get()));
414  iov.iov_len = pkt.length();
415 
416  if(pTunTap_->writev(&iov, 1) < 0)
417  {
419  ERROR_LEVEL,
420  "TRANSPORTI %03hu VirtualTransport::%s %s",
421  id_,
422  __func__,
423  strerror(errno));
424 
425  commonLayerStatistics_.processOutbound(pkt,
426  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
427  DROP_CODE_WRITE_ERROR);
428  }
429  else
430  {
432  DEBUG_LEVEL,
433  "TRANSPORTI %03hu VirtualTransport::%s src %hu, dst %hu, dscp %hhu, length %zu",
434  id_,
435  __func__,
436  pktInfo.getSource(),
437  pktInfo.getDestination(),
438  pktInfo.getPriority(),
439  pkt.length());
440 
441  commonLayerStatistics_.processOutbound(pkt,
442  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime));
443 
444  if(u64BitRate_)
445  {
446  // drain the bit pool
447  const size_t sizePending = pBitPool_->get(pkt.length() * 8);
448 
449  // check for bitpool error
450  if(sizePending != 0)
451  {
453  ERROR_LEVEL,
454  "TRANSPORTI %03hu VirtualTransport::%s bitpool request error %zd of %zd",
455  id_,
456  __func__,
457  sizePending,
458  pkt.length() * 8);
459  }
460  }
461  }
462 }
463 
464 
466 {
467  handleUpstreamControl(msgs);
468 }
469 
470 
471 
472 void EMANE::Transports::Virtual::VirtualTransport::handleUpstreamControl(const ControlMessages & msgs)
473 {
474  for(const auto & pMessage : msgs)
475  {
476  switch(pMessage->getId())
477  {
479  {
480  const auto pFlowControlControlMessage =
481  static_cast<const Controls::FlowControlControlMessage *>(pMessage);
482 
483  if(bFlowControlEnable_)
484  {
486  DEBUG_LEVEL,
487  "TRANSPORTI %03hu VirtualTransport::%s received a flow control"
488  " token update %hu tokens",
489  id_,
490  __func__,
491  pFlowControlControlMessage->getTokens());
492 
493  flowControlClient_.processFlowControlMessage(pFlowControlControlMessage);
494  }
495  else
496  {
498  ERROR_LEVEL,
499  "TRANSPORTI %03hu VirtualTransport::%s received a flow control"
500  " message but flow control is not enabled",
501  id_,
502  __func__);
503  }
504  }
505  break;
506 
508  {
509  const auto pR2RINeighborMetricControlMessage =
510  static_cast<const Controls::R2RINeighborMetricControlMessage *>(pMessage);
511 
512 
514  DEBUG_LEVEL,
515  Controls::R2RINeighborMetricControlMessageFormatter(pR2RINeighborMetricControlMessage),
516  "TRANSPORTI %03hu VirtualTransport::%s R2RINeighborMetricControlMessage",
517  id_,
518  __func__);
519  }
520  break;
521 
523  {
524  const auto pR2RIQueueMetricControlMessage =
525  static_cast<const Controls::R2RIQueueMetricControlMessage *>(pMessage);
526 
528  DEBUG_LEVEL,
529  Controls::R2RIQueueMetricControlMessageFormatter(pR2RIQueueMetricControlMessage),
530  "TRANSPORTI %03hu VirtualTransport::%s R2RIQueueMetricControlMessage",
531  id_,
532  __func__);
533  }
534  break;
535 
537  {
538  const auto pR2RISelfMetricControlMessage =
539  static_cast<const Controls::R2RISelfMetricControlMessage *>(pMessage);
540 
542  DEBUG_LEVEL,
543  Controls::R2RISelfMetricControlMessageFormatter(pR2RISelfMetricControlMessage),
544  "TRANSPORTI %03hu VirtualTransport::%s R2RISelfMetricControlMessage",
545  id_,
546  __func__);
547  }
548  break;
549 
550 
551 
553  {
554  const auto pSerializedControlMessage =
555  static_cast<const Controls::SerializedControlMessage *>(pMessage);
556 
557  switch(pSerializedControlMessage->getSerializedId())
558  {
560  {
561  std::unique_ptr<Controls::FlowControlControlMessage>
562  pFlowControlControlMessage{
564  pSerializedControlMessage->getSerialization())};
565 
566  if(bFlowControlEnable_)
567  {
569  ERROR_LEVEL,
570  "TRANSPORTI %03hu VirtualTransport::%s received a flow control"
571  " token update %hu tokens",
572  id_,
573  __func__,
574  pFlowControlControlMessage->getTokens());
575 
576  flowControlClient_.processFlowControlMessage(pFlowControlControlMessage.get());
577 
578  }
579  else
580  {
582  ERROR_LEVEL,
583  "TRANSPORTI %03hu VirtualTransport::%s received a flow control"
584  " message but flow control is not enabled",
585  id_,
586  __func__);
587  }
588  }
589  break;
590 
592  {
593  std::unique_ptr<Controls::R2RINeighborMetricControlMessage>
594  pR2RINeighborMetricControlMessage{
596  pSerializedControlMessage->getSerialization())};
597 
599  DEBUG_LEVEL,
601  pR2RINeighborMetricControlMessage.get()),
602  "TRANSPORTI %03hu VirtualTransport::%s",
603  id_,
604  __func__);
605  }
606  break;
607 
609  {
610  std::unique_ptr<Controls::R2RIQueueMetricControlMessage>
611  pR2RIQueueMetricControlMessage{
613  pSerializedControlMessage->getSerialization())};
614 
616  DEBUG_LEVEL,
618  pR2RIQueueMetricControlMessage.get()),
619  "TRANSPORTI %03hu VirtualTransport::%s",
620  id_,
621  __func__);
622  }
623  break;
624 
626  {
627  std::unique_ptr<Controls::R2RISelfMetricControlMessage>
628  pR2RISelfMetricControlMessage{
630  pSerializedControlMessage->getSerialization())};
631 
633  DEBUG_LEVEL,
635  pR2RISelfMetricControlMessage.get()),
636  "TRANSPORTI %03hu VirtualTransport::%s",
637  id_,
638  __func__);
639  }
640  break;
641 
642  default:
644  DEBUG_LEVEL,
645  "TRANSPORTI %03hu VirtualTransport::%s unknown serialized msg id %hu, ignore",
646  id_,
647  __func__,
648  pSerializedControlMessage->getSerializedId());
649 
650  }
651  }
652  break;
653 
654  default:
656  DEBUG_LEVEL,
657  "TRANSPORTI %03hu VirtualTransport::%s unknown msg id %hu, ignore",
658  id_,
659  __func__,
660  pMessage->getId());
661  }
662  }
663 }
664 
665 
666 void EMANE::Transports::Virtual::VirtualTransport::readDevice()
667 {
668  std::uint8_t buf[Utils::IP_MAX_PACKET];
669 
670  while(!bCanceled_)
671  {
672  ssize_t len{};
673 
674  memset(buf, 0x0, sizeof(buf));
675 
676  iovec iov;
677 
678  iov.iov_base = reinterpret_cast<char*>(buf);
679  iov.iov_len = sizeof(buf);
680 
681  // read from tuntap
682  if((len = pTunTap_->readv(&iov, 1)) < 0)
683  {
685  ERROR_LEVEL,
686  "TRANSPORTI %03hu VirtualTransport::%s %s",
687  id_,
688  __func__,
689  strerror(errno));
690 
691  break;
692  }
693  else
694  {
695  const TimePoint beginTime{Clock::now()};
696 
697  // frame sanity check
698  if(verifyFrame(buf, len) < 0)
699  {
701  ERROR_LEVEL,
702  "TRANSPORTI %03hu VirtualTransport::%s frame error",
703  id_,
704  __func__);
705  }
706  else
707  {
708  // NEM destination
709  NEMId nemDestination;
710 
711  // pkt tos/qos converted to dscp
712  std::uint8_t dscp{};
713 
714  // get dst and dscp values
715  if(parseFrame((const Utils::EtherHeader *)buf, nemDestination, dscp) < 0)
716  {
718  ERROR_LEVEL,
719  "TRANSPORTI %03hu VirtualTransport::%s frame parse error",
720  id_,
721  __func__);
722  }
723  else
724  {
726  DEBUG_LEVEL,
727  "TRANSPORTI %03hu VirtualTransport::%s src %hu, dst %hu, dscp %hhu, length %zd",
728  id_,
729  __func__,
730  id_,
731  nemDestination,
732  dscp,
733  len);
734 
735  // create downstream packet with packet info
736  DownstreamPacket pkt(PacketInfo (id_, nemDestination, dscp,Clock::now()), buf, len);
737 
738  commonLayerStatistics_.processInbound(pkt);
739 
740  // check flow control
741  if(bFlowControlEnable_)
742  {
743  auto status = flowControlClient_.removeToken();
744 
745  // block and wait for an available flow control token
746  if(!status.second)
747  {
749  ERROR_LEVEL,
750  "TRANSPORTI %03hu VirtualTransport::%s failed to remove token (tokens:%hu)",
751  id_,
752  __func__,
753  status.first);
754  // done
755  break;
756  }
757  else
758  {
760  DEBUG_LEVEL,
761  "TRANSPORTI %03hu VirtualTransport::%s removed token (tokens:%hu)",
762  id_,
763  __func__,
764  status.first);
765  }
766  }
767 
768  commonLayerStatistics_.processOutbound(pkt,
769  std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime));
770 
771  // send to downstream transport
773 
774  if(u64BitRate_)
775  {
776  // drain the bit pool
777  std::uint64_t sizePending {pBitPool_->get(len * 8)};
778 
779  // check for bitpool error
780  if(sizePending > 0)
781  {
783  ERROR_LEVEL,
784  "TRANSPORTI %03hu VirtualTransport::%s bitpool "
785  "request error %jd of %zd",
786  id_,
787  __func__,
788  sizePending,
789  len * 8);
790  }
791  }
792  }
793  }
794  }
795  }
796 }
797 
798 
799 
VirtualTransport(NEMId id, PlatformServiceProvider *pPlatformService)
A Packet class that allows upstream processing to strip layer headers as the packet travels up the st...
Implementation of a rate limiting bit pool.
Definition: bitpool.h:52
R2RI Queue Metric Control Message is sent to an NEM&#39;s transport layer to convey information about MAC...
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...
void initialize(Registrar &registrar) override
virtual ConfigurationRegistrar & configurationRegistrar()=0
#define LOGGER_VERBOSE_LOGGING(logger, level, fmt, args...)
virtual StatisticRegistrar & statisticRegistrar()=0
void processOutbound(const UpstreamPacket &pkt, Microseconds delay, size_t dropCode={})
void processFlowControlMessage(const Controls::FlowControlControlMessage *pMsg)
const std::uint16_t IP_MAX_PACKET
Max ip packet len.
Definition: netutils.h:358
std::list< const ControlMessage * > ControlMessages
Callable formatter object for R2RINeighborMetricControlMessage instances.
void registerNonNumeric(const std::string &sName, const ConfigurationProperties &properties=ConfigurationProperties::NONE, const std::initializer_list< T > &values={}, const std::string &sUsage="", std::size_t minOccurs=1, std::size_t maxOccurs=1, const std::string &sRegexPattern={})
void setMaxSize(std::uint64_t u64NewSize)
Definition: bitpool.inl:65
virtual int parseFrame(const Utils::EtherHeader *pEthHeader, EMANE::NEMId &dst, std::uint8_t &dscp)
The PlatformServiceProvider interface provides access to emulator services.
static FlowControlControlMessage * create(const Serialization &serialization)
void registerStatistics(StatisticRegistrar &statisticRegistrar)
int writev(const struct iovec *, size_t)
Definition: tuntap.cc:430
Store source, destination, creation time and priority information for a packet.
Definition: packetinfo.h:50
bool isAny() const
Definition: inetaddr.cc:389
#define NETWORK_DEVICE_PATH
Definition: tuntap.h:51
Callable formatter object for R2RISelfMetricControlMessage instances.
Callable formatter object for R2RIQueueMetricControlMessage instances.
#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...
std::string str(bool bWithPort=true) const
Definition: inetaddr.cc:409
int cancel(std::thread &thread)
Definition: threadutils.h:65
std::uint64_t get(std::uint64_t u64Request, bool bFullFill=true)
Definition: bitpool.inl:97
void processUpstreamPacket(UpstreamPacket &pkt, const ControlMessages &msgs)
std::uint16_t NEMId
Definition: types.h:52
static R2RISelfMetricControlMessage * create(const Serialization &serialization)
Flow Control Control Messages are sent between a MAC layer and a transport in order to communicate da...
DECLARE_TRANSPORT(EMANE::Transports::Virtual::VirtualTransport)
int set_ethaddr(const Utils::EtherAddr &)
Definition: tuntap.cc:381
PlatformServiceProvider * pPlatformService_
int readv(struct iovec *, size_t)
Definition: tuntap.cc:452
R2RI Neighbor Metric Control Message is sent to an NEM&#39;s transport layer to convey information about ...
const void * get() const
virtual LogServiceProvider & logService()=0
Component start exception is used to indicate an exception during transition to the start state...
virtual int verifyFrame(const void *buf, size_t len)
std::vector< ConfigurationNameAnyValues > ConfigurationUpdate
static R2RINeighborMetricControlMessage * create(const Serialization &serialization)
std::pair< std::uint16_t, bool > removeToken()
int set_addr(const INETAddr &, const INETAddr &)
Definition: tuntap.cc:208
void configure(const ConfigurationUpdate &update) override
R2RI Self Metric Control Message is sent to an NEM&#39;s transport layer to specify the parameters necess...
Clock::time_point TimePoint
Definition: types.h:50
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
Definition of the ethernet frame header.
Definition: netutils.h:434
void sendDownstreamPacket(DownstreamPacket &pkt, const ControlMessages &msgs=empty)
void updateArpCache(const Utils::EtherHeader *pEthHeader, EMANE::NEMId nemId)
void processInbound(const UpstreamPacket &pkt)
static R2RIQueueMetricControlMessage * create(const Serialization &serialization)
int open(const char *, const char *)
Definition: tuntap.cc:80
Virtual Device EMANE Transport.
void processUpstreamControl(const ControlMessages &msgs)