Exemple #1
0
	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
Exemple #2
0
    def __init__(self, configurations, text=False):
        _Configuration.__init__(self)
        self.api_encoder = environment.settings().api.encoder

        self._configurations = configurations
        self._text = text

        self.error = Error()
        self.scope = Scope()

        self.tokeniser = Tokeniser(self.scope, self.error, self.logger)

        params = (self.tokeniser, self.scope, self.error, self.logger)
        self.section = Section(*params)
        self.process = ParseProcess(*params)
        self.template = ParseTemplate(*params)
        self.template_neighbor = ParseTemplateNeighbor(*params)
        self.neighbor = ParseNeighbor(*params)
        self.family = ParseFamily(*params)
        self.addpath = ParseAddPath(*params)
        self.capability = ParseCapability(*params)
        self.api = ParseAPI(*params)
        self.api_send = ParseSend(*params)
        self.api_receive = ParseReceive(*params)
        self.static = ParseStatic(*params)
        self.static_route = ParseStaticRoute(*params)
        self.announce = SectionAnnounce(*params)
        self.announce_ipv4 = AnnounceIPv4(*params)
        self.announce_ipv6 = AnnounceIPv6(*params)
        self.announce_l2vpn = AnnounceL2VPN(*params)
        self.flow = ParseFlow(*params)
        self.flow_route = ParseFlowRoute(*params)
        self.flow_match = ParseFlowMatch(*params)
        self.flow_then = ParseFlowThen(*params)
        self.flow_scope = ParseFlowScope(*params)
        self.l2vpn = ParseL2VPN(*params)
        self.vpls = ParseVPLS(*params)
        self.operational = ParseOperational(*params)

        # We should check if name are unique when running Section.__init__

        self._structure = {
            'root': {
                'class': self.section,
                'commands': [],
                'sections': {
                    'process': self.process.name,
                    'neighbor': self.neighbor.name,
                    'template': self.template.name,
                },
            },
            self.process.name: {
                'class': self.process,
                'commands': self.process.known.keys(),
                'sections': {},
            },
            self.template.name: {
                'class': self.template,
                'commands': self.template.known.keys(),
                'sections': {
                    'neighbor': self.template_neighbor.name,
                },
            },
            self.template_neighbor.name: {
                'class': self.template_neighbor,
                'commands': self.template_neighbor.known.keys(),
                'sections': {
                    'family': self.family.name,
                    'capability': self.capability.name,
                    'add-path': self.addpath.name,
                    'api': self.api.name,
                    'static': self.static.name,
                    'flow': self.flow.name,
                    'l2vpn': self.l2vpn.name,
                    'operational': self.operational.name,
                    'announce': self.announce.name,
                },
            },
            self.neighbor.name: {
                'class': self.neighbor,
                'commands': self.neighbor.known.keys(),
                'sections': {
                    'family': self.family.name,
                    'capability': self.capability.name,
                    'add-path': self.addpath.name,
                    'api': self.api.name,
                    'static': self.static.name,
                    'flow': self.flow.name,
                    'l2vpn': self.l2vpn.name,
                    'operational': self.operational.name,
                    'announce': self.announce.name,
                },
            },
            self.family.name: {
                'class': self.family,
                'commands': self.family.known.keys(),
                'sections': {},
            },
            self.capability.name: {
                'class': self.capability,
                'commands': self.capability.known.keys(),
                'sections': {},
            },
            self.addpath.name: {
                'class': self.addpath,
                'commands': self.addpath.known.keys(),
                'sections': {},
            },
            self.api.name: {
                'class': self.api,
                'commands': self.api.known.keys(),
                'sections': {
                    'send': self.api_send.name,
                    'receive': self.api_receive.name,
                },
            },
            self.api_send.name: {
                'class': self.api_send,
                'commands': self.api_send.known.keys(),
                'sections': {},
            },
            self.api_receive.name: {
                'class': self.api_receive,
                'commands': self.api_receive.known.keys(),
                'sections': {},
            },
            self.announce.name: {
                'class': self.announce,
                'commands': self.announce.known.keys(),
                'sections': {
                    'ipv4': self.announce_ipv4.name,
                    'ipv6': self.announce_ipv6.name,
                    'l2vpn': self.announce_l2vpn.name,
                },
            },
            self.announce_ipv4.name: {
                'class':
                self.announce_ipv4,
                'commands': [
                    'unicast', 'multicast', 'nlri-mpls', 'mpls-vpn', 'flow',
                    'flow-vpn'
                ],
                'sections': {},
            },
            self.announce_ipv6.name: {
                'class':
                self.announce_ipv6,
                'commands': [
                    'unicast', 'multicast', 'nlri-mpls', 'mpls-vpn', 'flow',
                    'flow-vpn'
                ],
                'sections': {},
            },
            self.announce_l2vpn.name: {
                'class': self.announce_l2vpn,
                'commands': [
                    'vpls',
                ],
                'sections': {},
            },
            self.static.name: {
                'class': self.static,
                'commands': ['route', 'attributes'],
                'sections': {
                    'route': self.static_route.name,
                },
            },
            self.static_route.name: {
                'class': self.static_route,
                'commands': self.static_route.known.keys(),
                'sections': {},
            },
            self.flow.name: {
                'class': self.flow,
                'commands': self.flow.known.keys(),
                'sections': {
                    'route': self.flow_route.name,
                },
            },
            self.flow_route.name: {
                'class': self.flow_route,
                'commands': self.flow_route.known.keys(),
                'sections': {
                    'match': self.flow_match.name,
                    'then': self.flow_then.name,
                    'scope': self.flow_scope.name,
                },
            },
            self.flow_match.name: {
                'class': self.flow_match,
                'commands': self.flow_match.known.keys(),
                'sections': {},
            },
            self.flow_then.name: {
                'class': self.flow_then,
                'commands': self.flow_then.known.keys(),
                'sections': {},
            },
            self.flow_scope.name: {
                'class': self.flow_scope,
                'commands': self.flow_scope.known.keys(),
                'sections': {}
            },
            self.l2vpn.name: {
                'class': self.l2vpn,
                'commands': self.l2vpn.known.keys(),
                'sections': {
                    'vpls': self.vpls.name,
                },
            },
            self.vpls.name: {
                'class': self.vpls,
                'commands': self.l2vpn.known.keys(),
                'sections': {},
            },
            self.operational.name: {
                'class': self.operational,
                'commands': self.operational.known.keys(),
                'sections': {}
            },
        }

        self._neighbors = {}
        self._previous_neighbors = {}
    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
Exemple #4
0
    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
