コード例 #1
0
ファイル: __init__.py プロジェクト: rendoaw/exabgp34-bgpls
	def unpack_message (cls, data, negotiated):
		logger = Logger()

		length = len(data)

		# This could be speed up massively by changing the order of the IF
		if length == 4 and data == '\x00\x00\x00\x00':
			return EOR(AFI.ipv4,SAFI.unicast,IN.ANNOUNCED)  # pylint: disable=E1101
		if length == 11 and data.startswith(EOR.NLRI.PREFIX):
			return EOR.unpack_message(data,negotiated)

		withdrawn, _attributes, announced = cls.split(data)
		attributes = Attributes.unpack(_attributes,negotiated)

		if not withdrawn:
			logger.parser("no withdrawn NLRI")
		if not announced:
			logger.parser("no announced NLRI")

		# Is the peer going to send us some Path Information with the route (AddPath)
		addpath = negotiated.addpath.receive(AFI(AFI.ipv4),SAFI(SAFI.unicast))

		# empty string for NoIP, the packed IP otherwise (without the 3/4 bytes of attributes headers)
		_nexthop = attributes.get(Attribute.CODE.NEXT_HOP,NoIP)
		nexthop = _nexthop.packed

		# XXX: NEXTHOP MUST NOT be the IP address of the receiving speaker.

		nlris = []
		while withdrawn:
			length,nlri = NLRI.unpack(AFI.ipv4,SAFI.unicast,withdrawn,addpath,nexthop,IN.WITHDRAWN)
			logger.parser(LazyFormat("parsed withdraw nlri %s payload " % nlri,withdrawn[:len(nlri)]))
			withdrawn = withdrawn[length:]
			nlris.append(nlri)

		while announced:
			length,nlri = NLRI.unpack(AFI.ipv4,SAFI.unicast,announced,addpath,nexthop,IN.ANNOUNCED)
			logger.parser(LazyFormat("parsed announce nlri %s payload " % nlri,announced[:len(nlri)]))
			announced = announced[length:]
			nlris.append(nlri)

		# required for 'is' comparaison
		UNREACH = [EMPTY_MPURNLRI,]
		REACH = [EMPTY_MPRNLRI,]

		unreach = attributes.pop(MPURNLRI.ID,UNREACH)
		reach = attributes.pop(MPRNLRI.ID,REACH)

		for mpr in unreach:
			nlris.extend(mpr.nlris)

		for mpr in reach:
			nlris.extend(mpr.nlris)

		if not attributes and not nlris:
			# Careful do not use == or != as the comparaison does not work
			if unreach is UNREACH and reach is REACH:
				return EOR(AFI(AFI.ipv4),SAFI(SAFI.unicast))
			if unreach is not UNREACH:
				return EOR(unreach[0].afi,unreach[0].safi)
			if reach is not REACH:
				return EOR(reach[0].afi,reach[0].safi)
			raise RuntimeError('This was not expected')

		return Update(nlris,attributes)
コード例 #2
0
 def __init__(self, afi, safi, action=None):
     self.nlris = [
         EOR.NLRI(afi, safi, action),
     ]
     self.attributes = Attributes()
コード例 #3
0
    def unpack_message(cls, data, negotiated):
        logger = Logger()

        length = len(data)

        # This could be speed up massively by changing the order of the IF
        if length == 4 and data == '\x00\x00\x00\x00':
            return EOR(AFI.ipv4, SAFI.unicast, IN.ANNOUNCED)  # pylint: disable=E1101
        if length == 11 and data.startswith(EOR.NLRI.PREFIX):
            return EOR.unpack_message(data, negotiated)

        withdrawn, _attributes, announced = cls.split(data)
        attributes = Attributes.unpack(_attributes, negotiated)

        if not withdrawn:
            logger.parser("no withdrawn NLRI")
        if not announced:
            logger.parser("no announced NLRI")

        # Is the peer going to send us some Path Information with the route (AddPath)
        addpath = negotiated.addpath.receive(AFI(AFI.ipv4), SAFI(SAFI.unicast))

        # empty string for NoIP, the packed IP otherwise (without the 3/4 bytes of attributes headers)
        _nexthop = attributes.get(Attribute.CODE.NEXT_HOP, NoIP)
        nexthop = _nexthop.packed

        # XXX: NEXTHOP MUST NOT be the IP address of the receiving speaker.

        nlris = []
        while withdrawn:
            length, nlri = NLRI.unpack(AFI.ipv4, SAFI.unicast, withdrawn,
                                       addpath, nexthop, IN.WITHDRAWN)
            logger.parser(
                LazyFormat("parsed withdraw nlri %s payload " % nlri,
                           withdrawn[:len(nlri)]))
            withdrawn = withdrawn[length:]
            nlris.append(nlri)

        while announced:
            length, nlri = NLRI.unpack(AFI.ipv4, SAFI.unicast, announced,
                                       addpath, nexthop, IN.ANNOUNCED)
            logger.parser(
                LazyFormat("parsed announce nlri %s payload " % nlri,
                           announced[:len(nlri)]))
            announced = announced[length:]
            nlris.append(nlri)

        # required for 'is' comparaison
        UNREACH = [
            EMPTY_MPURNLRI,
        ]
        REACH = [
            EMPTY_MPRNLRI,
        ]

        unreach = attributes.pop(MPURNLRI.ID, UNREACH)
        reach = attributes.pop(MPRNLRI.ID, REACH)

        for mpr in unreach:
            nlris.extend(mpr.nlris)

        for mpr in reach:
            nlris.extend(mpr.nlris)

        if not attributes and not nlris:
            # Careful do not use == or != as the comparaison does not work
            if unreach is UNREACH and reach is REACH:
                return EOR(AFI(AFI.ipv4), SAFI(SAFI.unicast))
            if unreach is not UNREACH:
                return EOR(unreach[0].afi, unreach[0].safi)
            if reach is not REACH:
                return EOR(reach[0].afi, reach[0].safi)
            raise RuntimeError('This was not expected')

        return Update(nlris, attributes)
