59 const std::uint16_t DROP_CODE_WRITE_ERROR = 1;
60 const std::uint16_t DROP_CODE_FRAME_ERROR = 2;
69 EthernetTransport(id, pPlatformService),
74 flowControlClient_{*
this},
75 bFlowControlEnable_{},
76 commonLayerStatistics_{STATISTIC_TABLE_LABELS}
107 "Virtual device name.");
110 configRegistrar.registerNonNumeric<std::string>(
"devicepath",
113 "Path to the tuntap device.");
115 configRegistrar.registerNumeric<std::uint64_t>(
"bitrate",
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.");
123 configRegistrar.registerNumeric<
bool>(
"broadcastmodeenable",
126 "Broadcast all packets to all NEMs.");
129 configRegistrar.registerNumeric<
bool>(
"arpcacheenable",
132 "Enable ARP request/reply monitoring to map Ethernet address to NEM.");
135 configRegistrar.registerNumeric<
bool>(
"arpmodeenable",
138 "Enable ARP on the virtual device.");
140 configRegistrar.registerNumeric<
bool>(
"flowcontrolenable",
143 "Enables downstream traffic flow control with a corresponding flow" 144 " control capable NEM layer.");
146 configRegistrar.registerNonNumeric<
INETAddr>(
"address",
149 "IPv4 or IPv6 virutal device address.");
151 configRegistrar.registerNonNumeric<
INETAddr>(
"mask",
154 "IPv4 or IPv6 virutal device addres network mask.");
165 for(
const auto & item : update)
167 if(item.first ==
"bitrate")
169 u64BitRate_ = item.second[0].asUINT64();
173 "TRANSPORTI %03hu VirtualTransport::%s %s: %ju",
179 else if(item.first ==
"devicepath")
181 sDevicePath_ = item.second[0].asString();
185 "TRANSPORTI %03hu VirtualTransport::%s %s: %s",
189 sDevicePath_.c_str());
191 else if(item.first ==
"device")
193 sDeviceName_ = item.second[0].asString();
197 "TRANSPORTI %03hu VirtualTransport::%s %s: %s",
201 sDeviceName_.c_str());
203 else if(item.first ==
"mask")
205 mask_ = item.second[0].asINETAddr();
209 "TRANSPORTI %03hu VirtualTransport::%s %s: %s",
213 mask_.
str(
false).c_str());
215 else if(item.first ==
"address")
217 address_ = item.second[0].asINETAddr();
221 "TRANSPORTI %03hu VirtualTransport::%s %s: %s",
225 address_.
str(
false).c_str());
227 else if(item.first ==
"arpmodeenable")
229 bARPMode_ = item.second[0].asBool();
233 "TRANSPORTI %03hu VirtualTransport::%s %s: %d",
239 else if(item.first ==
"broadcastmodeenable")
245 "TRANSPORTI %03hu VirtualTransport::%s %s: %d",
251 else if(item.first ==
"arpcacheenable")
257 "TRANSPORTI %03hu VirtualTransport::%s %s: %d",
263 else if(item.first ==
"flowcontrolenable")
265 bFlowControlEnable_ = item.second[0].asBool();
269 "TRANSPORTI %03hu VirtualTransport::%s %s: %d",
273 bFlowControlEnable_);
277 throw makeException<ConfigureException>(
"VirtualTransport: " 278 "Unexpected configuration item %s",
288 if(pTunTap_->
open(sDevicePath_.c_str(), sDeviceName_.c_str()) < 0)
290 std::stringstream ssDescription;
291 ssDescription <<
"could not open tuntap device path " 301 std::stringstream ssDescription;
302 ssDescription <<
"could not set tuntap eth address " 308 if(pTunTap_->
activate(bARPMode_) < 0)
310 std::stringstream ssDescription;
311 ssDescription <<
"could not activate tuntap arp mode " 318 if(!address_.
isAny())
321 if(pTunTap_->
set_addr(address_, mask_) < 0)
323 std::stringstream ssDescription;
324 ssDescription <<
"could not set tuntap address " 326 ssDescription <<
" mask " 338 thread_ = std::thread{&VirtualTransport::readDevice,
this};
343 if(bFlowControlEnable_)
345 flowControlClient_.
start();
349 "TRANSPORTI %03hu VirtualTransport::%s sent a flow control" 350 " token request, a handshake response is required to process" 360 if(thread_.joinable())
362 if(bFlowControlEnable_)
364 flowControlClient_.
stop();
395 "TRANSPORTI %03hu VirtualTransport::%s frame error",
400 handleUpstreamControl(msgs);
413 iov.iov_base =
const_cast<char*
>(
reinterpret_cast<const char*
>(pkt.
get()));
414 iov.iov_len = pkt.
length();
416 if(pTunTap_->
writev(&iov, 1) < 0)
420 "TRANSPORTI %03hu VirtualTransport::%s %s",
426 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime),
427 DROP_CODE_WRITE_ERROR);
433 "TRANSPORTI %03hu VirtualTransport::%s src %hu, dst %hu, dscp %hhu, length %zu",
437 pktInfo.getDestination(),
438 pktInfo.getPriority(),
442 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime));
447 const size_t sizePending = pBitPool_->
get(pkt.
length() * 8);
454 "TRANSPORTI %03hu VirtualTransport::%s bitpool request error %zd of %zd",
467 handleUpstreamControl(msgs);
472 void EMANE::Transports::Virtual::VirtualTransport::handleUpstreamControl(
const ControlMessages & msgs)
474 for(
const auto & pMessage : msgs)
476 switch(pMessage->getId())
480 const auto pFlowControlControlMessage =
483 if(bFlowControlEnable_)
487 "TRANSPORTI %03hu VirtualTransport::%s received a flow control" 488 " token update %hu tokens",
491 pFlowControlControlMessage->getTokens());
499 "TRANSPORTI %03hu VirtualTransport::%s received a flow control" 500 " message but flow control is not enabled",
509 const auto pR2RINeighborMetricControlMessage =
516 "TRANSPORTI %03hu VirtualTransport::%s R2RINeighborMetricControlMessage",
524 const auto pR2RIQueueMetricControlMessage =
530 "TRANSPORTI %03hu VirtualTransport::%s R2RIQueueMetricControlMessage",
538 const auto pR2RISelfMetricControlMessage =
544 "TRANSPORTI %03hu VirtualTransport::%s R2RISelfMetricControlMessage",
554 const auto pSerializedControlMessage =
557 switch(pSerializedControlMessage->getSerializedId())
561 std::unique_ptr<Controls::FlowControlControlMessage>
562 pFlowControlControlMessage{
564 pSerializedControlMessage->getSerialization())};
566 if(bFlowControlEnable_)
570 "TRANSPORTI %03hu VirtualTransport::%s received a flow control" 571 " token update %hu tokens",
574 pFlowControlControlMessage->getTokens());
583 "TRANSPORTI %03hu VirtualTransport::%s received a flow control" 584 " message but flow control is not enabled",
593 std::unique_ptr<Controls::R2RINeighborMetricControlMessage>
594 pR2RINeighborMetricControlMessage{
596 pSerializedControlMessage->getSerialization())};
601 pR2RINeighborMetricControlMessage.get()),
602 "TRANSPORTI %03hu VirtualTransport::%s",
610 std::unique_ptr<Controls::R2RIQueueMetricControlMessage>
611 pR2RIQueueMetricControlMessage{
613 pSerializedControlMessage->getSerialization())};
618 pR2RIQueueMetricControlMessage.get()),
619 "TRANSPORTI %03hu VirtualTransport::%s",
627 std::unique_ptr<Controls::R2RISelfMetricControlMessage>
628 pR2RISelfMetricControlMessage{
630 pSerializedControlMessage->getSerialization())};
635 pR2RISelfMetricControlMessage.get()),
636 "TRANSPORTI %03hu VirtualTransport::%s",
645 "TRANSPORTI %03hu VirtualTransport::%s unknown serialized msg id %hu, ignore",
648 pSerializedControlMessage->getSerializedId());
657 "TRANSPORTI %03hu VirtualTransport::%s unknown msg id %hu, ignore",
666 void EMANE::Transports::Virtual::VirtualTransport::readDevice()
674 memset(buf, 0x0,
sizeof(buf));
678 iov.iov_base =
reinterpret_cast<char*
>(buf);
679 iov.iov_len =
sizeof(buf);
682 if((len = pTunTap_->
readv(&iov, 1)) < 0)
686 "TRANSPORTI %03hu VirtualTransport::%s %s",
702 "TRANSPORTI %03hu VirtualTransport::%s frame error",
709 NEMId nemDestination;
719 "TRANSPORTI %03hu VirtualTransport::%s frame parse error",
727 "TRANSPORTI %03hu VirtualTransport::%s src %hu, dst %hu, dscp %hhu, length %zd",
741 if(bFlowControlEnable_)
750 "TRANSPORTI %03hu VirtualTransport::%s failed to remove token (tokens:%hu)",
761 "TRANSPORTI %03hu VirtualTransport::%s removed token (tokens:%hu)",
769 std::chrono::duration_cast<Microseconds>(Clock::now() - beginTime));
777 std::uint64_t sizePending {pBitPool_->
get(len * 8)};
784 "TRANSPORTI %03hu VirtualTransport::%s bitpool " 785 "request error %jd of %zd",
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.
R2RI Queue Metric Control Message is sent to an NEM's transport layer to convey information about MAC...
The Registrar interface provides access to all of the emulator registrars.
A Serialized Control Message is used to encapsulate Serializable control messages as they traverse pr...
void initialize(Registrar ®istrar) 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.
std::list< const ControlMessage * > ControlMessages
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)
virtual int parseFrame(const Utils::EtherHeader *pEthHeader, EMANE::NEMId &dst, std::uint8_t &dscp)
static FlowControlControlMessage * create(const Serialization &serialization)
void registerStatistics(StatisticRegistrar &statisticRegistrar)
int writev(const struct iovec *, size_t)
Store source, destination, creation time and priority information for a packet.
#define NETWORK_DEVICE_PATH
#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
int cancel(std::thread &thread)
std::uint64_t get(std::uint64_t u64Request, bool bFullFill=true)
void processUpstreamPacket(UpstreamPacket &pkt, const ControlMessages &msgs)
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 &)
int readv(struct iovec *, size_t)
R2RI Neighbor Metric Control Message is sent to an NEM's transport layer to convey information about ...
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 &)
void postStart() override
void configure(const ConfigurationUpdate &update) override
R2RI Self Metric Control Message is sent to an NEM's transport layer to specify the parameters necess...
Clock::time_point TimePoint
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
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 *)
Virtual Device EMANE Transport.
void processUpstreamControl(const ControlMessages &msgs)