예제 #1
0
    def test4_DistinctAttributes(self):
        atts1 = Attributes()
        atts1.add(LocalPreference(10))

        atts2 = Attributes()
        atts2.add(LocalPreference(20))

        self.assertNotEqual(atts1, atts2)
예제 #2
0
    def test5_SameAttributes(self):
        atts1 = Attributes()
        atts1.add(LocalPreference(10))

        atts2 = Attributes()
        atts2.add(LocalPreference(10))

        self.assertEqual(hash(atts1), hash(atts2))
        self.assertEqual(atts1, atts2)
예제 #3
0
    def pack(self, negotiated, with_default=True, add_mp={}):
        local_asn = negotiated.local_as
        peer_asn = negotiated.peer_as

        message = ''

        default = {
            Attribute.CODE.ORIGIN:
            lambda l, r: Origin(Origin.IGP),
            #Attribute.CODE.AS_PATH: lambda l,r: ASPath([],[]) if l == r else ASPath([local_asn,],[]),
            Attribute.CODE.LOCAL_PREF:
            lambda l, r: LocalPreference(100) if l == r else NOTHING,
        }

        if hasattr(negotiated.neighbor, 'bgpsec'):
            if negotiated.neighbor.bgpsec:
                default[Attribute.CODE.BGPSEC] = lambda l, r: BGPSEC(
                    negotiated, add_mp)
            else:
                default[Attribute.CODE.AS_PATH] = lambda l, r: ASPath([], [
                ]) if l == r else ASPath([
                    local_asn,
                ], [])

        check = {
            Attribute.CODE.NEXT_HOP: lambda l, r, nh: nh.ipv4() is True,
            Attribute.CODE.LOCAL_PREF: lambda l, r, nh: l == r,
        }

        keys = self.keys()
        alls = set(keys + default.keys() if with_default else [])

        for code in sorted(alls):
            if code in (Attribute.CODE.INTERNAL_SPLIT,
                        Attribute.CODE.INTERNAL_WATCHDOG,
                        Attribute.CODE.INTERNAL_WITHDRAW,
                        Attribute.CODE.INTERNAL_NAME):
                continue

            if code not in keys and code in default:
                message += default[code](local_asn, peer_asn).pack(negotiated)
                continue

            attribute = self[code]

            if code in check and not check[code](local_asn, peer_asn,
                                                 attribute):
                continue

            if code in Attributes.MULTIPLE:
                for attr in attribute:
                    message += attr.pack(negotiated)
            else:
                message += attribute.pack(negotiated)

        return message
예제 #4
0
    def pack(self, negotiated, with_default=True):
        asn4 = negotiated.asn4
        local_asn = negotiated.local_as
        peer_asn = negotiated.peer_as

        if negotiated.neighbor.aigp is None:
            aigp = True if local_asn == peer_asn else False
        else:
            aigp = negotiated.neighbor.aigp

        message = ''

        default = {
            AID.ORIGIN:
            lambda l, r: Origin(Origin.IGP),
            AID.AS_PATH:
            lambda l, r: ASPath([], []) if l == r else ASPath([
                local_asn,
            ], []),
            AID.LOCAL_PREF:
            lambda l, r: LocalPreference('\x00\x00\x00d')
            if l == r else NOTHING,
        }

        check = {
            AID.NEXT_HOP: lambda l, r, nh: nh.afi == AFI.ipv4,
            AID.LOCAL_PREF: lambda l, r, nh: l == r,
        }

        if with_default:
            keys = set(self.keys() + default.keys())
        else:
            keys = set(self.keys())

        # AGGREGATOR generate both AGGREGATOR and AS4_AGGREGATOR
        for code in sorted(keys):
            if code in (AID.INTERNAL_SPLIT, AID.INTERNAL_WATCHDOG,
                        AID.INTERNAL_WITHDRAW):
                continue
            if code in self:
                if code == AID.AIGP and not aigp:
                    continue
                if code in check:
                    if check[code](local_asn, peer_asn, self[code]):
                        message += self[code].pack(asn4)
                        continue
                else:
                    message += self[code].pack(asn4)
                    continue
            else:
                if code in default:
                    message += default[code](local_asn, peer_asn).pack(asn4)

        return message
