def post(self): for inherit in self.scope.pop('inherit', []): data = self.scope.template('neighbor', inherit) self.scope.inherit(data) local = self.scope.get() neighbor = Neighbor() # XXX: use the right class for the data type # XXX: we can use the scope.nlri interface ( and rename it ) to set some values neighbor.router_id = local.get('router-id', None) neighbor.peer_address = local.get('peer-address', None) neighbor.local_address = local.get('local-address', None) neighbor.local_as = local.get('local-as', None) neighbor.peer_as = local.get('peer-as', None) neighbor.passive = local.get('passive', False) neighbor.listen = local.get('listen', 0) neighbor.connect = local.get('connect', 0) neighbor.hold_time = local.get('hold-time', HoldTime(180)) neighbor.host_name = local.get('host-name', host()) neighbor.domain_name = local.get('domain-name', domain()) neighbor.md5_password = local.get('md5-password', None) neighbor.md5_base64 = local.get('md5-base64', None) neighbor.md5_ip = local.get('md5-ip', neighbor.local_address) neighbor.description = local.get('description', '') neighbor.flush = local.get('auto-flush', True) neighbor.adj_rib_out = local.get('adj-rib-out', True) neighbor.adj_rib_in = local.get('adj-rib-in', True) neighbor.aigp = local.get('aigp', None) neighbor.ttl_out = local.get('outgoing-ttl', None) neighbor.ttl_in = local.get('incoming-ttl', None) neighbor.group_updates = local.get('group-updates', True) neighbor.manual_eor = local.get('manual-eor', False) capability = local.get('capability', {}) neighbor.add_path = capability.get('add-path', 0) neighbor.asn4 = capability.get('asn4', True) neighbor.extended_message = capability.get('extended-message', True) neighbor.multisession = capability.get('multi-session', False) neighbor.operational = capability.get('operational', False) neighbor.route_refresh = capability.get('route-refresh', 0) if capability.get('graceful-restart', False) is not False: neighbor.graceful_restart = capability.get( 'graceful-restart', 0) or int(neighbor.hold_time) neighbor.api = ParseAPI.flatten(local.pop('api', {})) families = [] for family in ParseFamily.convert: for pair in local.get('family', {}).get(family, []): families.append(pair) families = families or NLRI.known_families() for family in families: neighbor.add_family(family) if neighbor.add_path: add_path = local.get('add-path', {}) if add_path: for family in ParseAddPath.convert: for pair in add_path.get(family, []): if pair not in families: self.logger.debug( 'skipping add-path family %s as it is not negotiated' % pair, 'configuration') continue neighbor.add_addpath(pair) else: for family in families: neighbor.add_addpath(family) neighbor.changes = [] neighbor.changes.extend(self.scope.pop_routes()) # old format for section in ('static', 'l2vpn', 'flow'): routes = local.get(section, {}).get('routes', []) for route in routes: route.nlri.action = OUT.ANNOUNCE neighbor.changes.extend(routes) routes = local.get('routes', []) for route in routes: route.nlri.action = OUT.ANNOUNCE neighbor.changes.extend(routes) messages = local.get('operational', {}).get('routes', []) if neighbor.local_address is None: neighbor.auto_discovery = True neighbor.local_address = None neighbor.md5_ip = None if not neighbor.router_id and neighbor.peer_address.afi == AFI.ipv4 and not neighbor.auto_discovery: neighbor.router_id = neighbor.local_address if neighbor.route_refresh: if neighbor.adj_rib_out: self.logger.debug( 'route-refresh requested, enabling adj-rib-out', 'configuration') missing = neighbor.missing() if missing: return self.error.set('incomplete neighbor, missing %s' % missing) if not neighbor.auto_discovery and neighbor.local_address.afi != neighbor.peer_address.afi: return self.error.set( 'local-address and peer-address must be of the same family') neighbor.range_size = neighbor.peer_address.mask.size() if neighbor.range_size > 1 and not neighbor.passive: return self.error.set( 'can only use ip ranges for the peer address with passive neighbors' ) if neighbor.peer_address.top() in self._neighbors: return self.error.set('duplicate peer definition %s' % neighbor.peer_address.top()) self._neighbors.append(neighbor.peer_address.top()) if neighbor.md5_password: try: md5 = base64.b64decode( neighbor.md5_password ) if neighbor.md5_base64 else neighbor.md5_password except TypeError as e: return self.error.set( "Invalid base64 encoding of MD5 password.") else: if len(md5) > 80: return self.error.set( 'MD5 password must be no larger than 80 characters') # check we are not trying to announce routes without the right MP announcement for change in neighbor.changes: family = change.nlri.family() if family not in families and family != (AFI.ipv4, SAFI.unicast): return self.error.set( 'Trying to announce a route of type %s,%s when we are not announcing the family to our peer' % change.nlri.family()) def _init_neighbor(neighbor): families = neighbor.families() for change in neighbor.changes: if change.nlri.family() in families: # This add the family to neighbor.families() neighbor.rib.outgoing.add_to_rib_watchdog(change) for message in messages: if message.family() in families: if message.name == 'ASM': neighbor.asm[message.family()] = message else: neighbor.messages.append(message) self.neighbors[neighbor.name()] = neighbor # create one neighbor object per family for multisession if neighbor.multisession and len(neighbor.families()) > 1: for family in neighbor.families(): # XXX: FIXME: Ok, it works but it takes LOTS of memory .. m_neighbor = deepcopy(neighbor) m_neighbor.make_rib() m_neighbor.rib.outgoing.families = [family] _init_neighbor(m_neighbor) else: neighbor.make_rib() _init_neighbor(neighbor) return True
def post (self): local = self.scope.pop_context(self.name) neighbor = Neighbor() # XXX: use the right class for the data type # XXX: we can use the scope.nlri interface ( and rename it ) to set some values neighbor.router_id = local.get('router-id',None) neighbor.peer_address = local.get('peer-address',None) neighbor.local_address = local.get('local-address',None) neighbor.local_as = local.get('local-as',None) neighbor.peer_as = local.get('peer-as',None) neighbor.passive = local.get('passive',False) neighbor.listen = local.get('listen',0) neighbor.hold_time = local.get('hold-time',HoldTime(180)) neighbor.host_name = local.get('host-name',_hostname()) neighbor.domain_name = local.get('domain-name',_domainname()) neighbor.md5 = local.get('md5',None) neighbor.description = local.get('description','') neighbor.flush = local.get('auto-flush',True) neighbor.adjribout = local.get('adj-rib-out',True) neighbor.aigp = local.get('aigp',None) neighbor.ttl = local.get('ttl-security',None) neighbor.group_updates = local.get('group-updates',True) neighbor.manual_eor = local.get('manual-eor', False) neighbor.api = ParseAPI.extract() # capabilities capability = local.get('capability',{}) neighbor.graceful_restart = capability.get('graceful-restart',0) or int(neighbor.hold_time) neighbor.add_path = capability.get('add-path',0) neighbor.asn4 = capability.get('asn4',True) neighbor.multisession = capability.get('multi-session',False) neighbor.operational = capability.get('operational',False) neighbor.route_refresh = capability.get('route-refresh',0) families = [] for family in ParseFamily.convert.keys(): for pair in local.get('family',{}).get(family,[]): families.append(pair) families = families or NLRI.known_families() if (AFI.ipv4,SAFI.unicast) not in families: families.append((AFI(AFI.ipv4),SAFI(SAFI.unicast))) for family in families: neighbor.add_family(family) neighbor.changes = [] for section in ('static','l2vpn','flow'): routes = local.get(section,{}).get('routes',[]) for route in routes: route.nlri.action = OUT.ANNOUNCE neighbor.changes.extend(routes) messages = local.get('operational',{}).get('routes',[]) if not neighbor.router_id: neighbor.router_id = neighbor.local_address if neighbor.graceful_restart is None: neighbor.graceful_restart = int(neighbor.hold_time) if neighbor.route_refresh: if neighbor.adjribout: self.logger.configuration('route-refresh requested, enabling adj-rib-out') missing = neighbor.missing() if missing: return self.error.set('incomplete neighbor, missing %s' % missing) if neighbor.local_address.afi != neighbor.peer_address.afi: return self.error.set('local-address and peer-address must be of the same family') if neighbor.peer_address.top() in self._neighbors: return self.error.set('duplicate peer definition %s' % neighbor.peer_address.top()) self._neighbors.append(neighbor.peer_address.top()) # check we are not trying to announce routes without the right MP announcement for change in neighbor.changes: family = change.nlri.family() if family not in families and family != (AFI.ipv4,SAFI.unicast): return self.error.set('Trying to announce a route of type %s,%s when we are not announcing the family to our peer' % change.nlri.family()) def _init_neighbor (neighbor): families = neighbor.families() for change in neighbor.changes: if change.nlri.family() in families: # This add the family to neighbor.families() neighbor.rib.outgoing.insert_announced_watchdog(change) for message in messages: if message.family() in families: if message.name == 'ASM': neighbor.asm[message.family()] = message else: neighbor.messages.append(message) self.neighbors[neighbor.name()] = neighbor # create one neighbor object per family for multisession if neighbor.multisession and len(neighbor.families()) > 1: for family in neighbor.families(): # XXX: FIXME: Ok, it works but it takes LOTS of memory .. m_neighbor = deepcopy(neighbor) m_neighbor.make_rib() m_neighbor.rib.outgoing.families = [family] _init_neighbor(m_neighbor) else: neighbor.make_rib() _init_neighbor(neighbor) return True
def post(self): local = self.scope.pop_context(self.name) neighbor = Neighbor() # XXX: use the right class for the data type # XXX: we can use the scope.nlri interface ( and rename it ) to set some values neighbor.router_id = local.get('router-id', None) neighbor.peer_address = local.get('peer-address', None) neighbor.local_address = local.get('local-address', None) neighbor.local_as = local.get('local-as', None) neighbor.peer_as = local.get('peer-as', None) neighbor.passive = local.get('passive', False) neighbor.listen = local.get('listen', 0) neighbor.hold_time = local.get('hold-time', HoldTime(180)) neighbor.host_name = local.get('host-name', _hostname()) neighbor.domain_name = local.get('domain-name', _domainname()) neighbor.md5 = local.get('md5', None) neighbor.description = local.get('description', '') neighbor.flush = local.get('auto-flush', True) neighbor.adjribout = local.get('adj-rib-out', True) neighbor.aigp = local.get('aigp', None) neighbor.ttl = local.get('ttl-security', None) neighbor.group_updates = local.get('group-updates', True) neighbor.manual_eor = local.get('manual-eor', False) neighbor.api = ParseAPI.extract() # capabilities capability = local.get('capability', {}) neighbor.add_path = capability.get('add-path', 0) neighbor.asn4 = capability.get('asn4', True) neighbor.multisession = capability.get('multi-session', False) neighbor.operational = capability.get('operational', False) neighbor.route_refresh = capability.get('route-refresh', 0) if capability.get('graceful-restart', False) is not False: neighbor.graceful_restart = capability.get( 'graceful-restart', 0) or int(neighbor.hold_time) families = [] for family in ParseFamily.convert.keys(): for pair in local.get('family', {}).get(family, []): families.append(pair) families = families or NLRI.known_families() if (AFI.ipv4, SAFI.unicast) not in families: families.append((AFI(AFI.ipv4), SAFI(SAFI.unicast))) for family in families: neighbor.add_family(family) neighbor.changes = [] for section in ('static', 'l2vpn', 'flow'): routes = local.get(section, {}).get('routes', []) for route in routes: route.nlri.action = OUT.ANNOUNCE neighbor.changes.extend(routes) messages = local.get('operational', {}).get('routes', []) if not neighbor.router_id: neighbor.router_id = neighbor.local_address if neighbor.route_refresh: if neighbor.adjribout: self.logger.configuration( 'route-refresh requested, enabling adj-rib-out') missing = neighbor.missing() if missing: return self.error.set('incomplete neighbor, missing %s' % missing) if neighbor.local_address.afi != neighbor.peer_address.afi: return self.error.set( 'local-address and peer-address must be of the same family') if neighbor.peer_address.top() in self._neighbors: return self.error.set('duplicate peer definition %s' % neighbor.peer_address.top()) self._neighbors.append(neighbor.peer_address.top()) # check we are not trying to announce routes without the right MP announcement for change in neighbor.changes: family = change.nlri.family() if family not in families and family != (AFI.ipv4, SAFI.unicast): return self.error.set( 'Trying to announce a route of type %s,%s when we are not announcing the family to our peer' % change.nlri.family()) def _init_neighbor(neighbor): families = neighbor.families() for change in neighbor.changes: if change.nlri.family() in families: # This add the family to neighbor.families() neighbor.rib.outgoing.insert_announced_watchdog(change) for message in messages: if message.family() in families: if message.name == 'ASM': neighbor.asm[message.family()] = message else: neighbor.messages.append(message) self.neighbors[neighbor.name()] = neighbor # create one neighbor object per family for multisession if neighbor.multisession and len(neighbor.families()) > 1: for family in neighbor.families(): # XXX: FIXME: Ok, it works but it takes LOTS of memory .. m_neighbor = deepcopy(neighbor) m_neighbor.make_rib() m_neighbor.rib.outgoing.families = [family] _init_neighbor(m_neighbor) else: neighbor.make_rib() _init_neighbor(neighbor) return True
def post (self): for inherit in self.scope.pop('inherit',[]): data = self.scope.template('neighbor',inherit) self.scope.inherit(data) local = self.scope.get() neighbor = Neighbor() # XXX: use the right class for the data type # XXX: we can use the scope.nlri interface ( and rename it ) to set some values neighbor.router_id = local.get('router-id',None) neighbor.peer_address = local.get('peer-address',None) neighbor.local_address = local.get('local-address',None) neighbor.local_as = local.get('local-as',None) neighbor.peer_as = local.get('peer-as',None) neighbor.passive = local.get('passive',False) neighbor.listen = local.get('listen',0) neighbor.connect = local.get('connect',0) neighbor.hold_time = local.get('hold-time',HoldTime(180)) neighbor.host_name = local.get('host-name',host()) neighbor.domain_name = local.get('domain-name',domain()) neighbor.md5_password = local.get('md5-password',None) neighbor.md5_base64 = local.get('md5-base64', None) neighbor.md5_ip = local.get('md5-ip',neighbor.local_address) neighbor.description = local.get('description','') neighbor.flush = local.get('auto-flush',True) neighbor.adj_rib_out = local.get('adj-rib-out',True) neighbor.adj_rib_in = local.get('adj-rib-in',True) neighbor.aigp = local.get('aigp',None) neighbor.ttl_out = local.get('outgoing-ttl',None) neighbor.ttl_in = local.get('incoming-ttl',None) neighbor.group_updates = local.get('group-updates',True) neighbor.manual_eor = local.get('manual-eor', False) capability = local.get('capability',{}) neighbor.add_path = capability.get('add-path',0) neighbor.asn4 = capability.get('asn4',True) neighbor.extended_message = capability.get('extended-message',True) neighbor.multisession = capability.get('multi-session',False) neighbor.operational = capability.get('operational',False) neighbor.route_refresh = capability.get('route-refresh',0) if capability.get('graceful-restart',False) is not False: neighbor.graceful_restart = capability.get('graceful-restart',0) or int(neighbor.hold_time) neighbor.api = ParseAPI.flatten(local.pop('api',{})) families = [] for family in ParseFamily.convert: for pair in local.get('family',{}).get(family,[]): families.append(pair) families = families or NLRI.known_families() for family in families: neighbor.add_family(family) if neighbor.add_path: add_path = local.get('add-path',{}) if add_path: for family in ParseAddPath.convert: for pair in add_path.get(family,[]): if pair not in families: self.logger.debug('skipping add-path family %s as it is not negotiated' % pair,'configuration') continue neighbor.add_addpath(pair) else: for family in families: neighbor.add_addpath(family) neighbor.changes = [] neighbor.changes.extend(self.scope.pop_routes()) # old format for section in ('static','l2vpn','flow'): routes = local.get(section,{}).get('routes',[]) for route in routes: route.nlri.action = OUT.ANNOUNCE neighbor.changes.extend(routes) routes = local.get('routes',[]) for route in routes: route.nlri.action = OUT.ANNOUNCE neighbor.changes.extend(routes) messages = local.get('operational',{}).get('routes',[]) if neighbor.local_address is None: neighbor.auto_discovery = True neighbor.local_address = None neighbor.md5_ip = None if not neighbor.router_id: if neighbor.peer_address.afi == AFI.ipv4 and not neighbor.auto_discovery: neighbor.router_id = neighbor.local_address else: return self.error.set('missing router-id for the peer, it can not be set using the local-ip') if neighbor.route_refresh: if neighbor.adj_rib_out: self.logger.debug('route-refresh requested, enabling adj-rib-out','configuration') missing = neighbor.missing() if missing: return self.error.set('incomplete neighbor, missing %s' % missing) if not neighbor.auto_discovery and neighbor.local_address.afi != neighbor.peer_address.afi: return self.error.set('local-address and peer-address must be of the same family') neighbor.range_size = neighbor.peer_address.mask.size() if neighbor.range_size > 1 and not neighbor.passive: return self.error.set('can only use ip ranges for the peer address with passive neighbors') if neighbor.peer_address.top() in self._neighbors: return self.error.set('duplicate peer definition %s' % neighbor.peer_address.top()) self._neighbors.append(neighbor.peer_address.top()) if neighbor.md5_password: try: md5 = base64.b64decode(neighbor.md5_password) if neighbor.md5_base64 else neighbor.md5_password except TypeError as e: return self.error.set("Invalid base64 encoding of MD5 password.") else: if len(md5) > 80: return self.error.set('MD5 password must be no larger than 80 characters') # check we are not trying to announce routes without the right MP announcement for change in neighbor.changes: family = change.nlri.family() if family not in families and family != (AFI.ipv4,SAFI.unicast): return self.error.set('Trying to announce a route of type %s,%s when we are not announcing the family to our peer' % change.nlri.family()) def _init_neighbor (neighbor): families = neighbor.families() for change in neighbor.changes: if change.nlri.family() in families: # This add the family to neighbor.families() neighbor.rib.outgoing.add_to_rib_watchdog(change) for message in messages: if message.family() in families: if message.name == 'ASM': neighbor.asm[message.family()] = message else: neighbor.messages.append(message) self.neighbors[neighbor.name()] = neighbor # create one neighbor object per family for multisession if neighbor.multisession and len(neighbor.families()) > 1: for family in neighbor.families(): # XXX: FIXME: Ok, it works but it takes LOTS of memory .. m_neighbor = deepcopy(neighbor) m_neighbor.make_rib() m_neighbor.rib.outgoing.families = [family] _init_neighbor(m_neighbor) else: neighbor.make_rib() _init_neighbor(neighbor) return True
def _make_neighbor (self, scope): # we have local_scope[-2] as the group template and local_scope[-1] as the peer specific if len(scope) > 1: for key,content in scope[-2].iteritems(): if key not in scope[-1]: scope[-1][key] = deepcopy(content) elif key == 'announce': scope[-1][key].extend(scope[-2][key]) neighbor = Neighbor() for local_scope in scope: value = local_scope.get('router-id','') if value: neighbor.router_id = value value = local_scope.get('peer-address','') if value: neighbor.peer_address = value value = local_scope.get('local-address','') if value: neighbor.local_address = value value = local_scope.get('local-as','') if value: neighbor.local_as = value value = local_scope.get('peer-as','') if value: neighbor.peer_as = value value = local_scope.get('passive',False) if value: neighbor.passive = value value = local_scope.get('listen',0) if value: neighbor.listen = value value = local_scope.get('hold-time','') if value: neighbor.hold_time = value neighbor.host_name = local_scope.get('host-name',hostname()) neighbor.domain_name = local_scope.get('domain-name',domainname()) neighbor.changes = local_scope.get('announce',[]) messages = local_scope.get('operational-message',[]) # we want to have a socket for the cli if self.fifo: _cli_name = 'CLI' self.processes[_cli_name] = { 'neighbor': '*', 'encoder': 'json', 'run': [sys.executable, sys.argv[0]], 'neighbor-changes': False, 'receive-consolidate': False, 'receive-packets': False, 'receive-parsed': False, 'send-consolidate': False, 'send-packets': False, 'send-parsed': False, } for direction in ['send','receive']: for message in [ Message.CODE.NOTIFICATION, Message.CODE.OPEN, Message.CODE.KEEPALIVE, Message.CODE.UPDATE, Message.CODE.ROUTE_REFRESH, Message.CODE.OPERATIONAL ]: self.processes[_cli_name]['%s-%d' % (direction,message)] = False for name in self.processes.keys(): process = self.processes[name] neighbor.api.set('neighbor-changes',process.get('neighbor-changes',False)) for direction in ['send','receive']: for option in ['packets','consolidate','parsed']: neighbor.api.set_value(direction,option,process.get('%s-%s' % (direction,option),False)) for message in [ Message.CODE.NOTIFICATION, Message.CODE.OPEN, Message.CODE.KEEPALIVE, Message.CODE.UPDATE, Message.CODE.ROUTE_REFRESH, Message.CODE.OPERATIONAL ]: neighbor.api.set_message(direction,message,process.get('%s-%d' % (direction,message),False)) if not neighbor.router_id: neighbor.router_id = neighbor.local_address local_scope = scope[-1] neighbor.description = local_scope.get('description','') neighbor.md5 = local_scope.get('md5',None) neighbor.ttl = local_scope.get('ttl-security',None) neighbor.group_updates = local_scope.get('group-updates',None) neighbor.route_refresh = local_scope.get('route-refresh',0) neighbor.graceful_restart = local_scope.get('graceful-restart',0) if neighbor.graceful_restart is None: # README: Should it be a subclass of int ? neighbor.graceful_restart = int(neighbor.hold_time) neighbor.multisession = local_scope.get('multi-session',False) neighbor.operational = local_scope.get('capa-operational',False) neighbor.add_path = local_scope.get('add-path',0) neighbor.flush = local_scope.get('auto-flush',True) neighbor.adjribout = local_scope.get('adj-rib-out',True) neighbor.asn4 = local_scope.get('asn4',True) neighbor.aigp = local_scope.get('aigp',None) if neighbor.route_refresh and not neighbor.adjribout: return self.error.set('incomplete option route-refresh and no adj-rib-out') # XXX: check that if we have any message, we have parsed/packets # XXX: and vice-versa missing = neighbor.missing() if missing: return self.error.set('incomplete neighbor, missing %s' % missing) if neighbor.local_address.afi != neighbor.peer_address.afi: return self.error.set('local-address and peer-address must be of the same family') if neighbor.peer_address.ip in self._neighbors: return self.error.set('duplicate peer definition %s' % neighbor.peer_address.ip) openfamilies = local_scope.get('families','everything') # announce every family we known if neighbor.multisession and openfamilies == 'everything': # announce what is needed, and no more, no need to have lots of TCP session doing nothing _families = set() for change in neighbor.changes: _families.add((change.nlri.afi,change.nlri.safi)) families = list(_families) elif openfamilies in ('all','everything'): families = NLRI.known_families() # only announce what you have as routes elif openfamilies == 'minimal': _families = set() for change in neighbor.changes: _families.add((change.nlri.afi,change.nlri.safi)) families = list(_families) else: families = openfamilies # check we are not trying to announce routes without the right MP announcement for family in neighbor.families(): if family not in families: afi,safi = family return self.error.set('Trying to announce a route of type %s,%s when we are not announcing the family to our peer' % (afi,safi)) # add the families to the list of families known initial_families = list(neighbor.families()) for family in families: if family not in initial_families : # we are modifying the data used by .families() here neighbor.add_family(family) if neighbor.group_updates is None: neighbor.group_updates = True def _init_neighbor (neighbor): families = neighbor.families() for change in neighbor.changes: if change.nlri.family() in families: # This add the family to neighbor.families() neighbor.rib.outgoing.insert_announced_watchdog(change) for message in messages: if message.family() in families: if message.name == 'ASM': neighbor.asm[message.family()] = message else: neighbor.messages.append(message) self._neighbors[neighbor.name()] = neighbor # create one neighbor object per family for multisession if neighbor.multisession and len(neighbor.families()) > 1: for family in neighbor.families(): # XXX: FIXME: Ok, it works but it takes LOTS of memory .. m_neighbor = deepcopy(neighbor) m_neighbor.make_rib() m_neighbor.rib.outgoing.families = [family] _init_neighbor(m_neighbor) else: neighbor.make_rib() _init_neighbor(neighbor) # display configuration for line in str(neighbor).split('\n'): self.logger.configuration(line) self.logger.configuration("\n") # ... scope.pop(-1) return True
def post(self): for inherited in self.scope.pop('inherit', []): data = self.scope.template('neighbor', inherited) self.scope.inherit(data) local = self.scope.get() neighbor = Neighbor() for option in neighbor.defaults: conf = local.get(option, None) if conf is not None: neighbor[option] = conf # XXX: use the right class for the data type # XXX: we can use the scope.nlri interface ( and rename it ) to set some values capability = local.get('capability', {}) for option in neighbor.Capability.defaults: conf = capability.get(option, None) if conf is not None: neighbor['capability'][option] = conf neighbor.api = ParseAPI.flatten(local.pop('api', {})) missing = neighbor.missing() if missing: return self.error.set(missing) neighbor.infer() families = [] for family in ParseFamily.convert: for pair in local.get('family', {}).get(family, []): families.append(pair) families = families or NLRI.known_families() for family in families: neighbor.add_family(family) if neighbor['capability']['add-path']: add_path = local.get('add-path', {}) if add_path: for family in ParseAddPath.convert: for pair in add_path.get(family, []): if pair not in families: log.debug( 'skipping add-path family ' + str(pair) + ' as it is not negotiated', 'configuration') continue neighbor.add_addpath(pair) else: for family in families: neighbor.add_addpath(family) # The default is to auto-detect by the presence of the nexthop block # if this is manually set, then we honor it nexthop = local.get('nexthop', {}) if neighbor['capability']['nexthop'] is None and nexthop: neighbor['capability']['nexthop'] = True if neighbor['capability']['nexthop']: nexthops = [] for family in nexthop: nexthops.extend(nexthop[family]) if nexthops: for afi, safi, nhafi in nexthops: if (afi, safi) not in neighbor.families(): log.debug( 'skipping nexthop afi,safi ' + str(afi) + '/' + str(safi) + ' as it is not negotiated', 'configuration', ) continue if (nhafi, safi) not in neighbor.families(): log.debug( 'skipping nexthop afi ' + str(nhafi) + '/' + str(safi) + ' as it is not negotiated', 'configuration', ) continue neighbor.add_nexthop(afi, safi, nhafi) neighbor.changes = [] neighbor.changes.extend(self.scope.pop_routes()) # old format for section in ('static', 'l2vpn', 'flow'): routes = local.get(section, {}).get('routes', []) for route in routes: route.nlri.action = OUT.ANNOUNCE neighbor.changes.extend(routes) routes = local.get('routes', []) for route in routes: route.nlri.action = OUT.ANNOUNCE neighbor.changes.extend(routes) messages = local.get('operational', {}).get('routes', []) if neighbor['local-address'] is None: neighbor.auto_discovery = True neighbor['local-address'] = None neighbor['md5-ip'] = None if not neighbor['router-id']: if neighbor[ 'peer-address'].afi == AFI.ipv4 and not neighbor.auto_discovery: neighbor['router-id'] = neighbor['local-address'] else: return self.error.set( 'missing router-id for the peer, it can not be set using the local-ip' ) if neighbor['capability']['route-refresh']: if neighbor['adj-rib-out']: log.debug('route-refresh requested, enabling adj-rib-out', 'configuration') missing = neighbor.missing() if missing: return self.error.set('incomplete neighbor, missing %s' % missing) if not neighbor.auto_discovery and neighbor[ 'local-address'].afi != neighbor['peer-address'].afi: return self.error.set( 'local-address and peer-address must be of the same family') neighbor.range_size = neighbor['peer-address'].mask.size() if neighbor.range_size > 1 and not (neighbor['passive'] or getenv().bgp.passive): return self.error.set( 'can only use ip ranges for the peer address with passive neighbors' ) if neighbor.index() in self._neighbors: return self.error.set('duplicate peer definition %s' % neighbor['peer-address'].top()) self._neighbors.append(neighbor.index()) if neighbor['md5-password']: try: md5 = base64.b64decode( neighbor['md5-password'] ) if neighbor['md5-base64'] else neighbor['md5-password'] except TypeError as e: return self.error.set( f"Invalid base64 encoding of MD5 password ({e})") else: if len(md5) > 80: return self.error.set( 'MD5 password must be no larger than 80 characters') # check we are not trying to announce routes without the right MP announcement for change in neighbor.changes: family = change.nlri.family() if family not in families and family != (AFI.ipv4, SAFI.unicast): return self.error.set( 'Trying to announce a route of type %s,%s when we are not announcing the family to our peer' % change.nlri.family()) def _init_neighbor(neighbor): families = neighbor.families() for change in neighbor.changes: if change.nlri.family() in families: # This add the family to neighbor.families() neighbor.rib.outgoing.add_to_rib_watchdog(change) for message in messages: if message.family() in families: if message.name == 'ASM': neighbor.asm[message.family()] = message else: neighbor.messages.append(message) self.neighbors[neighbor.name()] = neighbor # create one neighbor object per family for multisession if neighbor['capability']['multi-session'] and len( neighbor.families()) > 1: for family in neighbor.families(): # XXX: FIXME: Ok, it works but it takes LOTS of memory .. m_neighbor = deepcopy(neighbor) m_neighbor.make_rib() m_neighbor.rib.outgoing.families = [family] _init_neighbor(m_neighbor) else: neighbor.make_rib() _init_neighbor(neighbor) local.clear() return True
def make(self, scope, configuration): # we have local_scope[-2] as the group template and local_scope[-1] as the peer specific if len(scope) > 1: for key, content in scope[-2].iteritems(): if key not in scope[-1]: scope[-1][key] = deepcopy(content) elif key == 'announce': scope[-1][key].extend(scope[-2][key]) neighbor = Neighbor() for local_scope in scope: value = local_scope.get('router-id', '') if value: neighbor.router_id = value value = local_scope.get('peer-address', '') if value: neighbor.peer_address = value value = local_scope.get('local-address', '') if value: neighbor.local_address = value value = local_scope.get('local-as', '') if value: neighbor.local_as = value value = local_scope.get('peer-as', '') if value: neighbor.peer_as = value value = local_scope.get('passive', False) if value: neighbor.passive = value value = local_scope.get('listen', 0) if value: neighbor.listen = value value = local_scope.get('hold-time', '') if value: neighbor.hold_time = value neighbor.host_name = local_scope.get('host-name', hostname()) neighbor.domain_name = local_scope.get('domain-name', domainname()) neighbor.changes = local_scope.get('announce', []) messages = local_scope.get('operational-message', []) # we want to have a socket for the cli if self.fifo: _cli_name = 'CLI' configuration.processes[_cli_name] = { 'neighbor': '*', 'encoder': 'json', 'run': [sys.executable, sys.argv[0]], 'neighbor-changes': False, 'receive-consolidate': False, 'receive-packets': False, 'receive-parsed': False, 'send-consolidate': False, 'send-packets': False, 'send-parsed': False, } for direction in ['send', 'receive']: for message in [ Message.CODE.NOTIFICATION, Message.CODE.OPEN, Message.CODE.KEEPALIVE, Message.CODE.UPDATE, Message.CODE.ROUTE_REFRESH, Message.CODE.OPERATIONAL ]: configuration.processes[_cli_name]['%s-%d' % (direction, message)] = False for name in configuration.processes.keys(): process = configuration.processes[name] neighbor.api.set('neighbor-changes', process.get('neighbor-changes', False)) for direction in ['send', 'receive']: for option in ['packets', 'consolidate', 'parsed']: neighbor.api.set_value( direction, option, process.get('%s-%s' % (direction, option), False)) for message in [ Message.CODE.NOTIFICATION, Message.CODE.OPEN, Message.CODE.KEEPALIVE, Message.CODE.UPDATE, Message.CODE.ROUTE_REFRESH, Message.CODE.OPERATIONAL ]: neighbor.api.set_message( direction, message, process.get('%s-%d' % (direction, message), False)) if not neighbor.router_id: neighbor.router_id = neighbor.local_address local_scope = scope[-1] neighbor.description = local_scope.get('description', '') neighbor.md5 = local_scope.get('md5', None) neighbor.ttl = local_scope.get('ttl-security', None) neighbor.group_updates = local_scope.get('group-updates', None) neighbor.route_refresh = local_scope.get('route-refresh', 0) neighbor.graceful_restart = local_scope.get('graceful-restart', 0) if neighbor.graceful_restart is None: # README: Should it be a subclass of int ? neighbor.graceful_restart = int(neighbor.hold_time) neighbor.multisession = local_scope.get('multi-session', False) neighbor.operational = local_scope.get('operational', False) neighbor.add_path = local_scope.get('add-path', 0) neighbor.flush = local_scope.get('auto-flush', True) neighbor.adjribout = local_scope.get('adj-rib-out', True) neighbor.asn4 = local_scope.get('asn4', True) neighbor.aigp = local_scope.get('aigp', None) if neighbor.route_refresh and not neighbor.adjribout: return self.error.set( 'incomplete option route-refresh and no adj-rib-out') # XXX: check that if we have any message, we have parsed/packets # XXX: and vice-versa missing = neighbor.missing() if missing: return self.error.set('incomplete neighbor, missing %s' % missing) if neighbor.local_address.afi != neighbor.peer_address.afi: return self.error.set( 'local-address and peer-address must be of the same family') if neighbor.peer_address.ip in self._neighbors: return self.error.set('duplicate peer definition %s' % neighbor.peer_address.ip) openfamilies = local_scope.get('families', 'everything') # announce every family we known if neighbor.multisession and openfamilies == 'everything': # announce what is needed, and no more, no need to have lots of TCP session doing nothing _families = set() for change in neighbor.changes: _families.add((change.nlri.afi, change.nlri.safi)) families = list(_families) elif openfamilies in ('all', 'everything'): families = NLRI.known_families() # only announce what you have as routes elif openfamilies == 'minimal': _families = set() for change in neighbor.changes: _families.add((change.nlri.afi, change.nlri.safi)) families = list(_families) else: families = openfamilies # check we are not trying to announce routes without the right MP announcement for family in neighbor.families(): if family not in families: afi, safi = family return self.error.set( 'Trying to announce a route of type %s,%s when we are not announcing the family to our peer' % (afi, safi)) # add the families to the list of families known initial_families = list(neighbor.families()) for family in families: if family not in initial_families: # we are modifying the data used by .families() here neighbor.add_family(family) if neighbor.group_updates is None: neighbor.group_updates = True def _init_neighbor(neighbor): families = neighbor.families() for change in neighbor.changes: if change.nlri.family() in families: # This add the family to neighbor.families() neighbor.rib.outgoing.insert_announced_watchdog(change) for message in messages: if message.family() in families: if message.name == 'ASM': neighbor.asm[message.family()] = message else: neighbor.messages.append(message) self._neighbors[neighbor.name()] = neighbor # create one neighbor object per family for multisession if neighbor.multisession and len(neighbor.families()) > 1: for family in neighbor.families(): # XXX: FIXME: Ok, it works but it takes LOTS of memory .. m_neighbor = deepcopy(neighbor) m_neighbor.make_rib() m_neighbor.rib.outgoing.families = [family] _init_neighbor(m_neighbor) else: neighbor.make_rib() _init_neighbor(neighbor) # display configuration for line in str(neighbor).split('\n'): self.logger.configuration(line) self.logger.configuration("\n") # ... scope.pop(-1) return True