LLDP數(shù)據(jù)包中添加自定義LLDPDU

在LLDP數(shù)據(jù)包中添加自定義LLDPDU

如何在LLDP數(shù)據(jù)包中攜帶發(fā)送時(shí)間戳
LLDP描述文件:ryu/lib/packet/lldp.py

一、lldp.py

  1. 增添 TLV 類型
  2. 增添 TimeStamp 類
  3. lldp 類的修改

1.1 lldp.py :增添TLV類型:TimeStamp

  # LLDP TLV type
  LLDP_TLV_END = 0                        # End of LLDPDU
  LLDP_TLV_CHASSIS_ID = 1                 # Chassis ID
  LLDP_TLV_PORT_ID = 2                    # Port ID
  LLDP_TLV_TTL = 3                        # Time To Live
  LLDP_TLV_PORT_DESCRIPTION = 4           # Port Description
  LLDP_TLV_SYSTEM_NAME = 5                # System Name
  LLDP_TLV_SYSTEM_DESCRIPTION = 6         # System Description
  LLDP_TLV_SYSTEM_CAPABILITIES = 7        # System Capabilities
  LLDP_TLV_MANAGEMENT_ADDRESS = 8         # Management Address
  LLDP_TLV_ORGANIZATIONALLY_SPECIFIC = 127  # organizationally Specific TLVs
  LLDP_TLV_SEND_TIME = 11  # Time stamp for sending LLDP packet, using for delay measurement.

增添發(fā)送時(shí)間戳:LLDP_TLV_SEND_TIME = 11 ,用于解析

1.2 lldp.py :增添 TimeStamp 類

參考lldp.py中的 TTL 類

@lldp.set_tlv_type(LLDP_TLV_SEND_TIME)
class TimeStamp(LLDPBasicTLV):
    _PACK_STR = '!d'
    _PACK_SIZE = struct.calcsize(_PACK_STR)
    _LEN_MIN = _PACK_SIZE
    _LEN_MAX = _PACK_SIZE
  
    def __init__(self, buf=None, *args, **kwargs):
        super(TimeStamp, self).__init__(buf, *args, **kwargs)
        if buf:
        (self.timestamp, ) = struct.unpack(
                self._PACK_STR, self.tlv_info[:self._PACK_SIZE])
        else:
            self.timestamp = kwargs['timestamp']
            self.len = self._PACK_SIZE
            assert self._len_valid()
            self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len

        def serialize(self):
            return struct.pack('!Hd', self.typelen, self.timestamp)

1.3 lldp.py : lldp 類的修改

去掉最后一項(xiàng),即不判斷最后一個(gè)為END

def _tlvs_valid(self):
    return (self.tlvs[0].tlv_type == LLDP_TLV_CHASSIS_ID and
      self.tlvs[1].tlv_type == LLDP_TLV_PORT_ID and
      self.tlvs[2].tlv_type == LLDP_TLV_TTL)

修改 break 條件

def _parser(cls, buf)
    tlvs = []
    while buf:
        tlv_type = LLDPBasicTlv.get_type(buf)
        tlv = cls._tlv_parsers[tlv_type](buf)
        tlvs.append(tlv)
        offset = LLDP_TLV_SIZE + tlv.len
        buf = buf[offset:]
        if tlv.tlv_type == LLDP_TLV_SEND_TIME: # END 改為LLDP_TLV_SEND_TIME
            break
        assert len(buf) > 0
    lldp_pkt = cls(tlvs)
    assert lldp_pkt._tlvs_len_valid()
    assert lldp_pkt._tlvs_valid()
    return lldp_pkt, None, buf

二、switches.py:

  1. switches.py文件中的LLDPPacket類完成了LLDP數(shù)據(jù)包的初始化和序列化實(shí)現(xiàn)
  2. lldp_packet方法可以構(gòu)造LLDP數(shù)據(jù)包,并返回序列化之后的數(shù)據(jù)。在此函數(shù)中,我們需要添加timestamp的TLV
  3. lldp_parse:將獲取到的字節(jié)流的數(shù)據(jù)解析為對應(yīng)的LLDP數(shù)據(jù)包,由于在發(fā)送之前,我們加入了一個(gè)timestamp的TLV,所以解析時(shí)需要完成這個(gè)TLV的解析,并將TimeStamp作為返回值返回

