6
6
Copyright (c) 2009-2013 Exa Networks. All rights reserved.
9
from collections import deque
9
11
from exabgp.protocol.family import AFI
10
13
from exabgp.bgp.message.open.holdtime import HoldTime
11
14
from exabgp.bgp.message.open.capability import AddPath
12
from exabgp.bgp.message.update.attribute.id import AttributeID
14
from exabgp.structure.api import APIOptions
16
from exabgp.rib.watchdog import Watchdog
18
from exabgp.structure.log import Logger
16
from exabgp.reactor.api.encoding import APIOptions
18
from exabgp.rib import RIB
20
20
# The definition of a neighbor (from reading the configuration)
21
21
class Neighbor (object):
22
# This need to be global, all neighbor share the same data !
23
# It allows us to use the information when performing global routing table update calculation
26
22
def __init__ (self):
27
self.logger = Logger()
23
# self.logger should not be used here as long as we do use deepcopy as it contains a Lock
28
24
self.description = ''
29
25
self.router_id = None
30
26
self.local_address = None
39
35
self.group_updates = None
41
39
self.api = APIOptions()
44
44
self.route_refresh = False
45
45
self.graceful_restart = False
46
46
self.multisession = None
47
47
self.add_path = None
49
50
self._families = []
53
self.operational = None
56
self.messages = deque()
57
self.refresh = deque()
60
self.rib = RIB(self.name(),self.adjribout,self._families)
62
# will resend all the routes once we reconnect
65
self.messages = deque()
66
self.refresh = deque()
68
# back to square one, all the routes are removed
71
self.messages = deque()
72
self.refresh = deque()
53
75
if self.multisession:
54
session = "/ ".join("%s-%s" % (afi,safi) for (afi,safi) in self.families())
76
session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families())
56
78
session = 'in-open'
57
return "%s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (self.peer_address,self.local_address,self.local_as,self.peer_as,self.router_id,session)
79
return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % (self.peer_address,self.local_address,self.local_as,self.peer_as,self.router_id,session)
59
81
def families (self):
60
82
# this list() is important .. as we use the function to modify self._families
61
83
return list(self._families)
63
def every_routes (self):
64
for family in list(self._routes.keys()):
65
for route in self._routes[family]:
69
# This function returns a hash and not a list as "in" tests are O(n) with lists and O(1) with hash
70
# and with ten thousands routes this makes an enormous difference (60 seconds to 2)
73
for family in list(self._routes.keys()):
74
for route in self._routes[family]:
78
for route in self.watchdog.filtered(_routes(self)):
79
routes[route.index()] = route
82
85
def add_family (self,family):
86
# the families MUST be sorted for neighbor indexing name to be predictable for API users
83
87
if not family in self.families():
84
self._families.append(family)
91
for afi,safi in self._families:
92
d.setdefault(afi,[]).append(safi)
93
self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])]
86
def remove_family_and_routes (self,family):
95
def remove_family (self,family):
87
96
if family in self.families():
88
97
self._families.remove(family)
89
if family in self._routes:
90
del self._routes[family]
92
def add_route (self,route):
93
self.watchdog.integrate(route)
94
self._routes.setdefault((route.nlri.afi,route.nlri.safi),set()).add(route)
96
def remove_route (self,route):
99
routes = self._routes[(route.nlri.afi,route.nlri.safi)]
100
if route.nlri.afi in (AFI.ipv4,AFI.ipv6):
101
for r in list(routes):
102
if r.nlri == route.nlri and \
103
r.attributes.get(AttributeID.NEXT_HOP,None) == route.attributes.get(AttributeID.NEXT_HOP,None):
113
def set_routes (self,routes):
114
# routes can be a generator for self.everyroutes, if we delete self._families
115
# then the generator will return an empty content when ran, so we can not use add_route
118
f.setdefault((route.nlri.afi,route.nlri.safi),set()).add(route)
121
99
def missing (self):
122
100
if self.local_address is None: return 'local-address'
141
120
self.graceful_restart == other.graceful_restart and \
142
121
self.multisession == other.multisession and \
143
122
self.add_path == other.add_path and \
123
self.operational == other.operational and \
144
124
self.group_updates == other.group_updates and \
125
self.flush == other.flush and \
126
self.adjribout == other.adjribout and \
145
127
self.families() == other.families()
147
129
def __ne__(self, other):
148
130
return not self.__eq__(other)
150
def pprint (self,with_routes=True):
153
routes += '\nstatic { '
154
for route in self.every_routes():
155
routes += '\n %s' % route
132
def pprint (self,with_changes=True):
135
changes += '\nstatic { '
136
for changes in self.rib.incoming.queued_changes():
137
changes += '\n %s' % changes.extensive()
159
141
for afi,safi in self.families():
160
142
families += '\n %s %s;' % (afi.name(),safi.name())
163
_api.extend([' neighbor-changes;\n',] if self.api.neighbor_changes else [])
164
_api.extend([' receive-packets;\n',] if self.api.receive_packets else [])
165
_api.extend([' send-packets;\n',] if self.api.send_packets else [])
166
_api.extend([' receive-routes;\n',] if self.api.receive_routes else [])
145
_api.extend([' neighbor-changes;\n',] if self.api.neighbor_changes else [])
146
_api.extend([' receive-packets;\n',] if self.api.receive_packets else [])
147
_api.extend([' send-packets;\n',] if self.api.send_packets else [])
148
_api.extend([' receive-routes;\n',] if self.api.receive_routes else [])
149
_api.extend([' receive-operational;\n',] if self.api.receive_operational else [])
167
150
api = ''.join(_api)
188
171
self.local_address,
174
'\n passive;\n' if self.passive else '',
192
176
' group-updates: %s;\n' % self.group_updates if self.group_updates else '',
177
' auto-flush: %s;\n' % 'true' if self.flush else 'false',
178
' adj-rib-out: %s;\n' % 'true' if self.adjribout else 'false',
193
179
' md5: %d;\n' % self.ttl if self.ttl else '',
194
180
' ttl-security: %d;\n' % self.ttl if self.ttl else '',
195
181
' asn4 enable;\n' if self.asn4 else ' asn4 disable;\n',