Exemple #5
0
class Configuration(_Configuration):
    def __init__(self, configurations, text=False):
        _Configuration.__init__(self)
        self.api_encoder = environment.settings().api.encoder

        self._configurations = configurations
        self._text = text

        self.error = Error()
        self.scope = Scope()

        self.tokeniser = Tokeniser(self.scope, self.error, self.logger)

        params = (self.tokeniser, self.scope, self.error, self.logger)
        self.section = Section(*params)
        self.process = ParseProcess(*params)
        self.template = ParseTemplate(*params)
        self.template_neighbor = ParseTemplateNeighbor(*params)
        self.neighbor = ParseNeighbor(*params)
        self.family = ParseFamily(*params)
        self.addpath = ParseAddPath(*params)
        self.capability = ParseCapability(*params)
        self.api = ParseAPI(*params)
        self.api_send = ParseSend(*params)
        self.api_receive = ParseReceive(*params)
        self.static = ParseStatic(*params)
        self.static_route = ParseStaticRoute(*params)
        self.announce = SectionAnnounce(*params)
        self.announce_ipv4 = AnnounceIPv4(*params)
        self.announce_ipv6 = AnnounceIPv6(*params)
        self.announce_l2vpn = AnnounceL2VPN(*params)
        self.flow = ParseFlow(*params)
        self.flow_route = ParseFlowRoute(*params)
        self.flow_match = ParseFlowMatch(*params)
        self.flow_then = ParseFlowThen(*params)
        self.flow_scope = ParseFlowScope(*params)
        self.l2vpn = ParseL2VPN(*params)
        self.vpls = ParseVPLS(*params)
        self.operational = ParseOperational(*params)

        # We should check if name are unique when running Section.__init__

        self._structure = {
            'root': {
                'class': self.section,
                'commands': [],
                'sections': {
                    'process': self.process.name,
                    'neighbor': self.neighbor.name,
                    'template': self.template.name,
                },
            },
            self.process.name: {
                'class': self.process,
                'commands': self.process.known.keys(),
                'sections': {},
            },
            self.template.name: {
                'class': self.template,
                'commands': self.template.known.keys(),
                'sections': {
                    'neighbor': self.template_neighbor.name,
                },
            },
            self.template_neighbor.name: {
                'class': self.template_neighbor,
                'commands': self.template_neighbor.known.keys(),
                'sections': {
                    'family': self.family.name,
                    'capability': self.capability.name,
                    'add-path': self.addpath.name,
                    'api': self.api.name,
                    'static': self.static.name,
                    'flow': self.flow.name,
                    'l2vpn': self.l2vpn.name,
                    'operational': self.operational.name,
                    'announce': self.announce.name,
                },
            },
            self.neighbor.name: {
                'class': self.neighbor,
                'commands': self.neighbor.known.keys(),
                'sections': {
                    'family': self.family.name,
                    'capability': self.capability.name,
                    'add-path': self.addpath.name,
                    'api': self.api.name,
                    'static': self.static.name,
                    'flow': self.flow.name,
                    'l2vpn': self.l2vpn.name,
                    'operational': self.operational.name,
                    'announce': self.announce.name,
                },
            },
            self.family.name: {
                'class': self.family,
                'commands': self.family.known.keys(),
                'sections': {},
            },
            self.capability.name: {
                'class': self.capability,
                'commands': self.capability.known.keys(),
                'sections': {},
            },
            self.addpath.name: {
                'class': self.addpath,
                'commands': self.addpath.known.keys(),
                'sections': {},
            },
            self.api.name: {
                'class': self.api,
                'commands': self.api.known.keys(),
                'sections': {
                    'send': self.api_send.name,
                    'receive': self.api_receive.name,
                },
            },
            self.api_send.name: {
                'class': self.api_send,
                'commands': self.api_send.known.keys(),
                'sections': {},
            },
            self.api_receive.name: {
                'class': self.api_receive,
                'commands': self.api_receive.known.keys(),
                'sections': {},
            },
            self.announce.name: {
                'class': self.announce,
                'commands': self.announce.known.keys(),
                'sections': {
                    'ipv4': self.announce_ipv4.name,
                    'ipv6': self.announce_ipv6.name,
                    'l2vpn': self.announce_l2vpn.name,
                },
            },
            self.announce_ipv4.name: {
                'class':
                self.announce_ipv4,
                'commands': [
                    'unicast', 'multicast', 'nlri-mpls', 'mpls-vpn', 'flow',
                    'flow-vpn'
                ],
                'sections': {},
            },
            self.announce_ipv6.name: {
                'class':
                self.announce_ipv6,
                'commands': [
                    'unicast', 'multicast', 'nlri-mpls', 'mpls-vpn', 'flow',
                    'flow-vpn'
                ],
                'sections': {},
            },
            self.announce_l2vpn.name: {
                'class': self.announce_l2vpn,
                'commands': [
                    'vpls',
                ],
                'sections': {},
            },
            self.static.name: {
                'class': self.static,
                'commands': ['route', 'attributes'],
                'sections': {
                    'route': self.static_route.name,
                },
            },
            self.static_route.name: {
                'class': self.static_route,
                'commands': self.static_route.known.keys(),
                'sections': {},
            },
            self.flow.name: {
                'class': self.flow,
                'commands': self.flow.known.keys(),
                'sections': {
                    'route': self.flow_route.name,
                },
            },
            self.flow_route.name: {
                'class': self.flow_route,
                'commands': self.flow_route.known.keys(),
                'sections': {
                    'match': self.flow_match.name,
                    'then': self.flow_then.name,
                    'scope': self.flow_scope.name,
                },
            },
            self.flow_match.name: {
                'class': self.flow_match,
                'commands': self.flow_match.known.keys(),
                'sections': {},
            },
            self.flow_then.name: {
                'class': self.flow_then,
                'commands': self.flow_then.known.keys(),
                'sections': {},
            },
            self.flow_scope.name: {
                'class': self.flow_scope,
                'commands': self.flow_scope.known.keys(),
                'sections': {}
            },
            self.l2vpn.name: {
                'class': self.l2vpn,
                'commands': self.l2vpn.known.keys(),
                'sections': {
                    'vpls': self.vpls.name,
                },
            },
            self.vpls.name: {
                'class': self.vpls,
                'commands': self.l2vpn.known.keys(),
                'sections': {},
            },
            self.operational.name: {
                'class': self.operational,
                'commands': self.operational.known.keys(),
                'sections': {}
            },
        }

        self._neighbors = {}
        self._previous_neighbors = {}

    def _clear(self):
        self.processes = {}
        self._previous_neighbors = self.neighbors
        self.neighbors = {}
        self._neighbors = {}

    # clear the parser data (ie: free memory)
    def _cleanup(self):
        self.error.clear()
        self.tokeniser.clear()
        self.scope.clear()

        self.process.clear()
        self.template.clear()
        self.template_neighbor.clear()
        self.neighbor.clear()
        self.family.clear()
        self.capability.clear()
        self.api.clear()
        self.api_send.clear()
        self.api_receive.clear()
        self.announce_ipv6.clear()
        self.announce_ipv4.clear()
        self.announce_l2vpn.clear()
        self.announce.clear()
        self.static.clear()
        self.static_route.clear()
        self.flow.clear()
        self.flow_route.clear()
        self.flow_match.clear()
        self.flow_then.clear()
        self.flow_scope.clear()
        self.l2vpn.clear()
        self.vpls.clear()
        self.operational.clear()

    def _rollback_reload(self):
        self.neighbors = self._previous_neighbors
        self.processes = self.process.processes
        self._neighbors = {}
        self._previous_neighbors = {}

    def _commit_reload(self):
        self.neighbors = self.neighbor.neighbors
        # XXX: Yes, we do not detect changes in processes and restart anything ..
        # XXX: This is a bug ..
        self.processes = self.process.processes
        self._neighbors = {}

        # Add the changes prior to the reload to the neighbor to correct handling of deleted routes
        for neighbor in self.neighbors:
            if neighbor in self._previous_neighbors:
                self.neighbors[
                    neighbor].backup_changes = self._previous_neighbors[
                        neighbor].changes

        self._previous_neighbors = {}
        self._cleanup()

    def reload(self):
        try:
            return self._reload()
        except KeyboardInterrupt:
            return self.error.set(
                'configuration reload aborted by ^C or SIGINT')
        except Error as exc:
            if environment.settings().debug.configuration:
                raise
            return self.error.set(
                'problem parsing configuration file line %d\n'
                'error message: %s' % (self.tokeniser.index_line, exc))
        except StandardError as exc:
            if environment.settings().debug.configuration:
                raise
            return self.error.set(
                'problem parsing configuration file line %d\n'
                'error message: %s' % (self.tokeniser.index_line, exc))

    def _reload(self):
        # taking the first configuration available (FIFO buffer)
        fname = self._configurations.pop(0)
        self._configurations.append(fname)

        # clearing the current configuration to be able to re-parse it
        self._clear()

        if self._text:
            if not self.tokeniser.set_text(fname):
                return False
        else:
            if not self.tokeniser.set_file(fname):
                return False

        if self.parseSection('root') is not True:
            # XXX: Should it be in neighbor ?
            self.process.add_api()
            self._rollback_reload()

            return self.error.set(
                "\n"
                "syntax error in section %s\n"
                "line %d: %s\n"
                "\n%s" % (self.scope.location(), self.tokeniser.number,
                          ' '.join(self.tokeniser.line), str(self.error)))

        self.process.add_api()
        self._commit_reload()
        self._link()
        self.debug_check_route()
        self.debug_self_check()
        return True

    def _link(self):
        for neighbor in six.itervalues(self.neighbors):
            api = neighbor.api
            for process in api.get('processes', []):
                self.processes.setdefault(
                    process, {})['neighbor-changes'] = api['neighbor-changes']
                self.processes.setdefault(process,
                                          {})['negotiated'] = api['negotiated']
                self.processes.setdefault(process, {})['fsm'] = api['fsm']
                self.processes.setdefault(process,
                                          {})['signal'] = api['signal']
                for way in ('send', 'receive'):
                    for name in ('parsed', 'packets', 'consolidate'):
                        key = "%s-%s" % (way, name)
                        if api[key]:
                            self.processes[process].setdefault(key, []).append(
                                neighbor.router_id)
                    for name in ('open', 'update', 'notification', 'keepalive',
                                 'refresh', 'operational'):
                        key = "%s-%s" % (way, name)
                        if api[key]:
                            self.processes[process].setdefault(key, []).append(
                                neighbor.router_id)

    def partial(self, section, text):
        self._cleanup(
        )  # this perform a big cleanup (may be able to be smarter)
        self._clear()
        self.tokeniser.set_api(
            text if text.endswith(';') or text.endswith('}') else text + ' ;')

        if self.parseSection(section) is not True:
            self._rollback_reload()
            self.logger.debug(
                "\n"
                "syntax error in api command %s\n"
                "line %d: %s\n"
                "\n%s" % (self.scope.location(), self.tokeniser.number,
                          ' '.join(self.tokeniser.line), str(self.error)),
                'configuration')
            return False
        return True

    def _enter(self, name):
        location = self.tokeniser.iterate()
        self.logger.debug("> %-16s | %s" % (location, self.tokeniser.params()),
                          'configuration')

        if location not in self._structure[name]['sections']:
            return self.error.set('section %s is invalid in %s, %s' %
                                  (location, name, self.scope.location()))

        self.scope.enter(location)
        self.scope.to_context()

        class_name = self._structure[name]['sections'][location]
        instance = self._structure[class_name].get('class', None)
        if not instance:
            raise RuntimeError('This should not be happening, debug time !')

        if not instance.pre():
            return False

        if not self.dispatch(self._structure[name]['sections'][location]):
            return False

        if not instance.post():
            return False

        left = self.scope.leave()
        if not left:
            return self.error.set('closing too many parenthesis')
        self.scope.to_context()

        self.logger.debug("< %-16s | %s" % (left, self.tokeniser.params()),
                          'configuration')
        return True

    def _run(self, name):
        command = self.tokeniser.iterate()
        self.logger.debug(". %-16s | %s" % (command, self.tokeniser.params()),
                          'configuration')

        if not self.run(name, command):
            return False
        return True

    def dispatch(self, name):
        while True:
            self.tokeniser()

            if self.tokeniser.end == ';':
                if self._run(name):
                    continue
                return False

            if self.tokeniser.end == '{':
                if self._enter(name):
                    continue
                return False

            if self.tokeniser.end == '}':
                return True

            if not self.tokeniser.end:  # finished
                return True

            return self.error.set('invalid syntax line %d' %
                                  self.tokeniser.index_line)
        return False

    def parseSection(self, name):
        if name not in self._structure:
            return self.error.set('option %s is not allowed here' % name)

        return self.dispatch(name)

    def run(self, name, command):
        # restore 'anounce attribute' to provide backward 3.4 compatibility
        if name == 'static' and command == 'attribute':
            command = 'attributes'
        if command not in self._structure[name]['commands']:
            return self.error.set('invalid keyword "%s"' % command)

        return self._structure[name]['class'].parse(name, command)

    def debug_check_route(self):
        # we are not really running the program, just want to ....
        if environment.settings().debug.route:
            from exabgp.configuration.check import check_message
            if check_message(self.neighbors,
                             environment.settings().debug.route):
                sys.exit(0)
            sys.exit(1)

    def debug_self_check(self):
        # we are not really running the program, just want check the configuration validity
        if environment.settings().debug.selfcheck:
            from exabgp.configuration.check import check_neighbor
            if check_neighbor(self.neighbors):
                sys.exit(0)
            sys.exit(1)
