~ubuntu-branches/ubuntu/utopic/exabgp/utopic

« back to all changes in this revision

Viewing changes to lib/exabgp/bgp/message/update/nlri/route.py

  • Committer: Package Import Robot
  • Author(s): Henry-Nicolas Tourneur
  • Date: 2014-03-08 19:07:00 UTC
  • mfrom: (1.1.8)
  • Revision ID: package-import@ubuntu.com-20140308190700-xjbibpg1g6001c9x
Tags: 3.3.1-1
* New upstream release
* Bump python minimal required version (2.7)
* Closes: #726066 Debian packaging improvements proposed by Vincent Bernat
* Closes: #703774 not existent rundir (/var/run/exabgp) after reboot

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# encoding: utf-8
2
 
"""
3
 
nlri.py
4
 
 
5
 
Created by Thomas Mangin on 2012-07-08.
6
 
Copyright (c) 2009-2013 Exa Networks. All rights reserved.
7
 
"""
8
 
 
9
 
import math
10
 
 
11
 
from struct import pack,unpack
12
 
from exabgp.protocol.family import AFI,SAFI
13
 
from exabgp.protocol.ip.inet import Inet
14
 
 
15
 
from exabgp.protocol.ip.address import Address
16
 
from exabgp.bgp.message.update.attribute.attributes import Attributes
17
 
 
18
 
from exabgp.bgp.message.notification import Notify
19
 
 
20
 
mask_to_bytes = {}
21
 
for netmask in range(0,129):
22
 
        mask_to_bytes[netmask] = int(math.ceil(float(netmask)/8))
23
 
 
24
 
# Take an integer an created it networked packed representation for the right family (ipv4/ipv6)
25
 
def pack_int (afi,integer,mask):
26
 
        return ''.join([chr((integer>>(offset*8)) & 0xff) for offset in range(NLRI.length[afi]-1,-1,-1)])
27
 
 
28
 
 
29
 
class PathInfo (object):
30
 
        def __init__ (self,integer=None,ip=None,packed=None):
31
 
                if packed:
32
 
                        self.value = packed
33
 
                elif ip:
34
 
                        self.value = ''.join([chr(int(_)) for _ in ip.split('.')])
35
 
                elif integer:
36
 
                        self.value = ''.join([chr((integer>>offset) & 0xff) for offset in [24,16,8,0]])
37
 
                else:
38
 
                        self.value = ''
39
 
                #sum(int(a)<<offset for (a,offset) in zip(ip.split('.'), range(24, -8, -8)))
40
 
 
41
 
        def __len__ (self):
42
 
                return len(self.value)
43
 
 
44
 
        def __str__ (self):
45
 
                if self.value:
46
 
                        return ' path-information %s' % '.'.join([str(ord(_)) for _ in self.value])
47
 
                return ''
48
 
 
49
 
        def pack (self):
50
 
                if self.value:
51
 
                        return self.value
52
 
                return '\x00\x00\x00\x00'
53
 
 
54
 
_NoPathInfo = PathInfo()
55
 
 
56
 
 
57
 
class Labels (object):
58
 
        biggest = pow(2,20)
59
 
 
60
 
        def __init__ (self,labels):
61
 
                self.labels = labels
62
 
                packed = []
63
 
                for label in labels:
64
 
                        # shift to 20 bits of the label to be at the top of three bytes and then truncate.
65
 
                        packed.append(pack('!L',label << 4)[1:])
66
 
                # Mark the bottom of stack with the bit
67
 
                if packed:
68
 
                        packed.pop()
69
 
                        packed.append(pack('!L',(label << 4)|1)[1:])
70
 
                self.packed = ''.join(packed)
71
 
                self._len = len(self.packed)
72
 
 
73
 
        def pack (self):
74
 
                return self.packed
75
 
 
76
 
        def __len__ (self):
77
 
                return self._len
78
 
 
79
 
        def __str__ (self):
80
 
                if self._len > 1:
81
 
                        return ' label [ %s ]' % ' '.join([str(_) for _ in self.labels])
82
 
                elif self._len == 1:
83
 
                        return ' label %s' % self.labels[0]
84
 
                else:
85
 
                        return ''
86
 
 
87
 
_NoLabels = Labels([])
88
 
 
89
 
