1 # Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 Library for reading/writing MRT (Multi-Threaded Routing Toolkit) Routing
18 Information Export Format [RFC6396].
29 from ryu.lib import addrconv
30 from ryu.lib import ip
31 from ryu.lib import stringify
32 from ryu.lib import type_desc
33 from ryu.lib.packet import bgp
34 from ryu.lib.packet import ospf
37 LOG = logging.getLogger(__name__)
40 @six.add_metaclass(abc.ABCMeta)
41 class MrtRecord(stringify.StringifyMixin, type_desc.TypeDisp):
45 _HEADER_FMT = '!IHHI' # the same as MRT Common Header
46 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
47 MESSAGE_CLS = None # parser class for message field
52 TYPE_TABLE_DUMP_V2 = 13
60 # List of MRT type using Extended Timestamp MRT Header
61 _EXT_TS_TYPES = [TYPE_BGP4MP_ET, TYPE_ISIS_ET, TYPE_OSPFv3_ET]
63 def __init__(self, message, timestamp=None, type_=None, subtype=None,
65 assert issubclass(message.__class__, MrtMessage)
66 self.message = message
67 self.timestamp = timestamp
69 type_ = self._rev_lookup_type(self.__class__)
72 subtype = self.MESSAGE_CLS._rev_lookup_type(message.__class__)
73 self.subtype = subtype
77 def parse_common_header(cls, buf):
78 header_fields = struct.unpack_from(
81 return list(header_fields), buf[cls.HEADER_SIZE:]
84 def parse_extended_header(cls, buf):
85 # If extended header field exist, override this in subclass.
89 def parse_pre(cls, buf):
90 buf = six.binary_type(buf) # for convenience
92 header_fields, _ = cls.parse_common_header(buf)
93 # timestamp = header_fields[0]
94 type_ = header_fields[1]
95 # subtype = header_fields[2]
96 length = header_fields[3]
97 if type_ in cls._EXT_TS_TYPES:
98 header_cls = ExtendedTimestampMrtRecord
100 header_cls = MrtCommonRecord
102 required_len = header_cls.HEADER_SIZE + length
108 buf = six.binary_type(buf) # for convenience
110 header_fields, rest = cls.parse_common_header(buf)
111 # timestamp = header_fields[0]
112 type_ = header_fields[1]
113 subtype = header_fields[2]
114 length = header_fields[3]
116 sub_cls = MrtRecord._lookup_type(type_)
117 extended_headers, rest = sub_cls.parse_extended_header(rest)
118 header_fields.extend(extended_headers)
120 msg_cls = sub_cls.MESSAGE_CLS._lookup_type(subtype)
121 message_bin = rest[:length]
122 message = msg_cls.parse(message_bin)
124 return sub_cls(message, *header_fields), rest[length:]
127 def serialize_header(self):
131 if self.timestamp is None:
132 self.timestamp = int(time.time())
134 buf = self.message.serialize()
136 self.length = len(buf) # fixup
138 return self.serialize_header() + buf
141 class MrtCommonRecord(MrtRecord):
143 MRT record using MRT Common Header.
146 # 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
147 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
149 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
154 # | Message... (variable) |
155 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
156 _HEADER_FMT = '!IHHI'
157 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
159 def serialize_header(self):
160 return struct.pack(self._HEADER_FMT,
162 self.type, self.subtype,
166 class ExtendedTimestampMrtRecord(MrtRecord):
168 MRT record using Extended Timestamp MRT Header.
171 # 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
172 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
178 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179 # | Microsecond Timestamp |
180 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
181 # | Message... (variable) |
182 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
183 _HEADER_FMT = '!IHHII'
184 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
185 _EXT_HEADER_FMT = '!I'
186 EXT_HEADER_SIZE = struct.calcsize(_EXT_HEADER_FMT)
188 def __init__(self, message, timestamp=None, type_=None, subtype=None,
189 ms_timestamp=None, length=None):
190 super(ExtendedTimestampMrtRecord, self).__init__(
191 message, timestamp, type_, subtype, length)
192 self.ms_timestamp = ms_timestamp
195 def parse_extended_header(cls, buf):
196 (ms_timestamp,) = struct.unpack_from(cls._EXT_HEADER_FMT, buf)
198 return [ms_timestamp], buf[cls.EXT_HEADER_SIZE:]
200 def serialize_header(self):
201 return struct.pack(self._HEADER_FMT,
203 self.type, self.subtype,
208 @six.add_metaclass(abc.ABCMeta)
209 class MrtMessage(stringify.StringifyMixin, type_desc.TypeDisp):
211 MRT Message in record.
224 class UnknownMrtMessage(MrtMessage):
226 MRT Message for the UNKNOWN Type.
229 def __init__(self, buf):
240 # Registers self to unknown(default) type
241 UnknownMrtMessage._UNKNOWN_TYPE = UnknownMrtMessage
244 @MrtRecord.register_unknown_type()
245 class UnknownMrtRecord(MrtCommonRecord):
247 MRT record for the UNKNOWN Type.
249 MESSAGE_CLS = UnknownMrtMessage
252 class Ospf2MrtMessage(MrtMessage):
254 MRT Message for the OSPFv2 Type.
257 # 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
258 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
259 # | Remote IP Address |
260 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
261 # | Local IP Address |
262 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
263 # | OSPF Message Contents (variable) |
264 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
265 _HEADER_FMT = '!4s4s'
266 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
274 def __init__(self, remote_ip, local_ip, ospf_message):
275 self.remote_ip = remote_ip
276 self.local_ip = local_ip
277 assert isinstance(ospf_message, ospf.OSPFMessage)
278 self.ospf_message = ospf_message
282 (remote_ip, local_ip) = struct.unpack_from(cls._HEADER_FMT, buf)
283 remote_ip = addrconv.ipv4.bin_to_text(remote_ip)
284 local_ip = addrconv.ipv4.bin_to_text(local_ip)
285 ospf_message, _, _ = ospf.OSPFMessage.parser(buf[cls.HEADER_SIZE:])
287 return cls(remote_ip, local_ip, ospf_message)
290 return (addrconv.ipv4.text_to_bin(self.remote_ip)
291 + addrconv.ipv4.text_to_bin(self.local_ip)
292 + self.ospf_message.serialize())
295 @MrtRecord.register_type(MrtRecord.TYPE_OSPFv2)
296 class Ospf2MrtRecord(MrtCommonRecord):
298 MRT Record for the OSPFv2 Type.
300 MESSAGE_CLS = Ospf2MrtMessage
302 def __init__(self, message, timestamp=None, type_=None, subtype=0,
304 super(Ospf2MrtRecord, self).__init__(
305 message=message, timestamp=timestamp, type_=type_,
306 subtype=subtype, length=length)
309 # Registers self to unknown(default) type
310 Ospf2MrtMessage._UNKNOWN_TYPE = Ospf2MrtMessage
313 @six.add_metaclass(abc.ABCMeta)
314 class TableDumpMrtMessage(MrtMessage):
316 MRT Message for the TABLE_DUMP Type.
319 # 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
320 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
321 # | View Number | Sequence Number |
322 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
323 # | Prefix (variable) |
324 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
325 # | Prefix Length | Status |
326 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
327 # | Originated Time |
328 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
329 # | Peer IP Address (variable) |
330 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331 # | Peer AS | Attribute Length |
332 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
333 # | BGP Attribute... (variable)
334 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
335 _HEADER_FMT = '' # should be defined in subclass
344 def __init__(self, view_num, seq_num, prefix, prefix_len, status,
345 originated_time, peer_ip, peer_as, bgp_attributes,
347 self.view_num = view_num
348 self.seq_num = seq_num
350 self.prefix_len = prefix_len
351 # Status in the TABLE_DUMP Type SHOULD be set to 1
354 self.originated_time = originated_time
355 self.peer_ip = peer_ip
356 self.peer_as = peer_as
357 self.attr_len = attr_len
358 assert isinstance(bgp_attributes, (list, tuple))
359 for attr in bgp_attributes:
360 assert isinstance(attr, bgp._PathAttribute)
361 self.bgp_attributes = bgp_attributes
365 (view_num, seq_num, prefix, prefix_len, status, originated_time,
366 peer_ip, peer_as, attr_len) = struct.unpack_from(cls._HEADER_FMT, buf)
367 prefix = ip.bin_to_text(prefix)
368 peer_ip = ip.bin_to_text(peer_ip)
370 bgp_attr_bin = buf[cls.HEADER_SIZE:cls.HEADER_SIZE + attr_len]
373 attr, bgp_attr_bin = bgp._PathAttribute.parser(bgp_attr_bin)
374 bgp_attributes.append(attr)
376 return cls(view_num, seq_num, prefix, prefix_len, status,
377 originated_time, peer_ip, peer_as, bgp_attributes,
381 bgp_attrs_bin = bytearray()
382 for attr in self.bgp_attributes:
383 bgp_attrs_bin += attr.serialize()
384 self.attr_len = len(bgp_attrs_bin) # fixup
386 prefix = ip.text_to_bin(self.prefix)
387 peer_ip = ip.text_to_bin(self.peer_ip)
389 return struct.pack(self._HEADER_FMT,
390 self.view_num, self.seq_num,
392 self.prefix_len, self.status,
393 self.originated_time,
395 self.peer_as, self.attr_len) + bgp_attrs_bin
398 @MrtRecord.register_type(MrtRecord.TYPE_TABLE_DUMP)
399 class TableDumpMrtRecord(MrtCommonRecord):
401 MRT Record for the TABLE_DUMP Type.
403 MESSAGE_CLS = TableDumpMrtMessage
410 @TableDumpMrtMessage.register_type(TableDumpMrtRecord.SUBTYPE_AFI_IPv4)
411 class TableDumpAfiIPv4MrtMessage(TableDumpMrtMessage):
413 MRT Message for the TABLE_DUMP Type and the AFI_IPv4 subtype.
415 _HEADER_FMT = '!HH4sBBI4sHH'
416 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
419 @TableDumpMrtMessage.register_type(TableDumpMrtRecord.SUBTYPE_AFI_IPv6)
420 class TableDumpAfiIPv6MrtMessage(TableDumpMrtMessage):
422 MRT Message for the TABLE_DUMP Type and the AFI_IPv6 subtype.
424 _HEADER_FMT = '!HH16sBBI16sHH'
425 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
428 @six.add_metaclass(abc.ABCMeta)
429 class TableDump2MrtMessage(MrtMessage):
431 MRT Message for the TABLE_DUMP_V2 Type.
435 @MrtRecord.register_type(MrtRecord.TYPE_TABLE_DUMP_V2)
436 class TableDump2MrtRecord(MrtCommonRecord):
437 MESSAGE_CLS = TableDump2MrtMessage
440 SUBTYPE_PEER_INDEX_TABLE = 1
441 SUBTYPE_RIB_IPV4_UNICAST = 2
442 SUBTYPE_RIB_IPV4_MULTICAST = 3
443 SUBTYPE_RIB_IPV6_UNICAST = 4
444 SUBTYPE_RIB_IPV6_MULTICAST = 5
445 SUBTYPE_RIB_GENERIC = 6
446 SUBTYPE_RIB_IPV4_UNICAST_ADDPATH = 8
447 SUBTYPE_RIB_IPV4_MULTICAST_ADDPATH = 9
448 SUBTYPE_RIB_IPV6_UNICAST_ADDPATH = 10
449 SUBTYPE_RIB_IPV6_MULTICAST_ADDPATH = 11
450 SUBTYPE_RIB_GENERIC_ADDPATH = 12
453 @TableDump2MrtMessage.register_type(
454 TableDump2MrtRecord.SUBTYPE_PEER_INDEX_TABLE)
455 class TableDump2PeerIndexTableMrtMessage(TableDump2MrtMessage):
457 MRT Message for the TABLE_DUMP_V2 Type and the PEER_INDEX_TABLE subtype.
460 # 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
461 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
462 # | Collector BGP ID |
463 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
464 # | View Name Length | View Name (variable) |
465 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
466 # | Peer Count | Peer Entries (variable)
467 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
469 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
470 _PEER_COUNT_FMT = '!H'
471 PEER_COUNT_SIZE = struct.calcsize(_PEER_COUNT_FMT)
478 def __init__(self, bgp_id, peer_entries,
479 view_name='', view_name_len=None, peer_count=None):
481 assert isinstance(peer_entries, (list, tuple))
482 for p in peer_entries:
483 assert isinstance(p, MrtPeer)
484 self.peer_entries = peer_entries
485 assert isinstance(view_name, str)
486 self.view_name = view_name
487 self.view_name_len = view_name_len
488 self.peer_count = peer_count
492 (bgp_id, view_name_len) = struct.unpack_from(cls._HEADER_FMT, buf)
493 bgp_id = addrconv.ipv4.bin_to_text(bgp_id)
494 offset = cls.HEADER_SIZE
496 (view_name,) = struct.unpack_from('!%ds' % view_name_len, buf, offset)
497 view_name = str(view_name.decode('utf-8'))
498 offset += view_name_len
500 (peer_count,) = struct.unpack_from(cls._PEER_COUNT_FMT, buf, offset)
501 offset += cls.PEER_COUNT_SIZE
505 for i in range(peer_count):
506 p, rest = MrtPeer.parse(rest)
507 peer_entries.insert(i, p)
509 return cls(bgp_id, peer_entries, view_name, view_name_len, peer_count)
512 view_name = self.view_name.encode('utf-8')
513 self.view_name_len = len(view_name) # fixup
515 self.peer_count = len(self.peer_entries) # fixup
517 buf = struct.pack(self._HEADER_FMT,
518 addrconv.ipv4.text_to_bin(self.bgp_id),
519 self.view_name_len) + view_name
521 buf += struct.pack(self._PEER_COUNT_FMT,
524 for p in self.peer_entries:
530 class MrtPeer(stringify.StringifyMixin):
535 # 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
536 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
540 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541 # | Peer IP Address (variable) |
542 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
543 # | Peer AS (variable) |
544 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
546 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
555 # Bit 6: Peer AS number size: 0 = 2 bytes, 1 = 4 bytes
556 # Bit 7: Peer IP Address family: 0 = IPv4(4 bytes), 1 = IPv6(16 bytes)
557 IP_ADDR_FAMILY_BIT = 1 << 0
558 AS_NUMBER_SIZE_BIT = 1 << 1
567 def __init__(self, bgp_id, ip_addr, as_num, type_=0):
570 self.ip_addr = ip_addr
575 (type_, bgp_id) = struct.unpack_from(cls._HEADER_FMT, buf)
576 bgp_id = addrconv.ipv4.bin_to_text(bgp_id)
577 offset = cls.HEADER_SIZE
579 if type_ & cls.IP_ADDR_FAMILY_BIT:
580 # IPv6 address family
583 # IPv4 address family
585 ip_addr = ip.bin_to_text(buf[offset:offset + ip_addr_len])
586 offset += ip_addr_len
588 if type_ & cls.AS_NUMBER_SIZE_BIT:
589 # Four octet AS number
590 (as_num,) = struct.unpack_from('!I', buf, offset)
593 # Two octet AS number
594 (as_num,) = struct.unpack_from('!H', buf, offset)
597 return cls(bgp_id, ip_addr, as_num, type_), buf[offset:]
600 if ip.valid_ipv6(self.ip_addr):
601 # Sets Peer IP Address family bit to IPv6
602 self.type |= self.IP_ADDR_FAMILY_BIT
603 ip_addr = ip.text_to_bin(self.ip_addr)
605 if self.type & self.AS_NUMBER_SIZE_BIT or self.as_num > 0xffff:
606 # Four octet AS number
607 self.type |= self.AS_NUMBER_SIZE_BIT
608 as_num = struct.pack('!I', self.as_num)
610 # Two octet AS number
611 as_num = struct.pack('!H', self.as_num)
613 buf = struct.pack(self._HEADER_FMT,
615 addrconv.ipv4.text_to_bin(self.bgp_id))
617 return buf + ip_addr + as_num
620 @six.add_metaclass(abc.ABCMeta)
621 class TableDump2AfiSafiSpecificRibMrtMessage(TableDump2MrtMessage):
623 MRT Message for the TABLE_DUMP_V2 Type and the AFI/SAFI-specific
626 The AFI/SAFI-specific RIB subtypes consist of the RIB_IPV4_UNICAST,
627 RIB_IPV4_MULTICAST, RIB_IPV6_UNICAST, RIB_IPV6_MULTICAST and their
628 additional-path version subtypes.
631 # 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
632 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
633 # | Sequence Number |
634 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
636 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
637 # | Prefix (variable) |
638 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
639 # | Entry Count | RIB Entries (variable)
640 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
642 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
644 # Parser class to parse the Prefix field
645 _PREFIX_CLS = None # should be defined in subclass
647 # Is additional-path version?
650 def __init__(self, seq_num, prefix, rib_entries, entry_count=None):
651 self.seq_num = seq_num
652 assert isinstance(prefix, self._PREFIX_CLS)
654 self.entry_count = entry_count
655 assert isinstance(rib_entries, (list, tuple))
656 for rib_entry in rib_entries:
657 assert isinstance(rib_entry, MrtRibEntry)
658 self.rib_entries = rib_entries
661 def parse_rib_entries(cls, buf):
662 (entry_count,) = struct.unpack_from('!H', buf)
666 for i in range(entry_count):
667 r, rest = MrtRibEntry.parse(rest, is_addpath=cls._IS_ADDPATH)
668 rib_entries.insert(i, r)
670 return entry_count, rib_entries, rest
674 (seq_num,) = struct.unpack_from(cls._HEADER_FMT, buf)
675 rest = buf[cls.HEADER_SIZE:]
677 prefix, rest = cls._PREFIX_CLS.parser(rest)
679 entry_count, rib_entries, _ = cls.parse_rib_entries(rest)
681 return cls(seq_num, prefix, rib_entries, entry_count)
683 def serialize_rib_entries(self):
684 self.entry_count = len(self.rib_entries) # fixup
686 rib_entries_bin = bytearray()
687 for r in self.rib_entries:
688 rib_entries_bin += r.serialize()
690 return struct.pack('!H', self.entry_count) + rib_entries_bin
693 prefix_bin = self.prefix.serialize()
695 rib_bin = self.serialize_rib_entries() # entry_count + rib_entries
697 return struct.pack(self._HEADER_FMT,
698 self.seq_num) + prefix_bin + rib_bin
701 @TableDump2MrtMessage.register_type(
702 TableDump2MrtRecord.SUBTYPE_RIB_IPV4_UNICAST)
703 class TableDump2RibIPv4UnicastMrtMessage(
704 TableDump2AfiSafiSpecificRibMrtMessage):
706 MRT Message for the TABLE_DUMP_V2 Type and the
707 SUBTYPE_RIB_IPV4_UNICAST subtype.
709 _PREFIX_CLS = bgp.IPAddrPrefix
712 @TableDump2MrtMessage.register_type(
713 TableDump2MrtRecord.SUBTYPE_RIB_IPV4_MULTICAST)
714 class TableDump2RibIPv4MulticastMrtMessage(
715 TableDump2AfiSafiSpecificRibMrtMessage):
717 MRT Message for the TABLE_DUMP_V2 Type and the
718 SUBTYPE_RIB_IPV4_MULTICAST subtype.
720 _PREFIX_CLS = bgp.IPAddrPrefix
723 @TableDump2MrtMessage.register_type(
724 TableDump2MrtRecord.SUBTYPE_RIB_IPV6_UNICAST)
725 class TableDump2RibIPv6UnicastMrtMessage(
726 TableDump2AfiSafiSpecificRibMrtMessage):
728 MRT Message for the TABLE_DUMP_V2 Type and the
729 SUBTYPE_RIB_IPV6_MULTICAST subtype.
731 _PREFIX_CLS = bgp.IP6AddrPrefix
734 @TableDump2MrtMessage.register_type(
735 TableDump2MrtRecord.SUBTYPE_RIB_IPV6_MULTICAST)
736 class TableDump2RibIPv6MulticastMrtMessage(
737 TableDump2AfiSafiSpecificRibMrtMessage):
739 MRT Message for the TABLE_DUMP_V2 Type and the
740 SUBTYPE_RIB_IPV6_MULTICAST subtype.
742 _PREFIX_CLS = bgp.IP6AddrPrefix
745 @TableDump2MrtMessage.register_type(
746 TableDump2MrtRecord.SUBTYPE_RIB_IPV4_UNICAST_ADDPATH)
747 class TableDump2RibIPv4UnicastAddPathMrtMessage(
748 TableDump2AfiSafiSpecificRibMrtMessage):
750 MRT Message for the TABLE_DUMP_V2 Type and the
751 SUBTYPE_RIB_IPV4_UNICAST_ADDPATH subtype.
753 _PREFIX_CLS = bgp.IPAddrPrefix
757 @TableDump2MrtMessage.register_type(
758 TableDump2MrtRecord.SUBTYPE_RIB_IPV4_MULTICAST_ADDPATH)
759 class TableDump2RibIPv4MulticastAddPathMrtMessage(
760 TableDump2AfiSafiSpecificRibMrtMessage):
762 MRT Message for the TABLE_DUMP_V2 Type and the
763 SUBTYPE_RIB_IPV4_MULTICAST_ADDPATH subtype.
765 _PREFIX_CLS = bgp.IPAddrPrefix
769 @TableDump2MrtMessage.register_type(
770 TableDump2MrtRecord.SUBTYPE_RIB_IPV6_UNICAST_ADDPATH)
771 class TableDump2RibIPv6UnicastAddPathMrtMessage(
772 TableDump2AfiSafiSpecificRibMrtMessage):
774 MRT Message for the TABLE_DUMP_V2 Type and the
775 SUBTYPE_RIB_IPV6_UNICAST_ADDPATH subtype.
777 _PREFIX_CLS = bgp.IP6AddrPrefix
781 @TableDump2MrtMessage.register_type(
782 TableDump2MrtRecord.SUBTYPE_RIB_IPV6_MULTICAST_ADDPATH)
783 class TableDump2RibIPv6MulticastAddPathMrtMessage(
784 TableDump2AfiSafiSpecificRibMrtMessage):
786 MRT Message for the TABLE_DUMP_V2 Type and the
787 SUBTYPE_RIB_IPV6_MULTICAST_ADDPATH subtype.
789 _PREFIX_CLS = bgp.IP6AddrPrefix
793 @TableDump2MrtMessage.register_type(
794 TableDump2MrtRecord.SUBTYPE_RIB_GENERIC)
795 class TableDump2RibGenericMrtMessage(TableDump2MrtMessage):
797 MRT Message for the TABLE_DUMP_V2 Type and the generic RIB subtypes.
799 The generic RIB subtypes consist of the RIB_GENERIC and
800 RIB_GENERIC_ADDPATH subtypes.
803 # 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
804 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
805 # | Sequence Number |
806 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
807 # | Address Family Identifier |Subsequent AFI |
808 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
809 # | Network Layer Reachability Information (variable) |
810 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
811 # | Entry Count | RIB Entries (variable)
812 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
814 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
816 # Is additional-path version?
819 def __init__(self, seq_num, afi, safi, nlri, rib_entries,
821 self.seq_num = seq_num
824 assert isinstance(nlri, bgp._AddrPrefix)
826 self.entry_count = entry_count
827 assert isinstance(rib_entries, (list, tuple))
828 for rib_entry in rib_entries:
829 assert isinstance(rib_entry, MrtRibEntry)
830 self.rib_entries = rib_entries
833 def parse_rib_entries(cls, buf):
834 (entry_count,) = struct.unpack_from('!H', buf)
838 for i in range(entry_count):
839 r, rest = MrtRibEntry.parse(rest, is_addpath=cls._IS_ADDPATH)
840 rib_entries.insert(i, r)
842 return entry_count, rib_entries, rest
846 (seq_num, afi, safi) = struct.unpack_from(cls._HEADER_FMT, buf)
847 rest = buf[cls.HEADER_SIZE:]
849 nlri, rest = bgp.BGPNLRI.parser(rest)
851 entry_count, rib_entries, _ = cls.parse_rib_entries(rest)
853 return cls(seq_num, afi, safi, nlri, rib_entries, entry_count)
855 def serialize_rib_entries(self):
856 self.entry_count = len(self.rib_entries) # fixup
858 rib_entries_bin = bytearray()
859 for r in self.rib_entries:
860 rib_entries_bin += r.serialize()
862 return struct.pack('!H', self.entry_count) + rib_entries_bin
865 nlri_bin = self.nlri.serialize()
867 rib_bin = self.serialize_rib_entries() # entry_count + rib_entries
869 return struct.pack(self._HEADER_FMT,
871 self.afi, self.safi) + nlri_bin + rib_bin
874 @TableDump2MrtMessage.register_type(
875 TableDump2MrtRecord.SUBTYPE_RIB_GENERIC_ADDPATH)
876 class TableDump2RibGenericAddPathMrtMessage(TableDump2RibGenericMrtMessage):
878 MRT Message for the TABLE_DUMP_V2 Type and the RIB_GENERIC_ADDPATH
884 class MrtRibEntry(stringify.StringifyMixin):
889 # 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
890 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
892 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
893 # | Originated Time |
894 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
895 # | (Path Identifier) |
896 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
897 # | Attribute Length |
898 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
899 # | BGP Attributes... (variable)
900 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
901 # peer_index, originated_time, attr_len
903 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
904 # peer_index, originated_time, path_id, attr_len
905 _HEADER_FMT_ADDPATH = '!HIIH'
906 HEADER_SIZE_ADDPATH = struct.calcsize(_HEADER_FMT_ADDPATH)
908 def __init__(self, peer_index, originated_time, bgp_attributes,
909 attr_len=None, path_id=None):
910 self.peer_index = peer_index
911 self.originated_time = originated_time
912 assert isinstance(bgp_attributes, (list, tuple))
913 for attr in bgp_attributes:
914 assert isinstance(attr, bgp._PathAttribute)
915 self.bgp_attributes = bgp_attributes
916 self.attr_len = attr_len
917 self.path_id = path_id
920 def parse(cls, buf, is_addpath=False):
923 (peer_index, originated_time,
924 attr_len) = struct.unpack_from(cls._HEADER_FMT, buf)
925 _header_size = cls.HEADER_SIZE
927 (peer_index, originated_time, path_id,
928 attr_len) = struct.unpack_from(cls._HEADER_FMT_ADDPATH, buf)
929 _header_size = cls.HEADER_SIZE_ADDPATH
931 bgp_attr_bin = buf[_header_size:_header_size + attr_len]
934 attr, bgp_attr_bin = bgp._PathAttribute.parser(bgp_attr_bin)
935 bgp_attributes.append(attr)
937 return cls(peer_index, originated_time, bgp_attributes,
938 attr_len, path_id), buf[_header_size + attr_len:]
941 bgp_attrs_bin = bytearray()
942 for attr in self.bgp_attributes:
943 bgp_attrs_bin += attr.serialize()
944 self.attr_len = len(bgp_attrs_bin) # fixup
946 if self.path_id is None:
947 return struct.pack(self._HEADER_FMT,
949 self.originated_time,
950 self.attr_len) + bgp_attrs_bin
952 return struct.pack(self._HEADER_FMT_ADDPATH,
954 self.originated_time,
956 self.attr_len) + bgp_attrs_bin
959 @six.add_metaclass(abc.ABCMeta)
960 class Bgp4MpMrtMessage(MrtMessage):
962 MRT Message for the BGP4MP Type.
972 @MrtRecord.register_type(MrtRecord.TYPE_BGP4MP)
973 class Bgp4MpMrtRecord(MrtCommonRecord):
974 MESSAGE_CLS = Bgp4MpMrtMessage
977 SUBTYPE_BGP4MP_STATE_CHANGE = 0
978 SUBTYPE_BGP4MP_MESSAGE = 1
979 SUBTYPE_BGP4MP_MESSAGE_AS4 = 4
980 SUBTYPE_BGP4MP_STATE_CHANGE_AS4 = 5
981 SUBTYPE_BGP4MP_MESSAGE_LOCAL = 6
982 SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL = 7
983 SUBTYPE_BGP4MP_MESSAGE_ADDPATH = 8
984 SUBTYPE_BGP4MP_MESSAGE_AS4_ADDPATH = 9
985 SUBTYPE_BGP4MP_MESSAGE_LOCAL_ADDPATH = 10
986 SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH = 11
989 @MrtRecord.register_type(MrtRecord.TYPE_BGP4MP_ET)
990 class Bgp4MpEtMrtRecord(ExtendedTimestampMrtRecord):
991 MESSAGE_CLS = Bgp4MpMrtMessage
994 SUBTYPE_BGP4MP_STATE_CHANGE = 0
995 SUBTYPE_BGP4MP_MESSAGE = 1
996 SUBTYPE_BGP4MP_MESSAGE_AS4 = 4
997 SUBTYPE_BGP4MP_STATE_CHANGE_AS4 = 5
998 SUBTYPE_BGP4MP_MESSAGE_LOCAL = 6
999 SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL = 7
1000 SUBTYPE_BGP4MP_MESSAGE_ADDPATH = 8
1001 SUBTYPE_BGP4MP_MESSAGE_AS4_ADDPATH = 9
1002 SUBTYPE_BGP4MP_MESSAGE_LOCAL_ADDPATH = 10
1003 SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH = 11
1006 @Bgp4MpMrtMessage.register_type(
1007 Bgp4MpMrtRecord.SUBTYPE_BGP4MP_STATE_CHANGE)
1008 class Bgp4MpStateChangeMrtMessage(Bgp4MpMrtMessage):
1010 MRT Message for the BGP4MP Type and the BGP4MP_STATE_CHANGE subtype.
1013 # 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
1014 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1015 # | Peer AS Number | Local AS Number |
1016 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1017 # | Interface Index | Address Family |
1018 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1019 # | Peer IP Address (variable) |
1020 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1021 # | Local IP Address (variable) |
1022 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1023 # | Old State | New State |
1024 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1025 _HEADER_FMT = '!HHHH'
1026 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
1027 _ADDRS_FMT = '!%ds%ds'
1029 STATES_SIZE = struct.calcsize(_STATES_FMT)
1036 STATE_OPEN_CONFIRM = 5
1037 STATE_ESTABLISHED = 6
1039 # Address Family types
1043 def __init__(self, peer_as, local_as, if_index,
1044 peer_ip, local_ip, old_state, new_state, afi=None):
1045 self.peer_as = peer_as
1046 self.local_as = local_as
1047 self.if_index = if_index
1049 self.peer_ip = peer_ip
1050 self.local_ip = local_ip
1051 self.old_state = old_state
1052 self.new_state = new_state
1055 def parse(cls, buf):
1056 (peer_as, local_as, if_index, afi) = struct.unpack_from(
1057 cls._HEADER_FMT, buf)
1058 offset = cls.HEADER_SIZE
1060 if afi == cls.AFI_IPv4:
1062 addrs_fmt = cls._ADDRS_FMT % (4, 4)
1063 elif afi == cls.AFI_IPv6:
1065 addrs_fmt = cls._ADDRS_FMT % (16, 16)
1067 raise struct.error('Unsupported address family: %d' % afi)
1069 (peer_ip, local_ip) = struct.unpack_from(addrs_fmt, buf, offset)
1070 peer_ip = ip.bin_to_text(peer_ip)
1071 local_ip = ip.bin_to_text(local_ip)
1072 offset += struct.calcsize(addrs_fmt)
1074 (old_state, new_state) = struct.unpack_from(
1075 cls._STATES_FMT, buf, offset)
1077 return cls(peer_as, local_as, if_index,
1078 peer_ip, local_ip, old_state, new_state, afi)
1080 def serialize(self):
1082 if ip.valid_ipv4(self.peer_ip) and ip.valid_ipv4(self.local_ip):
1083 self.afi = self.AFI_IPv4
1084 elif ip.valid_ipv6(self.peer_ip) and ip.valid_ipv6(self.local_ip):
1085 self.afi = self.AFI_IPv6
1088 'peer_ip and local_ip must be the same address family: '
1089 'peer_ip=%s, local_ip=%s' % (self.peer_ip, self.local_ip))
1091 buf = struct.pack(self._HEADER_FMT,
1092 self.peer_as, self.local_as,
1093 self.if_index, self.afi)
1095 buf += ip.text_to_bin(self.peer_ip)
1096 buf += ip.text_to_bin(self.local_ip)
1098 buf += struct.pack(self._STATES_FMT,
1099 self.old_state, self.new_state)
1104 @Bgp4MpMrtMessage.register_type(
1105 Bgp4MpMrtRecord.SUBTYPE_BGP4MP_MESSAGE)
1106 class Bgp4MpMessageMrtMessage(Bgp4MpMrtMessage):
1108 MRT Message for the BGP4MP Type and the BGP4MP_MESSAGE subtype.
1111 # 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
1112 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1113 # | Peer AS Number | Local AS Number |
1114 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1115 # | Interface Index | Address Family |
1116 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1117 # | Peer IP Address (variable) |
1118 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1119 # | Local IP Address (variable) |
1120 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1121 # | BGP Message... (variable)
1122 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1123 _HEADER_FMT = '!HHHH'
1124 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
1125 _ADDRS_FMT = '!%ds%ds'
1127 # Address Family types
1131 def __init__(self, peer_as, local_as, if_index,
1132 peer_ip, local_ip, bgp_message, afi=None):
1133 self.peer_as = peer_as
1134 self.local_as = local_as
1135 self.if_index = if_index
1136 self.peer_ip = peer_ip
1137 self.local_ip = local_ip
1138 assert isinstance(bgp_message, bgp.BGPMessage)
1139 self.bgp_message = bgp_message
1143 def parse(cls, buf):
1144 (peer_as, local_as, if_index, afi) = struct.unpack_from(
1145 cls._HEADER_FMT, buf)
1146 offset = cls.HEADER_SIZE
1148 if afi == cls.AFI_IPv4:
1150 addrs_fmt = cls._ADDRS_FMT % (4, 4)
1151 elif afi == cls.AFI_IPv6:
1153 addrs_fmt = cls._ADDRS_FMT % (16, 16)
1155 raise struct.error('Unsupported address family: %d' % afi)
1157 (peer_ip, local_ip) = struct.unpack_from(addrs_fmt, buf, offset)
1158 peer_ip = ip.bin_to_text(peer_ip)
1159 local_ip = ip.bin_to_text(local_ip)
1160 offset += struct.calcsize(addrs_fmt)
1163 bgp_message, _, _ = bgp.BGPMessage.parser(rest)
1165 return cls(peer_as, local_as, if_index,
1166 peer_ip, local_ip, bgp_message, afi)
1168 def serialize(self):
1170 if ip.valid_ipv4(self.peer_ip) and ip.valid_ipv4(self.local_ip):
1171 self.afi = self.AFI_IPv4
1172 elif ip.valid_ipv6(self.peer_ip) and ip.valid_ipv6(self.local_ip):
1173 self.afi = self.AFI_IPv6
1176 'peer_ip and local_ip must be the same address family: '
1177 'peer_ip=%s, local_ip=%s' % (self.peer_ip, self.local_ip))
1179 buf = struct.pack(self._HEADER_FMT,
1180 self.peer_as, self.local_as,
1181 self.if_index, self.afi)
1183 buf += ip.text_to_bin(self.peer_ip)
1184 buf += ip.text_to_bin(self.local_ip)
1186 buf += self.bgp_message.serialize()
1191 @Bgp4MpMrtMessage.register_type(
1192 Bgp4MpMrtRecord.SUBTYPE_BGP4MP_MESSAGE_AS4)
1193 class Bgp4MpMessageAs4MrtMessage(Bgp4MpMessageMrtMessage):
1195 MRT Message for the BGP4MP Type and the BGP4MP_MESSAGE_AS4 subtype.
1198 # 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
1199 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1200 # | Peer AS Number |
1201 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1202 # | Local AS Number |
1203 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1204 # | Interface Index | Address Family |
1205 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1206 # | Peer IP Address (variable) |
1207 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1208 # | Local IP Address (variable) |
1209 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1210 # | BGP Message... (variable)
1211 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1212 _HEADER_FMT = '!IIHH'
1213 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
1216 @Bgp4MpMrtMessage.register_type(
1217 Bgp4MpMrtRecord.SUBTYPE_BGP4MP_STATE_CHANGE_AS4)
1218 class Bgp4MpStateChangeAs4MrtMessage(Bgp4MpStateChangeMrtMessage):
1220 MRT Message for the BGP4MP Type and the BGP4MP_STATE_CHANGE_AS4 subtype.
1223 # 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
1224 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1225 # | Peer AS Number |
1226 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1227 # | Local AS Number |
1228 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1229 # | Interface Index | Address Family |
1230 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1231 # | Peer IP Address (variable) |
1232 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1233 # | Local IP Address (variable) |
1234 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1235 # | Old State | New State |
1236 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1237 _HEADER_FMT = '!IIHH'
1238 HEADER_SIZE = struct.calcsize(_HEADER_FMT)
1241 @Bgp4MpMrtMessage.register_type(
1242 Bgp4MpMrtRecord.SUBTYPE_BGP4MP_MESSAGE_LOCAL)
1243 class Bgp4MpMessageLocalMrtMessage(Bgp4MpMessageMrtMessage):
1245 MRT Message for the BGP4MP Type and the BGP4MP_MESSAGE_LOCAL subtype.
1249 @Bgp4MpMrtMessage.register_type(
1250 Bgp4MpMrtRecord.SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL)
1251 class Bgp4MpMessageAs4LocalMrtMessage(Bgp4MpMessageAs4MrtMessage):
1253 MRT Message for the BGP4MP Type and the BGP4MP_MESSAGE_AS4_LOCAL subtype.
1258 # Currently, Ryu does not provide the packet library for ISIS protocol.
1259 # Implement parser for ISIS MRT message.
1260 # class IsisMrtRecord(MrtCommonRecord):
1261 # class IsisMrtMessage(MrtMessage):
1265 # Currently, Ryu does not provide the packet library for OSPFv3 protocol.
1266 # Implement the parser for OSPFv3 MRT message.
1267 # class Ospf3MrtRecord(MrtCommonRecord):
1268 # class Ospf3MrtMessage(MrtMessage):
1271 class Reader(object):
1273 MRT format file reader.
1275 ========= ================================================
1276 Argument Description
1277 ========= ================================================
1278 f File object which reading MRT format file
1280 ========= ================================================
1285 from ryu.lib import mrtlib
1288 for record in mrtlib.Reader(
1289 bz2.BZ2File('rib.YYYYMMDD.hhmm.bz2', 'rb')):
1290 print("%d, %s" % (count, record))
1294 def __init__(self, f):
1301 header_buf = self._f.read(MrtRecord.HEADER_SIZE)
1302 if len(header_buf) < MrtRecord.HEADER_SIZE:
1303 raise StopIteration()
1305 # Hack to avoid eating memory up
1306 self._f.seek(-MrtRecord.HEADER_SIZE, 1)
1307 required_len = MrtRecord.parse_pre(header_buf)
1308 buf = self._f.read(required_len)
1309 record, _ = MrtRecord.parse(buf)
1313 # for Python 3 compatible
1323 class Writer(object):
1325 MRT format file writer.
1327 ========= ================================================
1328 Argument Description
1329 ========= ================================================
1330 f File object which writing MRT format file
1332 ========= ================================================
1338 from ryu.lib import mrtlib
1339 from ryu.lib.packet import bgp
1341 mrt_writer = mrtlib.Writer(
1342 bz2.BZ2File('rib.YYYYMMDD.hhmm.bz2', 'wb'))
1344 prefix = bgp.IPAddrPrefix(24, '10.0.0.0')
1346 rib_entry = mrtlib.MrtRibEntry(
1348 originated_time=int(time.time()),
1349 bgp_attributes=[bgp.BGPPathAttributeOrigin(0)])
1351 message = mrtlib.TableDump2RibIPv4UnicastMrtMessage(
1354 rib_entries=[rib_entry])
1356 record = mrtlib.TableDump2MrtRecord(
1359 mrt_writer.write(record)
1362 def __init__(self, f):
1365 def write(self, record):
1366 if not isinstance(record, MrtRecord):
1368 'record should be an instance of MrtRecord subclass')
1370 self._f.write(record.serialize())