Exemple #6
0
    def __init__(self, configurations, text=False):
        _Configuration.__init__(self)
        self.api_encoder = environment.settings().api.encoder

        self._configurations = configurations
        self._text = text

        self.error = Error()
        self.scope = Scope()

        self.tokeniser = Tokeniser(self.scope, self.error, self.logger)

        generic = Section(self.tokeniser, self.scope, self.error, self.logger)
        self.process = ParseProcess(self.tokeniser, self.scope, self.error, self.logger)
        self.template = ParseTemplate(self.tokeniser, self.scope, self.error, self.logger)
        self.neighbor = ParseNeighbor(self.tokeniser, self.scope, self.error, self.logger)
        self.family = ParseFamily(self.tokeniser, self.scope, self.error, self.logger)
        self.capability = ParseCapability(self.tokeniser, self.scope, self.error, self.logger)
        self.api = ParseAPI(self.tokeniser, self.scope, self.error, self.logger)
        self.api_send = ParseSend(self.tokeniser, self.scope, self.error, self.logger)
        self.api_receive = ParseReceive(self.tokeniser, self.scope, self.error, self.logger)
        self.static = ParseStatic(self.tokeniser, self.scope, self.error, self.logger)
        self.static_route = ParseStaticRoute(self.tokeniser, self.scope, self.error, self.logger)
        self.flow = ParseFlow(self.tokeniser, self.scope, self.error, self.logger)
        self.flow_route = ParseFlowRoute(self.tokeniser, self.scope, self.error, self.logger)
        self.flow_match = ParseFlowMatch(self.tokeniser, self.scope, self.error, self.logger)
        self.flow_then = ParseFlowThen(self.tokeniser, self.scope, self.error, self.logger)
        self.l2vpn = ParseL2VPN(self.tokeniser, self.scope, self.error, self.logger)
        self.vpls = ParseVPLS(self.tokeniser, self.scope, self.error, self.logger)
        self.operational = ParseOperational(self.tokeniser, self.scope, self.error, self.logger)

        # We should check if name are unique when running Section.__init__

        self._structure = {
            "root": {
                "class": generic,
                "commands": [],
                "sections": {
                    "process": self.process.name,
                    "neighbor": self.neighbor.name,
                    "template": self.template.name,
                },
            },
            self.process.name: {"class": self.process, "commands": self.process.known.keys(), "sections": {}},
            self.template.name: {
                "class": self.template,
                "commands": self.template.known.keys(),
                "sections": {
                    "family": self.family.name,
                    "capability": self.capability.name,
                    "api": self.api.name,
                    "static": self.static.name,
                    "flow": self.flow.name,
                    "l2vpn": self.l2vpn.name,
                    "operational": self.operational.name,
                },
            },
            self.neighbor.name: {
                "class": self.neighbor,
                "commands": self.neighbor.known.keys(),
                "sections": {
                    "family": self.family.name,
                    "capability": self.capability.name,
                    "api": self.api.name,
                    "static": self.static.name,
                    "flow": self.flow.name,
                    "l2vpn": self.l2vpn.name,
                    "operational": self.operational.name,
                },
            },
            self.family.name: {"class": self.family, "commands": self.family.known.keys(), "sections": {}},
            self.capability.name: {"class": self.capability, "commands": self.capability.known.keys(), "sections": {}},
            self.api.name: {
                "class": self.api,
                "commands": self.api.known.keys(),
                "sections": {"send": self.api_send.name, "receive": self.api_receive.name},
            },
            self.api_send.name: {"class": self.api_send, "commands": self.api_send.known.keys(), "sections": {}},
            self.api_receive.name: {
                "class": self.api_receive,
                "commands": self.api_receive.known.keys(),
                "sections": {},
            },
            self.static.name: {
                "class": self.static,
                "commands": ["route", "attributes"],
                "sections": {"route": self.static_route.name},
            },
            self.static_route.name: {
                "class": self.static_route,
                "commands": self.static_route.known.keys(),
                "sections": {},
            },
            self.flow.name: {
                "class": self.flow,
                "commands": self.flow.known.keys(),
                "sections": {"route": self.flow_route.name},
            },
            self.flow_route.name: {
                "class": self.flow_route,
                "commands": self.flow_route.known.keys(),
                "sections": {"match": self.flow_match.name, "then": self.flow_then.name},
            },
            self.flow_match.name: {"class": self.flow_match, "commands": self.flow_match.known.keys(), "sections": {}},
            self.flow_then.name: {"class": self.flow_then, "commands": self.flow_then.known.keys(), "sections": {}},
            self.l2vpn.name: {
                "class": self.l2vpn,
                "commands": self.l2vpn.known.keys(),
                "sections": {"vpls": self.vpls.name},
            },
            self.vpls.name: {"class": self.vpls, "commands": self.l2vpn.known.keys(), "sections": {}},
            self.operational.name: {
                "class": self.operational,
                "commands": self.operational.known.keys(),
                "sections": {},
            },
        }

        self._neighbors = {}
        self._previous_neighbors = {}
Exemple #7
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.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 __init__ (self, configurations, text=False):
		_Configuration.__init__(self)
		self.api_encoder = environment.settings().api.encoder

		self._configurations = configurations
		self._text = text

		self.error  = Error  ()
		self.scope  = Scope  ()

		self.tokeniser = Tokeniser(self.scope,self.error,self.logger)

		params = (self.tokeniser,self.scope,self.error,self.logger)
		generic                  = Section               (*params)
		self.process             = ParseProcess          (*params)
		self.template            = ParseTemplate         (*params)
		self.template_neighbor   = ParseTemplateNeighbor (*params)
		self.neighbor            = ParseNeighbor         (*params)
		self.family              = ParseFamily           (*params)
		self.addpath             = ParseAddPath          (*params)
		self.capability          = ParseCapability       (*params)
		self.api                 = ParseAPI              (*params)
		self.api_send            = ParseSend             (*params)
		self.api_receive         = ParseReceive          (*params)
		self.static              = ParseStatic           (*params)
		self.static_route        = ParseStaticRoute      (*params)
		self.announce            = SectionAnnounce       (*params)
		self.announce_ipv4       = AnnounceIPv4          (*params)
		self.announce_ipv6       = AnnounceIPv6          (*params)
		self.announce_l2vpn      = AnnounceL2VPN         (*params)
		self.flow                = ParseFlow             (*params)
		self.flow_route          = ParseFlowRoute        (*params)
		self.flow_match          = ParseFlowMatch        (*params)
		self.flow_then           = ParseFlowThen         (*params)
		self.flow_scope          = ParseFlowScope        (*params)
		self.l2vpn               = ParseL2VPN            (*params)
		self.vpls                = ParseVPLS             (*params)
		self.operational         = ParseOperational      (*params)

		# We should check if name are unique when running Section.__init__

		self._structure = {
			'root': {
				'class':    generic,
				'commands': [],
				'sections': {
					'process': self.process.name,
					'neighbor': self.neighbor.name,
					'template': self.template.name,
				},
			},
			self.process.name: {
				'class':    self.process,
				'commands': self.process.known.keys(),
				'sections': {},
			},
			self.template.name: {
				'class':    self.template,
				'commands': self.template.known.keys(),
				'sections': {
					'neighbor':    self.template_neighbor.name,
				},
			},
			self.template_neighbor.name: {
				'class':    self.template_neighbor,
				'commands': self.template_neighbor.known.keys(),
				'sections': {
					'family':      self.family.name,
					'capability':  self.capability.name,
					'add-path':    self.addpath.name,
					'api':         self.api.name,
					'static':      self.static.name,
					'flow':        self.flow.name,
					'l2vpn':       self.l2vpn.name,
					'operational': self.operational.name,
					'announce':    self.announce.name,
				},
			},
			self.neighbor.name: {
				'class':    self.neighbor,
				'commands': self.neighbor.known.keys(),
				'sections': {
					'family':      self.family.name,
					'capability':  self.capability.name,
					'add-path':    self.addpath.name,
					'api':         self.api.name,
					'static':      self.static.name,
					'flow':        self.flow.name,
					'l2vpn':       self.l2vpn.name,
					'operational': self.operational.name,
					'announce':    self.announce.name,
				},
			},
			self.family.name: {
				'class':    self.family,
				'commands': self.family.known.keys(),
				'sections': {
				},
			},
			self.capability.name: {
				'class':    self.capability,
				'commands': self.capability.known.keys(),
				'sections': {
				},
			},
			self.addpath.name: {
				'class':    self.addpath,
				'commands': self.addpath.known.keys(),
				'sections': {
				},
			},
			self.api.name: {
				'class':    self.api,
				'commands': self.api.known.keys(),
				'sections': {
					'send':    self.api_send.name,
					'receive': self.api_receive.name,
				},
			},
			self.api_send.name: {
				'class':    self.api_send,
				'commands': self.api_send.known.keys(),
				'sections': {
				},
			},
			self.api_receive.name: {
				'class':    self.api_receive,
				'commands': self.api_receive.known.keys(),
				'sections': {
				},
			},
			self.announce.name: {
				'class':    self.announce,
				'commands': self.announce.known.keys(),
				'sections': {
					'ipv4': self.announce_ipv4.name,
					'ipv6': self.announce_ipv6.name,
					'l2vpn': self.announce_l2vpn.name,
				},
			},
			self.announce_ipv4.name: {
				'class':    self.announce_ipv4,
				'commands': ['unicast', 'multicast', 'nlri-mpls', 'mpls-vpn', 'flow', 'flow-vpn'],
				'sections': {
				},
			},
			self.announce_ipv6.name: {
				'class':    self.announce_ipv6,
				'commands': ['unicast', 'multicast', 'nlri-mpls', 'mpls-vpn', 'flow', 'flow-vpn'],
				'sections': {
				},
			},
			self.announce_l2vpn.name: {
				'class':    self.announce_l2vpn,
				'commands': ['vpls',],
				'sections': {
				},
			},
			self.static.name: {
				'class':    self.static,
				'commands': ['route','attributes'],
				'sections': {
					'route': self.static_route.name,
				},
			},
			self.static_route.name: {
				'class':    self.static_route,
				'commands': self.static_route.known.keys(),
				'sections': {
				},
			},
			self.flow.name: {
				'class':    self.flow,
				'commands': self.flow.known.keys(),
				'sections': {
					'route': self.flow_route.name,
				},
			},
			self.flow_route.name: {
				'class':    self.flow_route,
				'commands': self.flow_route.known.keys(),
				'sections': {
					'match': self.flow_match.name,
					'then':  self.flow_then.name,
					'scope': self.flow_scope.name,
				},
			},
			self.flow_match.name: {
				'class':    self.flow_match,
				'commands': self.flow_match.known.keys(),
				'sections': {
				},
			},
			self.flow_then.name: {
				'class':    self.flow_then,
				'commands': self.flow_then.known.keys(),
				'sections': {
				},
			},
			self.flow_scope.name: {
				'class':    self.flow_scope,
				'commands': self.flow_scope.known.keys(),
				'sections': {
				}
			},
			self.l2vpn.name: {
				'class':    self.l2vpn,
				'commands': self.l2vpn.known.keys(),
				'sections': {
					'vpls': self.vpls.name,
				},
			},
			self.vpls.name: {
				'class':    self.vpls,
				'commands': self.l2vpn.known.keys(),
				'sections': {
				},
			},
			self.operational.name: {
				'class':    self.operational,
				'commands': self.operational.known.keys(),
				'sections': {
				}
			},
		}

		self._neighbors = {}
		self._previous_neighbors = {}