class RouteDistinguisher (object):
90
 
        def __init__ (self,rd):
91
 
                self.rd = rd
92
 
                self._len = len(self.rd)
93
 
 
94
 
        def pack (self):
95
 
                return self.rd
96
 
 
97
 
        def __len__ (self):
98
 
                return self._len
99
 
 
100
 
        def __str__ (self):
101
 
                if not self.rd:
102
 
                        return ''
103
 
 
104
 
                t,c1,c2,c3 = unpack('!HHHH',self.rd)
105
 
                if t == 0:
106
 
                        rd = '%d:%d' % (c1,(c2<<16)+c3)
107
 
                elif t == 1:
108
 
                        rd = '%d.%d.%d.%d:%d' % (c1>>8,c1&0xFF,c2>>8,c2&0xFF,c3)
109
 
                elif t == 2:
110
 
                        rd = '%d:%d' % ((c1<<16)+c2,c3)
111
 
                else:
112
 
                        rd = str(self.rd)
113
 
 
114
 
                if self.rd:
115
 
                        return ' route-distinguisher %s' % rd
116
 
                return ''
117
 
 
118
 
_NoRD = RouteDistinguisher('')
119
 
 
120
 
class BGPPrefix (Inet):
121
 
        # have a .raw for the ip
122
 
        # have a .mask for the mask
123
 
        # have a .bgp with the bgp wire format of the prefix
124
 
 
125
 
        def __init__(self,afi,safi,packed,mask):
126
 
                self.mask = int(mask)
127
 
                Inet.__init__(self,afi,safi,packed)
128
 
 
129
 
        def __str__ (self):
130
 
                return "%s/%s" % (self.ip,self.mask)
131
 
 
132
 
        # The API requires addpath, but it is irrelevant here.
133
 
        def pack (self,addpath=None):
134
 
                return chr(self.mask) + self.prefix()
135
 
 
136
 
        def prefix (self):
137
 
                return self.packed[:mask_to_bytes[self.mask]]
138
 
 
139
 
        def __len__ (self):
140
 
                return mask_to_bytes[self.mask] + 1
141
 
 
142
 
 
143
 
class NLRI (BGPPrefix):
144
 
        def __init__(self,afi,safi,packed,mask):
145
 
                self.path_info = _NoPathInfo
146
 
                self.labels = _NoLabels
147
 
                self.rd = _NoRD
148
 
 
149
 
                BGPPrefix.__init__(self,afi,safi,packed,mask)
150
 
 
151
 
        def has_label (self):
152
 
                if self.afi == AFI.ipv4 and self.safi in (SAFI.nlri_mpls,SAFI.mpls_vpn):
153
 
                        return True
154
 
                if self.afi == AFI.ipv6 and self.safi == SAFI.mpls_vpn:
155
 
                        return True
156
 
                return False
157
 
 
158
 
        def __len__ (self):
159
 
                prefix_len = len(self.path_info) + len(self.labels) + len(self.rd)
160
 
                return 1 + prefix_len + mask_to_bytes[self.mask]
161
 
 
162
 
        def __str__ (self):
163
 
                return "%s%s%s%s" % (BGPPrefix.__str__(self),str(self.labels),str(self.path_info),str(self.rd))
164
 
 
165
 
        def __eq__ (self,other):
166
 
                return str(self) == str(other)
167
 
 
168
 
        def __ne__ (self,other):
169
 
                return not self.__eq__(other)
170
 
 
171
 
        def json (self):
172
 
                label = str(self.labels)
173
 
                pinfo = str(self.path_info)
174
 
                rdist = str(self.rd)
175
 
 
176
 
                r = []
177
 
                if label: r.append('"label": "%s"' % label)
178
 
                if pinfo: r.append('"path-information": "%s"' % pinfo)
179
 
                if rdist: r.append('"route-distinguisher": "%s"' % rdist)
180
 
                return '"%s": { %s }' % (BGPPrefix.__str__(self),", ".join(r))
181
 
 
182
 
        def pack (self,addpath):
183
 
                if addpath:
184
 
                        path_info = self.path_info.pack()
185
 
                else:
186
 
                        path_info = ''
187
 
 
188
 
                if self.has_label():
