def test4_DistinctAttributes(self): atts1 = Attributes() atts1.add(LocalPreference(10)) atts2 = Attributes() atts2.add(LocalPreference(20)) self.assertNotEqual(atts1, atts2)
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)
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
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
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
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
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
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)
def local_preference(tokeniser): value = tokeniser() if not value.isdigit(): raise ValueError('invalid local preference %s' % value) return LocalPreference(value)