Exemple #9
0
class Configuration(_Configuration):
    def __init__(self, configurations, text=False):
        _Configuration.__init__(self)
        self.api_encoder = environment.settings().api.encoder

        self._configurations = configurations
        self._text = text

        self.error = Error()
        self.scope = Scope()

        self.tokeniser = Tokeniser(self.scope, self.error, self.logger)

        generic = Section(self.tokeniser, self.scope, self.error, self.logger)
        self.process = ParseProcess(self.tokeniser, self.scope, self.error, self.logger)
        self.template = ParseTemplate(self.tokeniser, self.scope, self.error, self.logger)
        self.neighbor = ParseNeighbor(self.tokeniser, self.scope, self.error, self.logger)
        self.family = ParseFamily(self.tokeniser, self.scope, self.error, self.logger)
        self.capability = ParseCapability(self.tokeniser, self.scope, self.error, self.logger)
        self.api = ParseAPI(self.tokeniser, self.scope, self.error, self.logger)
        self.api_send = ParseSend(self.tokeniser, self.scope, self.error, self.logger)
        self.api_receive = ParseReceive(self.tokeniser, self.scope, self.error, self.logger)
        self.static = ParseStatic(self.tokeniser, self.scope, self.error, self.logger)
        self.static_route = ParseStaticRoute(self.tokeniser, self.scope, self.error, self.logger)
        self.flow = ParseFlow(self.tokeniser, self.scope, self.error, self.logger)
        self.flow_route = ParseFlowRoute(self.tokeniser, self.scope, self.error, self.logger)
        self.flow_match = ParseFlowMatch(self.tokeniser, self.scope, self.error, self.logger)
        self.flow_then = ParseFlowThen(self.tokeniser, self.scope, self.error, self.logger)
        self.l2vpn = ParseL2VPN(self.tokeniser, self.scope, self.error, self.logger)
        self.vpls = ParseVPLS(self.tokeniser, self.scope, self.error, self.logger)
        self.operational = ParseOperational(self.tokeniser, self.scope, self.error, self.logger)

        # We should check if name are unique when running Section.__init__

        self._structure = {
            "root": {
                "class": generic,
                "commands": [],
                "sections": {
                    "process": self.process.name,
                    "neighbor": self.neighbor.name,
                    "template": self.template.name,
                },
            },
            self.process.name: {"class": self.process, "commands": self.process.known.keys(), "sections": {}},
            self.template.name: {
                "class": self.template,
                "commands": self.template.known.keys(),
                "sections": {
                    "family": self.family.name,
                    "capability": self.capability.name,
                    "api": self.api.name,
                    "static": self.static.name,
                    "flow": self.flow.name,
                    "l2vpn": self.l2vpn.name,
                    "operational": self.operational.name,
                },
            },
            self.neighbor.name: {
                "class": self.neighbor,
                "commands": self.neighbor.known.keys(),
                "sections": {
                    "family": self.family.name,
                    "capability": self.capability.name,
                    "api": self.api.name,
                    "static": self.static.name,
                    "flow": self.flow.name,
                    "l2vpn": self.l2vpn.name,
                    "operational": self.operational.name,
                },
            },
            self.family.name: {"class": self.family, "commands": self.family.known.keys(), "sections": {}},
            self.capability.name: {"class": self.capability, "commands": self.capability.known.keys(), "sections": {}},
            self.api.name: {
                "class": self.api,
                "commands": self.api.known.keys(),
                "sections": {"send": self.api_send.name, "receive": self.api_receive.name},
            },
            self.api_send.name: {"class": self.api_send, "commands": self.api_send.known.keys(), "sections": {}},
            self.api_receive.name: {
                "class": self.api_receive,
                "commands": self.api_receive.known.keys(),
                "sections": {},
            },
            self.static.name: {
                "class": self.static,
                "commands": ["route", "attributes"],
                "sections": {"route": self.static_route.name},
            },
            self.static_route.name: {
                "class": self.static_route,
                "commands": self.static_route.known.keys(),
                "sections": {},
            },
            self.flow.name: {
                "class": self.flow,
                "commands": self.flow.known.keys(),
                "sections": {"route": self.flow_route.name},
            },
            self.flow_route.name: {
                "class": self.flow_route,
                "commands": self.flow_route.known.keys(),
                "sections": {"match": self.flow_match.name, "then": self.flow_then.name},
            },
            self.flow_match.name: {"class": self.flow_match, "commands": self.flow_match.known.keys(), "sections": {}},
            self.flow_then.name: {"class": self.flow_then, "commands": self.flow_then.known.keys(), "sections": {}},
            self.l2vpn.name: {
                "class": self.l2vpn,
                "commands": self.l2vpn.known.keys(),
                "sections": {"vpls": self.vpls.name},
            },
            self.vpls.name: {"class": self.vpls, "commands": self.l2vpn.known.keys(), "sections": {}},
            self.operational.name: {
                "class": self.operational,
                "commands": self.operational.known.keys(),
                "sections": {},
            },
        }

        self._neighbors = {}
        self._previous_neighbors = {}

    def _clear(self):
        self.processes = {}
        self.neighbors = {}
        self._neighbors = {}
        self._previous_neighbors = {}

        # clear the parser data (ie: free memory)

    def _cleanup(self):
        self.error.clear()
        self.tokeniser.clear()
        self.scope.clear()

        self.process.clear()
        self.template.clear()
        self.neighbor.clear()
        self.family.clear()
        self.capability.clear()
        self.api.clear()
        self.api_send.clear()
        self.api_receive.clear()
        self.static.clear()
        self.static_route.clear()
        self.flow.clear()
        self.flow_route.clear()
        self.flow_match.clear()
        self.flow_then.clear()
        self.l2vpn.clear()
        self.vpls.clear()
        self.operational.clear()

    def _rollback_reload(self):
        self.neighbors = self._previous_neighbors
        self._neighbors = {}
        self._previous_neighbors = {}

    def _commit_reload(self):
        self.neighbors = self.neighbor.neighbors
        # XXX: Yes, we do not detect changes in processes and restart anything ..
        # XXX: This is a bug ..
        self.processes = self.process.processes
        self._neighbors = {}

        # installing in the neighbor the API routes
        for neighbor in self.neighbors:
            if neighbor in self._previous_neighbors:
                self.neighbors[neighbor].changes = self._previous_neighbors[neighbor].changes

        self._previous_neighbors = {}
        self._cleanup()

    def reload(self):
        try:
            return self._reload()
        except KeyboardInterrupt:
            return self.error.set("configuration reload aborted by ^C or SIGINT")
        except Error, exc:
            if environment.settings().debug.configuration:
                raise
            return self.error.set(
                "problem parsing configuration file line %d\n" "error message: %s" % (self.tokeniser.index_line, exc)
            )
        except StandardError, exc:
            if environment.settings().debug.configuration:
                raise
            return self.error.set(
                "problem parsing configuration file line %d\n" "error message: %s" % (self.tokeniser.index_line, exc)
            )
Exemple #10
0
 def post(self):
     self.scope.merge('api', ParseAPI.extract())
     return True