189
 
                        length = len(self.labels)*8 + len(self.rd)*8 + self.mask
190
 
                        return path_info + chr(length) + self.labels.pack() + self.rd.pack() + self.packed[:mask_to_bytes[self.mask]]
191
 
                else:
192
 
                        return path_info + BGPPrefix.pack(self)
193
 
 
194
 
# Generate an NLRI from a BGP packet receive
195
 
def BGPNLRI (afi,safi,bgp,has_multiple_path):
196
 
        labels = []
197
 
        rd = ''
198
 
 
199
 
        if has_multiple_path:
200
 
                path_identifier = bgp[:4]
201
 
                bgp = bgp[4:]
202
 
        else:
203
 
                path_identifier = ''
204
 
 
205
 
        mask = ord(bgp[0])
206
 
        bgp = bgp[1:]
207
 
 
208
 
        if SAFI(safi).has_label():
209
 
                while bgp and mask >= 8:
210
 
                        label = int(unpack('!L',chr(0) + bgp[:3])[0])
211
 
                        bgp = bgp[3:]
212
 
                        labels.append(label>>4)
213
 
                        mask -= 24  # 3 bytes
214
 
                        if label & 1:
215
 
                                break
216
 
                        # This is a route withdrawal, or next-hop
217
 
                        if label == 0x000000 or label == 0x80000:
218
 
                                break
219
 
 
220
 
        if SAFI(safi).has_rd():
221
 
                mask -= 8*8  # the 8 bytes of the route distinguisher
222
 
                rd = bgp[:8]
223
 
                bgp = bgp[8:]
224
 
 
225
 
        if mask < 0:
226
 
                raise Notify(3,10,'invalid length in NLRI prefix')
227
 
 
228
 
        if not bgp and mask:
229
 
                raise Notify(3,10,'not enough data for the mask provided to decode the NLRI')
230
 
 
231
 
        size = mask_to_bytes[mask]
232
 
 
233
 
        if len(bgp) < size:
234
 
                raise Notify(3,10,'could not decode route with AFI %d sand SAFI %d' % (afi,safi))
235
 
 
236
 
        network = bgp[:size]
237
 
        # XXX: The padding calculation should really go into the NLRI class
238
 
        padding = '\0'*(NLRI.length[afi]-size)
239
 
        prefix = network + padding
240
 
        nlri = NLRI(afi,safi,prefix,mask)
241
 
 
242
 
        # XXX: Not the best interface but will do for now
243
 
        if safi:
244
 
                nlri.safi = SAFI(safi)
245
 
 
246
 
        if path_identifier:
247
 
                nlri.path_info = PathInfo(packed=path_identifier)
248
 
        if labels:
249
 
                nlri.labels = Labels(labels)
250
 
        if rd:
251
 
                nlri.rd = RouteDistinguisher(rd)
252
 
        return nlri
253
 
 
254
 
 
255
 
class Route (object):
256
 
        def __init__ (self,nlri):
257
 
                self.nlri = nlri
258
 
                self.attributes = Attributes()
259
 
 
260
 
        def __str__ (self):
261
 
                return "route %s%s" % (str(self.nlri),str(self.attributes))
262
 
 
263
 
        def __hash__(self):
264
 
                return hash(str(self))
265
 
 
266
 
        def __eq__(self, other):
267
 
                return str(self) == str(other)
268
 
 
269
 
        def __ne__ (self,other):
270
 
                return not self.__eq__(other)
271
 
 
272
 
        def extensive (self):
273
 
                return "%s %s%s" % (str(Address(self.nlri.afi,self.nlri.safi)),str(self.nlri),str(self.attributes))
274
 
 
275
 
        def index (self):
276
 
                return self.nlri.pack(True)+self.nlri.rd.rd
277
 
 
278
 
 
279
 
class RouteBGP (Route):
280
 
        def __init__ (self,nlri,action):
281
 
                self.action = action  # announce, announced, withdraw or withdrawn
282
 
                Route.__init__(self,nlri)
283
 
 
284
 
        def __str__ (self):
285
 
                return "%s %s" % (self.action,Route.__str__(self))
286
 
 
287
 
def routeFactory(afi,safi,data,path_info,state):
288
 
        return RouteBGP(BGPNLRI(afi,safi,data,path_info),state)