def unpack (cls, data, negotiated): nlris = [] # -- Reading AFI/SAFI afi,safi = unpack('!HB',data[:3]) offset = 3 data = data[offset:] if negotiated and (afi,safi) not in negotiated.families: raise Notify(3,0,'presented a non-negotiated family %s %s' % (AFI(afi),SAFI(safi))) # Is the peer going to send us some Path Information with the route (AddPath) addpath = negotiated.addpath.receive(afi,safi) while data: length,nlri = NLRI.unpack(afi,safi,data,addpath,None,IN.WITHDRAWN) nlris.append(nlri) data = data[length:] # logger.parser(LazyFormat("parsed withdraw mp nlri %s payload " % nlri,data[:length])) return cls(afi,safi,nlris)
def unpack(cls, data, negotiated): nlris = [] # -- Reading AFI/SAFI afi, safi = unpack('!HB', data[:3]) offset = 3 data = data[offset:] if negotiated and (afi, safi) not in negotiated.families: raise Notify( 3, 0, 'presented a non-negotiated family %s %s' % (AFI(afi), SAFI(safi))) # Is the peer going to send us some Path Information with the route (AddPath) addpath = negotiated.addpath.receive(afi, safi) while data: length, nlri = NLRI.unpack(afi, safi, data, addpath, None, IN.WITHDRAWN) nlris.append(nlri) data = data[length:] # logger.parser(LazyFormat("parsed withdraw mp nlri %s payload " % nlri,data[:length])) return cls(afi, safi, nlris)
def unpack (cls, data, negotiated): nlris = [] # -- Reading AFI/SAFI afi,safi = unpack('!HB',data[:3]) offset = 3 # we do not want to accept unknown families if negotiated and (afi,safi) not in 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-hop 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 safi in (SAFI.rtc,): if len_nh not in (4,16): raise Notify(3,0,'invalid ipv4 rtc 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) elif afi == AFI.l2vpn: if len_nh != 4: Notify(3,0,'invalid l2vpn next-hop length %d expected 4' % len_nh) size = len_nh - rd # XXX: FIXME: GET IT FROM CACHE HERE ? nhs = data[offset+rd:offset+rd+size] nexthops = [nhs[pos:pos+16] for pos in range(0,len(nhs),16)] # 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 = negotiated.addpath.receive(afi,safi) # Reading the NLRIs data = data[offset:] if not data: raise Notify(3,0,'No data to decode in an MPREACHNLRI but it is not an EOR %d/%d' % (afi,safi)) while data: if nexthops: for nexthop in nexthops: length,nlri = NLRI.unpack(afi,safi,data,addpath,nexthop,IN.ANNOUNCED) nlris.append(nlri) else: length,nlri = NLRI.unpack(afi,safi,data,addpath,'',IN.ANNOUNCED) nlris.append(nlri) if length == 0: raise RuntimeError("sub-calls should not return length zero") # logger.parser(LazyFormat("parsed announce mp nlri %s payload " % nlri,data[:length])) data = data[length:] return cls(afi,safi,nlris)
def unpack(cls, data, negotiated): nlris = [] # -- Reading AFI/SAFI afi, safi = unpack('!HB', data[:3]) offset = 3 # we do not want to accept unknown families if negotiated and (afi, safi) not in 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-hop 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 safi in (SAFI.rtc, ): if len_nh not in (4, 16): raise Notify( 3, 0, 'invalid ipv4 rtc 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) elif afi == AFI.l2vpn: if len_nh != 4: Notify(3, 0, 'invalid l2vpn next-hop length %d expected 4' % len_nh) size = len_nh - rd # XXX: FIXME: GET IT FROM CACHE HERE ? nhs = data[offset + rd:offset + rd + size] nexthops = [nhs[pos:pos + 16] for pos in range(0, len(nhs), 16)] # 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 = negotiated.addpath.receive(afi, safi) # Reading the NLRIs data = data[offset:] if not data: raise Notify( 3, 0, 'No data to decode in an MPREACHNLRI but it is not an EOR %d/%d' % (afi, safi)) while data: if nexthops: for nexthop in nexthops: length, nlri = NLRI.unpack(afi, safi, data, addpath, nexthop, IN.ANNOUNCED) nlris.append(nlri) else: length, nlri = NLRI.unpack(afi, safi, data, addpath, '', IN.ANNOUNCED) nlris.append(nlri) if length == 0: raise RuntimeError("sub-calls should not return length zero") # logger.parser(LazyFormat("parsed announce mp nlri %s payload " % nlri,data[:length])) data = data[length:] return cls(afi, safi, nlris)
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 == 23: return EOR(AFI.ipv4,SAFI.unicast,IN.ANNOUNCED) # pylint: disable=E1101 if length == 30 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 NoNextHop, the packed IP otherwise (without the 3/4 bytes of attributes headers) _nexthop = attributes.get(Attribute.CODE.NEXT_HOP,NoNextHop) 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)
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 == 23: return EOR(AFI.ipv4, SAFI.unicast, IN.ANNOUNCED) # pylint: disable=E1101 if length == 30 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 NoNextHop, the packed IP otherwise (without the 3/4 bytes of attributes headers) _nexthop = attributes.get(Attribute.CODE.NEXT_HOP, NoNextHop) 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)