Exemple #11
0
class Configuration (_Configuration):
	def __init__ (self, configurations, text=False):
		_Configuration.__init__(self)
		self.api_encoder = environment.settings().api.encoder

		self._configurations = configurations
		self._text = text

		self.error  = Error  ()
		self.scope  = Scope  ()

		self.tokeniser = Tokeniser(self.scope,self.error,self.logger)

		params = (self.tokeniser,self.scope,self.error,self.logger)
		generic                  = Section               (*params)
		self.process             = ParseProcess          (*params)
		self.template            = ParseTemplate         (*params)
		self.template_neighbor   = ParseTemplateNeighbor (*params)
		self.neighbor            = ParseNeighbor         (*params)
		self.family              = ParseFamily           (*params)
		self.addpath             = ParseAddPath          (*params)
		self.capability          = ParseCapability       (*params)
		self.api                 = ParseAPI              (*params)
		self.api_send            = ParseSend             (*params)
		self.api_receive         = ParseReceive          (*params)
		self.static              = ParseStatic           (*params)
		self.static_route        = ParseStaticRoute      (*params)
		self.announce            = SectionAnnounce       (*params)
		self.announce_ipv4       = AnnounceIPv4          (*params)
		self.announce_ipv6       = AnnounceIPv6          (*params)
		self.announce_l2vpn      = AnnounceL2VPN         (*params)
		self.flow                = ParseFlow             (*params)
		self.flow_route          = ParseFlowRoute        (*params)
		self.flow_match          = ParseFlowMatch        (*params)
		self.flow_then           = ParseFlowThen         (*params)
		self.flow_scope          = ParseFlowScope        (*params)
		self.l2vpn               = ParseL2VPN            (*params)
		self.vpls                = ParseVPLS             (*params)
		self.operational         = ParseOperational      (*params)

		# We should check if name are unique when running Section.__init__

		self._structure = {
			'root': {
				'class':    generic,
				'commands': [],
				'sections': {
					'process': self.process.name,
					'neighbor': self.neighbor.name,
					'template': self.template.name,
				},
			},
			self.process.name: {
				'class':    self.process,
				'commands': self.process.known.keys(),
				'sections': {},
			},
			self.template.name: {
				'class':    self.template,
				'commands': self.template.known.keys(),
				'sections': {
					'neighbor':    self.template_neighbor.name,
				},
			},
			self.template_neighbor.name: {
				'class':    self.template_neighbor,
				'commands': self.template_neighbor.known.keys(),
				'sections': {
					'family':      self.family.name,
					'capability':  self.capability.name,
					'add-path':    self.addpath.name,
					'api':         self.api.name,
					'static':      self.static.name,
					'flow':        self.flow.name,
					'l2vpn':       self.l2vpn.name,
					'operational': self.operational.name,
					'announce':    self.announce.name,
				},
			},
			self.neighbor.name: {
				'class':    self.neighbor,
				'commands': self.neighbor.known.keys(),
				'sections': {
					'family':      self.family.name,
					'capability':  self.capability.name,
					'add-path':    self.addpath.name,
					'api':         self.api.name,
					'static':      self.static.name,
					'flow':        self.flow.name,
					'l2vpn':       self.l2vpn.name,
					'operational': self.operational.name,
					'announce':    self.announce.name,
				},
			},
			self.family.name: {
				'class':    self.family,
				'commands': self.family.known.keys(),
				'sections': {
				},
			},
			self.capability.name: {
				'class':    self.capability,
				'commands': self.capability.known.keys(),
				'sections': {
				},
			},
			self.addpath.name: {
				'class':    self.addpath,
				'commands': self.addpath.known.keys(),
				'sections': {
				},
			},
			self.api.name: {
				'class':    self.api,
				'commands': self.api.known.keys(),
				'sections': {
					'send':    self.api_send.name,
					'receive': self.api_receive.name,
				},
			},
			self.api_send.name: {
				'class':    self.api_send,
				'commands': self.api_send.known.keys(),
				'sections': {
				},
			},
			self.api_receive.name: {
				'class':    self.api_receive,
				'commands': self.api_receive.known.keys(),
				'sections': {
				},
			},
			self.announce.name: {
				'class':    self.announce,
				'commands': self.announce.known.keys(),
				'sections': {
					'ipv4': self.announce_ipv4.name,
					'ipv6': self.announce_ipv6.name,
					'l2vpn': self.announce_l2vpn.name,
				},
			},
			self.announce_ipv4.name: {
				'class':    self.announce_ipv4,
				'commands': ['unicast', 'multicast', 'nlri-mpls', 'mpls-vpn', 'flow', 'flow-vpn'],
				'sections': {
				},
			},
			self.announce_ipv6.name: {
				'class':    self.announce_ipv6,
				'commands': ['unicast', 'multicast', 'nlri-mpls', 'mpls-vpn', 'flow', 'flow-vpn'],
				'sections': {
				},
			},
			self.announce_l2vpn.name: {
				'class':    self.announce_l2vpn,
				'commands': ['vpls',],
				'sections': {
				},
			},
			self.static.name: {
				'class':    self.static,
				'commands': ['route','attributes'],
				'sections': {
					'route': self.static_route.name,
				},
			},
			self.static_route.name: {
				'class':    self.static_route,
				'commands': self.static_route.known.keys(),
				'sections': {
				},
			},
			self.flow.name: {
				'class':    self.flow,
				'commands': self.flow.known.keys(),
				'sections': {
					'route': self.flow_route.name,
				},
			},
			self.flow_route.name: {
				'class':    self.flow_route,
				'commands': self.flow_route.known.keys(),
				'sections': {
					'match': self.flow_match.name,
					'then':  self.flow_then.name,
					'scope': self.flow_scope.name,
				},
			},
			self.flow_match.name: {
				'class':    self.flow_match,
				'commands': self.flow_match.known.keys(),
				'sections': {
				},
			},
			self.flow_then.name: {
				'class':    self.flow_then,
				'commands': self.flow_then.known.keys(),
				'sections': {
				},
			},
			self.flow_scope.name: {
				'class':    self.flow_scope,
				'commands': self.flow_scope.known.keys(),
				'sections': {
				}
			},
			self.l2vpn.name: {
				'class':    self.l2vpn,
				'commands': self.l2vpn.known.keys(),
				'sections': {
					'vpls': self.vpls.name,
				},
			},
			self.vpls.name: {
				'class':    self.vpls,
				'commands': self.l2vpn.known.keys(),
				'sections': {
				},
			},
			self.operational.name: {
				'class':    self.operational,
				'commands': self.operational.known.keys(),
				'sections': {
				}
			},
		}

		self._neighbors = {}
		self._previous_neighbors = {}

	def _clear (self):
		self.processes = {}
		self._previous_neighbors = self.neighbors
		self.neighbors = {}
		self._neighbors = {}

	# clear the parser data (ie: free memory)
	def _cleanup (self):
		self.error.clear()
		self.tokeniser.clear()
		self.scope.clear()

		self.process.clear()
		self.template.clear()
		self.template_neighbor.clear()
		self.neighbor.clear()
		self.family.clear()
		self.capability.clear()
		self.api.clear()
		self.api_send.clear()
		self.api_receive.clear()
		self.announce_ipv6.clear()
		self.announce_ipv4.clear()
		self.announce_l2vpn.clear()
		self.announce.clear()
		self.static.clear()
		self.static_route.clear()
		self.flow.clear()
		self.flow_route.clear()
		self.flow_match.clear()
		self.flow_then.clear()
		self.flow_scope.clear()
		self.l2vpn.clear()
		self.vpls.clear()
		self.operational.clear()

	def _rollback_reload (self):
		self.neighbors = self._previous_neighbors
		self.processes = self.process.processes
		self._neighbors = {}
		self._previous_neighbors = {}

	def _commit_reload (self):
		self.neighbors = self.neighbor.neighbors
		# XXX: Yes, we do not detect changes in processes and restart anything ..
		# XXX: This is a bug ..
		self.processes = self.process.processes
		self._neighbors = {}

		# Add the changes prior to the reload to the neighbor to correct handling of deleted routes
		for neighbor in self.neighbors:
			if neighbor in self._previous_neighbors:
				self.neighbors[neighbor].backup_changes = self._previous_neighbors[neighbor].changes

		self._previous_neighbors = {}
		self._cleanup()

	def reload (self):
		try:
			return self._reload()
		except KeyboardInterrupt:
			return self.error.set('configuration reload aborted by ^C or SIGINT')
		except Error as exc:
			if environment.settings().debug.configuration:
				raise
			return self.error.set(
				'problem parsing configuration file line %d\n'
				'error message: %s' % (self.tokeniser.index_line, exc)
			)
		except StandardError as exc:
			if environment.settings().debug.configuration:
				raise
			return self.error.set(
				'problem parsing configuration file line %d\n'
				'error message: %s' % (self.tokeniser.index_line, exc)
			)

	def _reload (self):
		# taking the first configuration available (FIFO buffer)
		fname = self._configurations.pop(0)
		self._configurations.append(fname)

		# clearing the current configuration to be able to re-parse it
		self._clear()

		if self._text:
			if not self.tokeniser.set_text(fname):
				return False
		else:
			if not self.tokeniser.set_file(fname):
				return False

		if self.section('root') is not True:
			# XXX: Should it be in neighbor ?
			self.process.add_api()
			self._rollback_reload()

			return self.error.set(
				"\n"
				"syntax error in section %s\n"
				"line %d: %s\n"
				"\n%s" % (
					self.scope.location(),
					self.tokeniser.number,
					' '.join(self.tokeniser.line),
					str(self.error)
				)
			)

		self.process.add_api()
		self._commit_reload()
		self._link()
		self.debug_check_route()
		self.debug_self_check()
		return True

	def _link (self):
		for neighbor in six.itervalues(self.neighbors):
			api = neighbor.api
			for process in api.get('processes',[]):
				self.processes.setdefault(process,{})['neighbor-changes'] = api['neighbor-changes']
				self.processes.setdefault(process,{})['negotiated'] = api['negotiated']
				self.processes.setdefault(process,{})['fsm'] = api['fsm']
				self.processes.setdefault(process,{})['signal'] = api['signal']
				for way in ('send','receive'):
					for name in ('parsed','packets','consolidate'):
						key = "%s-%s" % (way,name)
						if api[key]:
							self.processes[process].setdefault(key,[]).append(neighbor.router_id)
					for name in ('open', 'update', 'notification', 'keepalive', 'refresh', 'operational'):
						key = "%s-%s" % (way,name)
						if api[key]:
							self.processes[process].setdefault(key,[]).append(neighbor.router_id)

	def partial (self, section, text):
		self._cleanup()  # this perform a big cleanup (may be able to be smarter)
		self._clear()
		self.tokeniser.set_api(text if text.endswith(';') or text.endswith('}') else text + ' ;')

		if self.section(section) is not True:
			self._rollback_reload()
			self.logger.debug(
				"\n"
				"syntax error in api command %s\n"
				"line %d: %s\n"
				"\n%s" % (
					self.scope.location(),
					self.tokeniser.number,
					' '.join(self.tokeniser.line),
					str(self.error)
				),
				'configuration'
			)
			return False
		return True

	def _enter (self,name):
		location = self.tokeniser.iterate()
		self.logger.debug("> %-16s | %s" % (location,self.tokeniser.params()),'configuration')

		if location not in self._structure[name]['sections']:
			return self.error.set('section %s is invalid in %s, %s' % (location,name,self.scope.location()))

		self.scope.enter(location)
		self.scope.to_context()

		class_name = self._structure[name]['sections'][location]
		instance = self._structure[class_name].get('class',None)
		if not instance:
			raise RuntimeError('This should not be happening, debug time !')

		if not instance.pre():
			return False

		if not self.dispatch(self._structure[name]['sections'][location]):
			return False

		if not instance.post():
			return False

		left = self.scope.leave()
		if not left:
			return self.error.set('closing too many parenthesis')
		self.scope.to_context()

		self.logger.debug("< %-16s | %s" % (left,self.tokeniser.params()),'configuration')
		return True

	def _run (self,name):
		command = self.tokeniser.iterate()
		self.logger.debug(". %-16s | %s" % (command,self.tokeniser.params()),'configuration')

		if not self.run(name,command):
			return False
		return True

	def dispatch (self,name):
		while True:
			self.tokeniser()

			if self.tokeniser.end == ';':
				if self._run(name):
					continue
				return False

			if self.tokeniser.end == '{':
				if self._enter(name):
					continue
				return False

			if self.tokeniser.end == '}':
				return True

			if not self.tokeniser.end:  # finished
				return True

			return self.error.set('invalid syntax line %d' % self.tokeniser.index_line)
		return False

	def section (self, name):
		if name not in self._structure:
			return self.error.set('option %s is not allowed here' % name)

		return self.dispatch(name)

	def run (self, name, command):
		# restore 'anounce attribute' to provide backward 3.4 compatibility
		if name == 'static' and command == 'attribute':
			command = 'attributes'
		if command not in self._structure[name]['commands']:
			return self.error.set('invalid keyword "%s"' % command)

		return self._structure[name]['class'].parse(name,command)

	def debug_check_route (self):
		# we are not really running the program, just want to ....
		if environment.settings().debug.route:
			from exabgp.configuration.check import check_message
			if check_message(self.neighbors,environment.settings().debug.route):
				sys.exit(0)
			sys.exit(1)

	def debug_self_check (self):
		# we are not really running the program, just want check the configuration validity
		if environment.settings().debug.selfcheck:
			from exabgp.configuration.check import check_neighbor
			if check_neighbor(self.neighbors):
				sys.exit(0)
			sys.exit(1)
