本文档展示如何修改ndn-cxx和NFD的源码,添加一个值基本类型的Tag,下面的过程将展示添加一个值为uint64_t
类型的Tag SrcAddress。
添加Tag的含义
在NDNLPv2协议中定义了LpPacket,具体的格式如下:
LpPacket = LP-PACKET-TYPE TLV-LENGTH
*LpHeaderField
[Fragment]
LpHeaderField = Sequence
Sequence = SEQUENCE-TYPE TLV-LENGTH 8OCTET
Fragment = FRAGMENT-TYPE TLV-LENGTH 1*OCTET
- 其中
Fragment
放置的可以是一个NDN报的分片,或者是一个完整的NDN包(NDN包足够小,不需要分片的情况); -
*LpHeaderField
就是一系列的LpPacket的Header,类似一个变长的数组,所以可以自己定义新的LpHeader; - 所以添加一个新的Tag实际上就是添加一个新的LpHeader。
修改ndn-cxx
-
修改
ndn-cxx/lp/tlv.hpp
,为将要添加的新Tag分配一个新的TLV类型enum { LpPacket = 100, Fragment = 80, Sequence = 81, FragIndex = 82, FragCount = 83, PitToken = 98, Nack = 800, NackReason = 801, NextHopFaceId = 816, IncomingFaceId = 817, CachePolicy = 820, CachePolicyType = 821, CongestionMark = 832, Ack = 836, TxSequence = 840, NonDiscovery = 844, PrefixAnnouncement = 848, ///////////////////////////////////////////////////// add by qjm, for add new tag SrcAddress = 852 ///////////////////////////////////////////////////// };
如上所示,我们给新添加的Tag分配了一个TLV type,这个type是唯一标识一个TLV的。并且该值的分配也是需要遵循一定准则的,具体的分配规则可以参考:https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
Reserved Blocks¶
Two blocks of TLV-TYPEs have been reserved by link protocols:
-
[80, 100]
: 1-octet encoding -
[800, 1000]
: 3-octet encoding
TLV-TYPE numbers for LpHeaderField SHOULD be assigned according to the following rules:
- if the field can be safely ignored by a receiver that doesn't understand the field, pick an unused number in the range
[800, 959]
whose two least significant bits are00
. - if the field would occur frequently, pick an unused number in the range
[81, 99]
. - otherwise, pick an unused number in the range
[800, 959]
whose two least significant bits are效果01
.
Note: number assignment for a TLV-TYPE nested within a LpHeaderField is not restricted by the above rules.
-
-
修改
ndn-cxx/lp/tags.hpp
,定义一个新的Tag://///////////////////////////////////////////////// add by qjm, for add new tag typedef SimpleTag<uint64_t, 16> SrcAddressTag; ///////////////////////////////////////////////////
-
修改
ndn-cxx/lp/fields.hpp
,添加新Tag对应的Field:////////////////////////////////////////////////////// add by qjm, for add new tag typedef FieldDecl<field_location_tags::Header, uint64_t, tlv::SrcAddress> SrcAddressField; BOOST_CONCEPT_ASSERT((Field<SrcAddressField>)); ////////////////////////////////////////////////////// /** \brief Set of all field declarations. */ typedef boost ::mpl::set< FragmentField, SequenceField, FragIndexField, FragCountField, PitTokenField, NackField, NextHopFaceIdField, IncomingFaceIdField, CachePolicyField, CongestionMarkField, AckField, TxSequenceField, NonDiscoveryField, PrefixAnnouncementField, /////////////////////////////////////////////// add by qjm, for add new tag SrcAddressField /////////////////////////////////////////////// > FieldSet;
-
修改
ndn-cxx/face.cpp => extractLpLocalFields
:template<typename NetPkt> static void extractLpLocalFields(NetPkt &netPacket, const lp::Packet &lpPacket) { addTagFromField<lp::IncomingFaceIdTag, lp::IncomingFaceIdField>(netPacket, lpPacket); addTagFromField<lp::CongestionMarkTag, lp::CongestionMarkField>(netPacket, lpPacket); ////////////////////////////////////////////////////// add by qjm, for add new tag addTagFromField<lp::SrcAddressTag, lp::SrcAddressField>(netPacket, lpPacket); ////////////////////////////////////////////////////// }
上面的静态函数是在一个Face从Transport接收到一个Element,进行解析时调用的,功能是 将收到的LpPacket中的LpHeaderField提取,并保存到指定包的Tag列表当中。
-
如果插入的Tag要在Interest包中生效,则需要修改
ndn-cxx/impl/face-impl.hpp => asyncExpressInterest
:void asyncExpressInterest(RecordId id, shared_ptr<const Interest> interest, const DataCallback &afterSatisfied, const NackCallback &afterNacked, const TimeoutCallback &afterTimeout) { NDN_LOG_DEBUG("<I " << *interest); this->ensureConnected(true); const Interest &interest2 = *interest; auto &entry = m_pendingInterestTable.put(id, std::move(interest), afterSatisfied, afterNacked,afterTimeout, ref(m_scheduler)); lp::Packet lpPacket; addFieldFromTag<lp::NextHopFaceIdField, lp::NextHopFaceIdTag>(lpPacket, interest2); addFieldFromTag<lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, interest2); ////////////////////////////////////////////////////// add by qjm, for add new tag addFieldFromTag<lp::SrcAddressField, lp::SrcAddressTag>(lpPacket, interest2); ////////////////////////////////////////////////////// entry.recordForwarding(); m_face.m_transport->send(finishEncoding(std::move(lpPacket), interest2.wireEncode(), 'I', interest2.getName())); dispatchInterest(entry, interest2); }
上面新添的代码的功能是将一个要发送的包(Interest、Data等继承自TagHost)中的Tag提取处理出来,并作为一个LpHeaderField写入新构造的lpPacket当中。
-
如果插入的Tag要在Data包中生效,则需要修改
ndn-cxx/impl/face-impl.hpp => asyncPutData
:void asyncPutData(const Data &data) { NDN_LOG_DEBUG("<D " << data.getName()); bool shouldSendToForwarder = satisfyPendingInterests(data); if (!shouldSendToForwarder) { return; } this->ensureConnected(true); lp::Packet lpPacket; addFieldFromTag<lp::CachePolicyField, lp::CachePolicyTag>(lpPacket, data); addFieldFromTag<lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, data); /////////////////////////////////////////////////// add by qjm, for add new tag addFieldFromTag<lp::SrcAddressField, lp::SrcAddressTag>(lpPacket, data); ////////////////////////////////////////////////// m_face.m_transport->send(finishEncoding(std::move(lpPacket), data.wireEncode(), 'D', data.getName())); }
上面新添的代码的功能是将一个要发送的包(Interest、Data等继承自TagHost)中的Tag提取处理出来,并作为一个LpHeaderField写入新构造的lpPacket当中。
修改NFD
NFD中需要修改daemon/face/generic-link-service.cpp
中的两处代码:
-
GenericLinkService::decodeInterest
void GenericLinkService::decodeInterest(const Block &netPkt, const lp::Packet &firstPkt, const EndpointId &endpointId) { ..... /////////////////////////////////////////////// add by qjm, for add srcAddress Tag if (firstPkt.has<lp::SrcAddressField>()) { interest->setTag(make_shared<lp::SrcAddressTag>(firstPkt.get<lp::SrcAddressField>())); } /////////////////////////////////////////////// this->receiveInterest(*interest, endpointId); }
上面的代码在GenericLinkService解析Interest的时候,提取对应LpPacket中的Field,写入Interest的tags列表当中。
ps: 由于此处演示的是添加一个Tag,只对于Interest生效,所以需要修改这个函数,如果要对Data包或者Nack等包生效,类比上述代码,对
GenericLinkService::decodeData
,GenericLinkService::decodeNack
之类的进行修改即可 -
GenericLinkService::encodeLpFields
void GenericLinkService::encodeLpFields(const ndn::PacketBase &netPkt, lp::Packet &lpPacket) { ..... /////////////////////////////////////////////// add by qjm, for add srcAddress Tag auto srcAddressTag = netPkt.getTag<lp::SrcAddressTag>(); if (srcAddressTag != nullptr) { lpPacket.add<lp::SrcAddressField>(*srcAddressTag); } /////////////////////////////////////////////// auto pitToken = netPkt.getTag<lp::PitToken>(); if (pitToken != nullptr) { lpPacket.add<lp::PitTokenField>(*pitToken); } }
上面新添的代码会在发送一个包的时候调用,目的是将Tag提取出来,座位一个LpHeaderField 添加到LpPacket中。
网友评论