28 #include <ndn-cxx/lp/fields.hpp>
29 #include <ndn-cxx/lp/pit-token.hpp>
30 #include <ndn-cxx/lp/tags.hpp>
39 tlv::sizeOfVarNumber(
sizeof(uint64_t)) +
40 tlv::sizeOfNonNegativeInteger(UINT64_MAX);
44 , m_fragmenter(m_options.fragmenterOptions, this)
45 , m_reassembler(m_options.reassemblerOptions, this)
46 , m_reliability(m_options.reliabilityOptions, this)
82 GenericLinkService::requestIdlePacket()
87 this->sendLpPacket({});
91 GenericLinkService::sendLpPacket(lp::Packet&& pkt)
100 checkCongestionLevel(pkt);
103 auto block = pkt.wireEncode();
104 if (mtu !=
MTU_UNLIMITED && block.size() >
static_cast<size_t>(mtu)) {
113 GenericLinkService::doSendInterest(
const Interest& interest)
115 lp::Packet lpPacket(interest.wireEncode());
117 encodeLpFields(interest, lpPacket);
119 this->sendNetPacket(std::move(lpPacket),
true);
123 GenericLinkService::doSendData(
const Data& data)
125 lp::Packet lpPacket(data.wireEncode());
127 encodeLpFields(data, lpPacket);
129 this->sendNetPacket(std::move(lpPacket),
false);
133 GenericLinkService::doSendNack(
const lp::Nack& nack)
135 lp::Packet lpPacket(nack.getInterest().wireEncode());
136 lpPacket.add<lp::NackField>(nack.getHeader());
138 encodeLpFields(nack, lpPacket);
140 this->sendNetPacket(std::move(lpPacket),
false);
144 GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
146 std::for_each(pkts.begin(), pkts.end(), [
this] (lp::Packet& pkt) {
147 pkt.set<lp::SequenceField>(++m_lastSeqNo);
152 GenericLinkService::encodeLpFields(
const ndn::PacketBase& netPkt, lp::Packet& lpPacket)
155 auto incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
156 if (incomingFaceIdTag !=
nullptr) {
157 lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
161 auto congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
162 if (congestionMarkTag !=
nullptr) {
163 lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
167 auto nonDiscoveryTag = netPkt.getTag<lp::NonDiscoveryTag>();
168 if (nonDiscoveryTag !=
nullptr) {
169 lpPacket.add<lp::NonDiscoveryField>(*nonDiscoveryTag);
172 auto prefixAnnouncementTag = netPkt.getTag<lp::PrefixAnnouncementTag>();
173 if (prefixAnnouncementTag !=
nullptr) {
174 lpPacket.add<lp::PrefixAnnouncementField>(*prefixAnnouncementTag);
178 auto pitToken = netPkt.getTag<lp::PitToken>();
179 if (pitToken !=
nullptr) {
180 lpPacket.add<lp::PitTokenField>(*pitToken);
185 GenericLinkService::sendNetPacket(lp::Packet&& pkt,
bool isInterest)
187 std::vector<lp::Packet> frags;
213 frags.push_back(pkt);
216 frags.push_back(std::move(pkt));
220 if (frags.size() == 1) {
223 BOOST_ASSERT(!frags.front().has<lp::FragIndexField>());
224 BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
230 this->assignSequences(frags);
237 for (lp::Packet& frag : frags) {
238 this->sendLpPacket(std::move(frag));
243 GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
247 if (sendQueueLength < 0) {
251 if (sendQueueLength > 0) {
259 const auto now = time::steady_clock::now();
261 if (m_nextMarkTime == time::steady_clock::time_point::max()) {
265 else if (now >= m_nextMarkTime) {
266 pkt.set<lp::CongestionMarkField>(1);
270 ++m_nMarkedSinceInMarkingState;
273 time::nanoseconds interval(
static_cast<time::nanoseconds::rep
>(
275 std::sqrt(m_nMarkedSinceInMarkingState + 1)));
276 m_nextMarkTime += interval;
279 else if (m_nextMarkTime != time::steady_clock::time_point::max()) {
282 m_nextMarkTime = time::steady_clock::time_point::max();
283 m_nMarkedSinceInMarkingState = 0;
288 GenericLinkService::doReceivePacket(
const Block& packet,
const EndpointId& endpoint)
291 lp::Packet pkt(packet);
301 if (!pkt.has<lp::FragmentField>()) {
306 if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
312 auto [isReassembled, netPkt, firstPkt] = m_reassembler.
receiveFragment(endpoint, pkt);
314 this->decodeNetPacket(netPkt, firstPkt, endpoint);
317 catch (
const tlv::Error& e) {
324 GenericLinkService::decodeNetPacket(
const Block& netPkt,
const lp::Packet& firstPkt,
328 switch (netPkt.type()) {
330 if (firstPkt.has<lp::NackField>()) {
331 this->decodeNack(netPkt, firstPkt, endpointId);
334 this->decodeInterest(netPkt, firstPkt, endpointId);
338 this->decodeData(netPkt, firstPkt, endpointId);
342 NFD_LOG_FACE_WARN(
"unrecognized network-layer packet TLV-TYPE " << netPkt.type() <<
": DROP");
346 catch (
const tlv::Error& e) {
353 GenericLinkService::decodeInterest(
const Block& netPkt,
const lp::Packet& firstPkt,
356 BOOST_ASSERT(netPkt.type() == tlv::Interest);
357 BOOST_ASSERT(!firstPkt.has<lp::NackField>());
360 auto interest = make_shared<Interest>(netPkt);
362 if (firstPkt.has<lp::NextHopFaceIdField>()) {
364 interest->setTag(make_shared<lp::NextHopFaceIdTag>(firstPkt.get<lp::NextHopFaceIdField>()));
372 if (firstPkt.has<lp::CachePolicyField>()) {
378 if (firstPkt.has<lp::IncomingFaceIdField>()) {
382 if (firstPkt.has<lp::CongestionMarkField>()) {
383 interest->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
386 if (firstPkt.has<lp::NonDiscoveryField>()) {
388 interest->setTag(make_shared<lp::NonDiscoveryTag>(firstPkt.get<lp::NonDiscoveryField>()));
395 if (firstPkt.has<lp::PrefixAnnouncementField>()) {
401 if (firstPkt.has<lp::PitTokenField>()) {
402 interest->setTag(make_shared<lp::PitToken>(firstPkt.get<lp::PitTokenField>()));
409 GenericLinkService::decodeData(
const Block& netPkt,
const lp::Packet& firstPkt,
412 BOOST_ASSERT(netPkt.type() == tlv::Data);
415 auto data = make_shared<Data>(netPkt);
417 if (firstPkt.has<lp::NackField>()) {
423 if (firstPkt.has<lp::NextHopFaceIdField>()) {
429 if (firstPkt.has<lp::CachePolicyField>()) {
433 data->setTag(make_shared<lp::CachePolicyTag>(firstPkt.get<lp::CachePolicyField>()));
436 if (firstPkt.has<lp::IncomingFaceIdField>()) {
440 if (firstPkt.has<lp::CongestionMarkField>()) {
441 data->setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
444 if (firstPkt.has<lp::NonDiscoveryField>()) {
450 if (firstPkt.has<lp::PrefixAnnouncementField>()) {
452 data->setTag(make_shared<lp::PrefixAnnouncementTag>(firstPkt.get<lp::PrefixAnnouncementField>()));
455 NFD_LOG_FACE_WARN(
"received PrefixAnnouncement, but self-learning disabled: IGNORE");
463 GenericLinkService::decodeNack(
const Block& netPkt,
const lp::Packet& firstPkt,
466 BOOST_ASSERT(netPkt.type() == tlv::Interest);
467 BOOST_ASSERT(firstPkt.has<lp::NackField>());
469 lp::Nack nack((Interest(netPkt)));
470 nack.setHeader(firstPkt.get<lp::NackField>());
472 if (firstPkt.has<lp::NextHopFaceIdField>()) {
478 if (firstPkt.has<lp::CachePolicyField>()) {
484 if (firstPkt.has<lp::IncomingFaceIdField>()) {
488 if (firstPkt.has<lp::CongestionMarkField>()) {
489 nack.setTag(make_shared<lp::CongestionMarkTag>(firstPkt.get<lp::CongestionMarkField>()));
492 if (firstPkt.has<lp::NonDiscoveryField>()) {
498 if (firstPkt.has<lp::PrefixAnnouncementField>()) {
PacketCounter nInNetInvalid
Count of invalid reassembled network-layer packets dropped.
PacketCounter nDuplicateSequence
Count of LpPackets dropped due to duplicate Sequence numbers.
SizeCounter< LpReassembler > nReassembling
Count of network-layer packets currently being reassembled.
PacketCounter nFragmentationErrors
Count of failed fragmentations.
PacketCounter nCongestionMarked
Count of outgoing LpPackets that were marked with congestion marks.
PacketCounter nOutOverMtu
Count of outgoing LpPackets dropped due to exceeding MTU limit.
PacketCounter nInLpInvalid
Count of invalid LpPackets dropped before reassembly.
PacketCounter nReassemblyTimeouts
Count of dropped partial network-layer packets due to reassembly timeout.
ssize_t getEffectiveMtu() const final
void setOptions(const Options &options)
Sets the options used by GenericLinkService.
GenericLinkService(const Options &options={})
bool canOverrideMtuTo(ssize_t mtu) const
Whether MTU can be overridden to the specified value.
void receiveNack(const lp::Nack &nack, const EndpointId &endpoint)
Delivers received Nack to forwarding.
void receiveInterest(const Interest &interest, const EndpointId &endpoint)
Delivers received Interest to forwarding.
void notifyDroppedInterest(const Interest &packet)
void receiveData(const Data &data, const EndpointId &endpoint)
Delivers received Data to forwarding.
const Transport * getTransport() const noexcept
Returns the Transport to which this LinkService is attached.
void sendPacket(const Block &packet)
Send a lower-layer packet via Transport.
void setOptions(const Options &options)
Set options for fragmenter.
std::tuple< bool, std::vector< lp::Packet > > fragmentPacket(const lp::Packet &packet, size_t mtu)
Fragments a network-layer packet into link-layer packets.
std::tuple< bool, Block, lp::Packet > receiveFragment(const EndpointId &remoteEndpoint, const lp::Packet &packet)
Adds received fragment to the buffer.
signal::Signal< LpReassembler, EndpointId, size_t > beforeTimeout
Notifies before a partial packet is dropped due to timeout.
void setOptions(const Options &options)
Set options for reassembler.
signal::Signal< LpReliability, Interest > onDroppedInterest
Called when an Interest is dropped for exceeding the allowed number of retransmissions.
void piggyback(lp::Packet &pkt, ssize_t mtu)
Called by GenericLinkService to attach Acks onto an outgoing LpPacket.
static constexpr size_t RESERVED_HEADER_SPACE
TxSequence TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + lp::Sequence (8 octets)
void handleOutgoing(std::vector< lp::Packet > &frags, lp::Packet &&pkt, bool isInterest)
Observe outgoing fragment(s) of a network packet and store for potential retransmission.
bool processIncomingPacket(const lp::Packet &pkt)
Extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue.
void setOptions(const Options &options)
Set options for reliability.
virtual ssize_t getSendQueueLength()
Returns the current send queue length of the transport (in octets).
#define NFD_LOG_FACE_DEBUG(msg)
Log a message at DEBUG level.
#define NFD_LOG_FACE_WARN(msg)
Log a message at WARN level.
#define NFD_LOG_FACE_TRACE(msg)
Log a message at TRACE level.
#define NFD_LOG_INIT(name)
std::variant< std::monostate, ethernet::Address, udp::Endpoint > EndpointId
Identifies a remote endpoint on the link.
constexpr size_t CONGESTION_MARK_SIZE
constexpr ssize_t MIN_MTU
Minimum MTU that may be set.
constexpr ssize_t MTU_UNLIMITED
Indicates that the transport has no limit on payload size.
Options that control the behavior of GenericLinkService.
bool allowReassembly
Enables reassembly.
LpReassembler::Options reassemblerOptions
Options for reassembly.
LpFragmenter::Options fragmenterOptions
Options for fragmentation.
bool allowCongestionMarking
Enables send queue congestion detection and marking.
bool allowFragmentation
Enables fragmentation.
LpReliability::Options reliabilityOptions
Options for reliability.
bool allowSelfLearning
Enables self-learning forwarding support.
size_t defaultCongestionThreshold
Default congestion threshold in bytes.
time::nanoseconds baseCongestionMarkingInterval
Starting value for congestion marking interval.
ssize_t overrideMtu
Overrides the MTU provided by Transport.
bool allowLocalFields
Enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy.
bool isEnabled
Enables link-layer reliability.