mrtlib: Support RFC8050

Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
IWASE Yusuke 2018-03-30 11:33:56 +09:00 committed by FUJITA Tomonori
parent ccedf4cfb3
commit 807185470e

View File

@ -431,6 +431,11 @@ class TableDump2MrtRecord(MrtCommonRecord):
SUBTYPE_RIB_IPV6_UNICAST = 4
SUBTYPE_RIB_IPV6_MULTICAST = 5
SUBTYPE_RIB_GENERIC = 6
SUBTYPE_RIB_IPV4_UNICAST_ADDPATH = 8
SUBTYPE_RIB_IPV4_MULTICAST_ADDPATH = 9
SUBTYPE_RIB_IPV6_UNICAST_ADDPATH = 10
SUBTYPE_RIB_IPV6_MULTICAST_ADDPATH = 11
SUBTYPE_RIB_GENERIC_ADDPATH = 12
@TableDump2MrtMessage.register_type(
@ -595,7 +600,8 @@ class TableDump2AfiSafiSpecificRibMrtMessage(TableDump2MrtMessage):
RIB subtypes.
The AFI/SAFI-specific RIB subtypes consist of the RIB_IPV4_UNICAST,
RIB_IPV4_MULTICAST, RIB_IPV6_UNICAST, and RIB_IPV6_MULTICAST subtypes.
RIB_IPV4_MULTICAST, RIB_IPV6_UNICAST, RIB_IPV6_MULTICAST and their
additional-path version subtypes.
"""
# 0 1 2 3
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@ -614,6 +620,9 @@ class TableDump2AfiSafiSpecificRibMrtMessage(TableDump2MrtMessage):
# Parser class to parse the Prefix field
_PREFIX_CLS = None # should be defined in subclass
# Is additional-path version?
_IS_ADDPATH = False
def __init__(self, seq_num, prefix, rib_entries, entry_count=None):
self.seq_num = seq_num
assert isinstance(prefix, self._PREFIX_CLS)
@ -631,7 +640,7 @@ class TableDump2AfiSafiSpecificRibMrtMessage(TableDump2MrtMessage):
rest = buf[2:]
rib_entries = []
for i in range(entry_count):
r, rest = MrtRibEntry.parse(rest)
r, rest = MrtRibEntry.parse(rest, is_addpath=cls._IS_ADDPATH)
rib_entries.insert(i, r)
return entry_count, rib_entries, rest
@ -709,11 +718,62 @@ class TableDump2RibIPv6MulticastMrtMessage(
_PREFIX_CLS = bgp.IP6AddrPrefix
@TableDump2MrtMessage.register_type(
TableDump2MrtRecord.SUBTYPE_RIB_IPV4_UNICAST_ADDPATH)
class TableDump2RibIPv4UnicastAddPathMrtMessage(
TableDump2AfiSafiSpecificRibMrtMessage):
"""
MRT Message for the TABLE_DUMP_V2 Type and the
SUBTYPE_RIB_IPV4_UNICAST_ADDPATH subtype.
"""
_PREFIX_CLS = bgp.IPAddrPrefix
_IS_ADDPATH = True
@TableDump2MrtMessage.register_type(
TableDump2MrtRecord.SUBTYPE_RIB_IPV4_MULTICAST_ADDPATH)
class TableDump2RibIPv4MulticastAddPathMrtMessage(
TableDump2AfiSafiSpecificRibMrtMessage):
"""
MRT Message for the TABLE_DUMP_V2 Type and the
SUBTYPE_RIB_IPV4_MULTICAST_ADDPATH subtype.
"""
_PREFIX_CLS = bgp.IPAddrPrefix
_IS_ADDPATH = True
@TableDump2MrtMessage.register_type(
TableDump2MrtRecord.SUBTYPE_RIB_IPV6_UNICAST_ADDPATH)
class TableDump2RibIPv6UnicastAddPathMrtMessage(
TableDump2AfiSafiSpecificRibMrtMessage):
"""
MRT Message for the TABLE_DUMP_V2 Type and the
SUBTYPE_RIB_IPV6_UNICAST_ADDPATH subtype.
"""
_PREFIX_CLS = bgp.IP6AddrPrefix
_IS_ADDPATH = True
@TableDump2MrtMessage.register_type(
TableDump2MrtRecord.SUBTYPE_RIB_IPV6_MULTICAST_ADDPATH)
class TableDump2RibIPv6MulticastAddPathMrtMessage(
TableDump2AfiSafiSpecificRibMrtMessage):
"""
MRT Message for the TABLE_DUMP_V2 Type and the
SUBTYPE_RIB_IPV6_MULTICAST_ADDPATH subtype.
"""
_PREFIX_CLS = bgp.IP6AddrPrefix
_IS_ADDPATH = True
@TableDump2MrtMessage.register_type(
TableDump2MrtRecord.SUBTYPE_RIB_GENERIC)
class TableDump2RibGenericMrtMessage(TableDump2MrtMessage):
"""
MRT Message for the TABLE_DUMP_V2 Type and the RIB_GENERIC subtype.
MRT Message for the TABLE_DUMP_V2 Type and the generic RIB subtypes.
The generic RIB subtypes consist of the RIB_GENERIC and
RIB_GENERIC_ADDPATH subtypes.
"""
# 0 1 2 3
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@ -729,6 +789,9 @@ class TableDump2RibGenericMrtMessage(TableDump2MrtMessage):
_HEADER_FMT = '!IHB'
HEADER_SIZE = struct.calcsize(_HEADER_FMT)
# Is additional-path version?
_IS_ADDPATH = False
def __init__(self, seq_num, afi, safi, nlri, rib_entries,
entry_count=None):
self.seq_num = seq_num
@ -749,7 +812,7 @@ class TableDump2RibGenericMrtMessage(TableDump2MrtMessage):
rest = buf[2:]
rib_entries = []
for i in range(entry_count):
r, rest = MrtRibEntry.parse(rest)
r, rest = MrtRibEntry.parse(rest, is_addpath=cls._IS_ADDPATH)
rib_entries.insert(i, r)
return entry_count, rib_entries, rest
@ -784,6 +847,16 @@ class TableDump2RibGenericMrtMessage(TableDump2MrtMessage):
self.afi, self.safi) + nlri_bin + rib_bin
@TableDump2MrtMessage.register_type(
TableDump2MrtRecord.SUBTYPE_RIB_GENERIC_ADDPATH)
class TableDump2RibGenericAddPathMrtMessage(TableDump2RibGenericMrtMessage):
"""
MRT Message for the TABLE_DUMP_V2 Type and the RIB_GENERIC_ADDPATH
subtype.
"""
_IS_ADDPATH = True
class MrtRibEntry(stringify.StringifyMixin):
"""
MRT RIB Entry.
@ -795,15 +868,21 @@ class MrtRibEntry(stringify.StringifyMixin):
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | Originated Time |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | (Path Identifier) |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | Attribute Length |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | BGP Attributes... (variable)
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# peer_index, originated_time, attr_len
_HEADER_FMT = '!HIH'
HEADER_SIZE = struct.calcsize(_HEADER_FMT)
# peer_index, originated_time, path_id, attr_len
_HEADER_FMT_ADDPATH = '!HIIH'
HEADER_SIZE_ADDPATH = struct.calcsize(_HEADER_FMT_ADDPATH)
def __init__(self, peer_index, originated_time, bgp_attributes,
attr_len=None):
attr_len=None, path_id=None):
self.peer_index = peer_index
self.originated_time = originated_time
assert isinstance(bgp_attributes, (list, tuple))
@ -811,20 +890,28 @@ class MrtRibEntry(stringify.StringifyMixin):
assert isinstance(attr, bgp._PathAttribute)
self.bgp_attributes = bgp_attributes
self.attr_len = attr_len
self.path_id = path_id
@classmethod
def parse(cls, buf):
(peer_index, originated_time, attr_len) = struct.unpack_from(
cls._HEADER_FMT, buf)
def parse(cls, buf, is_addpath=False):
path_id = None
if not is_addpath:
(peer_index, originated_time,
attr_len) = struct.unpack_from(cls._HEADER_FMT, buf)
_header_size = cls.HEADER_SIZE
else:
(peer_index, originated_time, path_id,
attr_len) = struct.unpack_from(cls._HEADER_FMT_ADDPATH, buf)
_header_size = cls.HEADER_SIZE_ADDPATH
bgp_attr_bin = buf[cls.HEADER_SIZE:cls.HEADER_SIZE + attr_len]
bgp_attr_bin = buf[_header_size:_header_size + attr_len]
bgp_attributes = []
while bgp_attr_bin:
attr, bgp_attr_bin = bgp._PathAttribute.parser(bgp_attr_bin)
bgp_attributes.append(attr)
return cls(peer_index, originated_time, bgp_attributes,
attr_len), buf[cls.HEADER_SIZE + attr_len:]
attr_len, path_id), buf[_header_size + attr_len:]
def serialize(self):
bgp_attrs_bin = bytearray()
@ -832,10 +919,17 @@ class MrtRibEntry(stringify.StringifyMixin):
bgp_attrs_bin += attr.serialize()
self.attr_len = len(bgp_attrs_bin) # fixup
return struct.pack(self._HEADER_FMT,
self.peer_index,
self.originated_time,
self.attr_len) + bgp_attrs_bin
if self.path_id is None:
return struct.pack(self._HEADER_FMT,
self.peer_index,
self.originated_time,
self.attr_len) + bgp_attrs_bin
else:
return struct.pack(self._HEADER_FMT_ADDPATH,
self.peer_index,
self.originated_time,
self.path_id,
self.attr_len) + bgp_attrs_bin
@six.add_metaclass(abc.ABCMeta)
@ -856,6 +950,10 @@ class Bgp4MpMrtRecord(MrtCommonRecord):
SUBTYPE_BGP4MP_STATE_CHANGE_AS4 = 5
SUBTYPE_BGP4MP_MESSAGE_LOCAL = 6
SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL = 7
SUBTYPE_BGP4MP_MESSAGE_ADDPATH = 8
SUBTYPE_BGP4MP_MESSAGE_AS4_ADDPATH = 9
SUBTYPE_BGP4MP_MESSAGE_LOCAL_ADDPATH = 10
SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH = 11
@MrtRecord.register_type(MrtRecord.TYPE_BGP4MP_ET)
@ -869,6 +967,10 @@ class Bgp4MpEtMrtRecord(ExtendedTimestampMrtRecord):
SUBTYPE_BGP4MP_STATE_CHANGE_AS4 = 5
SUBTYPE_BGP4MP_MESSAGE_LOCAL = 6
SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL = 7
SUBTYPE_BGP4MP_MESSAGE_ADDPATH = 8
SUBTYPE_BGP4MP_MESSAGE_AS4_ADDPATH = 9
SUBTYPE_BGP4MP_MESSAGE_LOCAL_ADDPATH = 10
SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH = 11
@Bgp4MpMrtMessage.register_type(