2.1、switches.py:@staticmethod lldp_packet

1. 增添方法的參數(shù) timestamp

def lldp_packet(dpid, port_no, dl_addr, ttl, timestamp):

2. 增添 Timestamp 屬性

tlv_ttl = lldp.TTL(ttl=ttl)
tlv_timestamp = lldp.TimeStamp(timestamp=timestamp)
tlv_end = lldp.End()

3. 修改tlvs:增添 timestamp 參數(shù)

 tlvs = (tlv_chassis_id, tlv_port_id, tlv_ttl, tlv_timestamp, tlv_end)

2.2、switches.py:@staticmethod lldp_parse

tlv_timestamp = lldp_pkt.tlvs[11]
timestamp = tlv_timestamp
return  src_dpid, src_port_no, timestamp,

解析取出timestamp,要與之前LLDP聲明的一致,之前聲明的為11

2.3、switches.py: def _port_added 修改:增加時(shí)間戳

def _port_added(self, port):
    _time = time.time()
    lldp_data = LLDPPacket.lldp_packet(port.dpid, port.port_no,
                       port.hw_addr, self.DEFAULT_TTL, _time)

第二處:

LLDP_PACKET_LEN = len(LLDPPacket.lldp_packet(0, 0, DONTCARE_STR, 0, 0))

2.4 switches.py:增添返回的變量

調(diào)用了lldp_parse方法的地方,返回的值都要增添一個(gè)timestamp

src_dpid, src_port_no, timestamp = LLDPPacket.lldp_parse(msg.data)

2.5 發(fā)送LLDP報(bào)文出修改,每次重新插入時(shí)間戳

  def send_lldp_packet(self, port):
    try:
      port_data = self.ports.lldp_sent(port)
    except KeyError:
      # ports can be modified during our sleep in self.lldp_loop()
      # LOG.debug('send_lld error', exc_info=True)
      return
    if port_data.is_down:
      return

    dp = self.dps.get(port.dpid, None)
    if dp is None:
      # datapath was already deleted
      return
    timestamp = time.time()
    lldp_data = LLDPPacket.lldp_packet(
      port.dpid, port.port_no, port.hw_addr, self.DEFAULT_TTL, timestamp)
    # LOG.debug('lldp sent dpid=%s, port_no=%d', dp.id, port.port_no)
    # TODO:XXX
    if dp.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION:
      actions = [dp.ofproto_parser.OFPActionOutput(port.port_no)]
      dp.send_packet_out(actions=actions, data=lldp_data)
    elif dp.ofproto.OFP_VERSION >= ofproto_v1_2.OFP_VERSION:
      actions = [dp.ofproto_parser.OFPActionOutput(port.port_no)]
      out = dp.ofproto_parser.OFPPacketOut(
        datapath=dp, in_port=dp.ofproto.OFPP_CONTROLLER,
        buffer_id=dp.ofproto.OFP_NO_BUFFER, actions=actions,
        data=lldp_data)
      dp.send_msg(out)
    #print port_data #cat
    else:
      LOG.error('cannot send lldp packet. unsupported version. %x',
            dp.ofproto.OFP_VERSION)

注意

在Ryu的Switches模塊中,被發(fā)送的LLDP都是一次構(gòu)造之后保存起來,發(fā)送時(shí)直接發(fā)送的,所以添加的時(shí)間戳?xí)潭ㄔ诘谝淮螛?gòu)造時(shí)的時(shí)間。所以如果希望正確地插入發(fā)送時(shí)間戳,還需要進(jìn)行額外的邏輯修改。但是這也許就破壞了Ryu設(shè)計(jì)的完整性,所以如何操作還需要讀者自行斟酌。

參考:李呈: Ryu:如何在LLDP中添加自定義LLDPDU

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容