Esempio n. 1
0
    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.rate_limit = local.get('rate-limit', 0)
        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)

        if neighbor.local_address is None:
            return self.error.set('incomplete neighbor, missing local-address')
        if neighbor.local_as is None:
            return self.error.set('incomplete neighbor, missing local-as')
        if neighbor.peer_as is None:
            return self.error.set('incomplete neighbor, missing peer-as')

        capability = local.get('capability', {})
        neighbor.nexthop = capability.get('nexthop', None)
        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 ' + 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.nexthop is None and nexthop:
            neighbor.nexthop = True

        if neighbor.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():
                        self.logger.debug(
                            'skipping nexthop afi,safi ' + str(afi) + '/' +
                            str(safi) + ' as it is not negotiated',
                            'configuration')
                        continue
                    if (nhafi, safi) not in neighbor.families():
                        self.logger.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.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.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(
                    "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)

        local.clear()
        return True
Esempio n. 2
0
    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