mrtparse-1.6/0000755000175000017500000000000013125764616013676 5ustar t2munet2mune00000000000000mrtparse-1.6/examples/0000755000175000017500000000000013125764616015514 5ustar t2munet2mune00000000000000mrtparse-1.6/examples/README.rst0000644000175000017500000004455513125763144017213 0ustar t2munet2mune00000000000000Example Scripts =============== print\_all.py ------------- Description ~~~~~~~~~~~ This script displays the contents of a MRT format data. Usage ~~~~~ :: print_all.py path_to_file Result ~~~~~~ :: --------------------------------------------------------------- MRT Header Timestamp: 1392828028(2014-02-20 01:40:28) Type: 16(BGP4MP) Subtype: 5(BGP4MP_STATE_CHANGE_AS4) Length: 24 BGP4MP_STATE_CHANGE_AS4 Peer AS Number: 100 Local AS Number: 64512 Interface Index: 0 Address Family: 1(AFI_IPv4) Peer IP Address: 192.168.1.21 Local IP Address: 192.168.1.100 Old State: 5(OpenConfirm) New State: 6(Established) --------------------------------------------------------------- MRT Header Timestamp: 1392828028(2014-02-20 01:40:28) Type: 16(BGP4MP) Subtype: 4(BGP4MP_MESSAGE_AS4) ... If error occurred, it displays data in byte as below. :: --------------------------------------------------------------- MRT Header Timestamp: 1442843462(2015-09-21 22:51:02) Type: 16(BGP4MP) Subtype: 5(BGP4MP_STATE_CHANGE_AS4) Length: 12 MRT Data Error: Unsupported AFI 8(Unknown) 00 00 00 00 00 00 00 00 00 01 00 08 ... --------------------------------------------------------------- MRT Header Timestamp: 1443251615(2015-09-26 16:13:35) Type: 16(BGP4MP) Subtype: 2(BGP4MP_ENTRY) Length: 80 MRT Data Error: Unsupported BGP4MP subtype 2(BGP4MP_ENTRY) fd e8 fd e8 00 00 00 01 c0 a8 01 66 c0 a8 01 0a 00 00 00 01 56 06 43 5f 00 01 01 04 c0 a8 00 0b 10 c0 a8 00 2b 40 01 01 00 40 02 04 02 01 fd f3 40 05 04 00 00 00 64 c0 07 08 00 00 fd e8 c0 a8 00 0b 80 09 04 c0 a8 00 0b 80 0a 04 c0 a8 00 0a mrt2exabgp.py (formerly exabgp\_conf.py) ---------------------------------------- Description ~~~~~~~~~~~ | This script converts MRT format to ExaBGP_ config/API format and displays it. | If you want to know how to use ExaBGP API, please read `the wiki`_. .. _ExaBGP: https://github.com/Exa-Networks/exabgp .. _`the wiki`: https://github.com/YoshiyukiYamauchi/mrtparse/wiki Usage ~~~~~ :: usage: mrt2exabgp.py [-h] [-r ROUTER_ID] [-l LOCAL_AS] [-p PEER_AS] [-L LOCAL_ADDR] [-n NEIGHBOR] [-4 [NEXT_HOP]] [-6 [NEXT_HOP]] [-a] [-s] [-A] [-G [NUM]] [-g [NUM]] [-P] path_to_file This script converts to ExaBGP format. positional arguments: path_to_file specify path to MRT format file optional arguments: -h, --help show this help message and exit -r ROUTER_ID specify router-id (default: 192.168.0.1) -l LOCAL_AS specify local AS number (default: 64512) -p PEER_AS specify peer AS number (default: 65000) -L LOCAL_ADDR specify local address (default: 192.168.1.1) -n NEIGHBOR specify neighbor address (default: 192.168.1.100) -4 [NEXT_HOP] convert IPv4 entries and change IPv4 next-hop if specified -6 [NEXT_HOP] convert IPv6 entries and change IPv6 next-hop if specified -a convert all entries (default: convert only first entry per one prefix) -s convert only entries from a single asn (the peer asn, specify as -p PEER_ASN) -A convert to ExaBGP API format -G [NUM] convert to ExaBGP API format and group updates with the same attributes for each spceified the number of prefixes using "announce attributes ..." syntax (default: 1000000) -g [NUM] convert to ExaBGP API format and group updates with the same attributes for each spceified the number of prefixes using "announce attribute ..." old syntax (default: 1000000) -P convert to ExaBGP API program Result (Config format) ~~~~~~~~~~~~~~~~~~~~~~ Without "-A"/"-G"/"-g"/"-P" options, it outputs a ExaBGP config. :: neighbor 192.168.1.1 { router-id 192.168.0.2; local-address 192.168.1.2; local-as 64512; peer-as 65000; graceful-restart; aigp enable; static { route 1.0.0.0/24 origin IGP as-path [57821 12586 13101 15169 ] community [12586:147 12586:13000 64587:13101] next-hop 192.168.1.254; route 1.0.4.0/24 origin IGP as-path [57821 6939 4826 56203 ] next-hop 192.168.1.254; route 1.0.5.0/24 origin IGP as-path [57821 6939 4826 56203 ] next-hop 192.168.1.254; route 1.0.6.0/24 origin IGP as-path [57821 6939 4826 56203 ] next-hop 192.168.1.254; route 1.0.7.0/24 origin IGP as-path [57821 6939 4826 56203 56203 56203 ] next-hop 192.168.1.254; route 1.0.64.0/18 origin IGP as-path [57821 6939 4725 4725 7670 7670 7670 18144 ] atomic-aggregate aggregator (18144:219.118.225.189) next-hop 192.168.1.254; route 1.0.128.0/17 origin IGP as-path [57821 12586 3257 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254; route 1.0.128.0/18 origin IGP as-path [57821 12586 3257 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254; ... } } Result in "-A" option (API format) ~~~~~~~~~~~~~~~~~~~ This option is possible to improve the performance in most cases. :: announce route 1.0.0.0/24 origin IGP as-path [57821 12586 13101 15169 ] community [12586:147 12586:13000 64587:13101] next-hop 192.168.1.254 announce route 1.0.4.0/24 origin IGP as-path [57821 6939 4826 56203 ] next-hop 192.168.1.254 announce route 1.0.5.0/24 origin IGP as-path [57821 6939 4826 56203 ] next-hop 192.168.1.254 announce route 1.0.6.0/24 origin IGP as-path [57821 6939 4826 56203 ] next-hop 192.168.1.254 announce route 1.0.7.0/24 origin IGP as-path [57821 6939 4826 56203 56203 56203 ] next-hop 192.168.1.254 announce route 1.0.64.0/18 origin IGP as-path [57821 6939 4725 4725 7670 7670 7670 18144 ] atomic-aggregate aggregator (18144:219.118.225.189) next-hop 192.168.1.254 announce route 1.0.128.0/17 origin IGP as-path [57821 12586 3257 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254 announce route 1.0.128.0/18 origin IGP as-path [57821 12586 3257 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254 ... Result in "-G" option (API grouping format) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | This option is possible to improve the performance, especially when advertising huge prefixes like full internet routes. | It outputs with "announce attributes ..." syntax. | If you use MRT format data included "BGP4MP" or "BGP4MP_ET", you must use this or "-g" option. | In that case "NUM" argument is ignored even if specified it. :: announce attributes origin IGP as-path [57821 6939 4826 56203 ] next-hop 192.168.1.254 nlri 1.0.4.0/24 1.0.5.0/24 1.0.6.0/24 103.2.176.0/24 103.2.177.0/24 103.2.178.0/24 103.2.179.0/24 announce attributes origin IGP as-path [57821 6939 4826 56203 56203 56203 ] next-hop 192.168.1.254 nlri 1.0.7.0/24 announce attributes origin IGP as-path [57821 6939 4725 4725 7670 7670 7670 18144 ] atomic-aggregate aggregator (18144:219.118.225.189) next-hop 192.168.1.254 nlri 1.0.64.0/18 58.183.0.0/16 222.231.64.0/18 announce attributes origin IGP as-path [57821 12586 3257 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254 nlri 1.0.128.0/17 1.0.128.0/18 1.0.192.0/18 1.2.128.0/17 1.4.128.0/17 1.4.128.0/18 1.179.128.0/17 101.51.0.0/16 101.51.64.0/18 113.53.0.0/16 113.53.0.0/18 118.172.0.0/16 118.173.0.0/16 118.173.192.0/18 118.174.0.0/16 118.175.0.0/16 118.175.0.0/18 125.25.0.0/16 125.25.128.0/18 180.180.0.0/16 182.52.0.0/16 182.52.0.0/17 182.52.128.0/18 182.53.0.0/16 182.53.0.0/18 182.53.192.0/18 announce attributes origin IGP as-path [4608 1221 4637 4651 9737 23969 ] next-hop 192.168.1.254 nlri 1.0.128.0/24 announce attributes origin IGP as-path [57821 12586 3257 1299 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254 nlri 1.0.160.0/19 1.0.224.0/19 118.173.64.0/19 118.173.192.0/19 118.174.128.0/19 118.174.192.0/19 118.175.160.0/19 125.25.0.0/19 125.25.128.0/19 182.53.0.0/19 203.113.0.0/19 203.113.96.0/19 announce attributes origin IGP as-path [57821 12586 3257 4134 ] community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254 nlri 1.1.8.0/24 36.106.0.0/16 36.108.0.0/16 36.109.0.0/16 101.248.0.0/16 106.0.4.0/22 106.7.0.0/16 118.85.204.0/24 118.85.215.0/24 120.88.8.0/21 122.198.64.0/18 171.44.0.0/16 183.91.56.0/24 183.91.57.0/24 202.80.192.0/22 221.231.151.0/24 announce attributes origin IGP as-path [57821 12586 13101 15412 17408 58730 ] community [12586:147 12586:13000 64587:13101] next-hop 192.168.1.254 nlri 1.1.32.0/24 1.2.1.0/24 1.10.8.0/24 14.0.7.0/24 27.34.239.0/24 27.109.63.0/24 36.37.0.0/24 42.0.8.0/24 49.128.2.0/24 49.246.249.0/24 101.102.104.0/24 106.3.174.0/24 118.91.255.0/24 123.108.143.0/24 180.200.252.0/24 183.182.9.0/24 202.6.6.0/24 202.12.98.0/24 202.85.202.0/24 202.131.63.0/24 211.155.79.0/24 211.156.109.0/24 218.98.224.0/24 218.246.137.0/24 ... Result in "-g" option (API grouping format) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | This option is possible to improve the performance, especially when advertising huge prefixes like full internet routes. | It outputs with "announce attribute ..." old syntax. | If you use MRT format data included "BGP4MP" or "BGP4MP_ET", you must use this or "-G" option. | In that case "NUM" argument is ignored even if specified it. :: announce attribute origin IGP as-path [57821 6939 4826 56203 ] next-hop 192.168.1.254 nlri 1.0.4.0/24 1.0.5.0/24 1.0.6.0/24 103.2.176.0/24 103.2.177.0/24 103.2.178.0/24 103.2.179.0/24 announce attribute origin IGP as-path [57821 6939 4826 56203 56203 56203 ] next-hop 192.168.1.254 nlri 1.0.7.0/24 announce attribute origin IGP as-path [57821 6939 4725 4725 7670 7670 7670 18144 ] atomic-aggregate aggregator (18144:219.118.225.189) next-hop 192.168.1.254 nlri 1.0.64.0/18 58.183.0.0/16 222.231.64.0/18 announce attribute origin IGP as-path [57821 12586 3257 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254 nlri 1.0.128.0/17 1.0.128.0/18 1.0.192.0/18 1.2.128.0/17 1.4.128.0/17 1.4.128.0/18 1.179.128.0/17 101.51.0.0/16 101.51.64.0/18 113.53.0.0/16 113.53.0.0/18 118.172.0.0/16 118.173.0.0/16 118.173.192.0/18 118.174.0.0/16 118.175.0.0/16 118.175.0.0/18 125.25.0.0/16 125.25.128.0/18 180.180.0.0/16 182.52.0.0/16 182.52.0.0/17 182.52.128.0/18 182.53.0.0/16 182.53.0.0/18 182.53.192.0/18 announce attribute origin IGP as-path [4608 1221 4637 4651 9737 23969 ] next-hop 192.168.1.254 nlri 1.0.128.0/24 announce attribute origin IGP as-path [57821 12586 3257 1299 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254 nlri 1.0.160.0/19 1.0.224.0/19 118.173.64.0/19 118.173.192.0/19 118.174.128.0/19 118.174.192.0/19 118.175.160.0/19 125.25.0.0/19 125.25.128.0/19 182.53.0.0/19 203.113.0.0/19 203.113.96.0/19 announce attribute origin IGP as-path [57821 12586 3257 4134 ] community [12586:145 12586:12000 64587:3257] next-hop 192.168.1.254 nlri 1.1.8.0/24 36.106.0.0/16 36.108.0.0/16 36.109.0.0/16 101.248.0.0/16 106.0.4.0/22 106.7.0.0/16 118.85.204.0/24 118.85.215.0/24 120.88.8.0/21 122.198.64.0/18 171.44.0.0/16 183.91.56.0/24 183.91.57.0/24 202.80.192.0/22 221.231.151.0/24 announce attribute origin IGP as-path [57821 12586 13101 15412 17408 58730 ] community [12586:147 12586:13000 64587:13101] next-hop 192.168.1.254 nlri 1.1.32.0/24 1.2.1.0/24 1.10.8.0/24 14.0.7.0/24 27.34.239.0/24 27.109.63.0/24 36.37.0.0/24 42.0.8.0/24 49.128.2.0/24 49.246.249.0/24 101.102.104.0/24 106.3.174.0/24 118.91.255.0/24 123.108.143.0/24 180.200.252.0/24 183.182.9.0/24 202.6.6.0/24 202.12.98.0/24 202.85.202.0/24 202.131.63.0/24 211.155.79.0/24 211.156.109.0/24 218.98.224.0/24 218.246.137.0/24 ... Result in "-P" option (API program format) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | This option is useful when using the same MRT data repeatedly. | It can be used together with "-G" or "-g" option. :: #!/usr/bin/env python import sys import time msgs = [ 'announce route 0.0.0.0/0 origin IGP as-path [8758 6830 ] community [8758:110 8758:300] next-hop 192.168.1.254', 'announce route 1.0.4.0/24 origin IGP as-path [50304 174 4637 1221 38803 56203 ] next-hop 192.168.1.254', 'announce route 1.0.5.0/24 origin IGP as-path [50304 174 4637 1221 38803 56203 ] next-hop 192.168.1.254', 'announce route 1.0.6.0/24 origin IGP as-path [50304 174 4637 1221 38803 56203 56203 56203 ] next-hop 192.168.1.254', 'announce route 1.0.38.0/24 origin IGP as-path [50304 10026 24155 ] next-hop 192.168.1.254', 'announce route 1.0.64.0/18 origin IGP as-path [50304 174 209 2516 7670 18144 ] atomic-aggregate aggregator (18144:219.118.225.188) next-hop 192.168.1.254', 'announce route 1.0.128.0/17 origin IGP as-path [50304 24482 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) next-hop 192.168.1.254', 'announce route 1.0.128.0/18 origin IGP as-path [50304 24482 38040 9737 ] atomic-aggregate aggregator (9737:203.113.12.254) next-hop 192.168.1.254', ... ] while msgs: msg = msgs.pop(0) if isinstance(msg, str): sys.stdout.write(msg + '\n') sys.stdout.flush() else: time.sleep(msg) while True: time.sleep(1) slice.py -------- Description ~~~~~~~~~~~ | This script outputs the following data of a MRT format file. | | 1. The data for the interval of the specified seconds from the specified start time to the specified end time. | 2. The data from the specified start time to the specified end time. | 3. The data for the interval of the specified seconds. Usage ~~~~~ :: usage: slice.py [-h] [-s START\_TIME] [-e END\_TIME] [-i INTERVAL] [-c {gz,bz2}] path_to_file This script slices MRT format data. positional arguments: path_to_file specify path to MRT format file optional arguments: -h, --help show this help message and exit -s START_TIME specify start time in format YYYY-MM-DD HH:MM:SS -e END_TIME specify end time in format YYYY-MM-DD HH:MM:SS -i INTERVAL specify interval in seconds -c {gz,bz2} specify compress type (gz, bz2) Result ~~~~~~ :: # slice.py -s '2015-04-26 03:26:00' -e '2014-04-26 03:27:00' -i 10 -c bz2 -f latest-update.gz # ls latest-update-20150426-032600.bz2 latest-update-20150426-032610.bz2 latest-update-20150426-032620.bz2 latest-update-20150426-032630.bz2 latest-update-20150426-032640.bz2 latest-update-20150426-032650.bz2 summary.py ---------- Description ~~~~~~~~~~~ This script displays the summary of a MRT format file. Usage ~~~~~ :: summary.py path_to_file Result ~~~~~~ :: [2014-08-11 03:45:00 - 2014-08-11 03:49:59] BGP4MP: 5973 BGP4MP_MESSAGE: 34 UPDATE: 24 KEEPALIVE: 10 BGP4MP_MESSAGE_AS4: 5896 UPDATE: 5825 KEEPALIVE: 71 BGP4MP_STATE_CHANGE_AS4: 43 Idle: 1 Connect: 20 Active: 18 OpenSent: 4 mrt2bgpdump.py -------------- Description ~~~~~~~~~~~ This script converts to bgpdump_ format. .. _bgpdump: https://bitbucket.org/ripencc/bgpdump/wiki/Home Usage ~~~~~ :: usage: mrt2bgpdump.py [-h] [-m] [-M] [-O [file]] [-s] [-v] [-t {dump,change}][-p] path_to_file This script converts to bgpdump format. positional arguments: path_to_file specify path to MRT format file optional arguments: -h, --help show this help message and exit -m one-line per entry with unix timestamps -M one-line per entry with human readable timestamps(default format) -O [file] output to a specified file -s output to STDOUT(default output) -v output to STDERR -t {dump,change} timestamps for RIB dumps reflect the time of the dump or the last route modification(default: dump) -p show packet index at second position Result ~~~~~~ :: BGP4MP|0|1438386900|A|193.0.0.56|3333|204.80.242.0/24|3333 1273 7922 33667 54169 54169 54169 54169 54169 54169 54169 54169|IGP|193.0.0.56|0|0|1273:21000|NAG|| BGP4MP|1|1438386900|A|2405:fc00::6|37989|2001:4c0:2001::/48|37989 4844 2914 174 855|IGP|2405:fc00::6|0|0||NAG|| BGP4MP|1|1438386900|A|2405:fc00::6|37989|2001:4c0:6002::/48|37989 4844 2914 174 855|IGP|2405:fc00::6|0|0||NAG|| BGP4MP|2|1438386900|A|146.228.1.3|1836|189.127.0.0/21|1836 174 12956 262589 27693|IGP|146.228.1.3|0|0|1836:110 1836:6000 1836:6031|NAG|27693 189.127.15.253| BGP4MP|4|1438386900|A|2405:fc00::6|37989|2406:e400:1a::/48|37989 4844 7642|INCOMPLETE|2405:fc00::6|0|0||NAG|| BGP4MP|5|1438386900|A|2001:8e0:0:ffff::9|8758|2c0f:fe90::/32|8758 174 2914 30844 37105 37105 37105 36943|IGP|2001:8e0:0:ffff::9|0|0|174:21100 174:22005 8758:110 8758:301|NAG|| BGP4MP|6|1438386900|A|213.200.87.254|3257|187.110.144.0/20|3257 174 16735 27693 53117|IGP|213.200.87.254|0|10|3257:8093 3257:30235 3257:50002 3257:51100 3257:51102|NAG|| BGP4MP|7|1438386900|A|213.200.87.254|3257|187.95.16.0/20|3257 174 16735 27693 53081|IGP|213.200.87.254|0|10|3257:8063 3257:30252 3257:50002 3257:51300 3257:51302|NAG|| BGP4MP|8|1438386900|A|213.200.87.254|3257|189.127.208.0/21|3257 174 16735 27693 28235|IGP|213.200.87.254|0|10|3257:8093 3257:30235 3257:50002 3257:51100 3257:51102|NAG|| BGP4MP|8|1438386900|A|213.200.87.254|3257|189.127.216.0/21|3257 174 16735 27693 28235|IGP|213.200.87.254|0|10|3257:8093 3257:30235 3257:50002 3257:51100 3257:51102|NAG|| ... Authors ------- | Tetsumune KISO t2mune@gmail.com | Yoshiyuki YAMAUCHI info@greenhippo.co.jp | Nobuhiro ITOU js333123@gmail.com License ------- | Licensed under the `Apache License, Version 2.0`_ | Copyright © 2017 Tetsumune KISO .. _`Apache License, Version 2.0`: http://www.apache.org/licenses/LICENSE-2.0 mrtparse-1.6/examples/mrt2bgpdump.py0000755000175000017500000002616413125763144020340 0ustar t2munet2mune00000000000000#!/usr/bin/env python ''' mrt2bgpdump.py - a script to convert MRT format to bgpdump format. Copyright (C) 2017 Tetsumune KISO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Authors: Tetsumune KISO Yoshiyuki YAMAUCHI Nobuhiro ITOU ''' import sys, argparse, copy from datetime import * from mrtparse import * peer = None def parse_args(): p = argparse.ArgumentParser( description='This script converts to bgpdump format.') p.add_argument( '-m', dest='verbose', default=False, action='store_true', help='one-line per entry with unix timestamps') p.add_argument( '-M', dest='verbose', action='store_false', help='one-line per entry with human readable timestamps(default format)') p.add_argument( '-O', dest='output', default=sys.stdout, nargs='?', metavar='file', type=argparse.FileType('w'), help='output to a specified file') p.add_argument( '-s', dest='output', action='store_const', const=sys.stdout, help='output to STDOUT(default output)') p.add_argument( '-v', dest='output', action='store_const', const=sys.stderr, help='output to STDERR') p.add_argument( '-t', dest='ts_format', default='dump', choices=['dump', 'change'], help='timestamps for RIB dumps reflect the time of the dump \ or the last route modification(default: dump)') p.add_argument( '-p', dest='pkt_num', default=False, action='store_true', help='show packet index at second position') p.add_argument( 'path_to_file', help='specify path to MRT format file') return p.parse_args() class BgpDump: __slots__ = [ 'verbose', 'output', 'ts_format', 'pkt_num', 'type', 'num', 'ts', 'org_time', 'flag', 'peer_ip', 'peer_as', 'nlri', 'withdrawn', 'as_path', 'origin', 'next_hop', 'local_pref', 'med', 'comm', 'atomic_aggr', 'aggr', 'as4_path', 'as4_aggr', 'old_state', 'new_state', ] def __init__(self, args): self.verbose = args.verbose self.output = args.output self.ts_format = args.ts_format self.pkt_num = args.pkt_num self.type = '' self.num = 0 self.ts = 0 self.org_time = 0 self.flag = '' self.peer_ip = '' self.peer_as = 0 self.nlri = [] self.withdrawn = [] self.as_path = [] self.origin = '' self.next_hop = [] self.local_pref = 0 self.med = 0 self.comm = '' self.atomic_aggr = 'NAG' self.aggr = '' self.as4_path = [] self.as4_aggr = '' self.old_state = 0 self.new_state = 0 def print_line(self, prefix, next_hop): if self.ts_format == 'dump': d = self.ts else: d = self.org_time if self.verbose: d = str(d) else: d = datetime.utcfromtimestamp(d).\ strftime('%m/%d/%y %H:%M:%S') if self.pkt_num == True: d = '%d|%s' % (self.num, d) if self.flag == 'B' or self.flag == 'A': self.output.write('%s|%s|%s|%s|%s|%s|%s|%s' % ( self.type, d, self.flag, self.peer_ip, self.peer_as, prefix, self.merge_as_path(), self.origin)) if self.verbose == True: self.output.write('|%s|%d|%d|%s|%s|%s|\n' % ( next_hop, self.local_pref, self.med, self.comm, self.atomic_aggr, self.merge_aggr())) else: self.output.write('\n') elif self.flag == 'W': self.output.write('%s|%s|%s|%s|%s|%s\n' % ( self.type, d, self.flag, self.peer_ip, self.peer_as, prefix)) elif self.flag == 'STATE': self.output.write('%s|%s|%s|%s|%s|%d|%d\n' % ( self.type, d, self.flag, self.peer_ip, self.peer_as, self.old_state, self.new_state)) def print_routes(self): for withdrawn in self.withdrawn: if self.type == 'BGP4MP': self.flag = 'W' self.print_line(withdrawn, '') for nlri in self.nlri: if self.type == 'BGP4MP': self.flag = 'A' for next_hop in self.next_hop: self.print_line(nlri, next_hop) def td(self, m, count): self.type = 'TABLE_DUMP' self.flag = 'B' self.ts = m.ts self.num = count self.org_time = m.td.org_time self.peer_ip = m.td.peer_ip self.peer_as = m.td.peer_as self.nlri.append('%s/%d' % (m.td.prefix, m.td.plen)) for attr in m.td.attr: self.bgp_attr(attr) self.print_routes() def td_v2(self, m): global peer self.type = 'TABLE_DUMP2' self.flag = 'B' self.ts = m.ts if m.subtype == TD_V2_ST['PEER_INDEX_TABLE']: peer = copy.copy(m.peer.entry) elif (m.subtype == TD_V2_ST['RIB_IPV4_UNICAST'] or m.subtype == TD_V2_ST['RIB_IPV4_MULTICAST'] or m.subtype == TD_V2_ST['RIB_IPV6_UNICAST'] or m.subtype == TD_V2_ST['RIB_IPV6_MULTICAST']): self.num = m.rib.seq self.nlri.append('%s/%d' % (m.rib.prefix, m.rib.plen)) for entry in m.rib.entry: self.org_time = entry.org_time self.peer_ip = peer[entry.peer_index].ip self.peer_as = peer[entry.peer_index].asn self.as_path = [] self.origin = '' self.next_hop = [] self.local_pref = 0 self.med = 0 self.comm = '' self.atomic_aggr = 'NAG' self.aggr = '' self.as4_path = [] self.as4_aggr = '' for attr in entry.attr: self.bgp_attr(attr) self.print_routes() def bgp4mp(self, m, count): self.type = 'BGP4MP' self.ts = m.ts self.num = count self.org_time = m.ts self.peer_ip = m.bgp.peer_ip self.peer_as = m.bgp.peer_as if (m.subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE'] or m.subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE_AS4']): self.flag = 'STATE' self.old_state = m.bgp.old_state self.new_state = m.bgp.new_state self.print_line([], '') elif (m.subtype == BGP4MP_ST['BGP4MP_MESSAGE'] or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4'] or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL'] or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4_LOCAL']): if m.bgp.msg.type != BGP_MSG_T['UPDATE']: return for attr in m.bgp.msg.attr: self.bgp_attr(attr) for withdrawn in m.bgp.msg.withdrawn: self.withdrawn.append( '%s/%d' % (withdrawn.prefix, withdrawn.plen)) for nlri in m.bgp.msg.nlri: self.nlri.append('%s/%d' % (nlri.prefix, nlri.plen)) self.print_routes() def bgp_attr(self, attr): if attr.type == BGP_ATTR_T['ORIGIN']: self.origin = ORIGIN_T[attr.origin] elif attr.type == BGP_ATTR_T['NEXT_HOP']: self.next_hop.append(attr.next_hop) elif attr.type == BGP_ATTR_T['AS_PATH']: self.as_path = [] for seg in attr.as_path: if seg['type'] == AS_PATH_SEG_T['AS_SET']: self.as_path.append('{%s}' % ','.join(seg['val'])) elif seg['type'] == AS_PATH_SEG_T['AS_CONFED_SEQUENCE']: self.as_path.append('(' + seg['val'][0]) self.as_path += seg['val'][1:-1] self.as_path.append(seg['val'][-1] + ')') elif seg['type'] == AS_PATH_SEG_T['AS_CONFED_SET']: self.as_path.append('[%s]' % ','.join(seg['val'])) else: self.as_path += seg['val'] elif attr.type == BGP_ATTR_T['MULTI_EXIT_DISC']: self.med = attr.med elif attr.type == BGP_ATTR_T['LOCAL_PREF']: self.local_pref = attr.local_pref elif attr.type == BGP_ATTR_T['ATOMIC_AGGREGATE']: self.atomic_aggr = 'AG' elif attr.type == BGP_ATTR_T['AGGREGATOR']: self.aggr = '%s %s' % (attr.aggr['asn'], attr.aggr['id']) elif attr.type == BGP_ATTR_T['COMMUNITY']: self.comm = ' '.join(attr.comm) elif attr.type == BGP_ATTR_T['MP_REACH_NLRI']: self.next_hop = attr.mp_reach['next_hop'] if self.type != 'BGP4MP': return for nlri in attr.mp_reach['nlri']: self.nlri.append('%s/%d' % (nlri.prefix, nlri.plen)) elif attr.type == BGP_ATTR_T['MP_UNREACH_NLRI']: if self.type != 'BGP4MP': return for withdrawn in attr.mp_unreach['withdrawn']: self.withdrawn.append( '%s/%d' % (withdrawn.prefix, withdrawn.plen)) elif attr.type == BGP_ATTR_T['AS4_PATH']: self.as4_path = [] for seg in attr.as4_path: if seg['type'] == AS_PATH_SEG_T['AS_SET']: self.as4_path.append('{%s}' % ','.join(seg['val'])) elif seg['type'] == AS_PATH_SEG_T['AS_CONFED_SEQUENCE']: self.as4_path.append('(' + seg['val'][0]) self.as4_path += seg['val'][1:-1] self.as4_path.append(seg['val'][-1] + ')') elif seg['type'] == AS_PATH_SEG_T['AS_CONFED_SET']: self.as4_path.append('[%s]' % ','.join(seg['val'])) else: self.as4_path += seg['val'] elif attr.type == BGP_ATTR_T['AS4_AGGREGATOR']: self.as4_aggr = '%d %s' % (attr.as4_aggr['asn'], attr.as4_aggr['ip']) def merge_as_path(self): if len(self.as4_path): n = len(self.as_path) - len(self.as4_path) return ' '.join(self.as_path[:n] + self.as4_path) else: return ' '.join(self.as_path) def merge_aggr(self): if len(self.as4_aggr): return self.as4_aggr else: return self.aggr def main(): args = parse_args() d = Reader(args.path_to_file) count = 0 for m in d: m = m.mrt if m.err: continue b = BgpDump(args) if m.type == MRT_T['TABLE_DUMP']: b.td(m, count) elif m.type == MRT_T['TABLE_DUMP_V2']: b.td_v2(m) elif m.type == MRT_T['BGP4MP']: b.bgp4mp(m, count) count += 1 if __name__ == '__main__': main() mrtparse-1.6/examples/mrt2exabgp.py0000755000175000017500000004010313125763144020135 0ustar t2munet2mune00000000000000#!/usr/bin/env python ''' mrt2exabgp.py - a script to convert MRT format to ExaBGP format. Copyright (C) 2017 Tetsumune KISO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Authors: Tetsumune KISO Yoshiyuki YAMAUCHI Nobuhiro ITOU ''' from mrtparse import * import sys, re, argparse, time FLAG_T = { 'IPv4': 0x01, 'IPv6': 0x02, 'ALL' : 0x04, 'SINGLE' : 0x08, 'API' : 0x10, 'API_GROUP_OLD' : 0x20, 'API_GROUP' : 0x40, 'API_PROG' : 0x80, } class NotDisplay(Exception): pass def print_conf_header(args): print('''\ neighbor %s { router-id %s; local-address %s; local-as %d; peer-as %d; graceful-restart; aigp enable; static {''' % (args.neighbor, args.router_id, args.local_addr, \ args.local_as, args.peer_as)) def print_conf_footer(): print(' }\n}') def print_api_prog_header(): print('''\ #!/usr/bin/env python import sys import time msgs = [''') def print_api_prog_footer(): print('''\ ] while msgs: msg = msgs.pop(0) if isinstance(msg, str): sys.stdout.write(msg + '\\n') sys.stdout.flush() else: time.sleep(msg) while True: time.sleep(1) ''') def parse_args(): global flags p = argparse.ArgumentParser( description='This script converts to ExaBGP format.') p.add_argument( 'path_to_file', help='specify path to MRT format file') p.add_argument( '-r', type=str, default='192.168.0.1', dest='router_id', help='specify router-id (default: 192.168.0.1)') p.add_argument( '-l', type=int, default=64512, dest='local_as', help='specify local AS number (default: 64512)') p.add_argument( '-p', type=int, default=65000, dest='peer_as', help='specify peer AS number (default: 65000)') p.add_argument( '-L', type=str, default='192.168.1.1', dest='local_addr', help='specify local address (default: 192.168.1.1)') p.add_argument( '-n', type=str, default='192.168.1.100', dest='neighbor', help='specify neighbor address (default: 192.168.1.100)') p.add_argument( '-4', type=str, nargs='?', metavar='NEXT_HOP', dest='next_hop', help='convert IPv4 entries and change IPv4 next-hop if specified') p.add_argument( '-6', type=str, nargs='?', metavar='NEXT_HOP', dest='next_hop6', help='convert IPv6 entries and change IPv6 next-hop if specified''') p.add_argument( '-a', default=False, action='store_true', help='convert all entries \ (default: convert only first entry per one prefix)') p.add_argument( '-s', default=False, action='store_true', help='convert only entries from a single asn \ (the peer asn, specify as -p PEER_ASN)') p.add_argument( '-A', action='store_false', help='convert to ExaBGP API format') p.add_argument( '-G', type=int, default=1000000, nargs='?', metavar='NUM', dest='api_grp_num', help='convert to ExaBGP API format ' + 'and group updates with the same attributes ' + 'for each spceified the number of prefixes ' + 'using "announce attributes ..." syntax (default: 1000000)') p.add_argument( '-g', type=int, default=1000000, nargs='?', metavar='NUM', dest='api_grp_num', help='convert to ExaBGP API format ' + 'and group updates with the same attributes ' + 'for each spceified the number of prefixes ' + 'using "announce attribute ..." old syntax (default: 1000000)') p.add_argument( '-P', action='store_false', help='convert to ExaBGP API program') if re.search('^-', sys.argv[-1]): r = p.parse_args() else: r = p.parse_args(sys.argv[:-1]) r.path_to_file=sys.argv[-1] flags = 0x00 if '-4' in sys.argv: flags |= FLAG_T['IPv4'] if '-6' in sys.argv: flags |= FLAG_T['IPv6'] if '-4' not in sys.argv and '-6' not in sys.argv: flags = FLAG_T['IPv4'] | FLAG_T['IPv6'] if '-a' in sys.argv: flags |= FLAG_T['ALL'] if '-s' in sys.argv: flags |= FLAG_T['SINGLE'] if '-A' in sys.argv: flags |= FLAG_T['API'] if '-G' in sys.argv: flags |= FLAG_T['API'] | FLAG_T['API_GROUP'] if '-g' in sys.argv: flags |= FLAG_T['API'] | FLAG_T['API_GROUP_OLD'] | FLAG_T['API_GROUP'] if '-P' in sys.argv: flags |= FLAG_T['API'] | FLAG_T['API_PROG'] return (r, flags) def conv_format(args, flags, d): params = {} params['flags'] = flags params['next_hop'] = '' params['pre_line'] = '' params['post_line'] = '' params['prefix_num'] = 1 params['prefix_before'] = '' params['ts_before'] = -1 params['mp_withdrawn'] = None params['mp_nlri'] = None params['api_grp_syntax'] = 'attributes' params['api_grp'] = {} if flags & FLAG_T['API_GROUP_OLD']: params['api_grp_syntax'] = 'attribute' if flags & FLAG_T['API'] == 0: print_conf_header(args) elif flags & FLAG_T['API_PROG']: print_api_prog_header() params['pre_line'] = '\'' params['post_line'] = '\',' for m in d: m = m.mrt if m.err: continue if m.type == MRT_T['TABLE_DUMP_V2'] \ or m.type == MRT_T['TABLE_DUMP']: print_route_td(args, params, m) elif m.type == MRT_T['BGP4MP'] \ or m.type == MRT_T['BGP4MP_ET']: params['flags'] |= FLAG_T['API'] | FLAG_T['API_GROUP'] print_route_bgp4mp(args, params, m) if params['flags'] & FLAG_T['API'] == 0: print_conf_footer() else: if params['flags'] & FLAG_T['API_GROUP']: print_api_grp(args, params) if params['flags'] & FLAG_T['API_PROG']: print_api_prog_footer() else: while True: time.sleep(1) return 0 def print_route_td(args, params, m): entry = [] if m.type == MRT_T['TABLE_DUMP_V2']: if m.subtype == TD_V2_ST['RIB_IPV4_UNICAST']: if not params['flags'] & FLAG_T['IPv4']: return elif m.subtype == TD_V2_ST['RIB_IPV6_UNICAST']: if not params['flags'] & FLAG_T['IPv6']: return else: return prefix = '%s/%d' % (m.rib.prefix, m.rib.plen) if flags & FLAG_T['ALL']: entry = m.rib.entry else: entry.append(m.rib.entry[0]) elif m.type == MRT_T['TABLE_DUMP']: if m.subtype == TD_ST['AFI_IPv4']: if not params['flags'] & FLAG_T['IPv4']: return elif m.subtype == TD_ST['AFI_IPv6']: if not params['flags'] & FLAG_T['IPv6']: return else: return prefix = '%s/%d' % (m.td.prefix, m.td.plen) if params['flags'] & FLAG_T['ALL'] == 0: if prefix == params['prefix_before']: return else: entry.append(m.td) params['prefix_before'] = prefix else: entry.append(m.td) for e in entry: line = '' params['next_hop'] = '' try: for attr in e.attr: line += get_bgp_attr(args, params, m, attr) except NotDisplay: continue if params['flags'] & FLAG_T['API_GROUP']: params['api_grp'].setdefault('%s next-hop %s' \ % (line, params['next_hop']), []).append('%s' % prefix) elif params['flags'] & FLAG_T['API']: sys.stdout.write('%sannounce route %s%s next-hop %s%s\n' % (params['pre_line'], prefix, line, params['next_hop'], params['post_line'])) sys.stdout.flush() else: print(' route %s%s next-hop %s;' \ % (prefix, line, params['next_hop'])) if params['flags'] & FLAG_T['API_GROUP'] \ and params['prefix_num'] == args.api_grp_num: print_api_grp(args, params) params['api_grp'] = {} params['prefix_num'] = 0 params['prefix_num'] += 1 def print_api_grp(args, params): for k in params['api_grp']: sys.stdout.write('%sannounce %s%s nlri %s%s\n' \ % (params['pre_line'], params['api_grp_syntax'], k, ' '.join(params['api_grp'][k]), params['post_line'])) sys.stdout.flush() def print_route_bgp4mp(args, params, m): params['next_hop'] = '' params['mp_withdrawn'] = [] params['mp_nlri'] = [] if flags & FLAG_T['API_GROUP'] == 0: sys.stderr.write('Error: BGP4MP/BGP4MP_ET is only suuported ' \ + 'by API Grouping format.\n') sys.stderr.write('Error: You must run with -G or -g option.\n') exit(1) if m.subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE'] \ or m.subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE_AS4']: return if m.bgp.msg.type != BGP_MSG_T['UPDATE']: return msg = m.bgp.msg attr_line = '' try: for attr in msg.attr: attr_line += get_bgp_attr(args, params, m, attr) except NotDisplay: return wd_line = '' for wd in params['mp_withdrawn']: wd_line += ' %s/%s' % (wd.prefix, wd.plen) if len(msg.withdrawn) and params['flags'] & FLAG_T['IPv4']: for wd in msg.withdrawn: wd_line += ' %s/%s' % (wd.prefix, wd.plen) if len(wd_line): if params['next_hop']: attr_line += ' next-hop %s' % params['next_hop'] sys.stdout.write('%swithdrawn %s%s nlri%s%s\n' \ % (params['pre_line'], params['api_grp_syntax'], attr_line, wd_line, params['post_line'])) nlri_line = '' for nlri in params['mp_nlri']: nlri_line += ' %s/%s' % (nlri.prefix, nlri.plen) if len(msg.nlri) and params['flags'] & FLAG_T['IPv4']: for nlri in msg.nlri: nlri_line += ' %s/%s' % (nlri.prefix, nlri.plen) if len(nlri_line): sys.stdout.write('%sannounce %s%s next-hop %s nlri%s%s\n' \ % (params['pre_line'], params['api_grp_syntax'], attr_line, params['next_hop'], nlri_line, params['post_line'])) interval = 0 if params['ts_before'] >= 0: interval = m.ts - params['ts_before'] if m.type == MRT_T['BGP4MP_ET']: interval += m.micro_ts / 1000000.0 params['ts_before'] = m.ts if m.type == MRT_T['BGP4MP_ET']: params['ts_before'] += m.micro_ts if interval > 0: if params['flags'] & FLAG_T['API_PROG']: sys.stdout.write('%d,\n' % interval) else: time.sleep(interval) def get_bgp_attr(args, params, m, attr): line = '' r = re.compile("([0-9]+)\.([0-9]+)") if attr.type == BGP_ATTR_T['ATOMIC_AGGREGATE']: line += ' atomic-aggregate' if attr.type == BGP_ATTR_T['ORIGIN']: line += ' origin %s' % ORIGIN_T[attr.origin] elif attr.type == BGP_ATTR_T['AS_PATH']: if flags & FLAG_T['SINGLE']: if len(attr.as_path) == 0: raise NotDisplay() path_seg = attr.as_path[0] if path_seg['type'] != AS_PATH_SEG_T['AS_SEQUENCE'] \ or len(path_seg['val']) == 0 \ or path_seg['val'][0] != str(args.peer_as): raise NotDisplay() as_path = '' for path_seg in attr.as_path: if path_seg['type'] == AS_PATH_SEG_T['AS_SET']: as_path += '(%s) ' % ' '.join(path_seg['val']) else: as_path += '%s ' % ' '.join(path_seg['val']) line += ' as-path [%s]' % as_path elif attr.type == BGP_ATTR_T['NEXT_HOP']: params['next_hop'] = args.next_hop if args.next_hop else attr.next_hop elif attr.type == BGP_ATTR_T['MULTI_EXIT_DISC']: line += ' med %d' % attr.med elif attr.type == BGP_ATTR_T['LOCAL_PREF']: line += ' local-preference %d' % attr.local_pref elif attr.type == BGP_ATTR_T['AGGREGATOR']: asn = attr.aggr['asn'] m = r.search(asn) if m is not None: asn = int(m.group(1)) * 65536 + int(m.group(2)) line += ' aggregator (%s:%s)' % (str(asn), attr.aggr['id']) elif attr.type == BGP_ATTR_T['COMMUNITY']: comm = ' '.join(attr.comm) line += ' community [%s]' % comm elif attr.type == BGP_ATTR_T['ORIGINATOR_ID']: line += ' originator-id %s' % attr.org_id elif attr.type == BGP_ATTR_T['CLUSTER_LIST']: line += ' cluster-list [%s]' % ' '.join(attr.cl_list) elif attr.type == BGP_ATTR_T['MP_REACH_NLRI']: params['next_hop'] = attr.mp_reach['next_hop'][0] if m.type == MRT_T['TABLE_DUMP_V2']: if m.subtype == TD_V2_ST['RIB_IPV4_UNICAST'] and args.next_hop: params['next_hop'] = args.next_hop elif m.subtype == TD_V2_ST['RIB_IPV6_UNICAST'] and args.next_hop6: params['next_hop'] = args.next_hop6 elif m.type == MRT_T['TABLE_DUMP']: if m.subtype == TD_ST['AFI_IPv4'] and args.next_hop: params['next_hop'] = args.next_hop elif m.subtype == TD_ST['AFI_IPv6'] and args.next_hop6: params['next_hop'] = args.next_hop6 elif m.type == MRT_T['BGP4MP'] or m.type == MRT_T['BGP4MP_ET']: if attr.mp_reach['afi'] == AFI_T['IPv4'] \ and params['flags'] & FLAG_T['IPv4']: if args.next_hop: params['next_hop'] = args.next_hop if 'nlri' in attr.mp_reach: params['mp_nlri'] = attr.mp_reach['nlri'] elif attr.mp_reach['afi'] == AFI_T['IPv6'] \ and params['flags'] & FLAG_T['IPv6']: if args.next_hop6: params['next_hop'] = args.next_hop6 if 'nlri' in attr.mp_reach: params['mp_nlri'] = attr.mp_reach['nlri'] elif attr.type == BGP_ATTR_T['MP_UNREACH_NLRI']: if m.type == MRT_T['BGP4MP'] or m.type == MRT_T['BGP4MP_ET']: if attr.mp_unreach['afi'] == AFI_T['IPv4'] \ and params['flags'] & FLAG_T['IPv4']: if 'withdrawn' in attr.mp_unreach: params['mp_withdrawn'] = attr.mp_unreach['withdrawn'] elif attr.mp_unreach['afi'] == AFI_T['IPv6'] \ and params['flags'] & FLAG_T['IPv6']: if 'withdrawn' in attr.mp_unreach: params['mp_withdrawn'] = attr.mp_unreach['withdrawn'] elif attr.type == BGP_ATTR_T['EXTENDED_COMMUNITIES']: ext_comm_list = [] for ext_comm in attr.ext_comm: ext_comm_list.append('0x%016x' % ext_comm) line += ' extended-community [%s]' % ' '.join(ext_comm_list) elif attr.type == BGP_ATTR_T['AS4_PATH']: as4_path = '' for path_seg in attr.as4_path: if path_seg['type'] == AS_PATH_SEG_T['AS_SET']: as4_path += '(%s) ' % ' '.join(path_seg['val']) else: as4_path += '%s ' % ' '.join(path_seg['val']) line += ' as4-path [%s]' % as4_path elif attr.type == BGP_ATTR_T['AS4_AGGREGATOR']: asn = attr.as4_aggr['asn'] m = r.search(asn) if m is not None: asn = int(m.group(1)) * 65536 + int(m.group(2)) line += ' as4-aggregator (%s:%s)' % (str(asn), attr.as4_aggr['id']) elif attr.type == BGP_ATTR_T['AIGP']: line += ' aigp %d' % attr.aigp[0]['val'] elif attr.type == BGP_ATTR_T['LARGE_COMMUNITY']: large_comm = ' '.join(attr.large_comm) line += ' large-community [%s]' % large_comm return line def main(): (args, flags) = parse_args() d = Reader(args.path_to_file) conv_format(args, flags, d) if __name__ == '__main__': main() mrtparse-1.6/examples/print_all.py0000755000175000017500000004261013125763144020053 0ustar t2munet2mune00000000000000#!/usr/bin/env python ''' print_all.py - a script to print a MRT format data using mrtparse. Copyright (C) 2017 Tetsumune KISO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Authors: Tetsumune KISO Yoshiyuki YAMAUCHI Nobuhiro ITOU ''' import sys from optparse import OptionParser from datetime import * from mrtparse import * indt = ' ' * 4 indt_num = 0 contents = '' def prerror(m): print('%s: %s' % (MRT_ERR_C[m.err], m.err_msg)) if m.err == MRT_ERR_C['MRT Header Error']: buf = m.buf else: buf = m.buf[12:] s = '' for i in range(len(buf)): if isinstance(buf[i], str): s += '%02x ' % ord(buf[i]) else: s += '%02x ' % buf[i] if (i + 1) % 16 == 0: print(' %s' % s) s = '' elif (i + 1) % 8 == 0: s += ' ' if len(s): print(' %s' % s) def put_lines(*lines): global contents for line in lines: contents += indt * indt_num + line + '\n' def print_mrt(m): global indt_num indt_num = 0 put_lines('MRT Header') indt_num += 1 try: subtype = MRT_ST[m.type][m.subtype] except KeyError: subtype = 'Unknown' put_lines( 'Timestamp: %d(%s)' % (m.ts, datetime.fromtimestamp(m.ts)), 'Type: %d(%s)' % (m.type, MRT_T[m.type]), 'Subtype: %d(%s)' % (m.subtype, subtype), 'Length: %d' % m.len ) if m.type == MRT_T['BGP4MP_ET'] \ or m.type == MRT_T['ISIS_ET'] \ or m.type == MRT_T['OSPFv3_ET']: put_lines('Microsecond Timestamp: %d' % m.micro_ts) def print_td(m): global indt_num indt_num = 0 put_lines('%s' % MRT_T[m.type]) indt_num += 1 put_lines( 'View Number: %d' % m.td.view, 'Sequence Number: %d' % m.td.seq, 'Prefix: %s' % m.td.prefix, 'Prefix length: %d' % m.td.plen, 'Status: %d' % m.td.status, 'Originated Time: %d(%s)' % (m.td.org_time, datetime.fromtimestamp(m.td.org_time)), 'Peer IP Address: %s' % m.td.peer_ip, 'Peer AS: %s' % m.td.peer_as, 'Attribute Length: %d' % m.td.attr_len ) for attr in m.td.attr: print_bgp_attr(attr, 1) def print_td_v2(m): global indt_num indt_num = 0 put_lines('%s' % TD_V2_ST[m.subtype]) indt_num += 1 if m.subtype == TD_V2_ST['PEER_INDEX_TABLE']: put_lines( 'Collector: %s' % m.peer.collector, 'View Name Length: %d' % m.peer.view_len, 'View Name: %s' % m.peer.view, 'Peer Count: %d' % m.peer.count ) for entry in m.peer.entry: put_lines( 'Peer Type: 0x%02x' % entry.type, 'Peer BGP ID: %s' % entry.bgp_id, 'Peer IP Address: %s' % entry.ip, 'Peer AS: %s' % entry.asn ) elif m.subtype == TD_V2_ST['RIB_IPV4_UNICAST'] \ or m.subtype == TD_V2_ST['RIB_IPV4_MULTICAST'] \ or m.subtype == TD_V2_ST['RIB_IPV6_UNICAST'] \ or m.subtype == TD_V2_ST['RIB_IPV6_MULTICAST'] \ or m.subtype == TD_V2_ST['RIB_IPV4_UNICAST_ADDPATH'] \ or m.subtype == TD_V2_ST['RIB_IPV4_MULTICAST_ADDPATH'] \ or m.subtype == TD_V2_ST['RIB_IPV6_UNICAST_ADDPATH'] \ or m.subtype == TD_V2_ST['RIB_IPV6_MULTICAST_ADDPATH']: put_lines( 'Sequence Number: %d' % m.rib.seq, 'Prefix Length: %d' % m.rib.plen, 'Prefix: %s' % m.rib.prefix, 'Entry Count: %d' % m.rib.count ) for entry in m.rib.entry: indt_num = 1 put_lines( 'Peer Index: %d' % entry.peer_index, 'Originated Time: %d(%s)' % (entry.org_time, datetime.fromtimestamp(entry.org_time)) ) if entry.path_id is not None: put_lines('Path Identifier: %d' % entry.path_id) put_lines('Attribute Length: %d' % entry.attr_len) for attr in entry.attr: print_bgp_attr(attr, 1) elif m.subtype == TD_V2_ST['RIB_GENERIC'] \ or m.subtype == TD_V2_ST['RIB_GENERIC_ADDPATH']: put_lines( 'Sequence Number: %d' % m.rib.seq, 'AFI: %d(%s)' % (m.rib.afi, AFI_T[m.rib.afi]), 'SAFI: %d(%s)' % (m.rib.safi, SAFI_T[m.rib.safi]) ) for nlri in m.rib.nlri: print_nlri(nlri, 'NLRI', m.rib.safi) put_lines('Entry Count: %d' % m.rib.count) for entry in m.rib.entry: indt_num = 1 put_lines( 'Peer Index: %d' % entry.peer_index, 'Originated Time: %d(%s)' % (entry.org_time, datetime.fromtimestamp(entry.org_time)), 'Attribute Length: %d' % entry.attr_len ) for attr in entry.attr: print_bgp_attr(attr, 1) def print_bgp4mp(m): global indt_num indt_num = 0 put_lines('%s' % BGP4MP_ST[m.subtype]) indt_num += 1 put_lines( 'Peer AS Number: %s' % m.bgp.peer_as, 'Local AS Number: %s' % m.bgp.local_as, 'Interface Index: %d' % m.bgp.ifindex, 'Address Family: %d(%s)' % (m.bgp.af, AFI_T[m.bgp.af]), 'Peer IP Address: %s' % m.bgp.peer_ip, 'Local IP Address: %s' % m.bgp.local_ip ) if m.subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE'] \ or m.subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE_AS4']: put_lines( 'Old State: %d(%s)' % (m.bgp.old_state, BGP_FSM[m.bgp.old_state]), 'New State: %d(%s)' % (m.bgp.new_state, BGP_FSM[m.bgp.new_state]) ) elif m.subtype == BGP4MP_ST['BGP4MP_MESSAGE'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4_LOCAL'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_ADDPATH'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4_ADDPATH'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL_ADDPATH'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH']: print_bgp_msg(m.bgp.msg, m.subtype) def print_bgp_msg(msg, subtype): global indt_num indt_num = 0 put_lines('BGP Message') indt_num += 1 put_lines( 'Marker: -- ignored --', 'Length: %d' % msg.len, 'Type: %d(%s)' % (msg.type, BGP_MSG_T[msg.type]), ) if msg.type == BGP_MSG_T['OPEN']: put_lines( 'Version: %d' % msg.ver, 'My AS: %d' % msg.my_as, 'Hold Time: %d' % msg.holdtime, 'BGP Identifier: %s' % msg.bgp_id, 'Optional Parameter Length: %d' % msg.opt_len ) for opt in msg.opt_params: print_bgp_opt_params(opt) elif msg.type == BGP_MSG_T['UPDATE']: put_lines('Withdrawn Routes Length: %d' % msg.wd_len) for withdrawn in msg.withdrawn: print_nlri(withdrawn, 'Withdrawn Routes') put_lines('Total Path Attribute Length: %d' % msg.attr_len) for attr in msg.attr: print_bgp_attr(attr, 1) indt_num = 1 for nlri in msg.nlri: print_nlri(nlri, 'NLRI') elif msg.type == BGP_MSG_T['NOTIFICATION']: put_lines( 'Error Code: %d(%s)' % (msg.err_code, BGP_ERR_C[msg.err_code]), 'Error Subcode: %d(%s)' % (msg.err_subcode, BGP_ERR_SC[msg.err_code][msg.err_subcode]), 'Data: %s' % msg.data ) elif msg.type == BGP_MSG_T['ROUTE-REFRESH']: put_lines( 'AFI: %d(%s)' % (msg.afi, AFI_T[msg.afi]), 'Reserved: %d' % msg.rsvd, 'SAFI: %d(%s)' % (msg.safi, SAFI_T[msg.safi]) ) def print_bgp_opt_params(opt): global indt_num indt_num = 1 put_lines('Parameter Type/Length: %d/%d' % (opt.type, opt.len)) indt_num += 1 put_lines('%s' % BGP_OPT_PARAMS_T[opt.type]) if opt.type != BGP_OPT_PARAMS_T['Capabilities']: return indt_num += 1 put_lines( 'Capability Code: %d(%s)' % (opt.cap_type, BGP_CAP_C[opt.cap_type]), 'Capability Length: %d' % opt.cap_len ) if opt.cap_type == BGP_CAP_C['Multiprotocol Extensions for BGP-4']: put_lines( 'AFI: %d(%s)' % (opt.multi_ext['afi'], AFI_T[opt.multi_ext['afi']]), 'Reserved: %d' % opt.multi_ext['rsvd'], 'SAFI: %d(%s)' % (opt.multi_ext['safi'], SAFI_T[opt.multi_ext['safi']]) ) elif opt.cap_type == BGP_CAP_C['Route Refresh Capability for BGP-4']: pass elif opt.cap_type == BGP_CAP_C['Outbound Route Filtering Capability']: put_lines( 'AFI: %d(%s)' % (opt.orf['afi'], AFI_T[opt.orf['afi']]), 'Reserved: %d' % opt.orf['rsvd'], 'SAFI: %d(%s)' % (opt.orf['safi'], SAFI_T[opt.orf['safi']]), 'Number: %d' % opt.orf['number'] ) for entry in opt.orf['entry']: put_lines( 'Type: %d' % entry['type'], 'Send Receive: %d(%s)' % (entry['send_recv'], ORF_SEND_RECV[entry['send_recv']]) ) elif opt.cap_type == BGP_CAP_C['Graceful Restart Capability']: put_lines( 'Restart Flags: 0x%x' % opt.graceful_restart['flag'], 'Restart Time in Seconds: %d' % opt.graceful_restart['sec'] ) for entry in opt.graceful_restart['entry']: put_lines( 'AFI: %d(%s)' % (entry['afi'], AFI_T[entry['afi']]), 'SAFI: %d(%s)' % (entry['safi'], SAFI_T[entry['safi']]), 'Flag: 0x%02x' % entry['flag'] ) elif opt.cap_type == BGP_CAP_C['Support for 4-octet AS number capability']: put_lines('AS Number: %s' % opt.support_as4) elif opt.cap_type == BGP_CAP_C['ADD-PATH Capability']: for entry in opt.add_path: put_lines( 'AFI: %d(%s)' % (entry['afi'], AFI_T[entry['afi']]), 'SAFI: %d(%s)' % (entry['safi'], SAFI_T[entry['safi']]), 'Send Receive: %d(%s)' % (entry['send_recv'], ADD_PATH_SEND_RECV[entry['send_recv']]) ) def print_bgp_attr(attr, n): global indt_num indt_num = n put_lines( 'Path Attribute Flags/Type/Length: 0x%02x/%d/%d' % (attr.flag, attr.type, attr.len) ) indt_num += 1 line = '%s' % BGP_ATTR_T[attr.type] if attr.type == BGP_ATTR_T['ORIGIN']: put_lines(line + ': %d(%s)' % (attr.origin, ORIGIN_T[attr.origin])) elif attr.type == BGP_ATTR_T['AS_PATH']: put_lines(line) indt_num += 1 for path_seg in attr.as_path: put_lines( 'Path Segment Type: %d(%s)' % (path_seg['type'], AS_PATH_SEG_T[path_seg['type']]), 'Path Segment Length: %d' % path_seg['len'], 'Path Segment Value: %s' % ' '.join(path_seg['val']) ) elif attr.type == BGP_ATTR_T['NEXT_HOP']: put_lines(line + ': %s' % attr.next_hop) elif attr.type == BGP_ATTR_T['MULTI_EXIT_DISC']: put_lines(line + ': %d' % attr.med) elif attr.type == BGP_ATTR_T['LOCAL_PREF']: put_lines(line + ': %d' % attr.local_pref) elif attr.type == BGP_ATTR_T['ATOMIC_AGGREGATE']: put_lines(line) elif attr.type == BGP_ATTR_T['AGGREGATOR']: put_lines(line + ': %s %s' % (attr.aggr['asn'], attr.aggr['id'])) elif attr.type == BGP_ATTR_T['COMMUNITY']: put_lines(line + ': %s' % ' '.join(attr.comm)) elif attr.type == BGP_ATTR_T['ORIGINATOR_ID']: put_lines(line + ': %s' % attr.org_id) elif attr.type == BGP_ATTR_T['CLUSTER_LIST']: put_lines(line + ': %s' % ' '.join(attr.cl_list)) elif attr.type == BGP_ATTR_T['MP_REACH_NLRI']: put_lines(line) indt_num += 1 if 'afi' in attr.mp_reach: put_lines( 'AFI: %d(%s)' % (attr.mp_reach['afi'], AFI_T[attr.mp_reach['afi']]) ) if 'safi' in attr.mp_reach: put_lines( 'SAFI: %d(%s)' % (attr.mp_reach['safi'], SAFI_T[attr.mp_reach['safi']]) ) if attr.mp_reach['safi'] == SAFI_T['L3VPN_UNICAST'] \ or attr.mp_reach['safi'] == SAFI_T['L3VPN_MULTICAST']: put_lines('Route Distinguisher: %s' % attr.mp_reach['rd']) put_lines('Length: %d' % attr.mp_reach['nlen']) if 'next_hop' not in attr.mp_reach: return next_hop = " ".join(attr.mp_reach['next_hop']) put_lines('Next-Hop: %s' % next_hop) if 'nlri' in attr.mp_reach: for nlri in attr.mp_reach['nlri']: print_nlri(nlri, 'NLRI', attr.mp_reach['safi']) elif attr.type == BGP_ATTR_T['MP_UNREACH_NLRI']: put_lines(line) indt_num += 1 put_lines( 'AFI: %d(%s)' % (attr.mp_unreach['afi'], AFI_T[attr.mp_unreach['afi']]), 'SAFI: %d(%s)' % (attr.mp_unreach['safi'], SAFI_T[attr.mp_unreach['safi']]) ) if 'withdrawn' not in attr.mp_unreach: return for withdrawn in attr.mp_unreach['withdrawn']: print_nlri(withdrawn, 'Withdrawn Routes', attr.mp_unreach['safi']) elif attr.type == BGP_ATTR_T['EXTENDED_COMMUNITIES']: ext_comm_list = [] for ext_comm in attr.ext_comm: ext_comm_list.append('0x%016x' % ext_comm) put_lines(line + ': %s' % ' '.join(ext_comm_list)) elif attr.type == BGP_ATTR_T['AS4_PATH']: put_lines(line) indt_num += 1 for path_seg in attr.as4_path: put_lines( 'Path Segment Type: %d(%s)' % (path_seg['type'], AS_PATH_SEG_T[path_seg['type']]), 'Path Segment Length: %d' % path_seg['len'], 'Path Segment Value: %s' % ' '.join(path_seg['val']) ) elif attr.type == BGP_ATTR_T['AS4_AGGREGATOR']: put_lines( line + ': %s %s' % (attr.as4_aggr['asn'], attr.as4_aggr['id']) ) elif attr.type == BGP_ATTR_T['AIGP']: put_lines(line) indt_num += 1 for aigp in attr.aigp: put_lines( 'Type: %d' % aigp['type'], 'Length: %d' % aigp['len'], 'Value: %d' % aigp['val'] ) elif attr.type == BGP_ATTR_T['ATTR_SET']: put_lines(line) indt_num += 1 put_lines('Origin AS: %s' % attr.attr_set['origin_as']) for attr in attr.attr_set['attr']: print_bgp_attr(attr, 3) elif attr.type == BGP_ATTR_T['LARGE_COMMUNITY']: put_lines(line + ': %s' % ' '.join(attr.large_comm)) else: line += ': 0x' for c in attr.val: if isinstance(c, str): c = ord(c) line += '%02x' % c put_lines(line) def print_nlri(nlri, title, *args): global indt_num safi = args[0] if len(args) > 0 else 0 if safi == SAFI_T['L3VPN_UNICAST'] \ or safi == SAFI_T['L3VPN_MULTICAST']: put_lines('%s' % title) indt_num += 1 plen = nlri.plen - (len(nlri.label) * 3 + 8) * 8 l_all = [] l_val = [] for label in nlri.label: l_all.append('0x%06x' % label) l_val.append(str(label >> 4)) if nlri.path_id is not None: put_lines('Path Identifier: %d' % nlri.path_id) put_lines( 'Label: %s(%s)' % (' '.join(l_all), ' '.join(l_val)), 'Route Distinguisher: %s' % nlri.rd, 'Prefix: %s/%d' % (nlri.prefix, plen) ) indt_num -= 1 else: if nlri.path_id is not None: put_lines('%s' % title) indt_num += 1 put_lines( 'Path Identifier: %d' % nlri.path_id, 'Prefix: %s/%d' % (nlri.prefix, nlri.plen) ) indt_num -= 1 else: put_lines('%s: %s/%d' % (title, nlri.prefix, nlri.plen)) def main(): global contents if len(sys.argv) != 2: print('Usage: %s FILENAME' % sys.argv[0]) exit(1) d = Reader(sys.argv[1]) # if you want to use 'asdot+' or 'asdot' for AS numbers, # comment out either line below. # default is 'asplain'. # # as_repr(AS_REPR['asdot+']) # as_repr(AS_REPR['asdot']) for m in d: contents = '' m = m.mrt print('---------------------------------------------------------------') if m.err == MRT_ERR_C['MRT Header Error']: prerror(m) continue print_mrt(m) sys.stdout.write(contents) contents = '' if m.err == MRT_ERR_C['MRT Data Error']: prerror(m) continue if m.type == MRT_T['TABLE_DUMP']: print_td(m) elif m.type == MRT_T['TABLE_DUMP_V2']: print_td_v2(m) elif m.type == MRT_T['BGP4MP'] \ or m.type == MRT_T['BGP4MP_ET']: print_bgp4mp(m) sys.stdout.write(contents) if __name__ == '__main__': main() mrtparse-1.6/examples/slice.py0000755000175000017500000000602713125763144017170 0ustar t2munet2mune00000000000000#!/usr/bin/env python ''' slice.py - This script slices MRT format data. Copyright (C) 2017 Tetsumune KISO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Authors: Tetsumune KISO Yoshiyuki YAMAUCHI Nobuhiro ITOU ''' from mrtparse import * import argparse, time, gzip, bz2, re from datetime import datetime def parse_args(): parser = argparse.ArgumentParser( description='This script slices MRT format data.') parser.add_argument( 'path_to_file', help='specify path to MRT format file') parser.add_argument( '-s', type=str, metavar='START_TIME', dest='start_time', help='specify start time in format YYYY-MM-DD HH:MM:SS') parser.add_argument( '-e', type=str, metavar='END_TIME', dest='end_time', help='specify end time in format YYYY-MM-DD HH:MM:SS') parser.add_argument( '-i', type=int, metavar='INTERVAL', dest='interval', help='specify interval in seconds') parser.add_argument( '-c', type=str, choices=['gz', 'bz2'], dest='compress_type', help='specify compress type (gz, bz2)') return parser.parse_args() def conv_unixtime(t): try: t = datetime.strptime(t, '%Y-%m-%d %H:%M:%S') t = int(time.mktime(t.timetuple())) except TypeError: t = None except ValueError: print('error: invalid time \'%s\'' % t) exit(1) return t def file_open(f, t, c): f = re.sub(r'.gz$|.bz2$', '', f) t = datetime.fromtimestamp(t).strftime('%Y%m%d-%H%M%S') if c is None: return open('%s-%s' % (f, t), 'wb') elif c == 'gz': return gzip.GzipFile('%s-%s.%s' % (f, t, c), 'wb') elif c == 'bz2': return bz2.BZ2File('%s-%s.%s' % (f, t, c), 'wb') def slice_mrt(args): t = start_time = conv_unixtime(args.start_time) end_time = conv_unixtime(args.end_time) interval = args.interval if t is None: d = Reader(args.path_to_file) m = d.next() t = m.mrt.ts f = file_open(args.path_to_file, t, args.compress_type) d = Reader(args.path_to_file) for m in d: m = m.mrt if start_time and (m.ts < start_time): continue if end_time and (m.ts >= end_time): break if interval and (m.ts >= t + interval): f.close() t += interval f = file_open(args.path_to_file, t, args.compress_type) f.write(m.buf) f.close() def main(): args = parse_args() slice_mrt(args) if __name__ == '__main__': main() mrtparse-1.6/examples/summary.py0000755000175000017500000001174013125763144017564 0ustar t2munet2mune00000000000000#!/usr/bin/env python ''' summary.py - This script displays summary of MRT format data. Copyright (C) 2017 Tetsumune KISO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Authors: Tetsumune KISO Yoshiyuki YAMAUCHI Nobuhiro ITOU ''' import sys from mrtparse import * from datetime import datetime summary = {} start_time = end_time = 0 def count(d, k): try: d[k] += 1 except KeyError: d[k] = 1 def total(d): if isinstance(d, int): return d n = 0 for k in d: if isinstance(d[k], dict): n += total(d[k]) else: n += d[k] return n def print_line(lv, s, n): fmt = '%s%%-%ds%%8d' % (' ' * 4 * lv, 32 - 4 * lv) print(fmt % (s + ':', n)) def get_summary(f): global start_time, end_time d = Reader(f) m = d.next() start_time = end_time = m.mrt.ts d = Reader(f) for m in d: m = m.mrt if m.err: continue if m.ts < start_time: start_time = m.ts elif m.ts > end_time: end_time = m.ts if m.type == MRT_T['BGP4MP'] \ or m.type == MRT_T['BGP4MP_ET']: if not m.type in summary: summary[m.type] = {} if m.subtype == BGP4MP_ST['BGP4MP_MESSAGE'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4_LOCAL'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_ADDPATH'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4_ADDPATH'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL_ADDPATH'] \ or m.subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH']: if not m.subtype in summary[m.type]: summary[m.type][m.subtype] = {} count(summary[m.type][m.subtype], m.bgp.msg.type) elif m.subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE'] \ or m.subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE_AS4']: if not m.subtype in summary[m.type]: summary[m.type][m.subtype] = {} count(summary[m.type][m.subtype], m.bgp.new_state) else: count(summary[m.type], m.subtype) else: if hasattr(m, 'subtype'): if not m.type in summary: summary[m.type] = {} count(summary[m.type], m.subtype) else: count(summary, m.type) def print_summary(): print('[%s - %s]' % ( datetime.fromtimestamp(start_time).strftime('%Y-%m-%d %H:%M:%S'), datetime.fromtimestamp(end_time).strftime('%Y-%m-%d %H:%M:%S'))) for k1 in sorted(summary.keys()): print_line(0, MRT_T[k1], total(summary[k1])) if k1 == MRT_T['TABLE_DUMP']: for k2 in sorted(summary[k1].keys()): print_line(1, TD_ST[k2], total(summary[k1][k2])) elif k1 == MRT_T['TABLE_DUMP_V2']: for k2 in sorted(summary[k1].keys()): print_line(1, TD_V2_ST[k2], total(summary[k1][k2])) elif k1 == MRT_T['BGP4MP'] \ or k1 == MRT_T['BGP4MP_ET']: for k2 in sorted(summary[k1].keys()): print_line(1, BGP4MP_ST[k2], total(summary[k1][k2])) if k2 == BGP4MP_ST['BGP4MP_MESSAGE'] \ or k2 == BGP4MP_ST['BGP4MP_MESSAGE_AS4'] \ or k2 == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL'] \ or k2 == BGP4MP_ST['BGP4MP_MESSAGE_AS4_LOCAL'] \ or k2 == BGP4MP_ST['BGP4MP_MESSAGE_ADDPATH'] \ or k2 == BGP4MP_ST['BGP4MP_MESSAGE_AS4_ADDPATH'] \ or k2 == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL_ADDPATH'] \ or k2 == BGP4MP_ST['BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH']: for k3 in sorted(summary[k1][k2].keys()): print_line(2, BGP_MSG_T[k3], total(summary[k1][k2][k3])) elif k2 == BGP4MP_ST['BGP4MP_STATE_CHANGE'] \ or k2 == BGP4MP_ST['BGP4MP_STATE_CHANGE_AS4']: for k3 in sorted(summary[k1][k2].keys()): print_line(2, BGP_FSM[k3], total(summary[k1][k2][k3])) def main(): if len(sys.argv) != 2: print('Usage: %s FILENAME' % sys.argv[0]) exit(1) get_summary(sys.argv[1]) print_summary() if __name__ == '__main__': main() mrtparse-1.6/mrtparse/0000755000175000017500000000000013125764616015533 5ustar t2munet2mune00000000000000mrtparse-1.6/mrtparse/__init__.py0000644000175000017500000012755313125763264017657 0ustar t2munet2mune00000000000000''' mrtparse.py - MRT format data parser Copyright (C) 2017 Tetsumune KISO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Authors: Tetsumune KISO Yoshiyuki YAMAUCHI Nobuhiro ITOU ''' import sys import struct import socket import gzip import bz2 import collections import signal signal.signal(signal.SIGPIPE, signal.SIG_DFL) __version__ = '1.6' # Magic Number GZIP_MAGIC = b'\x1f\x8b' BZ2_MAGIC = b'\x42\x5a\x68' def reverse_defaultdict(d): ''' Reverse the keys and values of dictionaries. ''' for k in list(d.keys()): d[d[k]] = k d = collections.defaultdict(lambda: "Unknown", d) return d # Error codes for MrtFormatError exception MRT_ERR_C = reverse_defaultdict({ 1:'MRT Header Error', 2:'MRT Data Error', }) # AFI Types # Assigend by IANA AFI_T = reverse_defaultdict({ 1:'IPv4', 2:'IPv6', 25: 'L2VPN', }) # SAFI Types # Assigend by IANA SAFI_T = reverse_defaultdict({ 1:'UNICAST', 2:'MULTICAST', 65:'VPLS', 70:'EVPN', 128:'L3VPN_UNICAST', 129:'L3VPN_MULTICAST', }) # MRT Message Types # Defined in RFC6396 MRT_T = reverse_defaultdict({ 0:'NULL', # Deprecated in RFC6396 1:'START', # Deprecated in RFC6396 2:'DIE', # Deprecated in RFC6396 3:'I_AM_DEAD', # Deprecated in RFC6396 4:'PEER_DOWN', # Deprecated in RFC6396 5:'BGP', # Deprecated in RFC6396 6:'RIP', # Deprecated in RFC6396 7:'IDRP', # Deprecated in RFC6396 8:'RIPNG', # Deprecated in RFC6396 9:'BGP4PLUS', # Deprecated in RFC6396 10:'BGP4PLUS_01', # Deprecated in RFC6396 11:'OSPFv2', 12:'TABLE_DUMP', 13:'TABLE_DUMP_V2', 16:'BGP4MP', 17:'BGP4MP_ET', 32:'ISIS', 33:'ISIS_ET', 48:'OSPFv3', 49:'OSPFv3_ET', }) # BGP,BGP4PLUS,BGP4PLUS_01 Subtypes # Deprecated in RFC6396 BGP_ST = reverse_defaultdict({ 0:'BGP_NULL', 1:'BGP_UPDATE', 2:'BGP_PREF_UPDATE', 3:'BGP_STATE_CHANGE', 4:'BGP_SYNC', 5:'BGP_OPEN', 6:'BGP_NOTIFY', 7:'BGP_KEEPALIVE', }) # TABLE_DUMP Subtypes # Defined in RFC6396 TD_ST = reverse_defaultdict({ 1:'AFI_IPv4', 2:'AFI_IPv6', }) # TABLE_DUMP_V2 Subtypes # Defined in RFC6396 TD_V2_ST = reverse_defaultdict({ 1:'PEER_INDEX_TABLE', 2:'RIB_IPV4_UNICAST', 3:'RIB_IPV4_MULTICAST', 4:'RIB_IPV6_UNICAST', 5:'RIB_IPV6_MULTICAST', 6:'RIB_GENERIC', 7:'GEO_PEER_TABLE', # Defined in RFC6397 8:'RIB_IPV4_UNICAST_ADDPATH', # Defined in RFC8050 9:'RIB_IPV4_MULTICAST_ADDPATH', # Defined in RFC8050 10:'RIB_IPV6_UNICAST_ADDPATH', # Defined in RFC8050 11:'RIB_IPV6_MULTICAST_ADDPATH', # Defined in RFC8050 12:'RIB_GENERIC_ADDPATH', # Defined in RFC8050 }) # BGP4MP,BGP4MP_ET Subtypes # Defined in RFC6396 BGP4MP_ST = reverse_defaultdict({ 0:'BGP4MP_STATE_CHANGE', 1:'BGP4MP_MESSAGE', 2:'BGP4MP_ENTRY', # Deprecated in RFC6396 3:'BGP4MP_SNAPSHOT', # Deprecated in RFC6396 4:'BGP4MP_MESSAGE_AS4', 5:'BGP4MP_STATE_CHANGE_AS4', 6:'BGP4MP_MESSAGE_LOCAL', 7:'BGP4MP_MESSAGE_AS4_LOCAL', 8:'BGP4MP_MESSAGE_ADDPATH', # Defined in RFC8050 9:'BGP4MP_MESSAGE_AS4_ADDPATH', # Defined in RFC8050 10:'BGP4MP_MESSAGE_LOCAL_ADDPATH', # Defined in RFC8050 11:'BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH', # Defined in RFC8050 }) # MRT Message Subtypes # Defined in RFC6396 MRT_ST = collections.defaultdict(lambda: dict(), { 9:BGP_ST, 10:BGP_ST, 12:AFI_T, 13:TD_V2_ST, 16:BGP4MP_ST, 17:BGP4MP_ST, }) # BGP FSM States # Defined in RFC4271 BGP_FSM = reverse_defaultdict({ 1:'Idle', 2:'Connect', 3:'Active', 4:'OpenSent', 5:'OpenConfirm', 6:'Established', 7:'Clearing', # Used only in quagga? 8:'Deleted', # Used only in quagga? }) # BGP Attribute Types # Defined in RFC4271 BGP_ATTR_T = reverse_defaultdict({ 1:'ORIGIN', 2:'AS_PATH', 3:'NEXT_HOP', 4:'MULTI_EXIT_DISC', 5:'LOCAL_PREF', 6:'ATOMIC_AGGREGATE', 7:'AGGREGATOR', 8:'COMMUNITY', # Defined in RFC1997 9:'ORIGINATOR_ID', # Defined in RFC4456 10:'CLUSTER_LIST', # Defined in RFC4456 11:'DPA', # Deprecated in RFC6938 12:'ADVERTISER', # Deprecated in RFC6938 13:'RCID_PATH/CLUSTER_ID', # Deprecated in RFC6938 14:'MP_REACH_NLRI', # Defined in RFC4760 15:'MP_UNREACH_NLRI', # Defined in RFC4760 16:'EXTENDED_COMMUNITIES', # Defined in RFC4360 17:'AS4_PATH', # Defined in RFC6793 18:'AS4_AGGREGATOR', # Defined in RFC6793 26:'AIGP', # Defined in RFC7311 32:'LARGE_COMMUNITY', # Defined in draft-ietf-idr-large-community 128:'ATTR_SET', # Defined in RFC6368 }) # BGP ORIGIN Types # Defined in RFC4271 ORIGIN_T = reverse_defaultdict({ 0:'IGP', 1:'EGP', 2:'INCOMPLETE', }) # BGP AS_PATH Types # Defined in RFC4271 AS_PATH_SEG_T = reverse_defaultdict({ 1:'AS_SET', 2:'AS_SEQUENCE', 3:'AS_CONFED_SEQUENCE', # Defined in RFC5065 4:'AS_CONFED_SET', # Defined in RFC5065 }) # Reserved BGP COMMUNITY Types # Defined in RFC1997 COMM_T = reverse_defaultdict({ 0xffffff01:'NO_EXPORT', 0xffffff02:'NO_ADVERTISE', 0xffffff03:'NO_EXPORT_SCONFED', 0xffffff04:'NO_PEER', # Defined in RFC3765 }) # BGP Message Types # Defined in RFC4271 BGP_MSG_T = reverse_defaultdict({ 1:'OPEN', 2:'UPDATE', 3:'NOTIFICATION', 4:'KEEPALIVE', 5:'ROUTE-REFRESH', # Defined in RFC2918 }) # BGP Error Codes # Defined in RFC4271 BGP_ERR_C = reverse_defaultdict({ 1:'Message Header Error', 2:'OPEN Message Error', 3:'UPDATE Message Error', 4:'Hold Timer Expired', 5:'Finite State Machine Error', 6:'Cease', 7:'ROUTE-REFRESH Message Error', # Defined in RFC7313 }) # BGP Message Header Error Subcodes # Defined in RFC4271 BGP_HDR_ERR_SC = reverse_defaultdict({ 1:'Connection Not Synchronized', 2:'Bad Message Length', 3:'Bad Message Type', }) # OPEN Message Error Subcodes # Defined in RFC4271 BGP_OPEN_ERR_SC = reverse_defaultdict({ 1:'Unsupported Version Number', 2:'Bad Peer AS', 3:'Bad BGP Identifier', 4:'Unsupported Optional Parameter', 5:'[Deprecated]', 6:'Unacceptable Hold Time', 7:'Unsupported Capability', # Defined in RFC5492 }) # UPDATE Message Error Subcodes # Defined in RFC4271 BGP_UPDATE_ERR_SC = reverse_defaultdict({ 1:'Malformed Attribute List', 2:'Unrecognized Well-known Attribute', 3:'Missing Well-known Attribute', 4:'Attribute Flags Error', 5:'Attribute Length Error', 6:'Invalid ORIGIN Attribute', 7:'[Deprecated]', 8:'Invalid NEXT_HOP Attribute', 9:'Optional Attribute Error', 10:'Invalid Network Field', 11:'Malformed AS_PATH', }) # BGP Finite State Machine Error Subcodes # Defined in RFC6608 BGP_FSM_ERR_SC = reverse_defaultdict({ 0:'Unspecified Error', 1:'Receive Unexpected Message in OpenSent State', 2:'Receive Unexpected Message in OpenConfirm State', 3:'Receive Unexpected Message in Established State', }) # BGP Cease NOTIFICATION Message Subcodes # Defined in RFC4486 BGP_CEASE_ERR_SC = reverse_defaultdict({ 1:'Maximum Number of Prefixes Reached', 2:'Administrative Shutdown', 3:'Peer De-configured', 4:'Administrative Reset', 5:'Connection Rejected', 6:'Other Configuration Change', 7:'Connection Collision Resolution', 8:'Out of Resources', }) # BGP ROUTE-REFRESH Message Error subcodes # Defined in RFC7313 BGP_ROUTE_REFRESH_ERR_SC = reverse_defaultdict({ 1:'Invalid Message Length', }) # BGP Error Subcodes BGP_ERR_SC = collections.defaultdict(lambda: dict(), { 1:BGP_HDR_ERR_SC, 2:BGP_UPDATE_ERR_SC, 3:BGP_OPEN_ERR_SC, 4:BGP_UPDATE_ERR_SC, 5:BGP_FSM_ERR_SC, 6:BGP_CEASE_ERR_SC, 7:BGP_ROUTE_REFRESH_ERR_SC, }) # BGP OPEN Optional Parameter Types # Defined in RFC5492 BGP_OPT_PARAMS_T = reverse_defaultdict({ 1:'Authentication', # Deprecated 2:'Capabilities', }) # Capability Codes # Defined in RFC5492 BGP_CAP_C = reverse_defaultdict({ 1:'Multiprotocol Extensions for BGP-4', # Defined in RFC2858 2:'Route Refresh Capability for BGP-4', # Defined in RFC2918 3:'Outbound Route Filtering Capability', # Defined in RFC5291 4:'Multiple routes to a destination capability', # Defined in RFC3107 5:'Extended Next Hop Encoding', # Defined in RFC5549 64:'Graceful Restart Capability', # Defined in RFC4724 65:'Support for 4-octet AS number capability', # Defined in RFC6793 66:'[Deprecated]', # draft-ietf-idr-dynamic-cap 67:'Support for Dynamic Capability (capability specific)', # draft-ietf-idr-bgp-multisession 68:'Multisession BGP Capability', # Defined in RFC7911 69:'ADD-PATH Capability', # Defined in RFC7313 70:'Enhanced Route Refresh Capability', # draft-uttaro-idr-bgp-persistence 71:'Long-Lived Graceful Restart (LLGR) Capability', }) # Outbound Route Filtering Capability # Defined in RFC5291 ORF_T = reverse_defaultdict({ 64:'Address Prefix ORF', # Defined in RFC5292 65: 'CP-ORF', # Defined in RFC7543 }) ORF_SEND_RECV = reverse_defaultdict({ 1:'Receive', 2:'Send', 3:'Both', }) # ADD-PATH Capability # Defined in RFC7911 ADD_PATH_SEND_RECV = reverse_defaultdict({ 1:'Receive', 2:'Send', 3:'Both', }) # AS Number Representation AS_REPR = reverse_defaultdict({ 1:'asplain', 2:'asdot+', 3:'asdot', }) # MPLS Label LBL_BOTTOM = 0x01 # Defined in RFC3032 LBL_WITHDRAWN = 0x800000 # Defined in RFC3107 def as_len(n=None): ''' AS number length for AS_PATH attribute. ''' if n is not None: as_len.n = n try: return as_len.n except AttributeError: return 4 def as_repr(n=None): ''' AS number representation. Default is 'asplain'(defined in RFC5396). ''' if n is not None: as_repr.n = n try: return as_repr.n except AttributeError: return AS_REPR['asplain'] def af_num(afi=None, safi=None): ''' the values of AFI/SAFI. ''' if afi is not None: af_num.afi = afi af_num.safi = safi try: return (af_num.afi, af_num.safi) except AttributeError: return (0, 0) def is_add_path(f=None): ''' Flag for add-path. ''' if f is not None: is_add_path.f = f try: return is_add_path.f except AttributeError: return False class MrtFormatError(Exception): ''' Exception for invalid MRT formatted data. ''' def __init__(self, msg=''): Exception.__init__(self) self.msg = msg class Base: ''' Super class for all other classes. ''' __slots__ = ['buf', 'p'] def __init__(self): for slot in self.__slots__: setattr(self, slot, None) self.p = 0 def chk_buf(self, n): ''' Check whether there is sufficient buffers. ''' if len(self.buf) - self.p < n: raise MrtFormatError( 'Insufficient buffer %d < %d byte' % (len(self.buf) - self.p, n)) def val_num(self, n): ''' Convert buffers to integer. ''' self.chk_buf(n) val = 0 for i in self.buf[self.p:self.p+n]: val <<= 8 # for Python3 if isinstance(i, int): val += i # for Python2 else: val += struct.unpack('>B', i)[0] self.p += n return val def val_bytes(self, n): ''' Convert buffers to bytes. ''' self.chk_buf(n) val = self.buf[self.p:self.p+n] self.p += n return val def val_str(self, n): ''' Convert buffers to string. ''' self.chk_buf(n) val = self.buf[self.p:self.p+n] self.p += n # for Python2 if isinstance(val, str): return val # for Python3 else: return val.decode('utf-8') def val_addr(self, af, n=-1): ''' Convert buffers to IP address. ''' if af == AFI_T['IPv4']: m = 4 _af = socket.AF_INET elif af == AFI_T['IPv6']: m = 16 _af = socket.AF_INET6 else: raise MrtFormatError('Unsupported AFI %d(%s)' % (af, AFI_T[af])) n = m if n < 0 else (n + 7) // 8 self.chk_buf(n) addr = socket.inet_ntop( _af, self.buf[self.p:self.p+n] + b'\x00'*(m - n)) self.p += n return addr def val_asn(self, n): ''' Convert buffers to AS number. ''' asn = self.val_num(n) if as_repr() == AS_REPR['asplain'] \ or (as_repr() == AS_REPR['asdot'] and asn < 0x10000): return str(asn) else: return str(asn >> 16) + '.' + str(asn & 0xffff) def val_rd(self): ''' Convert buffers to route distinguisher. ''' rd = self.val_num(8) return str(rd >> 32) + ':' + str(rd & 0xffffffff) def val_nlri(self, n, af, saf=0): ''' Convert buffers to NLRI. ''' try: if is_add_path(): raise MrtFormatError p = self.p l = [] while p < n: nlri = Nlri(self.buf[p:]) p += nlri.unpack(af, saf) nlri.is_valid() nlri.is_dup(l) l.append(nlri) self.p = p except MrtFormatError: l = [] while self.p < n: nlri = Nlri(self.buf[self.p:]) self.p += nlri.unpack(af, saf, add_path=1) nlri.is_valid() l.append(nlri) return l class Reader(Base): ''' Reader for MRT format data. ''' __slots__ = ['buf', 'p', 'mrt', 'f'] def __init__(self, arg): Base.__init__(self) # for file instance if hasattr(arg, 'read'): self.f = arg # for file path elif isinstance(arg, str): f = open(arg, 'rb') hdr = f.read(max(len(BZ2_MAGIC), len(GZIP_MAGIC))) f.close() if hdr.startswith(BZ2_MAGIC): self.f = bz2.BZ2File(arg, 'rb') elif hdr.startswith(GZIP_MAGIC): self.f = gzip.GzipFile(arg, 'rb') else: self.f = open(arg, 'rb') else: sys.stderr.write("Error: Unsupported instance type\n") def close(self): ''' Close file object and stop iteration. ''' self.f.close() raise StopIteration def __iter__(self): return self def __next__(self): try: self.unpack_hdr() except MrtFormatError as e: self.mrt.err = MRT_ERR_C['MRT Header Error'] self.mrt.err_msg = e.msg return self try: self.unpack_data() except MrtFormatError as e: self.mrt.err = MRT_ERR_C['MRT Data Error'] self.mrt.err_msg = e.msg return self return self # for Python2 compatibility next = __next__ def unpack_hdr(self): ''' Decoder for MRT header. ''' as_len(4) af_num(0, 0) is_add_path(False) self.mrt = Mrt(self.f.read(12)) if len(self.mrt.buf) == 0: self.close() elif len(self.mrt.buf) < 12: raise MrtFormatError( 'Invalid MRT header length %d < 12 byte' % len(self.mrt.buf)) self.mrt.unpack() def unpack_data(self): ''' Decoder for MRT payload. ''' data = self.f.read(self.mrt.len) self.mrt.buf += data if len(data) < self.mrt.len: raise MrtFormatError( 'Invalid MRT data length %d < %d byte' % (len(data), self.mrt.len)) if len(MRT_ST[self.mrt.type]) \ and MRT_ST[self.mrt.type][self.mrt.subtype] == 'Unknown': raise MrtFormatError( 'Unsupported %s subtype %d(%s)' % (self.mrt.type, self.mrt.subtype, MRT_ST[self.mrt.type][self.mrt.subtype])) if self.mrt.type == MRT_T['TABLE_DUMP_V2']: self.unpack_td_v2(data) elif self.mrt.type == MRT_T['BGP4MP'] \ or self.mrt.type == MRT_T['BGP4MP_ET']: if self.mrt.subtype == BGP4MP_ST['BGP4MP_ENTRY'] \ or self.mrt.subtype == BGP4MP_ST['BGP4MP_SNAPSHOT']: self.p += self.mrt.len raise MrtFormatError( 'Unsupported %s subtype %d(%s)' % (MRT_T[self.mrt.type], self.mrt.subtype, BGP4MP_ST[self.mrt.subtype])) else: if self.mrt.type == MRT_T['BGP4MP_ET']: self.mrt.micro_ts = self.val_num(4) self.mrt.bgp = Bgp4Mp(data) self.mrt.bgp.unpack(self.mrt.subtype) elif self.mrt.type == MRT_T['TABLE_DUMP']: self.mrt.td = TableDump(data) self.mrt.td.unpack(self.mrt.subtype) else: self.p += self.mrt.len raise MrtFormatError( 'Unsupported MRT type %d(%s)' % (self.mrt.type, MRT_T[self.mrt.type])) return self.p def unpack_td_v2(self, data): ''' Decoder for Table_Dump_V2 format. ''' if self.mrt.subtype == TD_V2_ST['RIB_IPV4_UNICAST_ADDPATH'] \ or self.mrt.subtype == TD_V2_ST['RIB_IPV4_MULTICAST_ADDPATH'] \ or self.mrt.subtype == TD_V2_ST['RIB_IPV6_UNICAST_ADDPATH'] \ or self.mrt.subtype == TD_V2_ST['RIB_IPV6_MULTICAST_ADDPATH']: is_add_path(True) if self.mrt.subtype == TD_V2_ST['RIB_IPV4_UNICAST'] \ or self.mrt.subtype == TD_V2_ST['RIB_IPV4_MULTICAST'] \ or self.mrt.subtype == TD_V2_ST['RIB_IPV4_UNICAST_ADDPATH'] \ or self.mrt.subtype == TD_V2_ST['RIB_IPV4_MULTICAST_ADDPATH']: af_num.afi = AFI_T['IPv4'] self.mrt.rib = AfiSpecRib(data) self.mrt.rib.unpack() elif self.mrt.subtype == TD_V2_ST['RIB_IPV6_UNICAST'] \ or self.mrt.subtype == TD_V2_ST['RIB_IPV6_MULTICAST'] \ or self.mrt.subtype == TD_V2_ST['RIB_IPV6_UNICAST_ADDPATH'] \ or self.mrt.subtype == TD_V2_ST['RIB_IPV6_MULTICAST_ADDPATH']: af_num.afi = AFI_T['IPv6'] self.mrt.rib = AfiSpecRib(data) self.mrt.rib.unpack() elif self.mrt.subtype == TD_V2_ST['PEER_INDEX_TABLE']: self.mrt.peer = PeerIndexTable(data) self.mrt.peer.unpack() elif self.mrt.subtype == TD_V2_ST['RIB_GENERIC'] \ or self.mrt.subtype == TD_V2_ST['RIB_GENERIC_ADDPATH']: self.mrt.rib = RibGeneric(data) self.mrt.rib.unpack() else: self.p += self.mrt.len class Mrt(Base): ''' Class for MRT header. ''' __slots__ = [ 'buf', 'p', 'ts', 'type', 'subtype', 'len', 'micro_ts', 'bgp', 'peer', 'td', 'rib', 'err', 'err_msg' ] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self): ''' Decoder for MRT header. ''' self.ts = self.val_num(4) self.type = self.val_num(2) self.subtype = self.val_num(2) self.len = self.val_num(4) return self.p class TableDump(Base): ''' Class for Table_Dump format. ''' __slots__ = [ 'buf', 'p', 'view', 'seq', 'prefix', 'plen', 'status', 'org_time', 'peer_ip', 'peer_as', 'attr_len', 'attr' ] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self, subtype): ''' Decoder for Table_Dump format. ''' self.view = self.val_num(2) self.seq = self.val_num(2) self.prefix = self.val_addr(subtype) self.plen = self.val_num(1) self.status = self.val_num(1) self.org_time = self.val_num(4) # Considering the IPv4 peers advertising IPv6 Prefixes, first, # the Peer IP Address field is decoded as an IPv4 address. self.peer_ip = self.val_addr(AFI_T['IPv4']) if subtype == AFI_T['IPv6'] and self.val_num(12): self.p -= 16 self.peer_ip = self.val_addr(subtype) self.peer_as = self.val_asn(as_len(2)) attr_len = self.attr_len = self.val_num(2) self.attr = [] while attr_len > 0: attr = BgpAttr(self.buf[self.p:]) self.p += attr.unpack() self.attr.append(attr) attr_len -= attr.p return self.p class PeerIndexTable(Base): ''' Class for PEER_INDEX_TABLE format. ''' __slots__ = ['buf', 'p', 'collector', 'view_len', 'view', 'count', 'entry'] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self): ''' Decoder for PEER_INDEX_TABLE format. ''' self.collector = self.val_addr(AFI_T['IPv4']) self.view_len = self.val_num(2) self.view = self.val_str(self.view_len) self.count = self.val_num(2) self.entry = [] for _ in range(self.count): entry = PeerEntries(self.buf[self.p:]) self.p += entry.unpack() self.entry.append(entry) return self.p class PeerEntries(Base): ''' Class for Peer Entries. ''' __slots__ = ['buf', 'p', 'type', 'bgp_id', 'ip', 'asn'] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self): ''' Decoder for Peer Entries. ''' self.type = self.val_num(1) self.bgp_id = self.val_addr(AFI_T['IPv4']) af_num.afi = AFI_T['IPv6'] if self.type & 0x01 else AFI_T['IPv4'] self.ip = self.val_addr(af_num.afi) self.asn = self.val_asn(4 if self.type & (0x01 << 1) else 2) return self.p class RibGeneric(Base): ''' Class for RIB_GENERIC format. ''' __slots__ = ['buf', 'p', 'seq', 'afi', 'safi', 'nlri', 'count', 'entry'] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self): ''' Decoder for RIB_GENERIC format. ''' self.seq = self.val_num(4) af_num.afi = self.afi = self.val_num(2) af_num.safi = self.safi = self.val_num(1) n = self.val_num(1) self.p -= 1 self.nlri = self.val_nlri(self.p+(n+7)//8, self.afi, self.safi) self.count = self.val_num(2) self.entry = [] for _ in range(self.count): entry = RibEntries(self.buf[self.p:]) self.p += entry.unpack() self.entry.append(entry) return self.p class AfiSpecRib(Base): ''' Class for AFI/SAFI-Specific RIB format. ''' __slots__ = ['buf', 'p', 'seq', 'plen', 'prefix', 'count', 'entry'] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self): ''' Decoder for AFI/SAFI-Specific RIB format. ''' self.seq = self.val_num(4) self.plen = self.val_num(1) self.prefix = self.val_addr(af_num.afi, self.plen) self.count = self.val_num(2) self.entry = [] for _ in range(self.count): entry = RibEntries(self.buf[self.p:]) self.p += entry.unpack() self.entry.append(entry) return self.p class RibEntries(Base): ''' Class for Rib Entries format. ''' __slots__ = [ 'buf', 'p', 'peer_index', 'org_time', 'path_id', 'attr_len', 'attr' ] def __init__(self, buf): Base.__init__(self) self.buf = buf self.peer_index = None self.org_time = None self.path_id = None self.attr_len = None self.attr = None def unpack(self): ''' Decoder for Rib Entries format. ''' self.peer_index = self.val_num(2) self.org_time = self.val_num(4) if is_add_path(): self.path_id = self.val_num(4) attr_len = self.attr_len = self.val_num(2) self.attr = [] while attr_len > 0: attr = BgpAttr(self.buf[self.p:]) self.p += attr.unpack() self.attr.append(attr) attr_len -= attr.p return self.p class Bgp4Mp(Base): ''' Class for BGP4MP format. ''' __slots__ = [ 'buf', 'p', 'peer_as', 'local_as', 'ifindex', 'af', 'peer_ip', 'local_ip', 'old_state', 'new_state', 'msg' ] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self, subtype): ''' Decoder for BGP4MP format. ''' if subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE'] \ or subtype == BGP4MP_ST['BGP4MP_MESSAGE'] \ or subtype == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL'] \ or subtype == BGP4MP_ST['BGP4MP_MESSAGE_ADDPATH'] \ or subtype == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL_ADDPATH']: as_len(2) if subtype == BGP4MP_ST['BGP4MP_MESSAGE_ADDPATH'] \ or subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4_ADDPATH'] \ or subtype == BGP4MP_ST['BGP4MP_MESSAGE_LOCAL_ADDPATH'] \ or subtype == BGP4MP_ST['BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH']: is_add_path(True) self.peer_as = self.val_asn(as_len()) self.local_as = self.val_asn(as_len()) self.ifindex = self.val_num(2) af_num.afi = self.af = self.val_num(2) self.peer_ip = self.val_addr(self.af) self.local_ip = self.val_addr(self.af) if subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE'] \ or subtype == BGP4MP_ST['BGP4MP_STATE_CHANGE_AS4']: self.old_state = self.val_num(2) self.new_state = self.val_num(2) else: self.msg = BgpMessage(self.buf[self.p:]) self.p += self.msg.unpack() return self.p class BgpMessage(Base): ''' Class for BGP Message. ''' __slots__ = [ 'buf', 'p', 'marker', 'len', 'type', 'ver', 'my_as', 'holdtime', 'bgp_id', 'opt_len', 'opt_params', 'wd_len', 'withdrawn', 'attr_len', 'attr', 'nlri', 'err_code', 'err_subcode', 'data', 'afi', 'rsvd', 'safi' ] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self): ''' Decoder for BGP Message. ''' self.marker = self.val_bytes(16) self.len = self.val_num(2) self.type = self.val_num(1) if self.type == BGP_MSG_T['OPEN']: self.unpack_open() elif self.type == BGP_MSG_T['UPDATE']: self.unpack_update() elif self.type == BGP_MSG_T['NOTIFICATION']: self.unpack_notification() elif self.type == BGP_MSG_T['ROUTE-REFRESH']: self.unpack_route_refresh() self.p += self.len - self.p return self.p def unpack_open(self): ''' Decoder for BGP OPEN Message. ''' self.ver = self.val_num(1) self.my_as = self.val_num(2) self.holdtime = self.val_num(2) self.bgp_id = self.val_addr(AFI_T['IPv4']) opt_len = self.opt_len = self.val_num(1) self.opt_params = [] while opt_len > 0: opt_params = OptParams(self.buf[self.p:]) self.p += opt_params.unpack() self.opt_params.append(opt_params) opt_len -= opt_params.p def unpack_update(self): ''' Decoder for BGP UPDATE Message. ''' self.wd_len = self.val_num(2) self.withdrawn = self.val_nlri(self.p+self.wd_len, af_num.afi) self.attr_len = self.val_num(2) attr_len = self.p + self.attr_len self.attr = [] while self.p < attr_len: attr = BgpAttr(self.buf[self.p:]) self.p += attr.unpack() self.attr.append(attr) self.nlri = self.val_nlri(self.len, af_num.afi) def unpack_notification(self): ''' Decoder for BGP NOTIFICATION Message. ''' self.err_code = self.val_num(1) self.err_subcode = self.val_num(1) self.data = self.val_bytes(self.len - self.p) def unpack_route_refresh(self): ''' Decoder for BGP ROUTE-REFRESH Message. ''' self.afi = self.val_num(2) self.rsvd = self.val_num(1) self.safi = self.val_num(1) class OptParams(Base): ''' Class for BGP OPEN Optional Parameters. ''' __slots__ = [ 'buf', 'p', 'type', 'len', 'cap_type', 'cap_len', 'multi_ext', 'orf', 'graceful_restart', 'support_as4', 'add_path' ] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self): ''' Decoder for BGP OPEN Optional Parameters. ''' self.type = self.val_num(1) self.len = self.val_num(1) if self.type == BGP_OPT_PARAMS_T['Capabilities']: self.unpack_capabilities() else: self.p += self.len return self.p def unpack_capabilities(self): ''' Decoder for BGP Capabilities. ''' self.cap_type = self.val_num(1) self.cap_len = self.val_num(1) if self.cap_type == BGP_CAP_C['Multiprotocol Extensions for BGP-4']: self.unpack_multi_ext() elif self.cap_type == BGP_CAP_C['Route Refresh Capability for BGP-4']: self.p += self.len - 2 elif self.cap_type == BGP_CAP_C['Outbound Route Filtering Capability']: self.unpack_orf() elif self.cap_type == BGP_CAP_C['Graceful Restart Capability']: self.unpack_graceful_restart() elif self.cap_type == BGP_CAP_C['Support for 4-octet AS number capability']: self.unpack_support_as4() elif self.cap_type == BGP_CAP_C['ADD-PATH Capability']: self.unpack_add_path() else: self.p += self.len - 2 def unpack_multi_ext(self): ''' Decoder for Multiprotocol Extensions for BGP-4. ''' self.multi_ext = {} self.multi_ext['afi'] = self.val_num(2) self.multi_ext['rsvd'] = self.val_num(1) self.multi_ext['safi'] = self.val_num(1) def unpack_orf(self): ''' Decoder for Outbound Route Filtering Capability. ''' self.orf = {} self.orf['afi'] = self.val_num(2) self.orf['rsvd'] = self.val_num(1) self.orf['safi'] = self.val_num(1) self.orf['number'] = self.val_num(1) self.orf['entry'] = [] for _ in range(self.orf['number']): entry = {} entry['type'] = self.val_num(1) entry['send_recv'] = self.val_num(1) self.orf['entry'].append(entry) def unpack_graceful_restart(self): ''' Decoder for Graceful Restart Capability. ''' self.graceful_restart = {} n = self.val_num(2) self.graceful_restart['flag'] = n & 0xf000 self.graceful_restart['sec'] = n & 0x0fff self.graceful_restart['entry'] = [] cap_len = self.cap_len while cap_len > 2: entry = {} entry['afi'] = self.val_num(2) entry['safi'] = self.val_num(1) entry['flag'] = self.val_num(1) self.graceful_restart['entry'].append(entry) cap_len -= 4 def unpack_support_as4(self): ''' Decoder for Support for 4-octet AS number capability. ''' self.support_as4 = self.val_asn(4) def unpack_add_path(self): ''' Decoder for ADD-PATH Capability ''' self.add_path = [] cap_len = self.cap_len while cap_len > 2: entry = {} entry['afi'] = self.val_num(2) entry['safi'] = self.val_num(1) entry['send_recv'] = self.val_num(1) self.add_path.append(entry) cap_len -= 4 class BgpAttr(Base): ''' Class for BGP path attributes ''' __slots__ = [ 'buf', 'p', 'flag', 'type', 'len', 'origin', 'as_path', 'next_hop', 'med', 'local_pref', 'aggr', 'comm', 'org_id', 'cl_list', 'mp_reach', 'mp_unreach', 'ext_comm', 'as4_path', 'as4_aggr', 'aigp', 'attr_set', 'large_comm', 'val' ] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self): ''' Decoder for BGP path attributes ''' self.flag = self.val_num(1) self.type = self.val_num(1) if self.flag & 0x01 << 4: self.len = self.val_num(2) else: self.len = self.val_num(1) if self.type == BGP_ATTR_T['ORIGIN']: self.unpack_origin() elif self.type == BGP_ATTR_T['AS_PATH']: self.unpack_as_path() elif self.type == BGP_ATTR_T['NEXT_HOP']: self.unpack_next_hop() elif self.type == BGP_ATTR_T['MULTI_EXIT_DISC']: self.unpack_multi_exit_disc() elif self.type == BGP_ATTR_T['LOCAL_PREF']: self.unpack_local_pref() elif self.type == BGP_ATTR_T['AGGREGATOR']: self.unpack_aggregator() elif self.type == BGP_ATTR_T['COMMUNITY']: self.unpack_community() elif self.type == BGP_ATTR_T['ORIGINATOR_ID']: self.unpack_originator_id() elif self.type == BGP_ATTR_T['CLUSTER_LIST']: self.unpack_cluster_list() elif self.type == BGP_ATTR_T['MP_REACH_NLRI']: self.unpack_mp_reach_nlri() elif self.type == BGP_ATTR_T['MP_UNREACH_NLRI']: self.unpack_mp_unreach_nlri() elif self.type == BGP_ATTR_T['EXTENDED_COMMUNITIES']: self.unpack_extended_communities() elif self.type == BGP_ATTR_T['AS4_PATH']: self.unpack_as4_path() elif self.type == BGP_ATTR_T['AS4_AGGREGATOR']: self.unpack_as4_aggregator() elif self.type == BGP_ATTR_T['AIGP']: self.unpack_aigp() elif self.type == BGP_ATTR_T['ATTR_SET']: self.unpack_attr_set() elif self.type == BGP_ATTR_T['LARGE_COMMUNITY']: self.unpack_large_community() else: self.val = self.val_bytes(self.len) return self.p def unpack_origin(self): ''' Decoder for ORIGIN attribute ''' self.origin = self.val_num(1) def unpack_as_path(self): ''' Decoder for AS_PATH attribute ''' attr_len = self.p + self.len self.as_path = [] while self.p < attr_len: path_seg = {} path_seg['type'] = self.val_num(1) path_seg['len'] = self.val_num(1) path_seg['val'] = [] for _ in range(path_seg['len']): path_seg['val'].append(self.val_asn(as_len())) self.as_path.append(path_seg) def unpack_next_hop(self): ''' Decoder for NEXT_HOP attribute ''' if self.len == 4: self.next_hop = self.val_addr(AFI_T['IPv4']) elif self.len == 16: self.next_hop = self.val_addr(AFI_T['IPv6']) else: self.p += self.len self.next_hop = None def unpack_multi_exit_disc(self): ''' Decoder for MULTI_EXIT_DISC attribute ''' self.med = self.val_num(4) def unpack_local_pref(self): ''' Decoder for LOCAL_PREF attribute ''' self.local_pref = self.val_num(4) def unpack_aggregator(self): ''' Decoder for AGGREGATOR attribute ''' self.aggr = {} n = 2 if self.len < 8 else 4 self.aggr['asn'] = self.val_asn(n) self.aggr['id'] = self.val_addr(AFI_T['IPv4']) def unpack_community(self): ''' Decoder for COMMUNITY attribute ''' attr_len = self.p + self.len self.comm = [] while self.p < attr_len: val = self.val_num(4) self.comm.append( '%d:%d' % ((val & 0xffff0000) >> 16, val & 0x0000ffff)) def unpack_originator_id(self): ''' Decoder for ORIGINATOR_ID attribute ''' self.org_id = self.val_addr(AFI_T['IPv4']) def unpack_cluster_list(self): ''' Decoder for CLUSTER_LIST attribute ''' attr_len = self.p + self.len self.cl_list = [] while self.p < attr_len: self.cl_list.append(self.val_addr(AFI_T['IPv4'])) def unpack_mp_reach_nlri(self): ''' Decoder for MP_REACH_NLRI attribute ''' attr_len = self.p + self.len self.mp_reach = {} self.mp_reach['afi'] = self.val_num(2) if AFI_T[self.mp_reach['afi']] != 'Unknown': af_num.afi = self.mp_reach['afi'] af_num.safi = self.mp_reach['safi'] = self.val_num(1) self.mp_reach['nlen'] = self.val_num(1) if af_num.afi != AFI_T['IPv4'] and af_num.afi != AFI_T['IPv6']: self.p = attr_len return if af_num.safi != SAFI_T['UNICAST'] \ and af_num.safi != SAFI_T['MULTICAST'] \ and af_num.safi != SAFI_T['L3VPN_UNICAST'] \ and af_num.safi != SAFI_T['L3VPN_MULTICAST']: self.p = attr_len return if af_num.safi == SAFI_T['L3VPN_UNICAST'] \ or af_num.safi == SAFI_T['L3VPN_MULTICAST']: self.mp_reach['rd'] = self.val_rd() else: self.p -= 2 self.mp_reach = {} self.mp_reach['nlen'] = self.val_num(1) self.mp_reach['next_hop'] = [] self.mp_reach['next_hop'].append(self.val_addr(af_num.afi)) if self.mp_reach['nlen'] == 32 and af_num.afi == AFI_T['IPv6']: self.mp_reach['next_hop'].append(self.val_addr(af_num.afi)) if 'afi' in self.mp_reach: self.mp_reach['rsvd'] = self.val_num(1) self.mp_reach['nlri'] = self.val_nlri( attr_len, af_num.afi, af_num.safi) def unpack_mp_unreach_nlri(self): ''' Decoder for MP_UNREACH_NLRI attribute ''' attr_len = self.p + self.len self.mp_unreach = {} self.mp_unreach['afi'] = self.val_num(2) self.mp_unreach['safi'] = self.val_num(1) if self.mp_unreach['afi'] != AFI_T['IPv4'] \ and self.mp_unreach['afi'] != AFI_T['IPv6']: self.p = attr_len return if self.mp_unreach['safi'] != SAFI_T['UNICAST'] \ and self.mp_unreach['safi'] != SAFI_T['MULTICAST'] \ and self.mp_unreach['safi'] != SAFI_T['L3VPN_UNICAST'] \ and self.mp_unreach['safi'] != SAFI_T['L3VPN_MULTICAST']: self.p = attr_len return self.mp_unreach['withdrawn'] = self.val_nlri( attr_len, self.mp_unreach['afi'], self.mp_unreach['safi']) def unpack_extended_communities(self): ''' Decoder for EXT_COMMUNITIES attribute ''' attr_len = self.p + self.len self.ext_comm = [] while self.p < attr_len: ext_comm = self.val_num(8) self.ext_comm.append(ext_comm) def unpack_as4_path(self): ''' Decoder for AS4_PATH attribute ''' attr_len = self.p + self.len self.as4_path = [] while self.p < attr_len: path_seg = {} path_seg['type'] = self.val_num(1) path_seg['len'] = self.val_num(1) path_seg['val'] = [] for _ in range(path_seg['len']): path_seg['val'].append(self.val_asn(4)) self.as4_path.append(path_seg) def unpack_as4_aggregator(self): ''' Decoder for AS4_AGGREGATOR attribute ''' self.as4_aggr = {} self.as4_aggr['asn'] = self.val_asn(4) self.as4_aggr['id'] = self.val_addr(AFI_T['IPv4']) def unpack_aigp(self): ''' Decoder for AIGP attribute ''' attr_len = self.p + self.len self.aigp = [] while self.p < attr_len: aigp = {} aigp['type'] = self.val_num(1) aigp['len'] = self.val_num(2) aigp['val'] = self.val_num(aigp['len'] - 3) self.aigp.append(aigp) def unpack_attr_set(self): ''' Decoder for ATTR_SET attribute ''' attr_len = self.p + self.len self.attr_set = {} self.attr_set['origin_as'] = self.val_asn(4) attr_len -= 4 self.attr_set['attr'] = [] while self.p < attr_len: attr = BgpAttr(self.buf[self.p:]) self.p += attr.unpack() self.attr_set['attr'].append(attr) def unpack_large_community(self): ''' Decoder for LARGE_COMMUNITY attribute ''' attr_len = self.p + self.len self.large_comm = [] while self.p < attr_len: global_admin = self.val_num(4) local_data_part_1 = self.val_num(4) local_data_part_2 = self.val_num(4) self.large_comm.append( '%d:%d:%d' % (global_admin, local_data_part_1, local_data_part_2)) class Nlri(Base): ''' Class for NLRI. ''' __slots__ = ['buf', 'p', 'path_id', 'label', 'rd', 'plen', 'prefix'] def __init__(self, buf): Base.__init__(self) self.buf = buf def unpack(self, af, saf=0, add_path=0): ''' Decoder for NLRI. ''' if add_path: self.path_id = self.val_num(4) self.plen = plen = self.val_num(1) if saf == SAFI_T['L3VPN_UNICAST'] \ or saf == SAFI_T['L3VPN_MULTICAST']: plen = self.unpack_l3vpn(plen) if af == AFI_T['IPv4'] and plen > 32 \ or af == AFI_T['IPv6'] and plen > 128: raise MrtFormatError( 'Invalid prefix length %d (%s)' % (self.plen, AFI_T[af])) self.prefix = self.val_addr(af, plen) return self.p def unpack_l3vpn(self, plen): ''' Decoder for L3VPN NLRI. ''' self.label = [] while True: label = self.val_num(3) self.label.append(label) if label & LBL_BOTTOM or label == LBL_WITHDRAWN: break self.rd = self.val_rd() plen -= (3 * len(self.label) + 8) * 8 return plen def is_dup(self, l): ''' Check whether there is duplicate routes in NLRI. ''' for e in l: if self.plen == e.plen and self.prefix == e.prefix \ and self.label == e.label and self.rd == e.rd: raise MrtFormatError( 'Duplicate prefix %s/%d' % (self.prefix, self.plen)) def is_valid(self): ''' Check whether route is valid. ''' if self.label is not None: plen = self.plen - (len(self.label) * 3 + 8) * 8 else: plen = self.plen if ':' in self.prefix: b = socket.inet_pton(socket.AF_INET6, self.prefix) t = struct.unpack("!QQ", b) n = t[0] << 64 | t[1] plen_max = 128 else: b = socket.inet_pton(socket.AF_INET, self.prefix) n = struct.unpack("!L", b)[0] plen_max = 32 if n & ~(-1 << (plen_max - plen)): raise MrtFormatError( 'Invalid prefix %s/%d' % (self.prefix, self.plen)) mrtparse-1.6/mrtparse.egg-info/0000755000175000017500000000000013125764616017225 5ustar t2munet2mune00000000000000mrtparse-1.6/mrtparse.egg-info/PKG-INFO0000644000175000017500000002424213125764616020326 0ustar t2munet2mune00000000000000Metadata-Version: 1.1 Name: mrtparse Version: 1.6 Summary: MRT format data parser Home-page: https://github.com/YoshiyukiYamauchi/mrtparse Author: Tetsumune KISO, Yoshiyuki YAMAUCHI, Nobuhiro ITOU Author-email: t2mune@gmail.com, info@greenhippo.co.jp, js333123@gmail.com License: Apache License 2.0 Description: mrtparse ======== | mrtparse is a module to read and analyze the MRT format data. | The MRT format can be used to export routing protocol messages, state changes, and routing information base contents, and is defined in RFC6396_. | Programs like Quagga_ / Zebra_, BIRD_, OpenBGPD_ and PyRT_ can dump the MRT format data. | You can also download archives from `the Route Views Projects`_, `RIPE NCC`_. .. _RFC6396: https://tools.ietf.org/html/rfc6396 .. _Quagga: http://www.nongnu.org/quagga/ .. _Zebra: https://www.gnu.org/software/zebra/ .. _BIRD: http://bird.network.cz/ .. _OpenBGPD: http://www.openbgpd.org/ .. _PyRT: https://github.com/mor1/pyrt .. _`the Route Views Projects`: http://archive.routeviews.org/ .. _`RIPE NCC`: https://www.ripe.net/analyse/internet-measurements/routing-information-service-ris/ris-raw-data Supported MRT types ------------------- +-------------------+---------+ | Name | Value | +===================+=========+ | TABLE\_DUMP | 12 | +-------------------+---------+ | TABLE\_DUMP\_V2 | 13 | +-------------------+---------+ | BGP4MP | 16 | +-------------------+---------+ | BGP4MP\_ET | 17 | +-------------------+---------+ Supported TABLE_DUMP subtypes ------------------------------ +-------------------+---------+ | Name | Value | +===================+=========+ | AFI\_IPv4 | 1 | +-------------------+---------+ | AFI\_IPv6 | 2 | +-------------------+---------+ Supported TABLE_DUMP_V2 subtypes -------------------------------- +-------------------------------+---------+ | Name | Value | +===============================+=========+ | PEER_INDEX_TABLE | 1 | +-------------------------------+---------+ | RIB\_IPV4\_UNICAST | 2 | +-------------------------------+---------+ | RIB\_IPV4\_MULTICAST | 3 | +-------------------------------+---------+ | RIB\_IPV6\_UNICAST | 4 | +-------------------------------+---------+ | RIB\_IPV6\_MULTICAST | 5 | +-------------------------------+---------+ | RIB\_GENERIC | 6 | +-------------------------------+---------+ | RIB\_IPV4\_UNICAST\_ADDPATH | 8 | +-------------------------------+---------+ | RIB\_IPV4\_MULTICAST\_ADDPATH | 9 | +-------------------------------+---------+ | RIB\_IPV6\_UNICAST\_ADDPATH | 10 | +-------------------------------+---------+ | RIB\_IPV6\_MULTICAST\_ADDPATH | 11 | +-------------------------------+---------+ | RIB\_GENERIC\_ADDPATH | 12 | +-------------------------------+---------+ Supported BGP4MP/BGP4MP_ET subtypes ----------------------------------- +--------------------------------------+---------+ | Name | Value | +======================================+=========+ | BGP4MP\_STATE\_CHANGE | 0 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE | 1 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4 | 4 | +--------------------------------------+---------+ | BGP4MP\_STATE\_CHANGE\_AS4 | 5 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_LOCAL | 6 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4\_LOCAL | 7 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_ADDPATH | 8 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4\_ADDPATH | 9 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_LOCAL\_ADDPATH | 10 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4\_LOCAL\_ADDPATH | 11 | +--------------------------------------+---------+ Supported BGP capabilities -------------------------- +--------------------------------------------+---------+ | Name | Value | +============================================+=========+ | Multiprotocol Extensions for BGP-4 | 1 | +--------------------------------------------+---------+ | Route Refresh Capability for BGP-4 | 2 | +--------------------------------------------+---------+ | Outbound Route Filtering Capability | 3 | +--------------------------------------------+---------+ | Graceful Restart Capability | 64 | +--------------------------------------------+---------+ | Support for 4-octet AS number capability | 65 | +--------------------------------------------+---------+ | ADD-PATH Capability | 69 | +--------------------------------------------+---------+ Supported BGP attributes ------------------------ +-------------------------+---------+ | Name | Value | +=========================+=========+ | ORIGIN | 1 | +-------------------------+---------+ | AS\_PATH | 2 | +-------------------------+---------+ | NEXT\_HOP | 3 | +-------------------------+---------+ | MULTI\_EXIT\_DISC | 4 | +-------------------------+---------+ | LOCAL\_PREF | 5 | +-------------------------+---------+ | ATOMIC\_AGGREGATE | 6 | +-------------------------+---------+ | AGGREGATOR | 7 | +-------------------------+---------+ | COMMUNITY | 8 | +-------------------------+---------+ | ORIGINATOR\_ID | 9 | +-------------------------+---------+ | CLUSTER\_LIST | 10 | +-------------------------+---------+ | MP\_REACH\_NLRI | 14 | +-------------------------+---------+ | MP\_UNREACH\_NLRI | 15 | +-------------------------+---------+ | EXTENDED\_COMMUNITIES | 16 | +-------------------------+---------+ | AS4\_PATH | 17 | +-------------------------+---------+ | AS4\_AGGREGATOR | 18 | +-------------------------+---------+ | AIGP | 26 | +-------------------------+---------+ | LARGE\_COMMUNITY | 32 | +-------------------------+---------+ | ATTR\_SET | 128 | +-------------------------+---------+ Requirements ------------ Python2 or Python3 or PyPy or PyPy3 Installation ------------ :: $ pip install mrtparse or :: $ git clone https://github.com/YoshiyukiYamauchi/mrtparse.git $ cd mrtparse $ python setup.py install Usage ----- :: from mrtparse import * or :: import mrtparse Programming ----------- First, import the module. :: from mrtparse import * | And pass a MRT format data as a filepath string or file object to a class Reader(). | It is also supported gzip and bzip2 format. | You can retrieve each entry from the returned object using a loop and then process it. :: d = Reader(f) for m in d: We have prepared some example scripts and sample data in `"examples"`_ and `"samples"`_ directory. .. _`"examples"`: https://github.com/YoshiyukiYamauchi/mrtparse/tree/master/examples .. _`"samples"`: https://github.com/YoshiyukiYamauchi/mrtparse/tree/master/samples Authors ------- | Tetsumune KISO t2mune@gmail.com | Yoshiyuki YAMAUCHI info@greenhippo.co.jp | Nobuhiro ITOU js333123@gmail.com License ------- | Licensed under the `Apache License, Version 2.0`_ | Copyright © 2017 Tetsumune KISO .. _`Apache License, Version 2.0`: http://www.apache.org/licenses/LICENSE-2.0 Keywords: mrt bgp Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Internet Classifier: Topic :: System :: Networking mrtparse-1.6/mrtparse.egg-info/SOURCES.txt0000644000175000017500000000141613125764616021113 0ustar t2munet2mune00000000000000MANIFEST.in README.rst setup.cfg setup.py examples/README.rst examples/mrt2bgpdump.py examples/mrt2exabgp.py examples/print_all.py examples/slice.py examples/summary.py mrtparse/__init__.py mrtparse.egg-info/PKG-INFO mrtparse.egg-info/SOURCES.txt mrtparse.egg-info/dependency_links.txt mrtparse.egg-info/not-zip-safe mrtparse.egg-info/top_level.txt samples/README.rst samples/bird-mrtdump.conf samples/bird-mrtdump_bgp samples/bird-mrtdump_rib samples/bird.conf samples/bird6-mrtdump.conf samples/bird6-mrtdump_bgp samples/bird6-mrtdump_rib samples/bird6.conf samples/bird6_bgp samples/bird_bgp samples/openbgpd.conf samples/openbgpd_bgp samples/openbgpd_rib_table samples/openbgpd_rib_table-mp samples/openbgpd_rib_table-v2 samples/quagga.conf samples/quagga_bgp samples/quagga_ribmrtparse-1.6/mrtparse.egg-info/dependency_links.txt0000644000175000017500000000000113125764616023273 0ustar t2munet2mune00000000000000 mrtparse-1.6/mrtparse.egg-info/not-zip-safe0000644000175000017500000000000113125764161021446 0ustar t2munet2mune00000000000000 mrtparse-1.6/mrtparse.egg-info/top_level.txt0000644000175000017500000000001113125764616021747 0ustar t2munet2mune00000000000000mrtparse mrtparse-1.6/samples/0000755000175000017500000000000013125764616015342 5ustar t2munet2mune00000000000000mrtparse-1.6/samples/README.rst0000644000175000017500000001545713125763144017040 0ustar t2munet2mune00000000000000Sample MRT format Data ====================== BIRD ---- MRT Type/Subtype ~~~~~~~~~~~~~~~~ +-------------------------+-----------------+--------------------------------------+ | File Name | Type | Subtype | | | | | +=========================+=================+======================================+ | bird\_bgp | BGP4MP | | BGP4MP\_MESSAGE | | | | | BGP4MP\_MESSAGE\_AS4 | | | | | BGP4MP\_STATE\_CHANGE\_AS4 | +-------------------------+-----------------+--------------------------------------+ | bird6\_bgp | BGP4MP | | BGP4MP\_MESSAGE | | | | | BGP4MP\_MESSAGE\_AS4 | | | | | BGP4MP\_STATE\_CHANGE\_AS4 | +-------------------------+-----------------+--------------------------------------+ Summary ~~~~~~~ It generated by `BIRD`_, and includes IPv4/IPv6 peer, IPv4/IPv6 prefix, all BGP message types, ADD-PATH capability, and `LARGE_COMMUNITY`_. .. _`BIRD`: http://bird.network.cz/ .. _`LARGE_COMMUNITY`: http://largebgpcommunities.net/ BIRD (mrtdump branch) --------------------- MRT Type/Subtype ~~~~~~~~~~~~~~~~ +-------------------------+-----------------+--------------------------------------+ | File Name | Type | Subtype | | | | | +=========================+=================+======================================+ | bird-mrtdump\_bgp | BGP4MP | | BGP4MP\_MESSAGE | | | | | BGP4MP\_MESSAGE\_AS4\_ADDPATH | | | | | BGP4MP\_STATE\_CHANGE\_AS4 | +-------------------------+-----------------+--------------------------------------+ | bird-mrtdump\_rib | TABLE\_DUMP\_V2 | | PEER\_INDEX\_TABLE | | | | | RIB\_IPV4\_UNICAST | | | | | RIB\_IPV4\_UNICAST\_ADDPATH | +-------------------------+-----------------+--------------------------------------+ | bird6-mrtdump\_bgp | BGP4MP | | BGP4MP\_MESSAGE | | | | | BGP4MP\_MESSAGE\_AS4\_ADDPATH | | | | | BGP4MP\_STATE\_CHANGE\_AS4 | +-------------------------+-----------------+--------------------------------------+ | bird6-mrtdump\_rib | TABLE\_DUMP\_V2 | | PEER\_INDEX\_TABLE | | | | | RIB\_IPV6\_UNICAST | | | | | RIB\_IPV6\_UNICAST\_ADDPATH | +-------------------------+-----------------+--------------------------------------+ Summary ~~~~~~~ It generated by `BIRD (mrtdump branch)`_, and includes IPv4/IPv6 peer, IPv4/IPv6 prefix, all BGP message types, and ADD-PATH capability. This repository supports MRT subtypes for ADD-PATH capability. These are defined in `RFC8050`_. .. _`BIRD (mrtdump branch)`: https://gitlab.labs.nic.cz/labs/bird/tree/mrtdump .. _`RFC8050`: https://tools.ietf.org/html/RFC8050 OpenBGPD -------- MRT Type/Subtype ~~~~~~~~~~~~~~~~ +-------------------------+-----------------+--------------------------------------+ | File Name | Type | Subtype | | | | | +=========================+=================+======================================+ | openbgpd\_bgp | BGP4MP | | BGP4MP\_MESSAGE | | | | | BGP4MP\_MESSAGE\_AS4 | | | | | BGP4MP\_STATE\_CHANGE | | | | | BGP4MP\_STATE\_CHANGE\_AS4 | +-------------------------+-----------------+--------------------------------------+ | openbgpd\_rib\_table | TABLE\_DUMP | | AFI\_IPv4 | | | | | AFI\_IPv6 | +-------------------------+-----------------+--------------------------------------+ | openbgpd\_rib\_table-mp | BGP4MP | | BGP4MP\_ENTRY | +-------------------------+-----------------+--------------------------------------+ | openbgpd\_rib\_table-v2 | TABLE\_DUMP\_V2 | | PEER\_INDEX\_TABLE | | | | | RIB\_IPV4\_UNICAST | | | | | RIB\_IPV6\_UNICAST | | | | | RIB\_GENERIC | +-------------------------+-----------------+--------------------------------------+ Summary ~~~~~~~ It generated by `OpenBGPD`_, and includes IPv4/IPv6 peers, IPv4/IPv6/VPNv4 prefix, all BGP message types, and unsupported MRT subtype BGP4MP\_ENTRY. .. _`OpenBGPD`: http://www.openbgpd.org/ Quagga ------ MRT Type/Subtype ~~~~~~~~~~~~~~~~ +-------------------------+-----------------+--------------------------------------+ | File Name | Type | Subtype | | | | | +=========================+=================+======================================+ | quagga\_bgp | BGP4MP | | BGP4MP\_MESSAGE | | | | | BGP4MP\_MESSAGE\_AS4 | | | | | BGP4MP\_STATE\_CHANGE\_AS4 | +-------------------------+-----------------+--------------------------------------+ | quagga\_rib | TABLE\_DUMP\_V2 | | PEER\_INDEX\_TABLE | | | | | RIB\_IPV4\_UNICAST | | | | | RIB\_IPV6\_UNICAST | +-------------------------+-----------------+--------------------------------------+ Summary ~~~~~~~ It generated by `Quagga`_, and includes IPv4/IPv6 peers, IPv4/IPv6/VPNv4 prefix, and all BGP message types. .. _Quagga: http://www.nongnu.org/quagga/ Authors ------- | Tetsumune KISO t2mune@gmail.com | Yoshiyuki YAMAUCHI info@greenhippo.co.jp | Nobuhiro ITOU js333123@gmail.com License ------- | Licensed under the `Apache License, Version 2.0`_ | Copyright © 2017 Tetsumune KISO .. _`Apache License, Version 2.0`: http://www.apache.org/licenses/LICENSE-2.0 mrtparse-1.6/samples/bird-mrtdump.conf0000644000175000017500000000133413125763144020613 0ustar t2munet2mune00000000000000mrtdump protocols all; mrtdump "/tmp/bird-mrtdump_bgp"; mrtdump routes { filename "/tmp/bird-mrtdump_rib"; } log syslog { debug, trace, info, remote, warning, error, auth, fatal, bug }; log stderr all; log "/var/log/bird.log" all; debug protocols all; watchdog warning 5 s; watchdog timeout 30 s; router id 192.168.0.16; protocol kernel { learn; scan time 20; export all; } protocol device { scan time 10; } protocol direct { interface "*"; } protocol bgp { hold time 90; startup hold time 10; connect retry time 10; keepalive time 30; local as 65000; neighbor 192.168.0.10 as 65000; add paths on; enable route refresh on; graceful restart on; enable as4 on; } mrtparse-1.6/samples/bird-mrtdump_bgp0000644000175000017500000000352313125763144020521 0ustar t2munet2mune00000000000000X X X X Z f@@xA EGX X ' X X  S@@VVV@  @d d,   X  S@@@ @d X   X + X' ' X/ + XC ' XI ) XI XIXJXN XN XN  Z f@@xA EGXN XN ' XN XN  S@@VVV@  @d d,   XN  S@@@ @d X   XN + Xj ' mrtparse-1.6/samples/bird-mrtdump_rib0000644000175000017500000000303013125763144020516 0ustar t2munet2mune00000000000000X (master X X X  X X X X XS@@VVV@  @d d,   XS@@@ @d X   X XS@@VVV@  @d d,   XS@@@ @d X   X XS@@VVV@  @d d,   XS@@@ @d X   XP (master XP X XP  X XS X XS XOS@@VVV@  @d d,   XOS@@@ @d X   XS XOS@@VVV@  @d d,   XOS@@@ @d X   XS XOS@@VVV@  @d d,   XOS@@@ @d X   mrtparse-1.6/samples/bird.conf0000644000175000017500000000176713125763144017137 0ustar t2munet2mune00000000000000mrtdump protocols all; mrtdump "/tmp/bird_bgp"; log syslog { debug, trace, info, remote, warning, error, auth, fatal, bug }; log stderr all; log "/var/log/bird.log" all; debug protocols all; watchdog warning 5 s; watchdog timeout 30 s; router id 192.168.0.16; protocol kernel { learn; scan time 20; export all; } protocol device { scan time 10; } protocol direct { interface "*"; } protocol static { route 192.168.16.0/24 unreachable; } filter ibgp_out { if source = RTS_STATIC then { bgp_large_community.add((65000,4294967295,100)); bgp_large_community.add((65000,4294967295,200)); bgp_large_community.add((65000,4294967295,300)); accept; } reject; } protocol bgp { hold time 90; startup hold time 10; connect retry time 10; keepalive time 30; local as 65000; neighbor 192.168.0.10 as 65000; add paths on; enable route refresh on; graceful restart on; enable as4 on; export filter ibgp_out; } mrtparse-1.6/samples/bird6-mrtdump.conf0000644000175000017500000000133313125763144020700 0ustar t2munet2mune00000000000000mrtdump protocols all; mrtdump "/tmp/bird6-mrtdump_bgp"; mrtdump routes { filename "/tmp/bird6-mrtdump_rib"; } log syslog { debug, trace, info, remote, warning, error, auth, fatal, bug }; log stderr all; log "/var/log/bird6.log" all; debug protocols all; watchdog warning 5 s; watchdog timeout 30 s; router id 192.168.0.16; protocol kernel { learn; scan time 20; export all; } protocol device { scan time 10; } protocol direct { interface "*"; } protocol bgp { hold time 90; startup hold time 10; connect retry time 10; keepalive time 30; local as 65000; neighbor fd02::10 as 65000; add paths on; enable route refresh on; graceful restart on; enable as4 on; } mrtparse-1.6/samples/bird6-mrtdump_bgp0000644000175000017500000000510513125763144020605 0ustar t2munet2mune00000000000000X 0X0X0XwOZ 2@@xAEGX0X ?X0X @@VVV @d d,   L  @@@X @@@d X   L  @@@X JX( ?X2 CXF ?XI AXI0XI0XL0XP0XP0XP {OZ 2@@xAEGXP0XP ?XP0XP @@VVV @d d,   L  @@@XP @@@d X   L  @@@XP JXk ?mrtparse-1.6/samples/bird6-mrtdump_rib0000644000175000017500000000154413125763144020614 0ustar t2munet2mune00000000000000X @master X X X @XL@@VVV @d d,   XL@@@d X   X @XL@@VVV @d d,   XL@@@d X   X @XL@@VVV @d d,   XL@@@d X   X @X XP 'masterXP X XP @X mrtparse-1.6/samples/bird6.conf0000644000175000017500000000176213125763144017220 0ustar t2munet2mune00000000000000mrtdump protocols all; mrtdump "/tmp/bird6_bgp"; log syslog { debug, trace, info, remote, warning, error, auth, fatal, bug }; log stderr all; log "/var/log/bird6.log" all; debug protocols all; watchdog warning 5 s; watchdog timeout 30 s; router id 192.168.0.16; protocol kernel { learn; scan time 20; export all; } protocol device { scan time 10; } protocol direct { interface "*"; } protocol static { route fd02:17::/64 unreachable; } filter ibgp_out { if source = RTS_STATIC then { bgp_large_community.add((65000,4294967295,100)); bgp_large_community.add((65000,4294967295,200)); bgp_large_community.add((65000,4294967295,300)); accept; } reject; } protocol bgp { hold time 90; startup hold time 10; connect retry time 10; keepalive time 30; local as 65000; neighbor fd02::10 as 65000; add paths on; enable route refresh on; graceful restart on; enable as4 on; export filter ibgp_out; } mrtparse-1.6/samples/bird6_bgp0000644000175000017500000000572513125763144017127 0ustar t2munet2mune00000000000000X90X=0X=0X=wOZ 2@@xAEGX=0X=?X=0X=@@VVV @d d,   L  @@@X=@@@d X   L  @@@X=JX=y@@@d   $d,2  @XV?XdCXq?XډAXډ0Xډ0Xډ0Xڎ0Xڎ0Xڎ{OZ 2@@xAEGXڎ0Xڎ?Xڎ0Xڎ@@VVV @d d,   L  @@@Xڎ@@@d X   L  @@@XڎJXڎy@@@d   $d,2  @Xک?mrtparse-1.6/samples/bird_bgp0000644000175000017500000000414513125763144017034 0ustar t2munet2mune00000000000000X9X= X= X= Z f@@xA EGX= X=' X= X= S@@VVV@  @d d,   X= S@@@ @d X   X=+ X=} iJ@@@ @d   $d,XV' X^+ Xp' Xڄ) Xڄ XڄXچXڋ Xڋ Xڋ Z f@@xA EGXڋ Xڋ' Xڋ Xڋ S@@VVV@  @d d,   Xڋ S@@@ @d X   Xڋ+ Xڋ} iJ@@@ @d   $d,Xڢ' mrtparse-1.6/samples/openbgpd.conf0000644000175000017500000000062613125763144020006 0ustar t2munet2mune00000000000000# dump table "/tmp/openbgpd_rib_table" # dump table-v2 "/tmp/openbgpd_rib_table-v2" dump table-mp "/tmp/openbgpd_rib_table-mp" dump all in "/tmp/openbgpd_bgp" dump all out "/tmp/openbgpd_bgp" log updates AS 65000 router-id 192.168.0.19 listen on 192.168.0.19 holdtime 90 group ibgp { announce IPv4 unicast announce IPv4 vpn announce IPv6 unicast remote-as 65000 neighbor 192.168.0.10 } mrtparse-1.6/samples/openbgpd_bgp0000644000175000017500000002001013125763144017677 0ustar t2munet2mune00000000000000V',    V'f V']    5 AV'0    V'?    V'0    V(q fa DAA EV(f V(' fV(f V-    qZA  @  @  @    @@@dV-    jQ  @       @@@dV-    W@'  @  @  @@@dV-?    V- flU h@@@dd  V-v fbK  p@@@dd  V-' fV. fqZA  @  @  @    @@@dV. fjQ  @       @@@dV.k fW@'  @  @  @@@dV.X fD)@@@@d  V.T f@@@@ @d V.b fN4@@@@d  V.K f7@@@e@dV.P f<@@@ e@d V.L f8@@@d@d V.L f8@@@d@d V.L f8@@@ d@d VK?    VK' fV^+ fV^+ fV^+ fV`X fD)@@@@d  V`T f@@@@ @d V`b fN4@@@@d  V`K f7@@@e@dV`P f<@@@ e@d V`L f8@@@d@d V`L f8@@@d@d V`L f8@@@ d@d V` flU h@@@dd  V`v fbK  p@@@dd  V` fqZA  @  @  @    @@@dV` fjQ  @       @@@dV`k fW@'  @  @  @@@dVfC    Vh    qZA  @  @  @    @@@dVh    jQ  @       @@@dVh    W@'  @  @  @@@dV~' fV?    V) fVf Vf Vf Vq fa DAA EVf V' fVf V fqZA  @  @  @    @@@dV fjQ  @       @@@dVk fW@'  @  @  @@@dV' fV flU h@@@dd  Vv fbK  p@@@dd  VX fD)@@@@d  VT f@@@@ @d Vb fN4@@@@d  VK f7@@@e@dVP f<@@@ e@d VL f8@@@d@d VL f8@@@d@d VL f8@@@ d@d VA    V,    V,    V,    V]    5 AV0    V?    V0    V    qZA  @  @  @    @@@dV    jQ  @       @@@dV    W@'  @  @  @@@dV?    V' fmrtparse-1.6/samples/openbgpd_rib_table0000644000175000017500000000521213125763144021061 0ustar t2munet2mune00000000000000V HV 2@@@@d   V + V @@@ @dV 2 V @@@ d@dV 2 V @@@ e@dV 2 V @@@d@dV 2 V @@@d@dV =V '@@@@d   V +V @@@ @dV 2V @@@ e@dV 2 V @@@e@dV + V @@@ @dV [  @V  -@@@d  V [  @V -@@@d  V T  V  &@@@d  V T  V &@@@d  V [  V  -@@@d  V [  V -@@@d  V [  V  -@@@d  V [  V -@@@d  V [  V  -@@@d  V [  V -@@@d  V T  @V  &@@@d  V T  @V &@@@d  V T  @V  &@@@d  V T  @V &@@@d  V [  @V  -@@@d  V [  @V -@@@d  V [  @V  -@@@d  V [  @V -@@@d  V T  @V  &@@@d  V T  @V &@@@d  mrtparse-1.6/samples/openbgpd_rib_table-mp0000644000175000017500000000536513125763144021504 0ustar t2munet2mune00000000000000VPf VS+@@@d   V5f VS @@@dV<f VS @@d@dV<f VS @@e@dV<f VS @@d@dV<f VS @@d@dVFf VS @@@d   V4f VS @@@dV;f VS @@e@dV;f VS@@e@dV4f VS @@@dVd    VS  @  @@@dVLf VS  @  @@@dVe    VS    @@@dVMf VS    @@@dVl    VS    @@@dVTf VS    @@@dVl    VS    @@@dVTf VS    @@@dVl    VS    @@@dVTf VS    @@@dV]    VS  @  @@@dVEf VS  @  @@@dV]    VS  @  @@@dVEf VS  @  @@@dVd    VS  @  @@@dVLf VS  @  @@@dVd    VS  @  @@@dVLf VS  @  @@@dV]    VS  @  @@@dVEf VS  @  @@@dmrtparse-1.6/samples/openbgpd_rib_table-v20000644000175000017500000000413713125763144021413 0ustar t2munet2mune00000000000000V 9f    fV EV>4@@@@d   V ( V>@@@ @dV / V>@@@ d@dV / V>@@@ e@dV / V>@@@d@dV / V>@@@d@dV ;V>)@@@@d   V 'V>@@@ @dV .V>@@@ e@dV . V>@@@e@dV ' V>@@@ @dV q @  V>)@@@d  V>)@@@d  V k  V>"@@@d  V>"@@@d  V y  V>)@@@d  V>)@@@d  V y  V>)@@@d  V>)@@@d  V y  V>)@@@d  V>)@@@d  V c@  V>"@@@d  V>"@@@d  V c@  V>"@@@d  V>"@@@d  V q@  V>)@@@d  V>)@@@d  V q@  V>)@@@d  V>)@@@d  V c@  V>"@@@d  V>"@@@d  V XhV>9@@@@d   dV NpV>.@@@@d   dmrtparse-1.6/samples/quagga.conf0000644000175000017500000000153713125763144017457 0ustar t2munet2mune00000000000000! ! Zebra configuration saved from vty ! 2017/02/11 06:06:11 ! hostname bgpd password zebra log stdout ! router bgp 65000 bgp router-id 192.168.0.18 bgp log-neighbor-changes bgp graceful-restart timers bgp 30 90 neighbor 192.168.0.10 remote-as 65000 neighbor 192.168.0.10 soft-reconfiguration inbound neighbor fd02::10 remote-as 65000 neighbor fd02::10 soft-reconfiguration inbound ! address-family ipv4 multicast neighbor 192.168.0.10 activate exit-address-family ! address-family vpnv4 unicast neighbor 192.168.0.10 activate exit-address-family ! address-family ipv6 neighbor 192.168.0.10 activate neighbor fd02::10 activate exit-address-family ! address-family ipv6 multicast neighbor 192.168.0.10 activate neighbor fd02::10 activate exit-address-family ! dump bgp all /tmp/quagga_bgp dump bgp routes-mrt /tmp/quagga_rib 300 line vty ! mrtparse-1.6/samples/quagga_bgp0000644000175000017500000001277513125763144017371 0ustar t2munet2mune00000000000000X X X Z f@@xA EGX X' X X2 X2 X vS@@VVV@  @d d,   X @@VVV @d d,   0 @@@X @@ @d   @@@dN pI6 pI6 pI6 xI6 X @@@d   N pI7 pI7 pI7 xI7 X+ X2 X2 X0X0XwOZ 2@@xAEGX0X?X0XJX@@VVV @d d,   @  @@@XJX' X?X+ X+ X+ X+ X+ XCXCX'' X,?X5) X5 X5 X7AX70X70X< X< X< Z f@@xA EGX< X=' X= X=2 X=2 X= vS@@VVV@  @d d,   X= @@VVV @d d,   0 @@@X= @@ @d   @@@dN pI6 pI6 pI6 xI6 X= @@@d   N pI7 pI7 pI7 xI7 X=+ X=2 X=2 XD0XD0XDwOZ 2@@xAEGXD0XD?XD0XDJXD@@VVV @d d,   @  @@@XDJXW' X^?mrtparse-1.6/samples/quagga_rib0000644000175000017500000000212713125763144017363 0ustar t2munet2mune00000000000000X .  X XX<F@PVVV@  @d d,X XX<F@PVVV@  @d d,X XX<F@PVVV@  @d d,X @XDp@PVVV @d d,.  @X<`@PVVV @d d, @X @XDp@PVVV @d d,.  @X<`@PVVV @d d, @X @XDp@PVVV @d d,.  @X<`@PVVV @d d, @mrtparse-1.6/MANIFEST.in0000644000175000017500000000007113125763144015425 0ustar t2munet2mune00000000000000recursive-include examples * recursive-include samples * mrtparse-1.6/README.rst0000644000175000017500000001672613125763343015375 0ustar t2munet2mune00000000000000mrtparse ======== | mrtparse is a module to read and analyze the MRT format data. | The MRT format can be used to export routing protocol messages, state changes, and routing information base contents, and is defined in RFC6396_. | Programs like Quagga_ / Zebra_, BIRD_, OpenBGPD_ and PyRT_ can dump the MRT format data. | You can also download archives from `the Route Views Projects`_, `RIPE NCC`_. .. _RFC6396: https://tools.ietf.org/html/rfc6396 .. _Quagga: http://www.nongnu.org/quagga/ .. _Zebra: https://www.gnu.org/software/zebra/ .. _BIRD: http://bird.network.cz/ .. _OpenBGPD: http://www.openbgpd.org/ .. _PyRT: https://github.com/mor1/pyrt .. _`the Route Views Projects`: http://archive.routeviews.org/ .. _`RIPE NCC`: https://www.ripe.net/analyse/internet-measurements/routing-information-service-ris/ris-raw-data Supported MRT types ------------------- +-------------------+---------+ | Name | Value | +===================+=========+ | TABLE\_DUMP | 12 | +-------------------+---------+ | TABLE\_DUMP\_V2 | 13 | +-------------------+---------+ | BGP4MP | 16 | +-------------------+---------+ | BGP4MP\_ET | 17 | +-------------------+---------+ Supported TABLE_DUMP subtypes ------------------------------ +-------------------+---------+ | Name | Value | +===================+=========+ | AFI\_IPv4 | 1 | +-------------------+---------+ | AFI\_IPv6 | 2 | +-------------------+---------+ Supported TABLE_DUMP_V2 subtypes -------------------------------- +-------------------------------+---------+ | Name | Value | +===============================+=========+ | PEER_INDEX_TABLE | 1 | +-------------------------------+---------+ | RIB\_IPV4\_UNICAST | 2 | +-------------------------------+---------+ | RIB\_IPV4\_MULTICAST | 3 | +-------------------------------+---------+ | RIB\_IPV6\_UNICAST | 4 | +-------------------------------+---------+ | RIB\_IPV6\_MULTICAST | 5 | +-------------------------------+---------+ | RIB\_GENERIC | 6 | +-------------------------------+---------+ | RIB\_IPV4\_UNICAST\_ADDPATH | 8 | +-------------------------------+---------+ | RIB\_IPV4\_MULTICAST\_ADDPATH | 9 | +-------------------------------+---------+ | RIB\_IPV6\_UNICAST\_ADDPATH | 10 | +-------------------------------+---------+ | RIB\_IPV6\_MULTICAST\_ADDPATH | 11 | +-------------------------------+---------+ | RIB\_GENERIC\_ADDPATH | 12 | +-------------------------------+---------+ Supported BGP4MP/BGP4MP_ET subtypes ----------------------------------- +--------------------------------------+---------+ | Name | Value | +======================================+=========+ | BGP4MP\_STATE\_CHANGE | 0 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE | 1 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4 | 4 | +--------------------------------------+---------+ | BGP4MP\_STATE\_CHANGE\_AS4 | 5 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_LOCAL | 6 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4\_LOCAL | 7 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_ADDPATH | 8 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4\_ADDPATH | 9 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_LOCAL\_ADDPATH | 10 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4\_LOCAL\_ADDPATH | 11 | +--------------------------------------+---------+ Supported BGP capabilities -------------------------- +--------------------------------------------+---------+ | Name | Value | +============================================+=========+ | Multiprotocol Extensions for BGP-4 | 1 | +--------------------------------------------+---------+ | Route Refresh Capability for BGP-4 | 2 | +--------------------------------------------+---------+ | Outbound Route Filtering Capability | 3 | +--------------------------------------------+---------+ | Graceful Restart Capability | 64 | +--------------------------------------------+---------+ | Support for 4-octet AS number capability | 65 | +--------------------------------------------+---------+ | ADD-PATH Capability | 69 | +--------------------------------------------+---------+ Supported BGP attributes ------------------------ +-------------------------+---------+ | Name | Value | +=========================+=========+ | ORIGIN | 1 | +-------------------------+---------+ | AS\_PATH | 2 | +-------------------------+---------+ | NEXT\_HOP | 3 | +-------------------------+---------+ | MULTI\_EXIT\_DISC | 4 | +-------------------------+---------+ | LOCAL\_PREF | 5 | +-------------------------+---------+ | ATOMIC\_AGGREGATE | 6 | +-------------------------+---------+ | AGGREGATOR | 7 | +-------------------------+---------+ | COMMUNITY | 8 | +-------------------------+---------+ | ORIGINATOR\_ID | 9 | +-------------------------+---------+ | CLUSTER\_LIST | 10 | +-------------------------+---------+ | MP\_REACH\_NLRI | 14 | +-------------------------+---------+ | MP\_UNREACH\_NLRI | 15 | +-------------------------+---------+ | EXTENDED\_COMMUNITIES | 16 | +-------------------------+---------+ | AS4\_PATH | 17 | +-------------------------+---------+ | AS4\_AGGREGATOR | 18 | +-------------------------+---------+ | AIGP | 26 | +-------------------------+---------+ | LARGE\_COMMUNITY | 32 | +-------------------------+---------+ | ATTR\_SET | 128 | +-------------------------+---------+ Requirements ------------ Python2 or Python3 or PyPy or PyPy3 Installation ------------ :: $ pip install mrtparse or :: $ git clone https://github.com/YoshiyukiYamauchi/mrtparse.git $ cd mrtparse $ python setup.py install Usage ----- :: from mrtparse import * or :: import mrtparse Programming ----------- First, import the module. :: from mrtparse import * | And pass a MRT format data as a filepath string or file object to a class Reader(). | It is also supported gzip and bzip2 format. | You can retrieve each entry from the returned object using a loop and then process it. :: d = Reader(f) for m in d: We have prepared some example scripts and sample data in `"examples"`_ and `"samples"`_ directory. .. _`"examples"`: https://github.com/YoshiyukiYamauchi/mrtparse/tree/master/examples .. _`"samples"`: https://github.com/YoshiyukiYamauchi/mrtparse/tree/master/samples Authors ------- | Tetsumune KISO t2mune@gmail.com | Yoshiyuki YAMAUCHI info@greenhippo.co.jp | Nobuhiro ITOU js333123@gmail.com License ------- | Licensed under the `Apache License, Version 2.0`_ | Copyright © 2017 Tetsumune KISO .. _`Apache License, Version 2.0`: http://www.apache.org/licenses/LICENSE-2.0 mrtparse-1.6/setup.cfg0000644000175000017500000000010313125764616015511 0ustar t2munet2mune00000000000000[bdist_wheel] universal = 1 [egg_info] tag_build = tag_date = 0 mrtparse-1.6/setup.py0000644000175000017500000000516713125763144015414 0ustar t2munet2mune00000000000000''' setup.py - a setup script Copyright (C) 2017 Tetsumune KISO Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Authors: Tetsumune KISO Yoshiyuki YAMAUCHI Nobuhiro ITOU ''' try: from setuptools import setup except ImportError: from distutils.core import setup import os import sys from codecs import open import mrtparse here = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: long_descr = f.read() examples = 'mrtparse/examples' samples = 'mrtparse/samples' try: if 'install' in sys.argv: os.symlink('../examples', examples) os.symlink('../samples', samples) setup( name=mrtparse.__name__, version=mrtparse.__version__, description='MRT format data parser', long_description=long_descr, url='https://github.com/YoshiyukiYamauchi/mrtparse', author='Tetsumune KISO, Yoshiyuki YAMAUCHI, Nobuhiro ITOU', author_email='t2mune@gmail.com, info@greenhippo.co.jp, js333123@gmail.com', license='Apache License 2.0', platforms='any', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'Intended Audience :: Telecommunications Industry', 'License :: OSI Approved :: Apache Software License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Internet', 'Topic :: System :: Networking', ], keywords='mrt bgp', packages = ['mrtparse'], package_data={ 'mrtparse': [ 'examples/*.py', 'samples/bird*', 'samples/openbgpd*', 'samples/quagga*' ] }, zip_safe=False, ) finally: if 'install' in sys.argv: os.unlink(examples) os.unlink(samples) mrtparse-1.6/PKG-INFO0000644000175000017500000002424213125764616014777 0ustar t2munet2mune00000000000000Metadata-Version: 1.1 Name: mrtparse Version: 1.6 Summary: MRT format data parser Home-page: https://github.com/YoshiyukiYamauchi/mrtparse Author: Tetsumune KISO, Yoshiyuki YAMAUCHI, Nobuhiro ITOU Author-email: t2mune@gmail.com, info@greenhippo.co.jp, js333123@gmail.com License: Apache License 2.0 Description: mrtparse ======== | mrtparse is a module to read and analyze the MRT format data. | The MRT format can be used to export routing protocol messages, state changes, and routing information base contents, and is defined in RFC6396_. | Programs like Quagga_ / Zebra_, BIRD_, OpenBGPD_ and PyRT_ can dump the MRT format data. | You can also download archives from `the Route Views Projects`_, `RIPE NCC`_. .. _RFC6396: https://tools.ietf.org/html/rfc6396 .. _Quagga: http://www.nongnu.org/quagga/ .. _Zebra: https://www.gnu.org/software/zebra/ .. _BIRD: http://bird.network.cz/ .. _OpenBGPD: http://www.openbgpd.org/ .. _PyRT: https://github.com/mor1/pyrt .. _`the Route Views Projects`: http://archive.routeviews.org/ .. _`RIPE NCC`: https://www.ripe.net/analyse/internet-measurements/routing-information-service-ris/ris-raw-data Supported MRT types ------------------- +-------------------+---------+ | Name | Value | +===================+=========+ | TABLE\_DUMP | 12 | +-------------------+---------+ | TABLE\_DUMP\_V2 | 13 | +-------------------+---------+ | BGP4MP | 16 | +-------------------+---------+ | BGP4MP\_ET | 17 | +-------------------+---------+ Supported TABLE_DUMP subtypes ------------------------------ +-------------------+---------+ | Name | Value | +===================+=========+ | AFI\_IPv4 | 1 | +-------------------+---------+ | AFI\_IPv6 | 2 | +-------------------+---------+ Supported TABLE_DUMP_V2 subtypes -------------------------------- +-------------------------------+---------+ | Name | Value | +===============================+=========+ | PEER_INDEX_TABLE | 1 | +-------------------------------+---------+ | RIB\_IPV4\_UNICAST | 2 | +-------------------------------+---------+ | RIB\_IPV4\_MULTICAST | 3 | +-------------------------------+---------+ | RIB\_IPV6\_UNICAST | 4 | +-------------------------------+---------+ | RIB\_IPV6\_MULTICAST | 5 | +-------------------------------+---------+ | RIB\_GENERIC | 6 | +-------------------------------+---------+ | RIB\_IPV4\_UNICAST\_ADDPATH | 8 | +-------------------------------+---------+ | RIB\_IPV4\_MULTICAST\_ADDPATH | 9 | +-------------------------------+---------+ | RIB\_IPV6\_UNICAST\_ADDPATH | 10 | +-------------------------------+---------+ | RIB\_IPV6\_MULTICAST\_ADDPATH | 11 | +-------------------------------+---------+ | RIB\_GENERIC\_ADDPATH | 12 | +-------------------------------+---------+ Supported BGP4MP/BGP4MP_ET subtypes ----------------------------------- +--------------------------------------+---------+ | Name | Value | +======================================+=========+ | BGP4MP\_STATE\_CHANGE | 0 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE | 1 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4 | 4 | +--------------------------------------+---------+ | BGP4MP\_STATE\_CHANGE\_AS4 | 5 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_LOCAL | 6 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4\_LOCAL | 7 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_ADDPATH | 8 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4\_ADDPATH | 9 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_LOCAL\_ADDPATH | 10 | +--------------------------------------+---------+ | BGP4MP\_MESSAGE\_AS4\_LOCAL\_ADDPATH | 11 | +--------------------------------------+---------+ Supported BGP capabilities -------------------------- +--------------------------------------------+---------+ | Name | Value | +============================================+=========+ | Multiprotocol Extensions for BGP-4 | 1 | +--------------------------------------------+---------+ | Route Refresh Capability for BGP-4 | 2 | +--------------------------------------------+---------+ | Outbound Route Filtering Capability | 3 | +--------------------------------------------+---------+ | Graceful Restart Capability | 64 | +--------------------------------------------+---------+ | Support for 4-octet AS number capability | 65 | +--------------------------------------------+---------+ | ADD-PATH Capability | 69 | +--------------------------------------------+---------+ Supported BGP attributes ------------------------ +-------------------------+---------+ | Name | Value | +=========================+=========+ | ORIGIN | 1 | +-------------------------+---------+ | AS\_PATH | 2 | +-------------------------+---------+ | NEXT\_HOP | 3 | +-------------------------+---------+ | MULTI\_EXIT\_DISC | 4 | +-------------------------+---------+ | LOCAL\_PREF | 5 | +-------------------------+---------+ | ATOMIC\_AGGREGATE | 6 | +-------------------------+---------+ | AGGREGATOR | 7 | +-------------------------+---------+ | COMMUNITY | 8 | +-------------------------+---------+ | ORIGINATOR\_ID | 9 | +-------------------------+---------+ | CLUSTER\_LIST | 10 | +-------------------------+---------+ | MP\_REACH\_NLRI | 14 | +-------------------------+---------+ | MP\_UNREACH\_NLRI | 15 | +-------------------------+---------+ | EXTENDED\_COMMUNITIES | 16 | +-------------------------+---------+ | AS4\_PATH | 17 | +-------------------------+---------+ | AS4\_AGGREGATOR | 18 | +-------------------------+---------+ | AIGP | 26 | +-------------------------+---------+ | LARGE\_COMMUNITY | 32 | +-------------------------+---------+ | ATTR\_SET | 128 | +-------------------------+---------+ Requirements ------------ Python2 or Python3 or PyPy or PyPy3 Installation ------------ :: $ pip install mrtparse or :: $ git clone https://github.com/YoshiyukiYamauchi/mrtparse.git $ cd mrtparse $ python setup.py install Usage ----- :: from mrtparse import * or :: import mrtparse Programming ----------- First, import the module. :: from mrtparse import * | And pass a MRT format data as a filepath string or file object to a class Reader(). | It is also supported gzip and bzip2 format. | You can retrieve each entry from the returned object using a loop and then process it. :: d = Reader(f) for m in d: We have prepared some example scripts and sample data in `"examples"`_ and `"samples"`_ directory. .. _`"examples"`: https://github.com/YoshiyukiYamauchi/mrtparse/tree/master/examples .. _`"samples"`: https://github.com/YoshiyukiYamauchi/mrtparse/tree/master/samples Authors ------- | Tetsumune KISO t2mune@gmail.com | Yoshiyuki YAMAUCHI info@greenhippo.co.jp | Nobuhiro ITOU js333123@gmail.com License ------- | Licensed under the `Apache License, Version 2.0`_ | Copyright © 2017 Tetsumune KISO .. _`Apache License, Version 2.0`: http://www.apache.org/licenses/LICENSE-2.0 Keywords: mrt bgp Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Internet Classifier: Topic :: System :: Networking