本文檔展示如何修改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中。