コード例 #4
0
    def updates(self, grouped):
        if self._changes:
            dict_nlri = self._modify_nlri

            for family in self._seen:
                for change in self._seen[family].itervalues():
                    if change.index() not in self._modify_nlri:
                        change.nlri.action = OUT.WITHDRAW
                        self.insert_announced(change, True)

            for new in self._changes:
                self.insert_announced(new, True)
            self._changes = None
        # end of changes

        rr_announced = []

        for afi, safi in self._enhanced_refresh_start:
            rr_announced.append((afi, safi))
            yield Update(RouteRefresh(afi, safi, RouteRefresh.start),
                         Attributes())

        dict_sorted = self._modify_sorted
        dict_nlri = self._modify_nlri
        dict_attr = self._cache_attribute

        for attr_index, full_dict_change in dict_sorted.items():
            if self.cache:
                dict_change = {}
                for nlri_index, change in full_dict_change.iteritems():
                    family = change.nlri.family()
                    announced = self._seen.get(family, {})
                    if change.nlri.action == OUT.ANNOUNCE:
                        if nlri_index in announced:
                            old_change = announced[nlri_index]
                            # it is a duplicate route
                            if old_change.attributes.index(
                            ) == change.attributes.index(
                            ) and old_change.nlri.nexthop.index(
                            ) == change.nlri.nexthop.index():
                                continue
                    elif change.nlri.action == OUT.WITHDRAW:
                        if nlri_index not in announced:
                            if dict_nlri[
                                    nlri_index].nlri.action == OUT.ANNOUNCE:
                                continue
                    dict_change[nlri_index] = change
            else:
                dict_change = full_dict_change

            if not dict_change:
                continue

            attributes = dict_attr[attr_index].attributes

            # we NEED the copy provided by list() here as insert_announced can be called while we iterate
            changed = list(dict_change.itervalues())

            if grouped:
                update = Update(
                    [dict_nlri[nlri_index].nlri for nlri_index in dict_change],
                    attributes)
                for change in changed:
                    nlri_index = change.index()
                    del dict_sorted[attr_index][nlri_index]
                    del dict_nlri[nlri_index]
                # only yield once we have a consistent state, otherwise it will go wrong
                # as we will try to modify things we are using
                yield update
            else:
                updates = []
                for change in changed:
                    updates.append(Update([
                        change.nlri,
                    ], attributes))
                    nlri_index = change.index()
                    del dict_sorted[attr_index][nlri_index]
                    del dict_nlri[nlri_index]
                # only yield once we have a consistent state, otherwise it will go wrong
                # as we will try to modify things we are using
                for update in updates:
                    yield update

            if self.cache:
                announced = self._seen
                for change in changed:
                    if change.nlri.action == OUT.ANNOUNCE:
                        announced.setdefault(change.nlri.family(),
                                             {})[change.index()] = change
                    else:
                        family = change.nlri.family()
                        if family in announced:
                            announced[family].pop(change.index(), None)

        if rr_announced:
            for afi, safi in rr_announced:
                self._enhanced_refresh_start.remove((afi, safi))
                yield Update(RouteRefresh(afi, safi, RouteRefresh.end),
                             Attributes())

            for change in self._enhanced_refresh_delay:
                self.insert_announced(change, True)
            self.enhanced_refresh_delay = []

            for update in self.updates(grouped):
                yield update