Exemple #12
0
	def __init__ (self, configurations):
		_Configuration.__init__(self)
		self.api_encoder = environment.settings().api.encoder

		self._configurations = configurations

		self.error  = Error  ()
		self.scope  = Scope  ()

		self.tokeniser = Tokeniser(self.scope,self.error,self.logger)

		generic           = Section          (self.tokeniser,self.scope,self.error,self.logger)
		self.process      = ParseProcess     (self.tokeniser,self.scope,self.error,self.logger)
		self.template     = ParseTemplate    (self.tokeniser,self.scope,self.error,self.logger)
		self.neighbor     = ParseNeighbor    (self.tokeniser,self.scope,self.error,self.logger)
		self.family       = ParseFamily      (self.tokeniser,self.scope,self.error,self.logger)
		self.capability   = ParseCapability  (self.tokeniser,self.scope,self.error,self.logger)
		self.api          = ParseAPI         (self.tokeniser,self.scope,self.error,self.logger)
		self.api_send     = ParseSend        (self.tokeniser,self.scope,self.error,self.logger)
		self.api_receive  = ParseReceive     (self.tokeniser,self.scope,self.error,self.logger)
		self.static       = ParseStatic      (self.tokeniser,self.scope,self.error,self.logger)
		self.static_route = ParseStaticRoute (self.tokeniser,self.scope,self.error,self.logger)
		self.flow         = ParseFlow        (self.tokeniser,self.scope,self.error,self.logger)
		self.flow_route   = ParseFlowRoute   (self.tokeniser,self.scope,self.error,self.logger)
		self.flow_match   = ParseFlowMatch   (self.tokeniser,self.scope,self.error,self.logger)
		self.flow_then    = ParseFlowThen    (self.tokeniser,self.scope,self.error,self.logger)
		self.l2vpn        = ParseL2VPN       (self.tokeniser,self.scope,self.error,self.logger)
		self.vpls         = ParseVPLS        (self.tokeniser,self.scope,self.error,self.logger)
		self.operational  = ParseOperational (self.tokeniser,self.scope,self.error,self.logger)

		# We should check if name are unique when running Section.__init__

		self._structure = {
			'root': {
				'class':    generic,
				'commands': [],
				'sections': {
					'process': self.process.name,
					'neighbor': self.neighbor.name,
					'template': self.template.name,
				},
			},
			self.process.name: {
				'class':    self.process,
				'commands': self.process.known.keys(),
				'sections': {},
			},
			self.template.name: {
				'class':    self.template,
				'commands': self.template.known.keys(),
				'sections': {
					'family':      self.family.name,
					'capability':  self.capability.name,
					'api':         self.api.name,
					'static':      self.static.name,
					'flow':        self.flow.name,
					'l2vpn':       self.l2vpn.name,
					'operational': self.operational.name,
				},
			},
			self.neighbor.name: {
				'class':    self.neighbor,
				'commands': self.neighbor.known.keys(),
				'sections': {
					'family':      self.family.name,
					'capability':  self.capability.name,
					'api':         self.api.name,
					'static':      self.static.name,
					'flow':        self.flow.name,
					'l2vpn':       self.l2vpn.name,
					'operational': self.operational.name,
				},
			},
			self.family.name: {
				'class':    self.family,
				'commands': self.family.known.keys(),
				'sections': {
				},
			},
			self.capability.name: {
				'class':    self.capability,
				'commands': self.capability.known.keys(),
				'sections': {
				},
			},
			self.api.name: {
				'class':    self.api,
				'commands': self.api.known.keys(),
				'sections': {
					'send':    self.api_send.name,
					'receive': self.api_receive.name,
				},
			},
			self.api_send.name: {
				'class':    self.api_send,
				'commands': self.api_send.known.keys(),
				'sections': {
				},
			},
			self.api_receive.name: {
				'class':    self.api_receive,
				'commands': self.api_receive.known.keys(),
				'sections': {
				},
			},
			self.static.name: {
				'class':    self.static,
				'commands': 'route',
				'sections': {
					'route': self.static_route.name,
				},
			},
			self.static_route.name: {
				'class':    self.static_route,
				'commands': self.static_route.known.keys(),
				'sections': {
				},
			},
			self.flow.name: {
				'class':    self.flow,
				'commands': self.flow.known.keys(),
				'sections': {
					'route': self.flow_route.name,
				},
			},
			self.flow_route.name: {
				'class':    self.flow_route,
				'commands': self.flow_route.known.keys(),
				'sections': {
					'match': self.flow_match.name,
					'then':  self.flow_then.name,
				},
			},
			self.flow_match.name: {
				'class':    self.flow_match,
				'commands': self.flow_match.known.keys(),
				'sections': {
				},
			},
			self.flow_then.name: {
				'class':    self.flow_then,
				'commands': self.flow_then.known.keys(),
				'sections': {
				},
			},
			self.l2vpn.name: {
				'class':    self.l2vpn,
				'commands': self.l2vpn.known.keys(),
				'sections': {
					'vpls': self.vpls.name,
				},
			},
			self.vpls.name: {
				'class':    self.vpls,
				'commands': self.l2vpn.known.keys(),
				'sections': {
				},
			},
			self.operational.name: {
				'class':    self.operational,
				'commands': self.operational.known.keys(),
				'sections': {
				}
			},
		}

		self._neighbors = {}
		self._previous_neighbors = {}
