1# $Id: mrt.py 29 2007-01-26 02:29:07Z jon.oberheide $
2# -*- coding: utf-8 -*-
3"""Multi-threaded Routing Toolkit."""
4from __future__ import absolute_import
5
6from . import dpkt
7from . import bgp
8
9# Multi-threaded Routing Toolkit
10# http://www.ietf.org/internet-drafts/draft-ietf-grow-mrt-03.txt
11
12# MRT Types
13NULL = 0
14START = 1
15DIE = 2
16I_AM_DEAD = 3
17PEER_DOWN = 4
18BGP = 5  # Deprecated by BGP4MP
19RIP = 6
20IDRP = 7
21RIPNG = 8
22BGP4PLUS = 9  # Deprecated by BGP4MP
23BGP4PLUS_01 = 10  # Deprecated by BGP4MP
24OSPF = 11
25TABLE_DUMP = 12
26BGP4MP = 16
27BGP4MP_ET = 17
28ISIS = 32
29ISIS_ET = 33
30OSPF_ET = 64
31
32# BGP4MP Subtypes
33BGP4MP_STATE_CHANGE = 0
34BGP4MP_MESSAGE = 1
35BGP4MP_ENTRY = 2
36BGP4MP_SNAPSHOT = 3
37BGP4MP_MESSAGE_32BIT_AS = 4
38
39# Address Family Types
40AFI_IPv4 = 1
41AFI_IPv6 = 2
42
43
44class MRTHeader(dpkt.Packet):
45    __hdr__ = (
46        ('ts', 'I', 0),
47        ('type', 'H', 0),
48        ('subtype', 'H', 0),
49        ('len', 'I', 0)
50    )
51
52
53class TableDump(dpkt.Packet):
54    __hdr__ = (
55        ('view', 'H', 0),
56        ('seq', 'H', 0),
57        ('prefix', 'I', 0),
58        ('prefix_len', 'B', 0),
59        ('status', 'B', 1),
60        ('originated_ts', 'I', 0),
61        ('peer_ip', 'I', 0),
62        ('peer_as', 'H', 0),
63        ('attr_len', 'H', 0)
64    )
65
66    def unpack(self, buf):
67        dpkt.Packet.unpack(self, buf)
68        plen = self.attr_len
69        l_ = []
70        while plen > 0:
71            attr = bgp.BGP.Update.Attribute(self.data)
72            self.data = self.data[len(attr):]
73            plen -= len(attr)
74            l_.append(attr)
75        self.attributes = l_
76
77
78class BGP4MPMessage(dpkt.Packet):
79    __hdr__ = (
80        ('src_as', 'H', 0),
81        ('dst_as', 'H', 0),
82        ('intf', 'H', 0),
83        ('family', 'H', AFI_IPv4),
84        ('src_ip', 'I', 0),
85        ('dst_ip', 'I', 0)
86    )
87
88
89class BGP4MPMessage_32(dpkt.Packet):
90    __hdr__ = (
91        ('src_as', 'I', 0),
92        ('dst_as', 'I', 0),
93        ('intf', 'H', 0),
94        ('family', 'H', AFI_IPv4),
95        ('src_ip', 'I', 0),
96        ('dst_ip', 'I', 0)
97    )
98
99
100def test_tabledump():
101    from binascii import unhexlify
102    buf_tabledump = unhexlify(
103        '0001'           # view
104        '0002'           # seq
105        '00000003'       # prefix
106        '04'             # prefix_len
107        '05'             # status
108        '00000006'       # originated_ts
109        '00000007'       # peer_ip
110        '0008'           # peer_as
111
112        '0002'           # attr_len
113    )
114    buf_attrs = unhexlify(
115        '01'  # flags
116        '01'  # type (ORIGIN)
117
118        '01'  # length
119        '02'  # Origin.type (INCOMPLETE)
120    )
121    buf = buf_tabledump + buf_attrs
122    table_dump = TableDump(buf)
123    assert table_dump.view == 1
124    assert table_dump.seq == 2
125    assert table_dump.prefix == 3
126    assert table_dump.prefix_len == 4
127    assert table_dump.status == 5
128    assert table_dump.originated_ts == 6
129    assert table_dump.peer_ip == 7
130    assert table_dump.peer_as == 8
131    assert table_dump.attr_len == 2
132
133    assert len(table_dump.attributes) == 1
134    attr = table_dump.attributes[0]
135    assert isinstance(attr, bgp.BGP.Update.Attribute)
136    assert isinstance(attr.data, bgp.BGP.Update.Attribute.Origin)
137