예제 #5
0
    def pack(self, negotiated, with_default=True, add_mp={}):
        local_asn = negotiated.local_as
        peer_asn = negotiated.peer_as

        message = b''

        default = {
            Attribute.CODE.ORIGIN:
            lambda left, right: Origin(Origin.IGP),
            #Attribute.CODE.AS_PATH: lambda left,right: ASPath([],[]) if left == right else ASPath([local_asn,],[]),
            Attribute.CODE.LOCAL_PREF:
            lambda left, right: LocalPreference(100)
            if left == right else NOTHING,
        }

        if hasattr(negotiated.neighbor, 'bgpsec'):
            if negotiated.neighbor.bgpsec:
                default[Attribute.CODE.BGPSEC] = lambda l, r: BGPSEC(
                    negotiated, add_mp)
            else:
                default[Attribute.CODE.AS_PATH] = lambda l, r: ASPath([], [
                ]) if l == r else ASPath([
                    local_asn,
                ], [])

        skip = {
            Attribute.CODE.NEXT_HOP:
            lambda left, right, nh: nh.ipv4() is not True,
            Attribute.CODE.LOCAL_PREF: lambda left, right, nh: left != right,
        }

        keys = list(self)
        alls = set(keys + list(default) if with_default else [])

        for code in sorted(alls):
            if code in Attributes.INTERNAL:
                continue

            if code not in keys and code in default:
                message += default[code](local_asn, peer_asn).pack(negotiated)
                continue

            attribute = self[code]

            if code in skip and skip[code](local_asn, peer_asn, attribute):
                continue

            message += attribute.pack(negotiated)

        return message
예제 #6
0
    def pack(self, negotiated, with_default=True):
        local_asn = negotiated.local_as
        peer_asn = negotiated.peer_as

        message = ''

        default = {
            Attribute.CODE.ORIGIN:
            lambda l, r: Origin(Origin.IGP),
            Attribute.CODE.AS_PATH:
            lambda l, r: ASPath([], []) if l == r else ASPath([
                local_asn,
            ], []),
            Attribute.CODE.LOCAL_PREF:
            lambda l, r: LocalPreference(100) if l == r else NOTHING,
        }

        skip = {
            Attribute.CODE.NEXT_HOP: lambda l, r, nh: nh.ipv4() is not True,
            Attribute.CODE.LOCAL_PREF: lambda l, r, nh: l != r,
        }

        keys = self.keys()
        alls = set(keys + default.keys() if with_default else [])

        for code in sorted(alls):
            if code in (Attribute.CODE.INTERNAL_SPLIT,
                        Attribute.CODE.INTERNAL_WATCHDOG,
                        Attribute.CODE.INTERNAL_WITHDRAW,
                        Attribute.CODE.INTERNAL_NAME):
                continue

            if code not in keys and code in default:
                message += default[code](local_asn, peer_asn).pack(negotiated)
                continue

            attribute = self[code]

            if code in skip and skip[code](local_asn, peer_asn, attribute):
                continue

            if code in Attributes.MULTIPLE:
                for attr in attribute:
                    message += attr.pack(negotiated)
            else:
                message += attribute.pack(negotiated)

        return message
예제 #7
0
    def pack(self, negotiated, with_default=True):
        local_asn = negotiated.local_as
        peer_asn = negotiated.peer_as

        message = ''

        default = {
            Attribute.CODE.ORIGIN:
            lambda l, r: Origin(Origin.IGP),  # noqa
            Attribute.CODE.AS_PATH:
            lambda l, r: ASPath([], []) if l == r else ASPath([
                local_asn,
            ], []),  # noqa
            Attribute.CODE.LOCAL_PREF:
            lambda l, r: LocalPreference(100) if l == r else NOTHING,  # noqa
        }

        check = {
            Attribute.CODE.NEXT_HOP:
            lambda l, r, nh: nh.ipv4() == True,  # noqa
            Attribute.CODE.LOCAL_PREF: lambda l, r, nh: l == r,
        }

        if with_default:
            keys = set(self.keys() + default.keys())
        else:
            keys = set(self.keys())

        for code in sorted(keys):
            if code in (Attribute.CODE.INTERNAL_SPLIT,
                        Attribute.CODE.INTERNAL_WATCHDOG,
                        Attribute.CODE.INTERNAL_WITHDRAW,
                        Attribute.CODE.INTERNAL_NAME):
                continue
            if code in self:
                if code in check:
                    if check[code](local_asn, peer_asn, self[code]):
                        message += self[code].pack(negotiated)
                        continue
                else:
                    message += self[code].pack(negotiated)
                    continue
            else:
                if code in default:
                    message += default[code](local_asn,
                                             peer_asn).pack(negotiated)

        return message
예제 #8
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)
예제 #9
0
파일: parser.py 프로젝트: xw2060/exabgp
def local_preference(tokeniser):
    value = tokeniser()
    if not value.isdigit():
        raise ValueError('invalid local preference %s' % value)
    return LocalPreference(value)