Exemple #13
0
class Configuration (_Configuration):

	def __init__ (self, configurations):
		_Configuration.__init__(self)
		self.api_encoder = environment.settings().api.encoder

		self._configurations = configurations

		self.error  = Error  ()
		self.scope  = Scope  ()

		self.tokeniser = Tokeniser(self.scope,self.error,self.logger)

		generic           = Section          (self.tokeniser,self.scope,self.error,self.logger)
		self.process      = ParseProcess     (self.tokeniser,self.scope,self.error,self.logger)
		self.template     = ParseTemplate    (self.tokeniser,self.scope,self.error,self.logger)
		self.neighbor     = ParseNeighbor    (self.tokeniser,self.scope,self.error,self.logger)
		self.family       = ParseFamily      (self.tokeniser,self.scope,self.error,self.logger)
		self.capability   = ParseCapability  (self.tokeniser,self.scope,self.error,self.logger)
		self.api          = ParseAPI         (self.tokeniser,self.scope,self.error,self.logger)
		self.api_send     = ParseSend        (self.tokeniser,self.scope,self.error,self.logger)
		self.api_receive  = ParseReceive     (self.tokeniser,self.scope,self.error,self.logger)
		self.static       = ParseStatic      (self.tokeniser,self.scope,self.error,self.logger)
		self.static_route = ParseStaticRoute (self.tokeniser,self.scope,self.error,self.logger)
		self.flow         = ParseFlow        (self.tokeniser,self.scope,self.error,self.logger)
		self.flow_route   = ParseFlowRoute   (self.tokeniser,self.scope,self.error,self.logger)
		self.flow_match   = ParseFlowMatch   (self.tokeniser,self.scope,self.error,self.logger)
		self.flow_then    = ParseFlowThen    (self.tokeniser,self.scope,self.error,self.logger)
		self.l2vpn        = ParseL2VPN       (self.tokeniser,self.scope,self.error,self.logger)
		self.vpls         = ParseVPLS        (self.tokeniser,self.scope,self.error,self.logger)
		self.operational  = ParseOperational (self.tokeniser,self.scope,self.error,self.logger)

		# We should check if name are unique when running Section.__init__

		self._structure = {
			'root': {
				'class':    generic,
				'commands': [],
				'sections': {
					'process': self.process.name,
					'neighbor': self.neighbor.name,
					'template': self.template.name,
				},
			},
			self.process.name: {
				'class':    self.process,
				'commands': self.process.known.keys(),
				'sections': {},
			},
			self.template.name: {
				'class':    self.template,
				'commands': self.template.known.keys(),
				'sections': {
					'family':      self.family.name,
					'capability':  self.capability.name,
					'api':         self.api.name,
					'static':      self.static.name,
					'flow':        self.flow.name,
					'l2vpn':       self.l2vpn.name,
					'operational': self.operational.name,
				},
			},
			self.neighbor.name: {
				'class':    self.neighbor,
				'commands': self.neighbor.known.keys(),
				'sections': {
					'family':      self.family.name,
					'capability':  self.capability.name,
					'api':         self.api.name,
					'static':      self.static.name,
					'flow':        self.flow.name,
					'l2vpn':       self.l2vpn.name,
					'operational': self.operational.name,
				},
			},
			self.family.name: {
				'class':    self.family,
				'commands': self.family.known.keys(),
				'sections': {
				},
			},
			self.capability.name: {
				'class':    self.capability,
				'commands': self.capability.known.keys(),
				'sections': {
				},
			},
			self.api.name: {
				'class':    self.api,
				'commands': self.api.known.keys(),
				'sections': {
					'send':    self.api_send.name,
					'receive': self.api_receive.name,
				},
			},
			self.api_send.name: {
				'class':    self.api_send,
				'commands': self.api_send.known.keys(),
				'sections': {
				},
			},
			self.api_receive.name: {
				'class':    self.api_receive,
				'commands': self.api_receive.known.keys(),
				'sections': {
				},
			},
			self.static.name: {
				'class':    self.static,
				'commands': 'route',
				'sections': {
					'route': self.static_route.name,
				},
			},
			self.static_route.name: {
				'class':    self.static_route,
				'commands': self.static_route.known.keys(),
				'sections': {
				},
			},
			self.flow.name: {
				'class':    self.flow,
				'commands': self.flow.known.keys(),
				'sections': {
					'route': self.flow_route.name,
				},
			},
			self.flow_route.name: {
				'class':    self.flow_route,
				'commands': self.flow_route.known.keys(),
				'sections': {
					'match': self.flow_match.name,
					'then':  self.flow_then.name,
				},
			},
			self.flow_match.name: {
				'class':    self.flow_match,
				'commands': self.flow_match.known.keys(),
				'sections': {
				},
			},
			self.flow_then.name: {
				'class':    self.flow_then,
				'commands': self.flow_then.known.keys(),
				'sections': {
				},
			},
			self.l2vpn.name: {
				'class':    self.l2vpn,
				'commands': self.l2vpn.known.keys(),
				'sections': {
					'vpls': self.vpls.name,
				},
			},
			self.vpls.name: {
				'class':    self.vpls,
				'commands': self.l2vpn.known.keys(),
				'sections': {
				},
			},
			self.operational.name: {
				'class':    self.operational,
				'commands': self.operational.known.keys(),
				'sections': {
				}
			},
		}

		self._neighbors = {}
		self._previous_neighbors = {}

	def _clear (self):
		self.processes = {}
		self.neighbors = {}
		self._neighbors = {}
		self._previous_neighbors = {}

	# clear the parser data (ie: free memory)
	def _cleanup (self):
		self.error.clear()
		self.tokeniser.clear()
		self.scope.clear()

		self.process.clear()
		self.template.clear()
		self.neighbor.clear()
		self.family.clear()
		self.capability.clear()
		self.api.clear()
		self.api_send.clear()
		self.api_receive.clear()
		self.static.clear()
		self.static_route.clear()
		self.flow.clear()
		self.flow_route.clear()
		self.flow_match.clear()
		self.flow_then.clear()
		self.l2vpn.clear()
		self.vpls.clear()
		self.operational.clear()

	def _rollback_reload (self):
		self.neighbors = self._previous_neighbors
		self._neighbors = {}
		self._previous_neighbors = {}

	def _commit_reload (self):
		self.neighbors = self.neighbor.neighbors
		# XXX: Yes, we do not detect changes in processes and restart anything ..
		# XXX: This is a bug ..
		self.processes = self.process.processes
		self._neighbors = {}

		# installing in the neighbor the API routes
		for neighbor in self.neighbors:
			if neighbor in self._previous_neighbors:
				self.neighbors[neighbor].changes = self._previous_neighbors[neighbor].changes

		self._previous_neighbors = {}
		self._cleanup()

	def reload (self):
		try:
			return self._reload()
		except KeyboardInterrupt:
			return self.error.set('configuration reload aborted by ^C or SIGINT')
		except Error, exc:
			return self.error.set(
				'problem parsing configuration file line %d\n'
				'error message: %s' % (self.tokeniser.index_line, exc)
			)
		except StandardError, exc:
			if environment.settings().debug.configuration:
				raise
			return self.error.set(
				'problem parsing configuration file line %d\n'
				'error message: %s' % (self.tokeniser.index_line, exc)
			)
Exemple #14
0
    def __init__(self, configurations, text=False):
        _Configuration.__init__(self)
        self.api_encoder = environment.settings().api.encoder

        self._configurations = configurations
        self._text = text

        self.error = Error()
        self.scope = Scope()

        self.tokeniser = Tokeniser(self.scope, self.error, self.logger)

        generic = Section(self.tokeniser, self.scope, self.error, self.logger)
        self.process = ParseProcess(self.tokeniser, self.scope, self.error,
                                    self.logger)
        self.template = ParseTemplate(self.tokeniser, self.scope, self.error,
                                      self.logger)
        self.neighbor = ParseNeighbor(self.tokeniser, self.scope, self.error,
                                      self.logger)
        self.family = ParseFamily(self.tokeniser, self.scope, self.error,
                                  self.logger)
        self.capability = ParseCapability(self.tokeniser, self.scope,
                                          self.error, self.logger)
        self.api = ParseAPI(self.tokeniser, self.scope, self.error,
                            self.logger)
        self.api_send = ParseSend(self.tokeniser, self.scope, self.error,
                                  self.logger)
        self.api_receive = ParseReceive(self.tokeniser, self.scope, self.error,
                                        self.logger)
        self.static = ParseStatic(self.tokeniser, self.scope, self.error,
                                  self.logger)
        self.static_route = ParseStaticRoute(self.tokeniser, self.scope,
                                             self.error, self.logger)
        self.flow = ParseFlow(self.tokeniser, self.scope, self.error,
                              self.logger)
        self.flow_route = ParseFlowRoute(self.tokeniser, self.scope,
                                         self.error, self.logger)
        self.flow_match = ParseFlowMatch(self.tokeniser, self.scope,
                                         self.error, self.logger)
        self.flow_then = ParseFlowThen(self.tokeniser, self.scope, self.error,
                                       self.logger)
        self.l2vpn = ParseL2VPN(self.tokeniser, self.scope, self.error,
                                self.logger)
        self.vpls = ParseVPLS(self.tokeniser, self.scope, self.error,
                              self.logger)
        self.operational = ParseOperational(self.tokeniser, self.scope,
                                            self.error, self.logger)

        # We should check if name are unique when running Section.__init__

        self._structure = {
            'root': {
                'class': generic,
                'commands': [],
                'sections': {
                    'process': self.process.name,
                    'neighbor': self.neighbor.name,
                    'template': self.template.name,
                },
            },
            self.process.name: {
                'class': self.process,
                'commands': self.process.known.keys(),
                'sections': {},
            },
            self.template.name: {
                'class': self.template,
                'commands': self.template.known.keys(),
                'sections': {
                    'family': self.family.name,
                    'capability': self.capability.name,
                    'api': self.api.name,
                    'static': self.static.name,
                    'flow': self.flow.name,
                    'l2vpn': self.l2vpn.name,
                    'operational': self.operational.name,
                },
            },
            self.neighbor.name: {
                'class': self.neighbor,
                'commands': self.neighbor.known.keys(),
                'sections': {
                    'family': self.family.name,
                    'capability': self.capability.name,
                    'api': self.api.name,
                    'static': self.static.name,
                    'flow': self.flow.name,
                    'l2vpn': self.l2vpn.name,
                    'operational': self.operational.name,
                },
            },
            self.family.name: {
                'class': self.family,
                'commands': self.family.known.keys(),
                'sections': {},
            },
            self.capability.name: {
                'class': self.capability,
                'commands': self.capability.known.keys(),
                'sections': {},
            },
            self.api.name: {
                'class': self.api,
                'commands': self.api.known.keys(),
                'sections': {
                    'send': self.api_send.name,
                    'receive': self.api_receive.name,
                },
            },
            self.api_send.name: {
                'class': self.api_send,
                'commands': self.api_send.known.keys(),
                'sections': {},
            },
            self.api_receive.name: {
                'class': self.api_receive,
                'commands': self.api_receive.known.keys(),
                'sections': {},
            },
            self.static.name: {
                'class': self.static,
                'commands': ['route', 'attributes'],
                'sections': {
                    'route': self.static_route.name,
                },
            },
            self.static_route.name: {
                'class': self.static_route,
                'commands': self.static_route.known.keys(),
                'sections': {},
            },
            self.flow.name: {
                'class': self.flow,
                'commands': self.flow.known.keys(),
                'sections': {
                    'route': self.flow_route.name,
                },
            },
            self.flow_route.name: {
                'class': self.flow_route,
                'commands': self.flow_route.known.keys(),
                'sections': {
                    'match': self.flow_match.name,
                    'then': self.flow_then.name,
                },
            },
            self.flow_match.name: {
                'class': self.flow_match,
                'commands': self.flow_match.known.keys(),
                'sections': {},
            },
            self.flow_then.name: {
                'class': self.flow_then,
                'commands': self.flow_then.known.keys(),
                'sections': {},
            },
            self.l2vpn.name: {
                'class': self.l2vpn,
                'commands': self.l2vpn.known.keys(),
                'sections': {
                    'vpls': self.vpls.name,
                },
            },
            self.vpls.name: {
                'class': self.vpls,
                'commands': self.l2vpn.known.keys(),
                'sections': {},
            },
            self.operational.name: {
                'class': self.operational,
                'commands': self.operational.known.keys(),
                'sections': {}
            },
        }

        self._neighbors = {}
        self._previous_neighbors = {}
