Beispiel #1
0
def _NLRIFactory (afi,safi,bgp,has_multiple_path,nexthop,action):
	if has_multiple_path:
		path_identifier = bgp[:4]
		bgp = bgp[4:]
		length = 4
	else:
		path_identifier = ''
		length = 0

	labels,rd,mask,size,prefix,left = _nlrifactory(afi,safi,bgp,action)

	nlri = NLRI(afi,safi,prefix,mask,cachedNextHop(nexthop),action)

	if path_identifier:
		nlri.path_info = PathInfo(packed=path_identifier)
	if labels:
		nlri.labels = Labels(labels)
	if rd:
		nlri.rd = RouteDistinguisher(rd)

	return length + len(bgp) - len(left),nlri
Beispiel #2
0
def _NLRIFactory(afi, safi, bgp, has_multiple_path, nexthop, action):
    if has_multiple_path:
        path_identifier = bgp[:4]
        bgp = bgp[4:]
        length = 4
    else:
        path_identifier = ''
        length = 0

    labels, rd, mask, size, prefix, left = _nlrifactory(afi, safi, bgp, action)

    nlri = NLRI(afi, safi, prefix, mask, cachedNextHop(nexthop), action)

    if path_identifier:
        nlri.path_info = PathInfo(packed=path_identifier)
    if labels:
        nlri.labels = Labels(labels)
    if rd:
        nlri.rd = RouteDistinguisher(rd)

    return length + len(bgp) - len(left), nlri
