class Neighbor (object): def __init__ (self): # self.logger should not be used here as long as we do use deepcopy as it contains a Lock self.description = '' self.router_id = None self.local_address = None self.peer_address = None self.peer_as = None self.local_as = None self.hold_time = HoldTime(180) self.asn4 = None self.add_path = 0 self.md5 = None self.ttl = None self.group_updates = None self.flush = None self.adjribout = None self.api = APIOptions() # passive indicate that we do not establish outgoing connections self.passive = False # the port to listen on ( zero mean that we do not listen ) self.listen = 0 # capability self.route_refresh = False self.graceful_restart = False self.multisession = None self.add_path = None self.aigp = None self._families = [] self.rib = None # The routes we have parsed from the configuration self.changes = [] # On signal update, the previous routes so we can compare what changed self.backup_changes = [] self.operational = None self.eor = deque() self.asm = dict() self.messages = deque() self.refresh = deque() self.counter = Counter() def identificator (self): # It is possible to : # - have multiple exabgp toward one peer on the same host ( use of pid ) # - have more than once connection toward a peer # - each connection has it own neihgbor (hence why identificator is not in Protocol) return str(self.peer_address) def make_rib (self): self.rib = RIB(self.name(),self.adjribout,self._families) # will resend all the routes once we reconnect def reset_rib (self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib (self): self.rib.clear() self.messages = deque() self.refresh = deque() def name (self): if self.multisession: session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families()) else: session = 'in-open' 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) def families (self): # this list() is important .. as we use the function to modify self._families return list(self._families) def add_family (self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users if family not in self.families(): afi,safi = family d = dict() d[afi] = [safi,] for afi,safi in self._families: d.setdefault(afi,[]).append(safi) self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family (self, family): if family in self.families(): self._families.remove(family) def missing (self): if self.local_address is None: return 'local-address' if self.peer_address is None: return 'peer-address' if self.local_as is None: return 'local-as' if self.peer_as is None: return 'peer-as' if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id' return '' # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__ (self, other): return \ self.router_id == other.router_id and \ self.local_address == other.local_address and \ self.local_as == other.local_as and \ self.peer_address == other.peer_address and \ self.peer_as == other.peer_as and \ self.passive == other.passive and \ self.listen == other.listen and \ self.hold_time == other.hold_time and \ self.md5 == other.md5 and \ self.ttl == other.ttl and \ self.route_refresh == other.route_refresh and \ self.graceful_restart == other.graceful_restart and \ self.multisession == other.multisession and \ self.add_path == other.add_path and \ self.operational == other.operational and \ self.group_updates == other.group_updates and \ self.flush == other.flush and \ self.adjribout == other.adjribout and \ self.families() == other.families() def __ne__ (self, other): return not self.__eq__(other) def pprint (self, with_changes=True): changes = '' if with_changes: changes += '\nstatic { ' for changes in self.rib.incoming.queued_changes(): changes += '\n\t\t%s' % changes.extensive() changes += '\n}' families = '' for afi,safi in self.families(): families += '\n\t\t%s %s;' % (afi.name(),safi.name()) _extension_receive = { 'receive-parsed': 'parsed', 'receive-packets': 'packets', 'receive-parsed': 'parsed', 'consolidate': 'consolidate', 'neighbor-changes': 'neighbor-changes', Message.CODE.NOTIFICATION: 'notification', Message.CODE.OPEN: 'open', Message.CODE.KEEPALIVE: 'keepalive', Message.CODE.UPDATE: 'update', Message.CODE.ROUTE_REFRESH: 'refresh', Message.CODE.OPERATIONAL: 'operational', } _extension_send = { 'send-packets': 'packets', } _receive = [] for api,name in _extension_receive.items(): _receive.extend(['\t\t\t%s;\n' % name,] if self.api[api] else []) receive = ''.join(_receive) _send = [] for api,name in _extension_send.items(): _send.extend(['\t\t\t%s;\n' % name,] if self.api[api] else []) send = ''.join(_send) returned = \ 'neighbor %s {\n' \ '\tdescription "%s";\n' \ '\trouter-id %s;\n' \ '\tlocal-address %s;\n' \ '\tlocal-as %s;\n' \ '\tpeer-as %s;%s\n' \ '\thold-time %s;\n' \ '%s%s%s%s%s%s\n' \ '\tcapability {\n' \ '%s%s%s%s%s%s%s\t}\n' \ '\tfamily {%s\n' \ '\t}\n' \ '\tprocess {\n' \ '%s%s\t}%s\n' \ '}' % ( self.peer_address, self.description, self.router_id, self.local_address, self.local_as, self.peer_as, self.hold_time, '\n\tpassive;\n' if self.passive else '', '\n\tlisten %d;\n' % self.listen if self.listen else '', '\tgroup-updates: %s;\n' % (self.group_updates if self.group_updates else ''), '\tauto-flush: %s;\n' % ('true' if self.flush else 'false'), '\tadj-rib-out: %s;\n' % ('true' if self.adjribout else 'false'), '\tmd5 "%s";\n' % self.md5 if self.md5 else '', '\tttl-security: %s;\n' % (self.ttl if self.ttl else ''), '\t\tasn4 %s;\n' % ('enable' if self.asn4 else 'disable'), '\t\troute-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'), '\t\tgraceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'), '\t\tadd-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'), '\t\tmulti-session %s;\n' % ('enable' if self.multisession else 'disable'), '\t\toperational %s;\n' % ('enable' if self.operational else 'disable'), '\t\taigp %s;\n' % ('enable' if self.aigp else 'disable'), families, '\t\treceive {\n%s\t\t}\n' % receive if receive else '', '\t\tsend {\n%s\t\t}\n' % send if send else '', changes ) return returned.replace('\t',' ') def __str__ (self): return self.pprint(False)
class Neighbor (object): def __init__ (self): # self.logger should not be used here as long as we do use deepcopy as it contains a Lock self.description = '' self.router_id = None self.local_address = None self.peer_address = None self.peer_as = None self.local_as = None self.hold_time = HoldTime(180) self.asn4 = None self.add_path = 0 self.md5 = None self.ttl = None self.group_updates = None self.flush = None self.api = APIOptions() self.passive = False # capability self.route_refresh = False self.graceful_restart = False self.multisession = None self.add_path = None self.aigp = None self._families = [] self.rib = None self.operational = None self.asm = dict() self.messages = deque() self.refresh = deque() def make_rib (self): self.rib = RIB(self.name(),self._families) # will resend all the routes once we reconnect def reset_rib (self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib (self): self.rib.clear() self.messages = deque() self.refresh = deque() def name (self): if self.multisession: session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families()) else: session = 'in-open' 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) def families (self): # this list() is important .. as we use the function to modify self._families return list(self._families) def add_family (self,family): # the families MUST be sorted for neighbor indexing name to be predictable for API users if not family in self.families(): afi,safi = family d = dict() d[afi] = [safi,] for afi,safi in self._families: d.setdefault(afi,[]).append(safi) self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family (self,family): if family in self.families(): self._families.remove(family) def missing (self): if self.local_address is None: return 'local-address' if self.peer_address is None: return 'peer-address' if self.local_as is None: return 'local-as' if self.peer_as is None: return 'peer-as' if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id' return '' # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__ (self,other): return \ self.router_id == other.router_id and \ self.local_address == other.local_address and \ self.local_as == other.local_as and \ self.peer_address == other.peer_address and \ self.peer_as == other.peer_as and \ self.passive == other.passive and \ self.hold_time == other.hold_time and \ self.md5 == other.md5 and \ self.ttl == other.ttl and \ self.route_refresh == other.route_refresh and \ self.graceful_restart == other.graceful_restart and \ self.multisession == other.multisession and \ self.add_path == other.add_path and \ self.operational == other.operational and \ self.group_updates == other.group_updates and \ self.flush == other.flush and \ self.families() == other.families() def __ne__(self, other): return not self.__eq__(other) def pprint (self,with_changes=True): changes='' if with_changes: changes += '\nstatic { ' for changes in self.rib.incoming.queued_changes(): changes += '\n %s' % changes.extensive() changes += '\n}' families = '' for afi,safi in self.families(): families += '\n %s %s;' % (afi.name(),safi.name()) _api = [] _api.extend([' neighbor-changes;\n',] if self.api.neighbor_changes else []) _api.extend([' receive-packets;\n',] if self.api.receive_packets else []) _api.extend([' send-packets;\n',] if self.api.send_packets else []) _api.extend([' receive-routes;\n',] if self.api.receive_routes else []) _api.extend([' receive-operational;\n',] if self.api.receive_operational else []) api = ''.join(_api) return """\ neighbor %s { description "%s"; router-id %s; local-address %s; local-as %s; peer-as %s;%s hold-time %s; %s%s%s%s capability { %s%s%s%s%s%s%s } family {%s } process { %s }%s }""" % ( self.peer_address, self.description, self.router_id, self.local_address, self.local_as, self.peer_as, '\n passive;\n' if self.passive else '', self.hold_time, ' group-updates: %s;\n' % self.group_updates if self.group_updates else '', ' auto-flush: %s;\n' % 'true' if self.flush else 'false', ' md5: %d;\n' % self.ttl if self.ttl else '', ' ttl-security: %d;\n' % self.ttl if self.ttl else '', ' asn4 enable;\n' if self.asn4 else ' asn4 disable;\n', ' route-refresh;\n' if self.route_refresh else '', ' graceful-restart %s;\n' % self.graceful_restart if self.graceful_restart else '', ' add-path %s;\n' % AddPath.string[self.add_path] if self.add_path else '', ' multi-session;\n' if self.multisession else '', ' operational;\n' if self.operational else '', ' aigp;\n' if self.aigp else '', families, api, changes ) def __str__ (self): return self.pprint(False)
class Neighbor(object): def __init__(self): # self.logger should not be used here as long as we do use deepcopy as it contains a Lock self.description = '' self.router_id = None self.local_address = None self.peer_address = None self.peer_as = None self.local_as = None self.hold_time = HoldTime(180) self.asn4 = None self.add_path = 0 self.md5 = None self.ttl = None self.group_updates = None self.flush = None self.adjribout = None self.api = APIOptions() # passive indicate that we do not establish outgoing connections self.passive = False # the port to listen on ( zero mean that we do not listen ) self.listen = 0 # capability self.route_refresh = False self.graceful_restart = False self.multisession = None self.add_path = None self.aigp = None self._families = [] self.rib = None # The routes we have parsed from the configuration self.changes = [] # On signal update, the previous routes so we can compare what changed self.backup_changes = [] self.operational = None self.eor = deque() self.asm = dict() self.messages = deque() self.refresh = deque() self.counter = Counter() def identificator(self): # It is possible to : # - have multiple exabgp toward one peer on the same host ( use of pid ) # - have more than once connection toward a peer # - each connection has it own neihgbor (hence why identificator is not in Protocol) return str(self.peer_address) def make_rib(self): self.rib = RIB(self.name(), self.adjribout, self._families) # will resend all the routes once we reconnect def reset_rib(self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib(self): self.rib.clear() self.messages = deque() self.refresh = deque() def name(self): if self.multisession: session = '/'.join("%s-%s" % (afi.name(), safi.name()) for (afi, safi) in self.families()) else: session = 'in-open' 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) def families(self): # this list() is important .. as we use the function to modify self._families return list(self._families) def add_family(self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users if family not in self.families(): afi, safi = family d = dict() d[afi] = [ safi, ] for afi, safi in self._families: d.setdefault(afi, []).append(safi) self._families = [(afi, safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family(self, family): if family in self.families(): self._families.remove(family) def missing(self): if self.local_address is None: return 'local-address' if self.peer_address is None: return 'peer-address' if self.local_as is None: return 'local-as' if self.peer_as is None: return 'peer-as' if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id' return '' # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__(self, other): return \ self.router_id == other.router_id and \ self.local_address == other.local_address and \ self.local_as == other.local_as and \ self.peer_address == other.peer_address and \ self.peer_as == other.peer_as and \ self.passive == other.passive and \ self.listen == other.listen and \ self.hold_time == other.hold_time and \ self.md5 == other.md5 and \ self.ttl == other.ttl and \ self.route_refresh == other.route_refresh and \ self.graceful_restart == other.graceful_restart and \ self.multisession == other.multisession and \ self.add_path == other.add_path and \ self.operational == other.operational and \ self.group_updates == other.group_updates and \ self.flush == other.flush and \ self.adjribout == other.adjribout and \ self.families() == other.families() def __ne__(self, other): return not self.__eq__(other) def pprint(self, with_changes=True): changes = '' if with_changes: changes += '\nstatic { ' for changes in self.rib.incoming.queued_changes(): changes += '\n\t\t%s' % changes.extensive() changes += '\n}' families = '' for afi, safi in self.families(): families += '\n\t\t%s %s;' % (afi.name(), safi.name()) _extension_receive = { 'receive-parsed': 'parsed', 'receive-packets': 'packets', 'receive-parsed': 'parsed', 'consolidate': 'consolidate', 'neighbor-changes': 'neighbor-changes', Message.CODE.NOTIFICATION: 'notification', Message.CODE.OPEN: 'open', Message.CODE.KEEPALIVE: 'keepalive', Message.CODE.UPDATE: 'update', Message.CODE.ROUTE_REFRESH: 'refresh', Message.CODE.OPERATIONAL: 'operational', } _extension_send = { 'send-packets': 'packets', } _receive = [] for api, name in _extension_receive.items(): _receive.extend([ '\t\t\t%s;\n' % name, ] if self.api[api] else []) receive = ''.join(_receive) _send = [] for api, name in _extension_send.items(): _send.extend([ '\t\t\t%s;\n' % name, ] if self.api[api] else []) send = ''.join(_send) returned = \ 'neighbor %s {\n' \ '\tdescription "%s";\n' \ '\trouter-id %s;\n' \ '\tlocal-address %s;\n' \ '\tlocal-as %s;\n' \ '\tpeer-as %s;%s\n' \ '\thold-time %s;\n' \ '%s%s%s%s%s%s\n' \ '\tcapability {\n' \ '%s%s%s%s%s%s%s\t}\n' \ '\tfamily {%s\n' \ '\t}\n' \ '\tprocess {\n' \ '%s%s\t}%s\n' \ '}' % ( self.peer_address, self.description, self.router_id, self.local_address, self.local_as, self.peer_as, self.hold_time, '\n\tpassive;\n' if self.passive else '', '\n\tlisten %d;\n' % self.listen if self.listen else '', '\tgroup-updates: %s;\n' % (self.group_updates if self.group_updates else ''), '\tauto-flush: %s;\n' % ('true' if self.flush else 'false'), '\tadj-rib-out: %s;\n' % ('true' if self.adjribout else 'false'), '\tmd5 "%s";\n' % self.md5 if self.md5 else '', '\tttl-security: %s;\n' % (self.ttl if self.ttl else ''), '\t\tasn4 %s;\n' % ('enable' if self.asn4 else 'disable'), '\t\troute-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'), '\t\tgraceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'), '\t\tadd-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'), '\t\tmulti-session %s;\n' % ('enable' if self.multisession else 'disable'), '\t\toperational %s;\n' % ('enable' if self.operational else 'disable'), '\t\taigp %s;\n' % ('enable' if self.aigp else 'disable'), families, '\t\treceive {\n%s\t\t}\n' % receive if receive else '', '\t\tsend {\n%s\t\t}\n' % send if send else '', changes ) return returned.replace('\t', ' ') def __str__(self): return self.pprint(False)
class Neighbor(object): def __init__(self): # self.logger should not be used here as long as we do use deepcopy as it contains a Lock self.description = None self.router_id = None self.host_name = None self.domain_name = None self.local_address = None self.peer_address = None self.peer_as = None self.local_as = None self.hold_time = None self.asn4 = None self.add_path = None self.md5 = None self.ttl = None self.group_updates = None self.flush = None self.adjribout = None self.manual_eor = False self.api = None # passive indicate that we do not establish outgoing connections self.passive = False # the port to listen on ( zero mean that we do not listen ) self.listen = 0 # capability self.route_refresh = False self.graceful_restart = False self.multisession = None self.add_path = None self.aigp = None self._families = [] self.rib = None # The routes we have parsed from the configuration self.changes = [] # On signal update, the previous routes so we can compare what changed self.backup_changes = [] self.operational = None self.eor = deque() self.asm = dict() self.messages = deque() self.refresh = deque() self.counter = Counter() # It is possible to : # - have multiple exabgp toward one peer on the same host ( use of pid ) # - have more than once connection toward a peer # - each connection has it own neihgbor (hence why identificator is not in Protocol) self.uid = "%d-%s" % (os.getpid(), uuid.uuid1()) def make_rib(self): self.rib = RIB(self.name(), self.adjribout, self._families) # will resend all the routes once we reconnect def reset_rib(self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib(self): self.rib.clear() self.messages = deque() self.refresh = deque() def name(self): if self.multisession: session = "/".join("%s-%s" % (afi.name(), safi.name()) for (afi, safi) in self.families()) else: session = "in-open" 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, ) def families(self): # this list() is important .. as we use the function to modify self._families return list(self._families) def add_family(self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users if family not in self.families(): afi, safi = family d = dict() d[afi] = [safi] for afi, safi in self._families: d.setdefault(afi, []).append(safi) self._families = [(afi, safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family(self, family): if family in self.families(): self._families.remove(family) def missing(self): if self.local_address is None: return "local-address" if self.peer_address is None: return "peer-address" if self.local_as is None: return "local-as" if self.peer_as is None: return "peer-as" if self.peer_address.afi == AFI.ipv6 and not self.router_id: return "router-id" return "" # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__(self, other): return ( self.router_id == other.router_id and self.local_address == other.local_address and self.local_as == other.local_as and self.peer_address == other.peer_address and self.peer_as == other.peer_as and self.passive == other.passive and self.listen == other.listen and self.hold_time == other.hold_time and self.host_name == other.host_name and self.domain_name == other.domain_name and self.md5 == other.md5 and self.ttl == other.ttl and self.route_refresh == other.route_refresh and self.graceful_restart == other.graceful_restart and self.multisession == other.multisession and self.add_path == other.add_path and self.operational == other.operational and self.group_updates == other.group_updates and self.flush == other.flush and self.adjribout == other.adjribout and self.families() == other.families() ) def __ne__(self, other): return not self.__eq__(other) def pprint(self, with_changes=True): changes = "" if with_changes: changes += "\nstatic { " for changes in self.rib.incoming.queued_changes(): changes += "\n\t\t%s" % changes.extensive() changes += "\n}" families = "" for afi, safi in self.families(): families += "\n\t\t%s %s;" % (afi.name(), safi.name()) codes = Message.CODE _extension_receive = { "receive-packets": "packets", "receive-parsed": "parsed", "receive-consolidate": "consolidate", "receive-%s" % codes.NOTIFICATION.SHORT: "notification", "receive-%s" % codes.OPEN.SHORT: "open", "receive-%s" % codes.KEEPALIVE.SHORT: "keepalive", "receive-%s" % codes.UPDATE.SHORT: "update", "receive-%s" % codes.ROUTE_REFRESH.SHORT: "refresh", "receive-%s" % codes.OPERATIONAL.SHORT: "operational", } _extension_send = { "send-packets": "packets", "send-parsed": "parsed", "send-consolidate": "consolidate", "send-%s" % codes.NOTIFICATION.SHORT: "notification", "send-%s" % codes.OPEN.SHORT: "open", "send-%s" % codes.KEEPALIVE.SHORT: "keepalive", "send-%s" % codes.UPDATE.SHORT: "update", "send-%s" % codes.ROUTE_REFRESH.SHORT: "refresh", "send-%s" % codes.OPERATIONAL.SHORT: "operational", } _receive = [] for api, name in _extension_receive.items(): _receive.extend(["\t\t\t%s;\n" % name] if self.api[api] else []) receive = "".join(_receive) _send = [] for api, name in _extension_send.items(): _send.extend(["\t\t\t%s;\n" % name] if self.api[api] else []) send = "".join(_send) returned = ( "neighbor %s {\n" '\tdescription "%s";\n' "\trouter-id %s;\n" "\thost-name %s;\n" "\tdomain-name %s;\n" "\tlocal-address %s;\n" "\tlocal-as %s;\n" "\tpeer-as %s;\n" "\thold-time %s;\n" "\tmanual-eor %s;\n" "%s%s%s%s%s%s%s\n" "\tcapability {\n" "%s%s%s%s%s%s%s\t}\n" "\tfamily {%s\n" "\t}\n" "\tprocess {\n" "%s%s\t}%s\n" "}" % ( self.peer_address, self.description, self.router_id, self.host_name, self.domain_name, self.local_address, self.local_as, self.peer_as, self.hold_time, "true" if self.manual_eor else "false", "\n\tpassive;\n" if self.passive else "", "\n\tlisten %d;\n" % self.listen if self.listen else "", "\tgroup-updates: %s;\n" % (self.group_updates if self.group_updates else ""), "\tauto-flush: %s;\n" % ("true" if self.flush else "false"), "\tadj-rib-out: %s;\n" % ("true" if self.adjribout else "false"), '\tmd5 "%s";\n' % self.md5 if self.md5 else "", "\tttl-security: %s;\n" % (self.ttl if self.ttl else ""), "\t\tasn4 %s;\n" % ("enable" if self.asn4 else "disable"), "\t\troute-refresh %s;\n" % ("enable" if self.route_refresh else "disable"), "\t\tgraceful-restart %s;\n" % (self.graceful_restart if self.graceful_restart else "disable"), "\t\tadd-path %s;\n" % (AddPath.string[self.add_path] if self.add_path else "disable"), "\t\tmulti-session %s;\n" % ("enable" if self.multisession else "disable"), "\t\toperational %s;\n" % ("enable" if self.operational else "disable"), "\t\taigp %s;\n" % ("enable" if self.aigp else "disable"), families, "\t\treceive {\n%s\t\t}\n" % receive if receive else "", "\t\tsend {\n%s\t\t}\n" % send if send else "", changes, ) ) return returned.replace("\t", " ") def __str__(self): return self.pprint(False)
class Neighbor (object): _GLOBAL = {'uid': 1} def __init__ (self): # self.logger should not be used here as long as we do use deepcopy as it contains a Lock self.description = None self.router_id = None self.host_name = None self.domain_name = None self.local_address = None self.range_size = 1 # local_address uses auto discovery self.auto_discovery = False self.peer_address = None self.peer_as = None self.local_as = None self.hold_time = None self.asn4 = None self.nexthop = None self.add_path = None self.md5_password = None self.md5_base64 = False self.md5_ip = None self.ttl_in = None self.ttl_out = None self.group_updates = None self.flush = None self.adj_rib_in = None self.adj_rib_out = None self.manual_eor = False self.api = None # XXX: not scriptable - is replaced outside the class # passive indicate that we do not establish outgoing connections self.passive = False # the port to listen on ( zero mean that we do not listen ) self.listen = 0 # the port to connect to self.connect = 0 # was this Neighbor generated from a range self.generated = False # capability self.route_refresh = False self.graceful_restart = False self.multisession = None self.nexthop = None self.add_path = None self.aigp = None self._families = [] self._nexthop = [] self._addpath = [] self.rib = None # The routes we have parsed from the configuration self.changes = [] # On signal update, the previous routes so we can compare what changed self.backup_changes = [] self.operational = None self.eor = deque() self.asm = dict() self.messages = deque() self.refresh = deque() self.counter = Counter() self.ski = [] self.bgpsec_openssl_lib = [] self.bgpsec_crypto_init = [] self.bgpsec_pre_asns = [] self.bgpsec_pre_skis = [] self.bgpsec_send_receive = [] # It is possible to : # - have multiple exabgp toward one peer on the same host ( use of pid ) # - have more than once connection toward a peer # - each connection has it own neihgbor (hence why identificator is not in Protocol) self.uid = '%d' % self._GLOBAL['uid'] self._GLOBAL['uid'] += 1 def id (self): return 'neighbor-%s' % self.uid def make_rib (self): self.rib = RIB(self.name(),self.adj_rib_in,self.adj_rib_out,self._families) # will resend all the routes once we reconnect def reset_rib (self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib (self): self.rib.clear() self.messages = deque() self.refresh = deque() def name (self): if self.multisession: session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families()) else: session = 'in-open' return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % ( self.peer_address, self.local_address if self.peer_address is not None else 'auto', self.local_as if self.local_as is not None else 'auto', self.peer_as if self.peer_as is not None else 'auto', self.router_id, session ) def families (self): # this list() is important .. as we use the function to modify self._families return list(self._families) def nexthops (self): # this list() is important .. as we use the function to modify self._nexthop return list(self._nexthop) def addpaths (self): # this list() is important .. as we use the function to modify self._add_path return list(self._addpath) def add_family (self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users # this list() is important .. as we use the function to modify self._families if family not in self.families(): afi,safi = family d = dict() d[afi] = [safi,] for afi,safi in self._families: d.setdefault(afi,[]).append(safi) self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])] def add_nexthop (self, afi, safi, nhafi): if (afi,safi,nhafi) not in self._nexthop: self._nexthop.append((afi,safi,nhafi)) def add_addpath (self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users # this list() is important .. as we use the function to modify self._add_path if family not in self.addpaths(): afi,safi = family d = dict() d[afi] = [safi,] for afi,safi in self._addpath: d.setdefault(afi,[]).append(safi) self._addpath = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family (self, family): if family in self.families(): self._families.remove(family) def remove_nexthop (self, afi, safi, nhafi): if (afi,safi,nhafi) in self.nexthops(): self._nexthop.remove((afi,safi,nhafi)) def remove_addpath (self, family): if family in self.addpaths(): self._addpath.remove(family) def missing (self): if self.local_address is None and not self.auto_discovery: return 'local-address' if self.listen > 0 and self.auto_discovery: return 'local-address' if self.peer_address is None: return 'peer-address' if self.auto_discovery and not self.router_id: return 'router-id' if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id' return '' # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__ (self, other): # Comparing local_address is skipped in the case where either # peer is configured to auto discover its local address. In # this case it can happen that one local_address is None and # the other one will be set to the auto disocvered IP address. auto_discovery = self.auto_discovery or other.auto_discovery return \ self.router_id == other.router_id and \ (auto_discovery or self.local_address == other.local_address) and \ self.auto_discovery == other.auto_discovery and \ self.local_as == other.local_as and \ self.peer_address == other.peer_address and \ self.peer_as == other.peer_as and \ self.passive == other.passive and \ self.listen == other.listen and \ self.connect == other.connect and \ self.hold_time == other.hold_time and \ self.host_name == other.host_name and \ self.domain_name == other.domain_name and \ self.md5_password == other.md5_password and \ self.md5_ip == other.md5_ip and \ self.ttl_in == other.ttl_in and \ self.ttl_out == other.ttl_out and \ self.route_refresh == other.route_refresh and \ self.graceful_restart == other.graceful_restart and \ self.multisession == other.multisession and \ self.nexthop == other.nexthop and \ self.add_path == other.add_path and \ self.operational == other.operational and \ self.group_updates == other.group_updates and \ self.flush == other.flush and \ self.adj_rib_in == other.adj_rib_in and \ self.adj_rib_out == other.adj_rib_out and \ self.families() == other.families() def __ne__ (self, other): return not self.__eq__(other) def string (self, with_changes=True): changes = '' if with_changes: changes += '\nstatic { ' for changes in self.rib.incoming.queued_changes(): changes += '\n\t\t%s' % changes.extensive() changes += '\n}' families = '' for afi,safi in self.families(): families += '\n\t\t%s %s;' % (afi.name(),safi.name()) nexthops = '' for afi, safi, nexthop in self.nexthops(): nexthops += '\n\t\t%s %s %s;' % (afi.name(), safi.name(), nexthop.name()) addpaths = '' for afi,safi in self.addpaths(): addpaths += '\n\t\t%s %s;' % (afi.name(),safi.name()) codes = Message.CODE _extension_global = { 'neighbor-changes': 'neighbor-changes', 'negotiated': 'negotiated', 'fsm': 'fsm', 'signal': 'signal', } _extension_receive = { 'receive-packets': 'packets', 'receive-parsed': 'parsed', 'receive-consolidate': 'consolidate', 'receive-%s' % codes.NOTIFICATION.SHORT: 'notification', 'receive-%s' % codes.OPEN.SHORT: 'open', 'receive-%s' % codes.KEEPALIVE.SHORT: 'keepalive', 'receive-%s' % codes.UPDATE.SHORT: 'update', 'receive-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh', 'receive-%s' % codes.OPERATIONAL.SHORT: 'operational', } _extension_send = { 'send-packets': 'packets', 'send-parsed': 'parsed', 'send-consolidate': 'consolidate', 'send-%s' % codes.NOTIFICATION.SHORT: 'notification', 'send-%s' % codes.OPEN.SHORT: 'open', 'send-%s' % codes.KEEPALIVE.SHORT: 'keepalive', 'send-%s' % codes.UPDATE.SHORT: 'update', 'send-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh', 'send-%s' % codes.OPERATIONAL.SHORT: 'operational', } apis = '' for process in self.api.get('processes',[]): _global = [] _receive = [] _send = [] for api,name in _extension_global.items(): _global.extend(['\t\t%s;\n' % name,] if process in self.api[api] else []) for api,name in _extension_receive.items(): _receive.extend(['\t\t\t%s;\n' % name,] if process in self.api[api] else []) for api,name in _extension_send.items(): _send.extend(['\t\t\t%s;\n' % name,] if process in self.api[api] else []) _api = '\tapi {\n' _api += '\t\tprocesses [ %s ];\n' % process _api += ''.join(_global) if _receive: _api += '\t\treceive {\n' _api += ''.join(_receive) _api += '\t\t}\n' if _send: _api += '\t\tsend {\n' _api += ''.join(_send) _api += '\t\t}\n' _api += '\t}\n' apis += _api returned = \ 'neighbor %s {\n' \ '\tdescription "%s";\n' \ '\trouter-id %s;\n' \ '\thost-name %s;\n' \ '\tdomain-name %s;\n' \ '\tlocal-address %s;\n' \ '\tlocal-as %s;\n' \ '\tpeer-as %s;\n' \ '\thold-time %s;\n' \ '\tmanual-eor %s;\n' \ '%s%s%s%s%s%s%s%s%s%s%s\n' \ '\tcapability {\n' \ '%s%s%s%s%s%s%s%s%s\t}\n' \ '\tfamily {%s\n' \ '\t}\n' \ '\tnexthop {%s\n' \ '\t}\n' \ '\tadd-path {%s\n' \ '\t}\n' \ '%s' \ '%s' \ '}' % ( self.peer_address, self.description, self.router_id, self.host_name, self.domain_name, self.local_address if not self.auto_discovery else 'auto', self.local_as, self.peer_as, self.hold_time, 'true' if self.manual_eor else 'false', '\n\tpassive %s;\n' % ('true' if self.passive else 'false'), '\n\tlisten %d;\n' % self.listen if self.listen else '', '\n\tconnect %d;\n' % self.connect if self.connect else '', '\tgroup-updates %s;\n' % ('true' if self.group_updates else 'false'), '\tauto-flush %s;\n' % ('true' if self.flush else 'false'), '\tadj-rib-in %s;\n' % ('true' if self.adj_rib_in else 'false'), '\tadj-rib-out %s;\n' % ('true' if self.adj_rib_out else 'false'), '\tmd5-password "%s";\n' % self.md5_password if self.md5_password else '', '\tmd5-base64 %s;\n' % ('true' if self.md5_base64 is True else 'false' if self.md5_base64 is False else 'auto'), '\tmd5-ip "%s";\n' % self.md5_ip if not self.auto_discovery else '', '\toutgoing-ttl %s;\n' % self.ttl_out if self.ttl_out else '', '\tincoming-ttl %s;\n' % self.ttl_in if self.ttl_in else '', '\t\tasn4 %s;\n' % ('enable' if self.asn4 else 'disable'), '\t\troute-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'), '\t\tgraceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'), '\t\tnexthop %s;\n' % ('enable' if self.nexthop else 'disable'), '\t\tadd-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'), '\t\tmulti-session %s;\n' % ('enable' if self.multisession else 'disable'), '\t\toperational %s;\n' % ('enable' if self.operational else 'disable'), '\t\taigp %s;\n' % ('enable' if self.aigp else 'disable'), families, nexthops, addpaths, apis, changes ) # '\t\treceive {\n%s\t\t}\n' % receive if receive else '', # '\t\tsend {\n%s\t\t}\n' % send if send else '', return returned.replace('\t',' ') def __str__ (self): return self.string(False)
class Neighbor(dict): class Capability(dict): defaults = { 'asn4': True, 'extended-message': True, 'graceful-restart': False, 'multi-session': False, 'operational': False, 'add-path': 0, 'route-refresh': 0, 'nexthop': None, 'aigp': None, } defaults = { # Those are the field from the configuration 'description': '', 'router-id': None, 'local-address': None, 'peer-address': None, 'local-as': None, 'peer-as': None, # passive indicate that we do not establish outgoing connections 'passive': False, # the port to listen on ( zero mean that we do not listen ) 'listen': 0, # the port to connect to 'connect': 0, 'hold-time': HoldTime(180), 'rate-limit': 0, 'host-name': host(), 'domain-name': domain(), 'group-updates': True, 'auto-flush': True, 'adj-rib-in': True, 'adj-rib-out': True, 'manual-eor': False, # XXX: this should be under an MD5 sub-dict/object ? 'md5-password': None, 'md5-base64': False, 'md5-ip': None, 'outgoing-ttl': None, 'incoming-ttl': None, } _GLOBAL = {'uid': 1} def __init__(self): # super init self.update(self.defaults) # Those are subconf self.api = None # XXX: not scriptable - is replaced outside the class # internal or calculated field self['capability'] = self.Capability.defaults.copy() # local_address uses auto discovery self.auto_discovery = False self.range_size = 1 # was this Neighbor generated from a range self.generated = False self._families = [] self._nexthop = [] self._addpath = [] self.rib = None # The routes we have parsed from the configuration self.changes = [] # On signal update, the previous routes so we can compare what changed self.backup_changes = [] self.eor = deque() self.asm = dict() self.messages = deque() self.refresh = deque() self.counter = Counter() # It is possible to : # - have multiple exabgp toward one peer on the same host ( use of pid ) # - have more than once connection toward a peer # - each connection has it own neihgbor (hence why identificator is not in Protocol) self.uid = '%d' % self._GLOBAL['uid'] self._GLOBAL['uid'] += 1 def missing(self): if self['local-as'] is None: return 'incomplete neighbor, missing local-address' if self['local-as'] is None: return 'incomplete neighbor, missing local-as' if self['peer-as'] is None: return 'incomplete neighbor, missing peer-as' return '' def infer(self): if self['md5-ip'] is None: self['md5-ip'] = self['local-address'] if self['capability']['graceful-restart'] == 0: self['capability']['graceful-restart'] = int(self['hold-time']) def id(self): return 'neighbor-%s' % self.uid # This set must be unique between peer, not full draft-ietf-idr-bgp-multisession-07 def index(self): if self['listen'] != 0: return 'peer-ip %s listen %d' % (self['peer-address'], self['listen']) return self.name() def make_rib(self): self.rib = RIB(self.name(), self['adj-rib-in'], self['adj-rib-out'], self._families) # will resend all the routes once we reconnect def reset_rib(self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib(self): self.rib.clear() self.messages = deque() self.refresh = deque() def name(self): if self['capability']['multi-session']: session = '/'.join("%s-%s" % (afi.name(), safi.name()) for (afi, safi) in self.families()) else: session = 'in-open' return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % ( self['peer-address'], self['local-address'] if self['peer-address'] is not None else 'auto', self['local-as'] if self['local-as'] is not None else 'auto', self['peer-as'] if self['peer-as'] is not None else 'auto', self['router-id'], session, ) def families(self): # this list() is important .. as we use the function to modify self._families return list(self._families) def nexthops(self): # this list() is important .. as we use the function to modify self._nexthop return list(self._nexthop) def addpaths(self): # this list() is important .. as we use the function to modify self._add_path return list(self._addpath) def add_family(self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users # this list() is important .. as we use the function to modify self._families if family not in self.families(): afi, safi = family d = dict() d[afi] = [ safi, ] for afi, safi in self._families: d.setdefault(afi, []).append(safi) self._families = [(afi, safi) for afi in sorted(d) for safi in sorted(d[afi])] def add_nexthop(self, afi, safi, nhafi): if (afi, safi, nhafi) not in self._nexthop: self._nexthop.append((afi, safi, nhafi)) def add_addpath(self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users # this list() is important .. as we use the function to modify self._add_path if family not in self.addpaths(): afi, safi = family d = dict() d[afi] = [ safi, ] for afi, safi in self._addpath: d.setdefault(afi, []).append(safi) self._addpath = [(afi, safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family(self, family): if family in self.families(): self._families.remove(family) def remove_nexthop(self, afi, safi, nhafi): if (afi, safi, nhafi) in self.nexthops(): self._nexthop.remove((afi, safi, nhafi)) def remove_addpath(self, family): if family in self.addpaths(): self._addpath.remove(family) def missing(self): if self['local-address'] is None and not self.auto_discovery: return 'local-address' if self['listen'] > 0 and self.auto_discovery: return 'local-address' if self['peer-address'] is None: return 'peer-address' if self.auto_discovery and not self['router-id']: return 'router-id' if self['peer-address'].afi == AFI.ipv6 and not self['router-id']: return 'router-id' return '' # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__(self, other): # Comparing local_address is skipped in the case where either # peer is configured to auto discover its local address. In # this case it can happen that one local_address is None and # the other one will be set to the auto disocvered IP address. auto_discovery = self.auto_discovery or other.auto_discovery return (self['router-id'] == other['router-id'] and self['local-as'] == other['local-as'] and self['peer-address'] == other['peer-address'] and self['peer-as'] == other['peer-as'] and self['passive'] == other['passive'] and self['listen'] == other['listen'] and self['connect'] == other['connect'] and self['hold-time'] == other['hold-time'] and self['rate-limit'] == other['rate-limit'] and self['host-name'] == other['host-name'] and self['domain-name'] == other['domain-name'] and self['md5-password'] == other['md5-password'] and self['md5-ip'] == other['md5-ip'] and self['incoming-ttl'] == other['incoming-ttl'] and self['outgoing-ttl'] == other['outgoing-ttl'] and self['group-updates'] == other['group-updates'] and self['auto-flush'] == other['auto-flush'] and self['adj-rib-in'] == other['adj-rib-in'] and self['adj-rib-out'] == other['adj-rib-out'] and (auto_discovery or self['local-address'] == other['local-address']) and self['capability'] == other['capability'] and self.auto_discovery == other.auto_discovery and self.families() == other.families()) def __ne__(self, other): return not self.__eq__(other) def string(self, with_changes=True): changes = '' if with_changes: changes += '\nstatic { ' for change in self.rib.outgoing.queued_changes(): changes += '\n\t\t%s' % change.extensive() changes += '\n}' families = '' for afi, safi in self.families(): families += '\n\t\t%s %s;' % (afi.name(), safi.name()) nexthops = '' for afi, safi, nexthop in self.nexthops(): nexthops += '\n\t\t%s %s %s;' % (afi.name(), safi.name(), nexthop.name()) addpaths = '' for afi, safi in self.addpaths(): addpaths += '\n\t\t%s %s;' % (afi.name(), safi.name()) codes = Message.CODE _extension_global = { 'neighbor-changes': 'neighbor-changes', 'negotiated': 'negotiated', 'fsm': 'fsm', 'signal': 'signal', } _extension_receive = { 'receive-packets': 'packets', 'receive-parsed': 'parsed', 'receive-consolidate': 'consolidate', 'receive-%s' % codes.NOTIFICATION.SHORT: 'notification', 'receive-%s' % codes.OPEN.SHORT: 'open', 'receive-%s' % codes.KEEPALIVE.SHORT: 'keepalive', 'receive-%s' % codes.UPDATE.SHORT: 'update', 'receive-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh', 'receive-%s' % codes.OPERATIONAL.SHORT: 'operational', } _extension_send = { 'send-packets': 'packets', 'send-parsed': 'parsed', 'send-consolidate': 'consolidate', 'send-%s' % codes.NOTIFICATION.SHORT: 'notification', 'send-%s' % codes.OPEN.SHORT: 'open', 'send-%s' % codes.KEEPALIVE.SHORT: 'keepalive', 'send-%s' % codes.UPDATE.SHORT: 'update', 'send-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh', 'send-%s' % codes.OPERATIONAL.SHORT: 'operational', } apis = '' for process in self.api.get('processes', []): _global = [] _receive = [] _send = [] for api, name in _extension_global.items(): _global.extend([ '\t\t%s;\n' % name, ] if process in self.api[api] else []) for api, name in _extension_receive.items(): _receive.extend([ '\t\t\t%s;\n' % name, ] if process in self.api[api] else []) for api, name in _extension_send.items(): _send.extend([ '\t\t\t%s;\n' % name, ] if process in self.api[api] else []) _api = '\tapi {\n' _api += '\t\tprocesses [ %s ];\n' % process _api += ''.join(_global) if _receive: _api += '\t\treceive {\n' _api += ''.join(_receive) _api += '\t\t}\n' if _send: _api += '\t\tsend {\n' _api += ''.join(_send) _api += '\t\t}\n' _api += '\t}\n' apis += _api returned = ( 'neighbor %s {\n' '\tdescription "%s";\n' '\trouter-id %s;\n' '\thost-name %s;\n' '\tdomain-name %s;\n' '\tlocal-address %s;\n' '\tlocal-as %s;\n' '\tpeer-as %s;\n' '\thold-time %s;\n' '\trate-limit %s;\n' '\tmanual-eor %s;\n' '%s%s%s%s%s%s%s%s%s%s%s\n' '\tcapability {\n' '%s%s%s%s%s%s%s%s%s\t}\n' '\tfamily {%s\n' '\t}\n' '\tnexthop {%s\n' '\t}\n' '\tadd-path {%s\n' '\t}\n' '%s' '%s' '}' % ( self['peer-address'], self['description'], self['router-id'], self['host-name'], self['domain-name'], self['local-address'] if not self.auto_discovery else 'auto', self['local-as'], self['peer-as'], self['hold-time'], 'disable' if self['rate-limit'] == 0 else self['rate-limit'], 'true' if self['manual-eor'] else 'false', '\n\tpassive %s;\n' % ('true' if self['passive'] else 'false'), '\n\tlisten %d;\n' % self['listen'] if self['listen'] else '', '\n\tconnect %d;\n' % self['connect'] if self['connect'] else '', '\tgroup-updates %s;\n' % ('true' if self['group-updates'] else 'false'), '\tauto-flush %s;\n' % ('true' if self['auto-flush'] else 'false'), '\tadj-rib-in %s;\n' % ('true' if self['adj-rib-in'] else 'false'), '\tadj-rib-out %s;\n' % ('true' if self['adj-rib-out'] else 'false'), '\tmd5-password "%s";\n' % self['md5-password'] if self['md5-password'] else '', '\tmd5-base64 %s;\n' % ('true' if self['md5-base64'] is True else 'false' if self['md5-base64'] is False else 'auto'), '\tmd5-ip "%s";\n' % self['md5-ip'] if not self.auto_discovery else '', '\toutgoing-ttl %s;\n' % self['outgoing-ttl'] if self['outgoing-ttl'] else '', '\tincoming-ttl %s;\n' % self['incoming-ttl'] if self['incoming-ttl'] else '', '\t\tasn4 %s;\n' % ('enable' if self['capability']['asn4'] else 'disable'), '\t\troute-refresh %s;\n' % ('enable' if self['capability']['route-refresh'] else 'disable'), '\t\tgraceful-restart %s;\n' % (self['capability']['graceful-restart'] if self['capability']['graceful-restart'] else 'disable'), '\t\tnexthop %s;\n' % ('enable' if self['capability']['nexthop'] else 'disable'), '\t\tadd-path %s;\n' % (AddPath.string[self['capability']['add-path']] if self['capability']['add-path'] else 'disable'), '\t\tmulti-session %s;\n' % ('enable' if self['capability']['multi-session'] else 'disable'), '\t\toperational %s;\n' % ('enable' if self['capability']['operational'] else 'disable'), '\t\taigp %s;\n' % ('enable' if self['capability']['aigp'] else 'disable'), families, nexthops, addpaths, apis, changes, )) # '\t\treceive {\n%s\t\t}\n' % receive if receive else '', # '\t\tsend {\n%s\t\t}\n' % send if send else '', return returned.replace('\t', ' ') def __str__(self): return self.string(False)
class Neighbor (object): def __init__ (self): # self.logger should not be used here as long as we do use deepcopy as it contains a Lock self.description = '' self.router_id = None self.local_address = None self.peer_address = None self.peer_as = None self.local_as = None self.hold_time = HoldTime(180) self.asn4 = None self.add_path = 0 self.md5 = None self.ttl = None self.group_updates = None self.flush = None self.adjribout = None self.api = APIOptions() self.passive = False # capability self.route_refresh = False self.graceful_restart = False self.multisession = None self.add_path = None self.aigp = None self._families = [] self.rib = None self.operational = None self.eor = deque() self.asm = dict() self.messages = deque() self.refresh = deque() def identificator (self): # It is possible to : # - have multiple exabgp toward one peer on the same host ( use of pid ) # - have more than once connection toward a peer # - each connection has it own neihgbor (hence why identificator is not in Protocol) return str(self.peer_address) def make_rib (self): self.rib = RIB(self.name(),self.adjribout,self._families) # will resend all the routes once we reconnect def reset_rib (self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib (self): self.rib.clear() self.messages = deque() self.refresh = deque() def name (self): if self.multisession: session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families()) else: session = 'in-open' 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) def families (self): # this list() is important .. as we use the function to modify self._families return list(self._families) def add_family (self,family): # the families MUST be sorted for neighbor indexing name to be predictable for API users if not family in self.families(): afi,safi = family d = dict() d[afi] = [safi,] for afi,safi in self._families: d.setdefault(afi,[]).append(safi) self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family (self,family): if family in self.families(): self._families.remove(family) def missing (self): if self.local_address is None: return 'local-address' if self.peer_address is None: return 'peer-address' if self.local_as is None: return 'local-as' if self.peer_as is None: return 'peer-as' if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id' return '' # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__ (self,other): return \ self.router_id == other.router_id and \ self.local_address == other.local_address and \ self.local_as == other.local_as and \ self.peer_address == other.peer_address and \ self.peer_as == other.peer_as and \ self.passive == other.passive and \ self.hold_time == other.hold_time and \ self.md5 == other.md5 and \ self.ttl == other.ttl and \ self.route_refresh == other.route_refresh and \ self.graceful_restart == other.graceful_restart and \ self.multisession == other.multisession and \ self.add_path == other.add_path and \ self.operational == other.operational and \ self.group_updates == other.group_updates and \ self.flush == other.flush and \ self.adjribout == other.adjribout and \ self.families() == other.families() def __ne__(self, other): return not self.__eq__(other) def pprint (self,with_changes=True): changes='' if with_changes: changes += '\nstatic { ' for changes in self.rib.incoming.queued_changes(): changes += '\n %s' % changes.extensive() changes += '\n}' families = '' for afi,safi in self.families(): families += '\n %s %s;' % (afi.name(),safi.name()) _receive = [] _receive.extend([' parsed;\n',] if self.api['receive-parsed'] else []) _receive.extend([' packets;\n',] if self.api['receive-packets'] else []) _receive.extend([' consolidate;\n',] if self.api['consolidate'] else []) _receive.extend([' neighbor-changes;\n',] if self.api['neighbor-changes'] else []) _receive.extend([' notification;\n',] if self.api[Message.ID.NOTIFICATION] else []) _receive.extend([' open;\n',] if self.api[Message.ID.OPEN] else []) _receive.extend([' keepalive;\n',] if self.api[Message.ID.KEEPALIVE] else []) _receive.extend([' update;\n',] if self.api[Message.ID.UPDATE] else []) _receive.extend([' refresh;\n',] if self.api[Message.ID.ROUTE_REFRESH] else []) _receive.extend([' operational;\n',] if self.api[Message.ID.OPERATIONAL] else []) _receive.extend([' parsed;\n',] if self.api['receive-parsed'] else []) _receive.extend([' packets;\n',] if self.api['receive-packets'] else []) _receive.extend([' consolidate;\n',] if self.api['consolidate'] else []) receive = ''.join(_receive) _send = [] _send.extend([' packets;\n',] if self.api['send-packets'] else []) send = ''.join(_send) return """\ neighbor %s { description "%s"; router-id %s; local-address %s; local-as %s; peer-as %s;%s hold-time %s; %s%s%s%s%s capability { %s%s%s%s%s%s%s } family {%s } process { %s%s }%s }""" % ( self.peer_address, self.description, self.router_id, self.local_address, self.local_as, self.peer_as, '\n passive;\n' if self.passive else '', self.hold_time, ' group-updates: %s;\n' % (self.group_updates if self.group_updates else ''), ' auto-flush: %s;\n' % ('true' if self.flush else 'false'), ' adj-rib-out: %s;\n' % ('true' if self.adjribout else 'false'), ' md5 "%s";\n' % self.md5 if self.md5 else '', ' ttl-security: %s;\n' % (self.ttl if self.ttl else ''), ' asn4 %s;\n' % ('enable' if self.asn4 else 'disable'), ' route-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'), ' graceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'), ' add-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'), ' multi-session %s;\n' % ('enable' if self.multisession else 'disable'), ' operational %s;\n' % ('enable' if self.operational else 'disable'), ' aigp %s;\n' % ('enable' if self.aigp else 'disable'), families, ' receive {\n%s }\n' % receive if receive else '', ' send {\n%s }\n' % send if send else '', changes ) def __str__ (self): return self.pprint(False)
class Neighbor (object): def __init__ (self): # self.logger should not be used here as long as we do use deepcopy as it contains a Lock self.description = '' self.router_id = None self.local_address = None self.peer_address = None self.peer_as = None self.local_as = None self.hold_time = HoldTime(180) self.asn4 = None self.add_path = 0 self.md5 = None self.ttl = None self.group_updates = None self.flush = None self.adjribout = None self.api = APIOptions() self.passive = False # capability self.route_refresh = False self.graceful_restart = False self.multisession = None self.add_path = None self.aigp = None self._families = [] self.rib = None self.operational = None self.asm = dict() self.messages = deque() self.refresh = deque() def make_rib (self): self.rib = RIB(self.name(),self.adjribout,self._families) # will resend all the routes once we reconnect def reset_rib (self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib (self): self.rib.clear() self.messages = deque() self.refresh = deque() def name (self): if self.multisession: session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families()) else: session = 'in-open' 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) def families (self): # this list() is important .. as we use the function to modify self._families return list(self._families) def add_family (self,family): # the families MUST be sorted for neighbor indexing name to be predictable for API users if not family in self.families(): afi,safi = family d = dict() d[afi] = [safi,] for afi,safi in self._families: d.setdefault(afi,[]).append(safi) self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family (self,family): if family in self.families(): self._families.remove(family) def missing (self): if self.local_address is None: return 'local-address' if self.peer_address is None: return 'peer-address' if self.local_as is None: return 'local-as' if self.peer_as is None: return 'peer-as' if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id' return '' # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__ (self,other): return \ self.router_id == other.router_id and \ self.local_address == other.local_address and \ self.local_as == other.local_as and \ self.peer_address == other.peer_address and \ self.peer_as == other.peer_as and \ self.passive == other.passive and \ self.hold_time == other.hold_time and \ self.md5 == other.md5 and \ self.ttl == other.ttl and \ self.route_refresh == other.route_refresh and \ self.graceful_restart == other.graceful_restart and \ self.multisession == other.multisession and \ self.add_path == other.add_path and \ self.operational == other.operational and \ self.group_updates == other.group_updates and \ self.flush == other.flush and \ self.adjribout == other.adjribout and \ self.families() == other.families() def __ne__(self, other): return not self.__eq__(other) def pprint (self,with_changes=True): changes='' if with_changes: changes += '\nstatic { ' for changes in self.rib.incoming.queued_changes(): changes += '\n %s' % changes.extensive() changes += '\n}' families = '' for afi,safi in self.families(): families += '\n %s %s;' % (afi.name(),safi.name()) _api = [] _api.extend([' neighbor-changes;\n',] if self.api.neighbor_changes else []) _api.extend([' receive-packets;\n',] if self.api.receive_packets else []) _api.extend([' send-packets;\n',] if self.api.send_packets else []) _api.extend([' receive-routes;\n',] if self.api.receive_routes else []) _api.extend([' receive-operational;\n',] if self.api.receive_operational else []) api = ''.join(_api) return """\ neighbor %s { description "%s"; router-id %s; local-address %s; local-as %s; peer-as %s;%s hold-time %s; %s%s%s%s%s capability { %s%s%s%s%s%s%s } family {%s } process { %s }%s }""" % ( self.peer_address, self.description, self.router_id, self.local_address, self.local_as, self.peer_as, '\n passive;\n' if self.passive else '', self.hold_time, ' group-updates: %s;\n' % self.group_updates if self.group_updates else '', ' auto-flush: %s;\n' % 'true' if self.flush else 'false', ' adj-rib-out: %s;\n' % 'true' if self.adjribout else 'false', ' md5: %d;\n' % self.ttl if self.ttl else '', ' ttl-security: %d;\n' % self.ttl if self.ttl else '', ' asn4 enable;\n' if self.asn4 else ' asn4 disable;\n', ' route-refresh;\n' if self.route_refresh else '', ' graceful-restart %s;\n' % self.graceful_restart if self.graceful_restart else '', ' add-path %s;\n' % AddPath.string[self.add_path] if self.add_path else '', ' multi-session;\n' if self.multisession else '', ' operational;\n' if self.operational else '', ' aigp;\n' if self.aigp else '', families, api, changes ) def __str__ (self): return self.pprint(False)
class Neighbor(object): def __init__(self): # self.logger should not be used here as long as we do use deepcopy as it contains a Lock self.description = '' self.router_id = None self.local_address = None self.peer_address = None self.peer_as = None self.local_as = None self.hold_time = HoldTime(180) self.asn4 = None self.add_path = 0 self.md5 = None self.ttl = None self.group_updates = None self.flush = None self.adjribout = None self.api = APIOptions() self.passive = False # capability self.route_refresh = False self.graceful_restart = False self.multisession = None self.add_path = None self.aigp = None self._families = [] self.rib = None self.operational = None self.eor = deque() self.asm = dict() self.messages = deque() self.refresh = deque() def identificator(self): # It is possible to : # - have multiple exabgp toward one peer on the same host ( use of pid ) # - have more than once connection toward a peer # - each connection has it own neihgbor (hence why identificator is not in Protocol) return str(self.peer_address) def make_rib(self): self.rib = RIB(self.name(), self.adjribout, self._families) # will resend all the routes once we reconnect def reset_rib(self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib(self): self.rib.clear() self.messages = deque() self.refresh = deque() def name(self): if self.multisession: session = '/'.join("%s-%s" % (afi.name(), safi.name()) for (afi, safi) in self.families()) else: session = 'in-open' 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) def families(self): # this list() is important .. as we use the function to modify self._families return list(self._families) def add_family(self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users if not family in self.families(): afi, safi = family d = dict() d[afi] = [ safi, ] for afi, safi in self._families: d.setdefault(afi, []).append(safi) self._families = [(afi, safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family(self, family): if family in self.families(): self._families.remove(family) def missing(self): if self.local_address is None: return 'local-address' if self.peer_address is None: return 'peer-address' if self.local_as is None: return 'local-as' if self.peer_as is None: return 'peer-as' if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id' return '' # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__(self, other): return \ self.router_id == other.router_id and \ self.local_address == other.local_address and \ self.local_as == other.local_as and \ self.peer_address == other.peer_address and \ self.peer_as == other.peer_as and \ self.passive == other.passive and \ self.hold_time == other.hold_time and \ self.md5 == other.md5 and \ self.ttl == other.ttl and \ self.route_refresh == other.route_refresh and \ self.graceful_restart == other.graceful_restart and \ self.multisession == other.multisession and \ self.add_path == other.add_path and \ self.operational == other.operational and \ self.group_updates == other.group_updates and \ self.flush == other.flush and \ self.adjribout == other.adjribout and \ self.families() == other.families() def __ne__(self, other): return not self.__eq__(other) def pprint(self, with_changes=True): changes = '' if with_changes: changes += '\nstatic { ' for changes in self.rib.incoming.queued_changes(): changes += '\n %s' % changes.extensive() changes += '\n}' families = '' for afi, safi in self.families(): families += '\n %s %s;' % (afi.name(), safi.name()) _receive = [] _receive.extend([ ' parsed;\n', ] if self.api['receive-parsed'] else []) _receive.extend([ ' packets;\n', ] if self.api['receive-packets'] else []) _receive.extend([ ' consolidate;\n', ] if self.api['consolidate'] else []) _receive.extend([ ' neighbor-changes;\n', ] if self.api['neighbor-changes'] else []) _receive.extend([ ' notification;\n', ] if self.api[Message.ID.NOTIFICATION] else []) _receive.extend([ ' open;\n', ] if self.api[Message.ID.OPEN] else []) _receive.extend([ ' keepalive;\n', ] if self.api[Message.ID.KEEPALIVE] else []) _receive.extend([ ' update;\n', ] if self.api[Message.ID.UPDATE] else []) _receive.extend([ ' refresh;\n', ] if self.api[Message.ID.ROUTE_REFRESH] else []) _receive.extend([ ' operational;\n', ] if self.api[Message.ID.OPERATIONAL] else []) _receive.extend([ ' parsed;\n', ] if self.api['receive-parsed'] else []) _receive.extend([ ' packets;\n', ] if self.api['receive-packets'] else []) _receive.extend([ ' consolidate;\n', ] if self.api['consolidate'] else []) receive = ''.join(_receive) _send = [] _send.extend([ ' packets;\n', ] if self.api['send-packets'] else []) send = ''.join(_send) return """\ neighbor %s { description "%s"; router-id %s; local-address %s; local-as %s; peer-as %s;%s hold-time %s; %s%s%s%s%s capability { %s%s%s%s%s%s%s } family {%s } process { %s%s }%s }""" % (self.peer_address, self.description, self.router_id, self.local_address, self.local_as, self.peer_as, '\n passive;\n' if self.passive else '', self.hold_time, ' group-updates: %s;\n' % (self.group_updates if self.group_updates else ''), ' auto-flush: %s;\n' % ('true' if self.flush else 'false'), ' adj-rib-out: %s;\n' % ('true' if self.adjribout else 'false'), ' md5 "%s";\n' % self.md5 if self.md5 else '', ' ttl-security: %s;\n' % (self.ttl if self.ttl else ''), ' asn4 %s;\n' % ('enable' if self.asn4 else 'disable'), ' route-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'), ' graceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'), ' add-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'), ' multi-session %s;\n' % ('enable' if self.multisession else 'disable'), ' operational %s;\n' % ('enable' if self.operational else 'disable'), ' aigp %s;\n' % ('enable' if self.aigp else 'disable'), families, ' receive {\n%s }\n' % receive if receive else '', ' send {\n%s }\n' % send if send else '', changes) def __str__(self): return self.pprint(False)
class Neighbor (object): _GLOBAL = {'uid': 1} def __init__ (self): # self.logger should not be used here as long as we do use deepcopy as it contains a Lock self.description = None self.router_id = None self.host_name = None self.domain_name = None self.local_address = None self.range_size = 1 # local_address uses auto discovery self.auto_discovery = False self.peer_address = None self.peer_as = None self.local_as = None self.hold_time = None self.asn4 = None self.add_path = None self.md5_password = None self.md5_base64 = False self.md5_ip = None self.ttl_in = None self.ttl_out = None self.group_updates = None self.flush = None self.adj_rib_in = None self.adj_rib_out = None self.manual_eor = False self.api = None # XXX: not scriptable - is replaced outside the class # passive indicate that we do not establish outgoing connections self.passive = False # the port to listen on ( zero mean that we do not listen ) self.listen = 0 # the port to connect to self.connect = 0 # was this Neighbor generated from a range self.generated = False # capability self.route_refresh = False self.graceful_restart = False self.multisession = None self.add_path = None self.aigp = None self._families = [] self._addpaths = [] self.rib = None # The routes we have parsed from the configuration self.changes = [] # On signal update, the previous routes so we can compare what changed self.backup_changes = [] self.operational = None self.eor = deque() self.asm = dict() self.messages = deque() self.refresh = deque() self.counter = Counter() # It is possible to : # - have multiple exabgp toward one peer on the same host ( use of pid ) # - have more than once connection toward a peer # - each connection has it own neihgbor (hence why identificator is not in Protocol) self.uid = '%d' % self._GLOBAL['uid'] self._GLOBAL['uid'] += 1 def id (self): return 'neighbor-%s' % self.uid def make_rib (self): self.rib = RIB(self.name(),self.adj_rib_in,self.adj_rib_out,self._families) # will resend all the routes once we reconnect def reset_rib (self): self.rib.reset() self.messages = deque() self.refresh = deque() # back to square one, all the routes are removed def clear_rib (self): self.rib.clear() self.messages = deque() self.refresh = deque() def name (self): if self.multisession: session = '/'.join("%s-%s" % (afi.name(),safi.name()) for (afi,safi) in self.families()) else: session = 'in-open' return "neighbor %s local-ip %s local-as %s peer-as %s router-id %s family-allowed %s" % ( self.peer_address, self.local_address if self.peer_address is not None else 'auto', self.local_as if self.local_as is not None else 'auto', self.peer_as if self.peer_as is not None else 'auto', self.router_id, session ) def families (self): # this list() is important .. as we use the function to modify self._families return list(self._families) def addpaths (self): # this list() is important .. as we use the function to modify self._families return list(self._addpaths) def add_family (self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users # this list() is important .. as we use the function to modify self._families if family not in self.families(): afi,safi = family d = dict() d[afi] = [safi,] for afi,safi in self._families: d.setdefault(afi,[]).append(safi) self._families = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])] def add_addpath (self, family): # the families MUST be sorted for neighbor indexing name to be predictable for API users # this list() is important .. as we use the function to modify self._families if family not in self.addpaths(): afi,safi = family d = dict() d[afi] = [safi,] for afi,safi in self._addpaths: d.setdefault(afi,[]).append(safi) self._addpaths = [(afi,safi) for afi in sorted(d) for safi in sorted(d[afi])] def remove_family (self, family): if family in self.families(): self._families.remove(family) def remove_addpath (self, family): if family in self.addpaths(): self._addpaths.remove(family) def missing (self): if self.local_address is None and not self.auto_discovery: return 'local-address' if self.listen > 0 and self.auto_discovery: return 'local-address' if self.peer_address is None: return 'peer-address' if self.auto_discovery and not self.router_id: return 'router-id' if self.peer_address.afi == AFI.ipv6 and not self.router_id: return 'router-id' return '' # This function only compares the neighbor BUT NOT ITS ROUTES def __eq__ (self, other): # Comparing local_address is skipped in the case where either # peer is configured to auto discover its local address. In # this case it can happen that one local_address is None and # the other one will be set to the auto disocvered IP address. auto_discovery = self.auto_discovery or other.auto_discovery return \ self.router_id == other.router_id and \ (auto_discovery or self.local_address == other.local_address) and \ self.auto_discovery == other.auto_discovery and \ self.local_as == other.local_as and \ self.peer_address == other.peer_address and \ self.peer_as == other.peer_as and \ self.passive == other.passive and \ self.listen == other.listen and \ self.connect == other.connect and \ self.hold_time == other.hold_time and \ self.host_name == other.host_name and \ self.domain_name == other.domain_name and \ self.md5_password == other.md5_password and \ self.md5_ip == other.md5_ip and \ self.ttl_in == other.ttl_in and \ self.ttl_out == other.ttl_out and \ self.route_refresh == other.route_refresh and \ self.graceful_restart == other.graceful_restart and \ self.multisession == other.multisession and \ self.add_path == other.add_path and \ self.operational == other.operational and \ self.group_updates == other.group_updates and \ self.flush == other.flush and \ self.adj_rib_in == other.adj_rib_in and \ self.adj_rib_out == other.adj_rib_out and \ self.families() == other.families() def __ne__ (self, other): return not self.__eq__(other) def string (self, with_changes=True): changes = '' if with_changes: changes += '\nstatic { ' for changes in self.rib.incoming.queued_changes(): changes += '\n\t\t%s' % changes.extensive() changes += '\n}' families = '' for afi,safi in self.families(): families += '\n\t\t%s %s;' % (afi.name(),safi.name()) addpaths = '' for afi,safi in self.addpaths(): addpaths += '\n\t\t%s %s;' % (afi.name(),safi.name()) codes = Message.CODE _extension_global = { 'neighbor-changes': 'neighbor-changes', 'negotiated': 'negotiated', 'fsm': 'fsm', 'signal': 'signal', } _extension_receive = { 'receive-packets': 'packets', 'receive-parsed': 'parsed', 'receive-consolidate': 'consolidate', 'receive-%s' % codes.NOTIFICATION.SHORT: 'notification', 'receive-%s' % codes.OPEN.SHORT: 'open', 'receive-%s' % codes.KEEPALIVE.SHORT: 'keepalive', 'receive-%s' % codes.UPDATE.SHORT: 'update', 'receive-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh', 'receive-%s' % codes.OPERATIONAL.SHORT: 'operational', } _extension_send = { 'send-packets': 'packets', 'send-parsed': 'parsed', 'send-consolidate': 'consolidate', 'send-%s' % codes.NOTIFICATION.SHORT: 'notification', 'send-%s' % codes.OPEN.SHORT: 'open', 'send-%s' % codes.KEEPALIVE.SHORT: 'keepalive', 'send-%s' % codes.UPDATE.SHORT: 'update', 'send-%s' % codes.ROUTE_REFRESH.SHORT: 'refresh', 'send-%s' % codes.OPERATIONAL.SHORT: 'operational', } apis = '' for process in self.api.get('processes',[]): _global = [] _receive = [] _send = [] for api,name in _extension_global.items(): _global.extend(['\t\t%s;\n' % name,] if process in self.api[api] else []) for api,name in _extension_receive.items(): _receive.extend(['\t\t\t%s;\n' % name,] if process in self.api[api] else []) for api,name in _extension_send.items(): _send.extend(['\t\t\t%s;\n' % name,] if process in self.api[api] else []) _api = '\tapi {\n' _api += '\t\tprocesses [ %s ];\n' % process _api += ''.join(_global) if _receive: _api += '\t\treceive {\n' _api += ''.join(_receive) _api += '\t\t}\n' if _send: _api += '\t\tsend {\n' _api += ''.join(_send) _api += '\t\t}\n' _api += '\t}\n' apis += _api returned = \ 'neighbor %s {\n' \ '\tdescription "%s";\n' \ '\trouter-id %s;\n' \ '\thost-name %s;\n' \ '\tdomain-name %s;\n' \ '\tlocal-address %s;\n' \ '\tlocal-as %s;\n' \ '\tpeer-as %s;\n' \ '\thold-time %s;\n' \ '\tmanual-eor %s;\n' \ '%s%s%s%s%s%s%s%s%s%s%s\n' \ '\tcapability {\n' \ '%s%s%s%s%s%s%s%s\t}\n' \ '\tfamily {%s\n' \ '\t}\n' \ '\tadd-path {%s\n' \ '\t}\n' \ '%s' \ '%s' \ '}' % ( self.peer_address, self.description, self.router_id, self.host_name, self.domain_name, self.local_address if not self.auto_discovery else 'auto', self.local_as, self.peer_as, self.hold_time, 'true' if self.manual_eor else 'false', '\n\tpassive %s;\n' % ('true' if self.passive else 'false'), '\n\tlisten %d;\n' % self.listen if self.listen else '', '\n\tconnect %d;\n' % self.connect if self.connect else '', '\tgroup-updates %s;\n' % ('true' if self.group_updates else 'false'), '\tauto-flush %s;\n' % ('true' if self.flush else 'false'), '\tadj-rib-in %s;\n' % ('true' if self.adj_rib_in else 'false'), '\tadj-rib-out %s;\n' % ('true' if self.adj_rib_out else 'false'), '\tmd5-password "%s";\n' % self.md5_password if self.md5_password else '', '\tmd5-base64 %s;\n' % ('true' if self.md5_base64 is True else 'false' if self.md5_base64 is False else 'auto'), '\tmd5-ip "%s";\n' % self.md5_ip if not self.auto_discovery else '', '\toutgoing-ttl %s;\n' % self.ttl_out if self.ttl_out else '', '\tincoming-ttl %s;\n' % self.ttl_in if self.ttl_in else '', '\t\tasn4 %s;\n' % ('enable' if self.asn4 else 'disable'), '\t\troute-refresh %s;\n' % ('enable' if self.route_refresh else 'disable'), '\t\tgraceful-restart %s;\n' % (self.graceful_restart if self.graceful_restart else 'disable'), '\t\tadd-path %s;\n' % (AddPath.string[self.add_path] if self.add_path else 'disable'), '\t\tmulti-session %s;\n' % ('enable' if self.multisession else 'disable'), '\t\toperational %s;\n' % ('enable' if self.operational else 'disable'), '\t\taigp %s;\n' % ('enable' if self.aigp else 'disable'), families, addpaths, apis, changes ) # '\t\treceive {\n%s\t\t}\n' % receive if receive else '', # '\t\tsend {\n%s\t\t}\n' % send if send else '', return returned.replace('\t',' ') def __str__ (self): return self.string(False)