Exemple #15
0
class Configuration(_Configuration):
    def __init__(self, configurations, text=False):
        _Configuration.__init__(self)
        self.api_encoder = environment.settings().api.encoder

        self._configurations = configurations
        self._text = text

        self.error = Error()
        self.scope = Scope()

        self.tokeniser = Tokeniser(self.scope, self.error, self.logger)

        generic = Section(self.tokeniser, self.scope, self.error, self.logger)
        self.process = ParseProcess(self.tokeniser, self.scope, self.error,
                                    self.logger)
        self.template = ParseTemplate(self.tokeniser, self.scope, self.error,
                                      self.logger)
        self.neighbor = ParseNeighbor(self.tokeniser, self.scope, self.error,
                                      self.logger)
        self.family = ParseFamily(self.tokeniser, self.scope, self.error,
                                  self.logger)
        self.capability = ParseCapability(self.tokeniser, self.scope,
                                          self.error, self.logger)
        self.api = ParseAPI(self.tokeniser, self.scope, self.error,
                            self.logger)
        self.api_send = ParseSend(self.tokeniser, self.scope, self.error,
                                  self.logger)
        self.api_receive = ParseReceive(self.tokeniser, self.scope, self.error,
                                        self.logger)
        self.static = ParseStatic(self.tokeniser, self.scope, self.error,
                                  self.logger)
        self.static_route = ParseStaticRoute(self.tokeniser, self.scope,
                                             self.error, self.logger)
        self.flow = ParseFlow(self.tokeniser, self.scope, self.error,
                              self.logger)
        self.flow_route = ParseFlowRoute(self.tokeniser, self.scope,
                                         self.error, self.logger)
        self.flow_match = ParseFlowMatch(self.tokeniser, self.scope,
                                         self.error, self.logger)
        self.flow_then = ParseFlowThen(self.tokeniser, self.scope, self.error,
                                       self.logger)
        self.l2vpn = ParseL2VPN(self.tokeniser, self.scope, self.error,
                                self.logger)
        self.vpls = ParseVPLS(self.tokeniser, self.scope, self.error,
                              self.logger)
        self.operational = ParseOperational(self.tokeniser, self.scope,
                                            self.error, self.logger)

        # We should check if name are unique when running Section.__init__

        self._structure = {
            'root': {
                'class': generic,
                'commands': [],
                'sections': {
                    'process': self.process.name,
                    'neighbor': self.neighbor.name,
                    'template': self.template.name,
                },
            },
            self.process.name: {
                'class': self.process,
                'commands': self.process.known.keys(),
                'sections': {},
            },
            self.template.name: {
                'class': self.template,
                'commands': self.template.known.keys(),
                'sections': {
                    'family': self.family.name,
                    'capability': self.capability.name,
                    'api': self.api.name,
                    'static': self.static.name,
                    'flow': self.flow.name,
                    'l2vpn': self.l2vpn.name,
                    'operational': self.operational.name,
                },
            },
            self.neighbor.name: {
                'class': self.neighbor,
                'commands': self.neighbor.known.keys(),
                'sections': {
                    'family': self.family.name,
                    'capability': self.capability.name,
                    'api': self.api.name,
                    'static': self.static.name,
                    'flow': self.flow.name,
                    'l2vpn': self.l2vpn.name,
                    'operational': self.operational.name,
                },
            },
            self.family.name: {
                'class': self.family,
                'commands': self.family.known.keys(),
                'sections': {},
            },
            self.capability.name: {
                'class': self.capability,
                'commands': self.capability.known.keys(),
                'sections': {},
            },
            self.api.name: {
                'class': self.api,
                'commands': self.api.known.keys(),
                'sections': {
                    'send': self.api_send.name,
                    'receive': self.api_receive.name,
                },
            },
            self.api_send.name: {
                'class': self.api_send,
                'commands': self.api_send.known.keys(),
                'sections': {},
            },
            self.api_receive.name: {
                'class': self.api_receive,
                'commands': self.api_receive.known.keys(),
                'sections': {},
            },
            self.static.name: {
                'class': self.static,
                'commands': ['route', 'attributes'],
                'sections': {
                    'route': self.static_route.name,
                },
            },
            self.static_route.name: {
                'class': self.static_route,
                'commands': self.static_route.known.keys(),
                'sections': {},
            },
            self.flow.name: {
                'class': self.flow,
                'commands': self.flow.known.keys(),
                'sections': {
                    'route': self.flow_route.name,
                },
            },
            self.flow_route.name: {
                'class': self.flow_route,
                'commands': self.flow_route.known.keys(),
                'sections': {
                    'match': self.flow_match.name,
                    'then': self.flow_then.name,
                },
            },
            self.flow_match.name: {
                'class': self.flow_match,
                'commands': self.flow_match.known.keys(),
                'sections': {},
            },
            self.flow_then.name: {
                'class': self.flow_then,
                'commands': self.flow_then.known.keys(),
                'sections': {},
            },
            self.l2vpn.name: {
                'class': self.l2vpn,
                'commands': self.l2vpn.known.keys(),
                'sections': {
                    'vpls': self.vpls.name,
                },
            },
            self.vpls.name: {
                'class': self.vpls,
                'commands': self.l2vpn.known.keys(),
                'sections': {},
            },
            self.operational.name: {
                'class': self.operational,
                'commands': self.operational.known.keys(),
                'sections': {}
            },
        }

        self._neighbors = {}
        self._previous_neighbors = {}

    def _clear(self):
        self.processes = {}
        self.neighbors = {}
        self._neighbors = {}
        self._previous_neighbors = {}

    # clear the parser data (ie: free memory)
    def _cleanup(self):
        self.error.clear()
        self.tokeniser.clear()
        self.scope.clear()

        self.process.clear()
        self.template.clear()
        self.neighbor.clear()
        self.family.clear()
        self.capability.clear()
        self.api.clear()
        self.api_send.clear()
        self.api_receive.clear()
        self.static.clear()
        self.static_route.clear()
        self.flow.clear()
        self.flow_route.clear()
        self.flow_match.clear()
        self.flow_then.clear()
        self.l2vpn.clear()
        self.vpls.clear()
        self.operational.clear()

    def _rollback_reload(self):
        self.neighbors = self._previous_neighbors
        self._neighbors = {}
        self._previous_neighbors = {}

    def _commit_reload(self):
        self.neighbors = self.neighbor.neighbors
        # XXX: Yes, we do not detect changes in processes and restart anything ..
        # XXX: This is a bug ..
        self.processes = self.process.processes
        self._neighbors = {}

        # installing in the neighbor the API routes
        for neighbor in self.neighbors:
            if neighbor in self._previous_neighbors:
                self.neighbors[neighbor].changes = self._previous_neighbors[
                    neighbor].changes

        self._previous_neighbors = {}
        self._cleanup()

    def reload(self):
        try:
            return self._reload()
        except KeyboardInterrupt:
            return self.error.set(
                'configuration reload aborted by ^C or SIGINT')
        except Error, exc:
            if environment.settings().debug.configuration:
                raise
            return self.error.set(
                'problem parsing configuration file line %d\n'
                'error message: %s' % (self.tokeniser.index_line, exc))
        except StandardError, exc:
            if environment.settings().debug.configuration:
                raise
            return self.error.set(
                'problem parsing configuration file line %d\n'
                'error message: %s' % (self.tokeniser.index_line, exc))
Exemple #16
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