Skip to content

Commit ae55236

Browse files
committed
initial revision
0 parents  commit ae55236

File tree

8 files changed

+2388
-0
lines changed

8 files changed

+2388
-0
lines changed

pybgp/__init__.py

Whitespace-only changes.

pybgp/nlri.py

+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
2+
import array
3+
import struct
4+
import socket
5+
6+
from odict import OrderedDict as OD
7+
8+
class NLRI:
9+
def __init__(self, afi, safi, val):
10+
self.afi = afi
11+
self.safi = safi
12+
self.val = val
13+
14+
def encode(self):
15+
return self.val
16+
17+
class vpnv4(NLRI):
18+
def __init__(self, labels, rd, prefix):
19+
self.labels = labels
20+
self.rd = rd
21+
self.prefix = prefix
22+
23+
def __repr__(self):
24+
return '<vpnv4 label %s rd %s prefix %s>' % (
25+
','.join([str(l) for l in self.labels]),
26+
self.rd, self.prefix,
27+
)
28+
29+
def __str__(self):
30+
return '%s:%s' % (self.rd, self.prefix)
31+
32+
def __cmp__(self, other):
33+
if isinstance(other, vpnv4):
34+
return cmp(
35+
(self.labels, self.rd, self.prefix),
36+
(other.labels, other.rd, other.prefix),
37+
)
38+
return -1
39+
40+
41+
def encode(self):
42+
plen = 0
43+
v = ''
44+
labels = self.labels[:]
45+
46+
if not labels:
47+
return '\0'
48+
49+
labels = [l<<4 for l in labels]
50+
labels[-1] |= 1
51+
52+
for l in labels:
53+
lo = l & 0xff
54+
hi = (l & 0xffff00) >> 8
55+
v += struct.pack('>HB', hi, lo)
56+
plen += 24
57+
58+
l, r = self.rd.split(':')
59+
if '.' in l:
60+
ip = socket.inet_aton(l)
61+
rd = struct.pack('!H4sH', 1, ip, int(r))
62+
else:
63+
rd = struct.pack('!HHI', 0, int(l), int(r))
64+
65+
v += rd
66+
plen += 64
67+
68+
ip, masklen = self.prefix.split('/')
69+
ip = socket.inet_aton(ip)
70+
masklen = int(masklen)
71+
72+
plen += masklen
73+
if masklen > 24:
74+
v += ip
75+
elif masklen > 16:
76+
v += ip[:3]
77+
elif masklen > 8:
78+
v += ip[:2]
79+
elif masklen > 0:
80+
v += ip[:1]
81+
else:
82+
pass
83+
84+
return struct.pack('B', plen) + v
85+
86+
@classmethod
87+
def from_bytes(cls, plen, val):
88+
89+
if plen==0:
90+
# what the hell?
91+
return cls([], '0:0', '0.0.0.0/0')
92+
93+
idx = 0
94+
95+
# plen is the length, in bits, of all the MPLS labels, plus the 8-byte RD, plus the IP prefix
96+
labels = []
97+
while True:
98+
label, lo = struct.unpack_from('>HB', val, idx)
99+
bottom = lo & 1
100+
label = (label << 4) + (lo >> 4)
101+
idx += 3
102+
labels.append(label)
103+
plen -= 24
104+
if bottom:
105+
break
106+
rdtype, rd = struct.unpack_from('!H6s', val, idx)
107+
if rdtype==1:
108+
rdip, num = struct.unpack('!4sH', rd)
109+
rdip = socket.inet_ntoa(rdip)
110+
rd = '%s:%s' % (rdip, num)
111+
else:
112+
num1, num2 = struct.unpack('!HI', rd)
113+
rd = '%s:%s' % (num1, num2)
114+
115+
idx += 8
116+
plen -= 64
117+
118+
ipl = pb(plen)
119+
ip = val[idx:idx+ipl]
120+
idx += ipl
121+
122+
prefix = pip(ip, plen)
123+
124+
return cls(labels, rd, prefix)
125+
126+
127+
128+
class ipv4(NLRI):
129+
def __init__(self, prefix):
130+
self.prefix = prefix
131+
132+
def __cmp__(self, other):
133+
if isinstance(other, ipv4):
134+
aip, alen = self.prefix.split('/')
135+
alen = int(alen)
136+
aip = socket.inet_aton(aip)
137+
138+
bip, blen = other.prefix.split('/')
139+
blen = int(blen)
140+
bip = socket.inet_aton(bip)
141+
142+
return cmp((aip,alen),(bip,blen))
143+
144+
return -1
145+
146+
def encode(self):
147+
plen = 0
148+
v = ''
149+
150+
ip, masklen = self.prefix.split('/')
151+
ip = socket.inet_aton(ip)
152+
masklen = int(masklen)
153+
154+
plen += masklen
155+
if masklen > 24:
156+
v += ip
157+
elif masklen > 16:
158+
v += ip[:3]
159+
elif masklen > 8:
160+
v += ip[:2]
161+
elif masklen > 0:
162+
v += ip[:1]
163+
else:
164+
pass
165+
166+
return struct.pack('B', plen) + v
167+
168+
def __repr__(self):
169+
return '<ipv4 %s>' % (self.prefix,)
170+
171+
def __str__(self):
172+
return self.prefix
173+
174+
@classmethod
175+
def from_bytes(cls, plen, val):
176+
return cls(pip(val, plen))
177+
178+
179+
def pb(masklen):
180+
if masklen > 24:
181+
return 4
182+
elif masklen > 16:
183+
return 3
184+
elif masklen > 8:
185+
return 2
186+
elif masklen > 0:
187+
return 1
188+
return 0
189+
190+
def pip(pi, masklen):
191+
pi += '\x00\x00\x00\x00'
192+
return '%s/%s' % (socket.inet_ntoa(pi[:4]), masklen)
193+
194+
195+
def parse(bytes, afi=1, safi=0):
196+
rv = []
197+
198+
if afi==1 and safi==128:
199+
klass = vpnv4
200+
else:
201+
klass = ipv4
202+
203+
idx = 0
204+
while idx < len(bytes):
205+
plen, = struct.unpack_from('B', bytes, idx)
206+
idx += 1
207+
nbytes, rest = divmod(plen, 8)
208+
if rest:
209+
nbytes += 1
210+
val = bytes[idx:idx+nbytes]
211+
idx += nbytes
212+
213+
rv.append(klass.from_bytes(plen, val))
214+
215+
return rv

0 commit comments

Comments
 (0)