Beispiel #3
0
    def _factory(self, data):
        if not data:
            return self

        # We do not care if the attribute are transitive or not as we do not redistribute
        flag = Flag(ord(data[0]))
        code = AID(ord(data[1]))

        if flag & Flag.EXTENDED_LENGTH:
            length = unpack('!H', data[2:4])[0]
            offset = 4
        else:
            length = ord(data[2])
            offset = 3

        if self.hasmp:
            if code not in (AID.MP_REACH_NLRI, AID.MP_UNREACH_NLRI):
                self.cacheable = False
                self.prefix = ''
        else:
            self.prefix += data[:offset + length]

        data = data[offset:]
        next = data[length:]
        attribute = data[:length]

        logger = Logger()
        logger.parser(
            LazyFormat(
                "parsing flag %x type %02x (%s) len %02x %s" %
                (flag, int(code), code, length, 'payload ' if length else ''),
                od, data[:length]))

        if code == AID.ORIGIN and flag.matches(Origin.FLAG):
            # This if block should never be called anymore ...
            if not self.add_from_cache(code, attribute):
                self.add(Origin(ord(attribute)), attribute)
            return self.factory(next)

        # only 2-4% of duplicated data - is it worth to cache ?
        if code == AID.AS_PATH and flag.matches(ASPath.FLAG):
            if length:
                # we store the AS4_PATH as AS_PATH, do not over-write
                if not self.has(code):
                    if not self.add_from_cache(code, attribute):
                        self.add(self.__new_ASPath(attribute), attribute)
            return self.factory(next)

        if code == AID.AS4_PATH and flag.matches(AS4Path.FLAG):
            if length:
                # ignore the AS4_PATH on new spekers as required by RFC 4893 section 4.1
                if not self.negotiated.asn4:
                    # This replace the old AS_PATH
                    if not self.add_from_cache(code, attribute):
                        self.add(self.__new_ASPath4(attribute), attribute)
            return self.factory(next)

        if code == AID.NEXT_HOP and flag.matches(NextHop.FLAG):
            # XXX: FIXME: we are double caching the NH (once in the class, once here)
            if not self.add_from_cache(code, attribute):
                self.add(cachedNextHop(attribute), attribute)
            return self.factory(next)

        if code == AID.MED and flag.matches(MED.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(MED(attribute), attribute)
            return self.factory(next)

        if code == AID.LOCAL_PREF and flag.matches(LocalPreference.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(LocalPreference(attribute), attribute)
            return self.factory(next)

        if code == AID.ATOMIC_AGGREGATE and flag.matches(AtomicAggregate.FLAG):
            if not self.add_from_cache(code, attribute):
                raise Notify(
                    3, 2, 'invalid ATOMIC_AGGREGATE %s' %
                    [hex(ord(_)) for _ in attribute])
            return self.factory(next)

        if code == AID.AGGREGATOR and flag.matches(Aggregator.FLAG):
            # AS4_AGGREGATOR are stored as AGGREGATOR - so do not overwrite if exists
            if not self.has(code):
                if not self.add_from_cache(AID.AGGREGATOR, attribute):
                    self.add(Aggregator(attribute), attribute)
            return self.factory(next)

        if code == AID.AS4_AGGREGATOR and flag.matches(Aggregator.FLAG):
            if not self.add_from_cache(AID.AGGREGATOR, attribute):
                self.add(Aggregator(attribute), attribute)
            return self.factory(next)

        if code == AID.COMMUNITY and flag.matches(Communities.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(self.__new_communities(attribute), attribute)
            return self.factory(next)

        if code == AID.ORIGINATOR_ID and flag.matches(OriginatorID.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(OriginatorID(AFI.ipv4, SAFI.unicast, data[:4]),
                         attribute)
            return self.factory(next)

        if code == AID.CLUSTER_LIST and flag.matches(ClusterList.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(ClusterList(attribute), attribute)
            return self.factory(next)

        if code == AID.EXTENDED_COMMUNITY and flag.matches(ECommunities.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(self.__new_extended_communities(attribute), attribute)
            return self.factory(next)

        if code == AID.AIGP and flag.matches(AIGP.FLAG):
            if self.negotiated.neighbor.aigp:
                if not self.add_from_cache(code, attribute):
                    self.add(AIGP(attribute), attribute)
            return self.factory(next)

        if code == AID.MP_UNREACH_NLRI and flag.matches(MPURNLRI.FLAG):
            self.hasmp = True

            # -- Reading AFI/SAFI
            data = data[:length]
            afi, safi = unpack('!HB', data[:3])
            offset = 3
            data = data[offset:]

            if (afi, safi) not in self.negotiated.families:
                raise Notify(
                    3, 0,
                    'presented a non-negotiated family %d/%d' % (afi, safi))

            # Is the peer going to send us some Path Information with the route (AddPath)
            addpath = self.negotiated.addpath.receive(afi, safi)

            # XXX: we do assume that it is an EOR. most likely harmless
            if not data:
                self.mp_withdraw.append(NLRIEOR(afi, safi, IN.announced))
                return self.factory(next)

            while data:
                length, nlri = self.nlriFactory(afi, safi, data, addpath, None,
                                                IN.withdrawn)
                self.mp_withdraw.append(nlri)
                data = data[length:]
                logger.parser(
                    LazyFormat("parsed withdraw mp nlri %s payload " % nlri,
                               od, data[:length]))

            return self.factory(next)

        if code == AID.MP_REACH_NLRI and flag.matches(MPRNLRI.FLAG):
            self.hasmp = True

            data = data[:length]
            # -- Reading AFI/SAFI
            afi, safi = unpack('!HB', data[:3])
            offset = 3

            # we do not want to accept unknown families
            if (afi, safi) not in self.negotiated.families:
                raise Notify(
                    3, 0,
                    'presented a non-negotiated family %d/%d' % (afi, safi))

            # -- Reading length of next-hop
            len_nh = ord(data[offset])
            offset += 1

            rd = 0

            # check next-hope size
            if afi == AFI.ipv4:
                if safi in (SAFI.unicast, SAFI.multicast):
                    if len_nh != 4:
                        raise Notify(
                            3, 0,
                            'invalid ipv4 unicast/multicast next-hop length %d expected 4'
                            % len_nh)
                elif safi in (SAFI.mpls_vpn, ):
                    if len_nh != 12:
                        raise Notify(
                            3, 0,
                            'invalid ipv4 mpls_vpn next-hop length %d expected 12'
                            % len_nh)
                    rd = 8
                elif safi in (SAFI.flow_ip, ):
                    if len_nh not in (0, 4):
                        raise Notify(
                            3, 0,
                            'invalid ipv4 flow_ip next-hop length %d expected 4'
                            % len_nh)
                elif safi in (SAFI.flow_vpn, ):
                    if len_nh not in (0, 4):
                        raise Notify(
                            3, 0,
                            'invalid ipv4 flow_vpn next-hop length %d expected 4'
                            % len_nh)
            elif afi == AFI.ipv6:
                if safi in (SAFI.unicast, ):
                    if len_nh not in (16, 32):
                        raise Notify(
                            3, 0,
                            'invalid ipv6 unicast next-hop length %d expected 16 or 32'
                            % len_nh)
                elif safi in (SAFI.mpls_vpn, ):
                    if len_nh not in (24, 40):
                        raise Notify(
                            3, 0,
                            'invalid ipv6 mpls_vpn next-hop length %d expected 24 or 40'
                            % len_nh)
                    rd = 8
                elif safi in (SAFI.flow_ip, ):
                    if len_nh not in (0, 16, 32):
                        raise Notify(
                            3, 0,
                            'invalid ipv6 flow_ip next-hop length %d expected 0, 16 or 32'
                            % len_nh)
                elif safi in (SAFI.flow_vpn, ):
                    if len_nh not in (0, 16, 32):
                        raise Notify(
                            3, 0,
                            'invalid ipv6 flow_vpn next-hop length %d expected 0, 16 or 32'
                            % len_nh)
            size = len_nh - rd

            # XXX: FIXME: GET IT FROM CACHE HERE ?
            nh = data[offset + rd:offset + rd + size]

            # chech the RD is well zero
            if rd and sum([int(ord(_)) for _ in data[offset:8]]) != 0:
                raise Notify(
                    3, 0,
                    "MP_REACH_NLRI next-hop's route-distinguisher must be zero"
                )

            offset += len_nh

            # Skip a reserved bit as somone had to bug us !
            reserved = ord(data[offset])
            offset += 1

            if reserved != 0:
                raise Notify(3, 0,
                             'the reserved bit of MP_REACH_NLRI is not zero')

            # Is the peer going to send us some Path Information with the route (AddPath)
            addpath = self.negotiated.addpath.receive(afi, safi)

            # Reading the NLRIs
            data = data[offset:]

            while data:
                length, nlri = self.nlriFactory(afi, safi, data, addpath, nh,
                                                IN.announced)
                self.mp_announce.append(nlri)
                logger.parser(
                    LazyFormat("parsed announce mp nlri %s payload " % nlri,
                               od, data[:length]))
                data = data[length:]
            return self.factory(next)

        if flag & Flag.TRANSITIVE:
            if code in self.known_attributes:
                # XXX: FIXME: we should really close the session
                logger.parser(
                    'ignoring implemented invalid transitive attribute (code 0x%02X, flag 0x%02X)'
                    % (code, flag))
                return self.factory(next)

            if not self.add_from_cache(code, attribute):
                self.add(UnknownAttribute(code, flag, attribute), attribute)
            return self.factory(next)

        logger.parser(
            'ignoring non-transitive attribute (code 0x%02X, flag 0x%02X)' %
            (code, flag))
        return self.factory(next)
Beispiel #4
0
def _FlowNLRIFactory (afi,safi,nexthop,bgp,action):
	logger = Logger()
	logger.parser(LazyFormat("parsing flow nlri payload ",od,bgp))

	total = len(bgp)
	length,bgp = ord(bgp[0]),bgp[1:]

	if length & 0xF0 == 0xF0:  # bigger than 240
		extra,bgp = ord(bgp[0]),bgp[1:]
		length = ((length & 0x0F) << 16) + extra

	if length > len(bgp):
		raise Notify(3,10,'invalid length at the start of the the flow')

	bgp = bgp[:length]
	nlri = FlowNLRI(afi,safi)
	nlri.action = action

	if nexthop:
		nlri.nexthop = cachedNextHop(nexthop)

	if safi == SAFI.flow_vpn:
		nlri.rd = RouteDistinguisher(bgp[:8])
		bgp = bgp[8:]

	seen = []

	while bgp:
		what,bgp = ord(bgp[0]),bgp[1:]

		if what not in decode.get(afi,{}):
			raise Notify(3,10,'unknown flowspec component received for address family %d' % what)

		seen.append(what)
		if sorted(seen) != seen:
			raise Notify(3,10,'components are not sent in the right order %s' % seen)

		decoder = decode[afi][what]
		klass = factory[afi][what]

		if decoder == 'prefix':
			if afi == AFI.ipv4:
				_,rd,mask,size,prefix,left = _nlrifactory(afi,safi,bgp,action)
				adding = klass(prefix,mask)
				if not nlri.add(adding):
					raise Notify(3,10,'components are incompatible (two sources, two destinations, mix ipv4/ipv6) %s' % seen)
				logger.parser(LazyFormat("added flow %s (%s) payload " % (klass.NAME,adding),od,bgp[:-len(left)]))
				bgp = left
			else:
				byte,bgp = bgp[1],bgp[0]+bgp[2:]
				offset = ord(byte)
				_,rd,mask,size,prefix,left = _nlrifactory(afi,safi,bgp,action)
				adding = klass(prefix,mask,offset)
				if not nlri.add(adding):
					raise Notify(3,10,'components are incompatible (two sources, two destinations, mix ipv4/ipv6) %s' % seen)
				logger.parser(LazyFormat("added flow %s (%s) payload " % (klass.NAME,adding),od,bgp[:-len(left)]))
				bgp = left
		else:
			end = False
			while not end:
				byte,bgp = ord(bgp[0]),bgp[1:]
				end = CommonOperator.eol(byte)
				operator = CommonOperator.operator(byte)
				length = CommonOperator.length(byte)
				value,bgp = bgp[:length],bgp[length:]
				adding = klass.decoder(value)
				nlri.add(klass(operator,adding))
				logger.parser(LazyFormat("added flow %s (%s) operator %d len %d payload " % (klass.NAME,adding,byte,length),od,value))

	return total-len(bgp),nlri
Beispiel #5
0
    def _factory(self, data):
        if not data:
            return self

            # We do not care if the attribute are transitive or not as we do not redistribute
        flag = Flag(ord(data[0]))
        code = AID(ord(data[1]))

        if flag & Flag.EXTENDED_LENGTH:
            length = unpack("!H", data[2:4])[0]
            offset = 4
        else:
            length = ord(data[2])
            offset = 3

        if self.hasmp:
            if code not in (AID.MP_REACH_NLRI, AID.MP_UNREACH_NLRI):
                self.cacheable = False
                self.prefix = ""
        else:
            self.prefix += data[: offset + length]

        data = data[offset:]
        next = data[length:]
        attribute = data[:length]

        logger = Logger()
        logger.parser(
            LazyFormat(
                "parsing flag %x type %02x (%s) len %02x %s"
                % (flag, int(code), code, length, "payload " if length else ""),
                od,
                data[:length],
            )
        )

        if code == AID.ORIGIN and flag.matches(Origin.FLAG):
            # This if block should never be called anymore ...
            if not self.add_from_cache(code, attribute):
                self.add(Origin(ord(attribute)), attribute)
            return self.factory(next)

            # only 2-4% of duplicated data - is it worth to cache ?
        if code == AID.AS_PATH and flag.matches(ASPath.FLAG):
            if length:
                # we store the AS4_PATH as AS_PATH, do not over-write
                if not self.has(code):
                    if not self.add_from_cache(code, attribute):
                        self.add(self.__new_ASPath(attribute), attribute)
            return self.factory(next)

        if code == AID.AS4_PATH and flag.matches(AS4Path.FLAG):
            if length:
                # ignore the AS4_PATH on new spekers as required by RFC 4893 section 4.1
                if not self.negotiated.asn4:
                    # This replace the old AS_PATH
                    if not self.add_from_cache(code, attribute):
                        self.add(self.__new_ASPath4(attribute), attribute)
            return self.factory(next)

        if code == AID.NEXT_HOP and flag.matches(NextHop.FLAG):
            # XXX: FIXME: we are double caching the NH (once in the class, once here)
            if not self.add_from_cache(code, attribute):
                self.add(cachedNextHop(attribute), attribute)
            return self.factory(next)

        if code == AID.MED and flag.matches(MED.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(MED(attribute), attribute)
            return self.factory(next)

        if code == AID.LOCAL_PREF and flag.matches(LocalPreference.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(LocalPreference(attribute), attribute)
            return self.factory(next)

        if code == AID.ATOMIC_AGGREGATE and flag.matches(AtomicAggregate.FLAG):
            if not self.add_from_cache(code, attribute):
                raise Notify(3, 2, "invalid ATOMIC_AGGREGATE %s" % [hex(ord(_)) for _ in attribute])
            return self.factory(next)

        if code == AID.AGGREGATOR and flag.matches(Aggregator.FLAG):
            # AS4_AGGREGATOR are stored as AGGREGATOR - so do not overwrite if exists
            if not self.has(code):
                if not self.add_from_cache(AID.AGGREGATOR, attribute):
                    self.add(Aggregator(attribute), attribute)
            return self.factory(next)

        if code == AID.AS4_AGGREGATOR and flag.matches(Aggregator.FLAG):
            if not self.add_from_cache(AID.AGGREGATOR, attribute):
                self.add(Aggregator(attribute), attribute)
            return self.factory(next)

        if code == AID.COMMUNITY and flag.matches(Communities.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(self.__new_communities(attribute), attribute)
            return self.factory(next)

        if code == AID.ORIGINATOR_ID and flag.matches(OriginatorID.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(OriginatorID(AFI.ipv4, SAFI.unicast, data[:4]), attribute)
            return self.factory(next)

        if code == AID.CLUSTER_LIST and flag.matches(ClusterList.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(ClusterList(attribute), attribute)
            return self.factory(next)

        if code == AID.EXTENDED_COMMUNITY and flag.matches(ECommunities.FLAG):
            if not self.add_from_cache(code, attribute):
                self.add(self.__new_extended_communities(attribute), attribute)
            return self.factory(next)

        if code == AID.AIGP and flag.matches(AIGP.FLAG):
            if self.negotiated.neighbor.aigp:
                if not self.add_from_cache(code, attribute):
                    self.add(AIGP(attribute), attribute)
            return self.factory(next)

        if code == AID.MP_UNREACH_NLRI and flag.matches(MPURNLRI.FLAG):
            self.hasmp = True

            # -- Reading AFI/SAFI
            data = data[:length]
            afi, safi = unpack("!HB", data[:3])
            offset = 3
            data = data[offset:]

            if (afi, safi) not in self.negotiated.families:
                raise Notify(3, 0, "presented a non-negotiated family %d/%d" % (afi, safi))

                # Is the peer going to send us some Path Information with the route (AddPath)
            addpath = self.negotiated.addpath.receive(afi, safi)

            # XXX: we do assume that it is an EOR. most likely harmless
            if not data:
                self.mp_withdraw.append(NLRIEOR(afi, safi, IN.announced))
                return self.factory(next)

            while data:
                length, nlri = self.nlriFactory(afi, safi, data, addpath, None, IN.withdrawn)
                self.mp_withdraw.append(nlri)
                data = data[length:]
                logger.parser(LazyFormat("parsed withdraw mp nlri %s payload " % nlri, od, data[:length]))

            return self.factory(next)

        if code == AID.MP_REACH_NLRI and flag.matches(MPRNLRI.FLAG):
            self.hasmp = True

            data = data[:length]
            # -- Reading AFI/SAFI
            afi, safi = unpack("!HB", data[:3])
            offset = 3

            # we do not want to accept unknown families
            if (afi, safi) not in self.negotiated.families:
                raise Notify(3, 0, "presented a non-negotiated family %d/%d" % (afi, safi))

                # -- Reading length of next-hop
            len_nh = ord(data[offset])
            offset += 1

            rd = 0

            # check next-hope size
            if afi == AFI.ipv4:
                if safi in (SAFI.unicast, SAFI.multicast):
                    if len_nh != 4:
                        raise Notify(3, 0, "invalid ipv4 unicast/multicast next-hop length %d expected 4" % len_nh)
                elif safi in (SAFI.mpls_vpn,):
                    if len_nh != 12:
                        raise Notify(3, 0, "invalid ipv4 mpls_vpn next-hop length %d expected 12" % len_nh)
                    rd = 8
                elif safi in (SAFI.flow_ip,):
                    if len_nh not in (0, 4):
                        raise Notify(3, 0, "invalid ipv4 flow_ip next-hop length %d expected 4" % len_nh)
                elif safi in (SAFI.flow_vpn,):
                    if len_nh not in (0, 4):
                        raise Notify(3, 0, "invalid ipv4 flow_vpn next-hop length %d expected 4" % len_nh)
            elif afi == AFI.ipv6:
                if safi in (SAFI.unicast,):
                    if len_nh not in (16, 32):
                        raise Notify(3, 0, "invalid ipv6 unicast next-hop length %d expected 16 or 32" % len_nh)
                elif safi in (SAFI.mpls_vpn,):
                    if len_nh not in (24, 40):
                        raise Notify(3, 0, "invalid ipv6 mpls_vpn next-hop length %d expected 24 or 40" % len_nh)
                    rd = 8
                elif safi in (SAFI.flow_ip,):
                    if len_nh not in (0, 16, 32):
                        raise Notify(3, 0, "invalid ipv6 flow_ip next-hop length %d expected 0, 16 or 32" % len_nh)
                elif safi in (SAFI.flow_vpn,):
                    if len_nh not in (0, 16, 32):
                        raise Notify(3, 0, "invalid ipv6 flow_vpn next-hop length %d expected 0, 16 or 32" % len_nh)
            size = len_nh - rd

            # XXX: FIXME: GET IT FROM CACHE HERE ?
            nh = data[offset + rd : offset + rd + size]

            # chech the RD is well zero
            if rd and sum([int(ord(_)) for _ in data[offset:8]]) != 0:
                raise Notify(3, 0, "MP_REACH_NLRI next-hop's route-distinguisher must be zero")

            offset += len_nh

            # Skip a reserved bit as somone had to bug us !
            reserved = ord(data[offset])
            offset += 1

            if reserved != 0:
                raise Notify(3, 0, "the reserved bit of MP_REACH_NLRI is not zero")

                # Is the peer going to send us some Path Information with the route (AddPath)
            addpath = self.negotiated.addpath.receive(afi, safi)

            # Reading the NLRIs
            data = data[offset:]

            while data:
                length, nlri = self.nlriFactory(afi, safi, data, addpath, nh, IN.announced)
                self.mp_announce.append(nlri)
                logger.parser(LazyFormat("parsed announce mp nlri %s payload " % nlri, od, data[:length]))
                data = data[length:]
            return self.factory(next)

        if flag & Flag.TRANSITIVE:
            if code in self.known_attributes:
                # XXX: FIXME: we should really close the session
                logger.parser(
                    "ignoring implemented invalid transitive attribute (code 0x%02X, flag 0x%02X)" % (code, flag)
                )
                return self.factory(next)

            if not self.add_from_cache(code, attribute):
                self.add(UnknownAttribute(code, flag, attribute), attribute)
            return self.factory(next)

        logger.parser("ignoring non-transitive attribute (code 0x%02X, flag 0x%02X)" % (code, flag))
        return self.factory(next)
Beispiel #6
0
def _FlowNLRIFactory(afi, safi, nexthop, bgp, action):
    logger = Logger()
    logger.parser(LazyFormat("parsing flow nlri payload ", od, bgp))

    total = len(bgp)
    length, bgp = ord(bgp[0]), bgp[1:]

    if length & 0xF0 == 0xF0:  # bigger than 240
        extra, bgp = ord(bgp[0]), bgp[1:]
        length = ((length & 0x0F) << 16) + extra

    if length > len(bgp):
        raise Notify(3, 10, 'invalid length at the start of the the flow')

    bgp = bgp[:length]
    nlri = FlowNLRI(afi, safi)
    nlri.action = action

    if nexthop:
        nlri.nexthop = cachedNextHop(nexthop)

    if safi == SAFI.flow_vpn:
        nlri.rd = RouteDistinguisher(bgp[:8])
        bgp = bgp[8:]

    seen = []

    while bgp:
        what, bgp = ord(bgp[0]), bgp[1:]

        if what not in decode.get(afi, {}):
            raise Notify(
                3, 10,
                'unknown flowspec component received for address family %d' %
                what)

        seen.append(what)
        if sorted(seen) != seen:
            raise Notify(
                3, 10, 'components are not sent in the right order %s' % seen)

        decoder = decode[afi][what]
        klass = factory[afi][what]

        if decoder == 'prefix':
            if afi == AFI.ipv4:
                _, rd, mask, size, prefix, left = _nlrifactory(
                    afi, safi, bgp, action)
                adding = klass(prefix, mask)
                if not nlri.add(adding):
                    raise Notify(
                        3, 10,
                        'components are incompatible (two sources, two destinations, mix ipv4/ipv6) %s'
                        % seen)
                logger.parser(
                    LazyFormat(
                        "added flow %s (%s) payload " % (klass.NAME, adding),
                        od, bgp[:-len(left)]))
                bgp = left
            else:
                byte, bgp = bgp[1], bgp[0] + bgp[2:]
                offset = ord(byte)
                _, rd, mask, size, prefix, left = _nlrifactory(
                    afi, safi, bgp, action)
                adding = klass(prefix, mask, offset)
                if not nlri.add(adding):
                    raise Notify(
                        3, 10,
                        'components are incompatible (two sources, two destinations, mix ipv4/ipv6) %s'
                        % seen)
                logger.parser(
                    LazyFormat(
                        "added flow %s (%s) payload " % (klass.NAME, adding),
                        od, bgp[:-len(left)]))
                bgp = left
        else:
            end = False
            while not end:
                byte, bgp = ord(bgp[0]), bgp[1:]
                end = CommonOperator.eol(byte)
                operator = CommonOperator.operator(byte)
                length = CommonOperator.length(byte)
                value, bgp = bgp[:length], bgp[length:]
                adding = klass.decoder(value)
                nlri.add(klass(operator, adding))
                logger.parser(
                    LazyFormat(
                        "added flow %s (%s) operator %d len %d payload " %
                        (klass.NAME, adding, byte, length), od, value))

    return total - len(bgp), nlri