1
|
|
|
""" |
2
|
|
|
prefixv6.py |
3
|
|
|
Created by Tinus Flagstad & Håvard Eidnes on 2018-07-02. |
4
|
|
|
Copyright (c) 2009-2018 Exa Networks. All rights reserved. |
5
|
|
|
License: 3-clause BSD. (See the COPYRIGHT file) |
6
|
|
|
""" |
7
|
|
|
|
8
|
|
|
from struct import pack |
9
|
|
|
from struct import unpack |
10
|
|
|
import json |
11
|
|
|
|
12
|
|
|
from exabgp.bgp.message.update.nlri.bgpls.nlri import BGPLS |
13
|
|
|
from exabgp.bgp.message.update.nlri.bgpls.nlri import PROTO_CODES |
14
|
|
|
from exabgp.bgp.message.update.nlri.bgpls.tlvs.node import NodeDescriptor |
15
|
|
|
from exabgp.bgp.message.update.nlri.bgpls.tlvs.ospfroute import OspfRoute |
16
|
|
|
from exabgp.bgp.message.update.nlri.bgpls.tlvs.ipreach import IpReach |
17
|
|
|
|
18
|
|
|
# The IPv4 and IPv6 Prefix NLRIs (NLRI Type = 3 and Type = 4) use the |
19
|
|
|
# same format, as shown in the following figure. |
20
|
|
|
# |
21
|
|
|
# 0 1 2 3 |
22
|
|
|
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
23
|
|
|
# +-+-+-+-+-+-+-+-+ |
24
|
|
|
# | Protocol-ID | |
25
|
|
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
26
|
|
|
# | Identifier | |
27
|
|
|
# | (64 bits) | |
28
|
|
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
29
|
|
|
# // Local Node Descriptors (variable) // |
30
|
|
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
31
|
|
|
# // Prefix Descriptors (variable) // |
32
|
|
|
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
33
|
|
|
|
34
|
|
|
|
35
|
|
View Code Duplication |
@BGPLS.register |
|
|
|
|
36
|
|
|
class PREFIXv6(BGPLS): |
37
|
|
|
CODE = 4 |
38
|
|
|
NAME = "bgpls-prefix-v6" |
39
|
|
|
SHORT_NAME = "PREFIX_V6" |
40
|
|
|
|
41
|
|
|
def __init__ ( |
42
|
|
|
self,domain,proto_id,local_node, |
43
|
|
|
packed=None,ospf_type=None,prefix=None, |
44
|
|
|
nexthop=None,route_d=None,action=None, addpath=None): |
45
|
|
|
BGPLS.__init__(self,action,addpath) |
46
|
|
|
self.domain = domain |
47
|
|
|
self.ospf_type = ospf_type |
48
|
|
|
self.proto_id = proto_id |
49
|
|
|
self.local_node = local_node |
50
|
|
|
self.prefix = prefix |
51
|
|
|
self.nexthop = nexthop |
52
|
|
|
self._pack = packed |
53
|
|
|
self.route_d = route_d |
54
|
|
|
|
55
|
|
|
@classmethod |
56
|
|
|
def unpack_nlri (cls, data, rd): |
57
|
|
|
ospf_type = None |
58
|
|
|
proto_id = unpack('!B',data[0:1])[0] |
59
|
|
|
if proto_id not in PROTO_CODES.keys(): |
60
|
|
|
raise Exception('Protocol-ID {} is not valid'.format(proto_id)) |
61
|
|
|
domain = unpack('!Q',data[1:9])[0] |
62
|
|
|
tlvs = data[9:] |
63
|
|
|
|
64
|
|
|
while tlvs: |
65
|
|
|
tlv_type, tlv_length = unpack('!HH', tlvs[:4]) |
66
|
|
|
if tlv_type == 256: |
67
|
|
|
values = tlvs[4: 4 + tlv_length] |
68
|
|
|
local_node = [] |
69
|
|
|
while values: |
70
|
|
|
# Unpack Local Node Descriptor Sub-TLVs |
71
|
|
|
# We pass proto_id as TLV interpretation |
72
|
|
|
# follows IGP type |
73
|
|
|
node, left = NodeDescriptor.unpack(values, proto_id) |
74
|
|
|
local_node.append(node) |
75
|
|
|
if left == values: |
76
|
|
|
raise RuntimeError("sub-calls should consume data") |
77
|
|
|
values = left |
78
|
|
|
tlvs = tlvs[4 + tlv_length:] |
79
|
|
|
continue |
80
|
|
|
if tlv_type == 264: |
81
|
|
|
values = tlvs[4: 4 + tlv_length] |
82
|
|
|
ospf_type = OspfRoute.unpack(values) |
83
|
|
|
tlvs = tlvs[4 + tlv_length:] |
84
|
|
|
if tlv_type == 265: |
85
|
|
|
values = tlvs[4: 4 + tlv_length] |
86
|
|
|
prefix = IpReach.unpack(values, 4) |
87
|
|
|
tlvs = tlvs[4 + tlv_length:] |
88
|
|
|
|
89
|
|
|
return cls( |
90
|
|
|
domain=domain,proto_id=proto_id,packed=data, |
91
|
|
|
local_node=local_node,ospf_type=ospf_type, |
|
|
|
|
92
|
|
|
prefix=prefix,route_d=rd |
|
|
|
|
93
|
|
|
) |
94
|
|
|
|
95
|
|
|
def __eq__ (self, other): |
96
|
|
|
return \ |
97
|
|
|
isinstance(other, PREFIXv6) and \ |
98
|
|
|
self.CODE == other.CODE and \ |
99
|
|
|
self.domain == other.domain and \ |
100
|
|
|
self.proto_id == other.proto_id and \ |
101
|
|
|
self.route_d == other.route_d |
102
|
|
|
|
103
|
|
|
def __ne__ (self, other): |
104
|
|
|
return not self.__eq__(other) |
105
|
|
|
|
106
|
|
|
def __str__ (self): |
107
|
|
|
return self.json() |
108
|
|
|
|
109
|
|
|
def __hash__ (self): |
110
|
|
|
return hash((self)) |
111
|
|
|
|
112
|
|
|
def json (self, compact=None): |
113
|
|
|
nodes = ', '.join(d.json() for d in self.local_node) |
114
|
|
|
content = ', '.join([ |
115
|
|
|
'"ls-nlri-type": "%s"' % self.NAME, |
116
|
|
|
'"l3-routing-topology": %d' % int(self.domain), |
117
|
|
|
'"protocol-id": %d' % int(self.proto_id), |
118
|
|
|
'"node-descriptors": { %s }' % nodes, |
119
|
|
|
self.prefix.json(), |
120
|
|
|
'"nexthop": "%s"' % self.nexthop, |
121
|
|
|
]) |
122
|
|
|
if self.ospf_type: |
123
|
|
|
content += ', %s' % self.ospf_type.json() |
124
|
|
|
|
125
|
|
|
if self.route_d: |
126
|
|
|
content += ', %s' % self.route_d.json() |
127
|
|
|
|
128
|
|
|
return '{ %s }' % (content) |
129
|
|
|
|
130
|
|
|
def pack (self,negotiated=None): |
131
|
|
|
return self._pack |