aboutsummaryrefslogtreecommitdiff
path: root/rpkid/portal-gui/scripts/rpkigui-import-routes.py
blob: 4ca8ef96ad93516b8e9828b4e5123dad61d102f0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import sys, itertools, re
import struct
import _mysql_exceptions

from django.db import transaction, connection

import rpki
import rpki.gui.models
from rpki.gui.routeview import models
from rpki.resource_set import resource_range_ipv4, resource_range_ipv6

f = open(sys.argv[1])

prefixes = {}

ip_re = re.compile(r'^[0-9a-fA-F:.]+/\d{1,3}$')

class InvalidPrefix(Exception):
    pass

last_prefix = None
last_asn = None

for row in itertools.islice(f, 5, None):
    try:
        cols = row.split()

        prefix = cols[1]

        # index -1 is i/e/? for igp/egp
        origin_as = cols[-2]

        # FIXME: skip AS_SETs
        if origin_as[0] == '{':
            continue

        # the output may contain multiple paths to the same origin.
        # if this is the same prefix as the last entry, we don't need
        # to validate it again.
        if prefix != last_prefix:
            # validate the prefix since the "sh ip bgp" output is sometimes corrupt
            # by no space between the prefix and the next hop IP address.

            if not ip_re.match(prefix):
                net, bits = prefix.split('/')
                if len(bits) > 2 and int(bits[0]) <= 3:
                    print 'mask for %s looks fishy...' % prefix,
                    prefix = '%s/%s' % (net, bits[0:2])
                    print 'assuming it should be %s' % prefix
                if not ip_re.match(prefix):
                    raise InvalidPrefix(prefix)
            last_prefix = prefix
        elif origin_as == last_asn:
            # we are only interested in origins, so skip alternate paths
            # to same origin as last entry.
            continue
        last_asn = origin_as

        asns = prefixes.get(prefix)
        if not asns:
            asns = set()
            prefixes[prefix] = asns
        asns.add(int(origin_as))

    except InvalidPrefix, e:
        print >>sys.stderr, 'skipping bad entry: ' + row,
        print >>sys.stderr, e

f.close()

def commit():
    cursor = connection.cursor()

    try:
        print 'Dropping existing staging table...'
        cursor.execute('DROP TABLE IF EXISTS routeview_routeorigin_new')
    except _mysql_exceptions.Warning:
        pass

    print 'Creating staging table...'
    cursor.execute('CREATE TABLE routeview_routeorigin_new LIKE routeview_routeorigin')

    print 'Disabling autocommit...'
    cursor.execute('SET autocommit=0')

    print 'Adding rows to table...'
    for prefix, asns in prefixes.iteritems():
        family = 6 if ':' in prefix else 4
        cls = resource_range_ipv6 if family == 6 else resource_range_ipv4
        rng = cls.parse_str(prefix)

        if family == 4:
            xform = long
        else:
            xform = lambda v: struct.pack('!QQ', (long(v) >> 64) &0xffffffffffffffffL, long(v) & 0xFFFFFFFFFFFFFFFFL)

        cursor.executemany("INSERT INTO routeview_routeorigin_new SET asn=%s, prefix_min=%s, prefix_max=%s",
                    [(asn, xform(rng.min), xform(rng.max)) for asn in asns])

    print 'Committing...'
    cursor.execute('COMMIT')

    try:
        print 'Dropping old table...'
        cursor.execute('DROP TABLE IF EXISTS routeview_routeorigin_old')
    except _mysql_exceptions.Warning:
        pass

    print 'Swapping staging table with live table...'
    cursor.execute('RENAME TABLE routeview_routeorigin TO routeview_routeorigin_old, routeview_routeorigin_new TO routeview_routeorigin')

    transaction.commit_unless_managed()

commit()