6
Created by Thomas Mangin on 2009-11-05.
7
Copyright (c) 2009-2011 Exa Networks. All rights reserved.
12
from struct import pack
14
from exabgp.structure.address import AFI,SAFI
15
from exabgp.structure.asn import ASN
16
from exabgp.message import Message
18
# =================================================================== Open
23
def __init__ (self,version,asn,router_id,capabilities,hold_time):
24
self.version = Version(version)
26
self.hold_time = HoldTime(hold_time)
27
self.router_id = RouterID(router_id)
28
self.capabilities = capabilities
32
return self._message("%s%s%s%s%s" % (self.version.pack(),ASN(23456).pack(False),self.hold_time.pack(),self.router_id.pack(),self.capabilities.pack()))
33
return self._message("%s%s%s%s%s" % (self.version.pack(),self.asn.pack(False),self.hold_time.pack(),self.router_id.pack(),self.capabilities.pack()))
36
return "OPEN version=%d asn=%d hold_time=%s router_id=%s capabilities=[%s]" % (self.version, self.asn, self.hold_time, self.router_id,self.capabilities)
38
# =================================================================== Version
44
# =================================================================== HoldTime
48
return pack('!H',self)
56
# =================================================================== RouterID
58
class RouterID (object):
59
def __init__ (self,ip):
62
self.raw = socket.inet_pton(socket.AF_INET,ip)
64
raise ValueError('invalid IP address %s' % str(ip))
81
def __eq__ (self,other):
82
return self.ip == other.ip
84
# =================================================================== Graceful (Restart)
87
class Graceful (dict):
93
FORWARDING_STATE = 0x80
95
def __init__ (self,restart_flag,restart_time,protos):
97
self.restart_flag = restart_flag
98
self.restart_time = restart_time & Graceful.TIME_MASK
99
for afi,safi,family_flag in protos:
100
self[(afi,safi)] = family_flag & Graceful.FORWARDING_STATE
103
restart = pack('!H',((self.restart_flag << 12) | (self.restart_time & Graceful.TIME_MASK)))
104
families = [(afi.pack(),safi.pack(),chr(self[(afi,safi)])) for (afi,safi) in self.keys()]
105
sfamilies = ''.join(["%s%s%s" % (pafi,psafi,family) for (pafi,psafi,family) in families])
106
return ["%s%s" % (restart,sfamilies)]
109
families = [(str(afi),str(safi),hex(self[(afi,safi)])) for (afi,safi) in self.keys()]
110
sfamilies = ' '.join(["%s/%s=%s" % (afi,safi,family) for (afi,safi,family) in families])
111
return "Graceful Restart Flags %s Time %d %s" % (hex(self.restart_flag),self.restart_time,sfamilies)
116
# =================================================================== MultiProtocol
118
class MultiProtocol (list):
120
return 'Multiprotocol ' + ' '.join(["%s %s" % (safi,ssafi) for (safi,ssafi) in [(str(afi),str(safi)) for (afi,safi) in self]])
125
rs.append(pack('!H',v[0]) + pack('!H',v[1]))
128
# =================================================================== RouteRefresh
130
class RouteRefresh (list):
132
return "Route Refresh (unparsed)"
137
class CiscoRouteRefresh (list):
139
return "Cisco Route Refresh (unparsed)"
145
# =================================================================== Parameter
149
return [pack('!L',self)]
151
# =================================================================== Unknown
153
class Unknown (object):
154
def __init__ (self,value):
158
if self.value in Capabilities.reserved: return 'Reserved %s' % str(self.value)
159
if self.value in Capabilities.unassigned: return 'Unassigned %s' % str(self.value)
160
return 'unknown %s' % str(self.value)
165
# =================================================================== Parameter
167
class Parameter (int):
168
AUTHENTIFICATION_INFORMATION = 0x01 # Depreciated
172
if self == 0x01: return "AUTHENTIFICATION INFORMATION"
173
if self == 0x02: return "OPTIONAL"
176
# =================================================================== Capabilities
177
# http://www.iana.org/assignments/capability-codes/
179
class Capabilities (dict):
180
RESERVED = 0x00 # [RFC5492]
181
MULTIPROTOCOL_EXTENSIONS = 0x01 # [RFC2858]
182
ROUTE_REFRESH = 0x02 # [RFC2918]
183
OUTBOUND_ROUTE_FILTERING = 0x03 # [RFC5291]
184
MULTIPLE_ROUTES = 0x04 # [RFC3107]
185
EXTENDED_NEXT_HOP = 0x05 # [RFC5549]
187
GRACEFUL_RESTART = 0x40 # [RFC4724]
188
FOUR_BYTES_ASN = 0x41 # [RFC4893]
190
DYNAMIC_CAPABILITY = 0x43 # [Chen]
191
MULTISESSION_BGP = 0x44 # [Appanna]
192
ADD_PATH = 0x45 # [draft-ietf-idr-add-paths]
194
CISCO_ROUTE_REFRESH = 0x80 # I Can only find reference to this in the router logs
195
# 128-255 Reserved for Private Use [RFC5492]
197
unassigned = range(70,128)
198
reserved = range(128,256)
200
def announced (self,capability):
201
return self.has_key(capability)
205
for key in self.keys():
206
if key == self.MULTIPROTOCOL_EXTENSIONS:
207
r += ['Multiprotocol for ' + ' '.join(["%s %s" % (str(afi),str(safi)) for (afi,safi) in self[key]])]
208
elif key == self.ROUTE_REFRESH:
209
r += ['Route Refresh']
210
elif key == self.CISCO_ROUTE_REFRESH:
211
r += ['Cisco Route Refresh']
212
elif key == self.GRACEFUL_RESTART:
213
r += ['Graceful Restart']
214
elif key == self.FOUR_BYTES_ASN:
215
r += ['4Bytes AS %d' % self[key]]
216
elif key in self.reserved:
217
r += ['private use capability %d' % key]
218
elif key in self.unassigned:
219
r += ['unassigned capability %d' % key]
221
r += ['unhandled capability %d' % key]
224
def default (self,neighbor,restarted):
225
graceful = neighbor.graceful_restart
227
if os.environ.get('MINIMAL_MP','0') in ['','1','yes','Yes','YES']:
228
families = neighbor.families
231
families.append((AFI(AFI.ipv4),SAFI(SAFI.unicast)))
232
families.append((AFI(AFI.ipv6),SAFI(SAFI.unicast)))
233
families.append((AFI(AFI.ipv4),SAFI(SAFI.flow_ipv4)))
237
self[Capabilities.MULTIPROTOCOL_EXTENSIONS] = mp
238
self[Capabilities.FOUR_BYTES_ASN] = ASN4(neighbor.local_as)
242
self[Capabilities.GRACEFUL_RESTART] = Graceful(Graceful.RESTART_STATE,graceful,[(afi,safi,Graceful.FORWARDING_STATE) for (afi,safi) in families])
244
self[Capabilities.GRACEFUL_RESTART] = Graceful(0x0,graceful,[(afi,safi,Graceful.FORWARDING_STATE) for (afi,safi) in families])
251
for k,capabilities in self.iteritems():
252
for capability in capabilities.extract():
253
rs.append("%s%s%s" % (chr(k),chr(len(capability)),capability))
254
parameters = "".join(["%s%s%s" % (chr(2),chr(len(r)),r) for r in rs])
255
return "%s%s" % (chr(len(parameters)),parameters)