NDN新增tag的方案

本文档展示如何修改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:

    1. 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 are 00.
    2. if the field would occur frequently, pick an unused number in the range [81, 99].
    3. 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::decodeDataGenericLinkService::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中。

添加成功后的效果

Tag添加成功效果
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容