def parse(cls, value): try: afi, safi = struct.unpack('!HB', value[0:3]) except Exception: raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data='') nlri_bin = value[3:] # for IPv4 if afi == afn.AFNUM_INET: # VPNv4 if safi == safn.SAFNUM_LAB_VPNUNICAST: nlri = IPv4MPLSVPN.parse(nlri_bin, iswithdraw=True) return dict(afi_safi=(afi, safi), withdraw=nlri) # BGP flow spec elif safi == safn.SAFNUM_FSPEC_RULE: # if nlri length is greater than 240 bytes, it is encoded over 2 bytes withdraw_list = [] while nlri_bin: length = ord(nlri_bin[0]) if length >> 4 == 0xf and len(nlri_bin) > 2: length = struct.unpack('!H', nlri_bin[:2])[0] nlri_tmp = nlri_bin[2:length + 2] nlri_bin = nlri_bin[length + 2:] else: nlri_tmp = nlri_bin[1:length + 1] nlri_bin = nlri_bin[length + 1:] nlri = IPv4FlowSpec.parse(nlri_tmp) if nlri: withdraw_list.append(nlri) return dict(afi_safi=(afi, safi), withdraw=withdraw_list) else: return dict(afi_safi=(afn.AFNUM_INET, safi), withdraw=repr(nlri_bin)) # for ipv6 elif afi == afn.AFNUM_INET6: # for ipv6 unicast if safi == safn.SAFNUM_UNICAST: return dict(afi_safi=(afi, safi), withdraw=IPv6Unicast.parse(nlri_data=nlri_bin)) elif safi == safn.SAFNUM_LAB_VPNUNICAST: return dict(afi_safi=(afi, safi), withdraw=IPv6MPLSVPN.parse(value=nlri_bin, iswithdraw=True)) else: return dict(afi_safi=(afi, safi), withdraw=repr(nlri_bin)) # for l2vpn elif afi == afn.AFNUM_L2VPN: # for evpn if safi == safn.SAFNUM_EVPN: return dict(afi_safi=(afi, safi), withdraw=EVPN.parse(nlri_data=nlri_bin)) else: return dict(afi_safi=(afi, safi), withdraw=repr(nlri_bin)) else: return dict(afi_safi=(afi, safi), withdraw=repr(nlri_bin))
def test_withdraw_parse(self): nlri_hex = b'\x98\x80\x00\x00\x00\x00\x00\x64\x00\x00\x00\x0c\x20\x10\x00\x00\x00\x12\x00' \ b'\x04\x98\x80\x00\x00\x00\x00\x00\x64\x00\x00\x00\x0c\x20\x10\x00\x01\x00\x12\x00\x00' nlri_list = [ {'label': [524288], 'rd': '100:12', 'prefix': '2010:0:12:4::/64'}, {'label': [524288], 'rd': '100:12', 'prefix': '2010:1:12::/64'} ] self.assertEqual(nlri_list, IPv6MPLSVPN.parse(value=nlri_hex, iswithdraw=True))
def test_update_parse(self): nlri_hex = b'\x98\x00\x03\x61\x00\x00\x00\x64\x00\x00\x00\x0c\x20\x10\x00\x00\x00\x12\x00\x04' \ b'\x98\x00\x03\x71\x00\x00\x00\x64\x00\x00\x00\x0c\x20\x10\x00\x01\x00\x12\x00\x00' nlri_list = [ {'label': [54], 'rd': '100:12', 'prefix': '2010:0:12:4::/64'}, {'label': [55], 'rd': '100:12', 'prefix': '2010:1:12::/64'} ] self.assertEqual(nlri_list, IPv6MPLSVPN.parse(value=nlri_hex))
def parse(cls, value): try: afi, safi = struct.unpack('!HB', value[0:3]) except Exception: raise excep.UpdateMessageError(sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data='') nlri_bin = value[3:] # for IPv4 if afi == afn.AFNUM_INET: # VPNv4 if safi == safn.SAFNUM_LAB_VPNUNICAST: nlri = IPv4MPLSVPN.parse(nlri_bin, iswithdraw=True) return dict(afi_safi=(afi, safi), withdraw=nlri) # BGP flow spec elif safi == safn.SAFNUM_FSPEC_RULE: # if nlri length is greater than 240 bytes, it is encoded over 2 bytes withdraw_list = [] while nlri_bin: length = ord(nlri_bin[0]) if length >> 4 == 0xf and len(nlri_bin) > 2: length = struct.unpack('!H', nlri_bin[:2])[0] nlri_tmp = nlri_bin[2: length + 2] nlri_bin = nlri_bin[length + 2:] else: nlri_tmp = nlri_bin[1: length + 1] nlri_bin = nlri_bin[length + 1:] nlri = IPv4FlowSpec.parse(nlri_tmp) if nlri: withdraw_list.append(nlri) return dict(afi_safi=(afi, safi), withdraw=withdraw_list) else: return dict(afi_safi=(afn.AFNUM_INET, safi), withdraw=repr(nlri_bin)) # for ipv6 elif afi == afn.AFNUM_INET6: # for ipv6 unicast if safi == safn.SAFNUM_UNICAST: return dict(afi_safi=(afi, safi), withdraw=IPv6Unicast.parse(nlri_data=nlri_bin)) elif safi == safn.SAFNUM_LAB_VPNUNICAST: return dict(afi_safi=(afi, safi), withdraw=IPv6MPLSVPN.parse(value=nlri_bin, iswithdraw=True)) else: return dict(afi_safi=(afi, safi), withdraw=repr(nlri_bin)) # for l2vpn elif afi == afn.AFNUM_L2VPN: # for evpn if safi == safn.SAFNUM_EVPN: return dict(afi_safi=(afi, safi), withdraw=EVPN.parse(nlri_data=nlri_bin)) else: return dict(afi_safi=(afi, safi), withdraw=repr(nlri_bin)) else: return dict(afi_safi=(afi, safi), withdraw=repr(nlri_bin))
def test_update_parse(self): nlri_hex = b'\x98\x00\x03\x61\x00\x00\x00\x64\x00\x00\x00\x0c\x20\x10\x00\x00\x00\x12\x00\x04' \ b'\x98\x00\x03\x71\x00\x00\x00\x64\x00\x00\x00\x0c\x20\x10\x00\x01\x00\x12\x00\x00' nlri_list = [{ 'label': [54], 'rd': '100:12', 'prefix': '2010:0:12:4::/64' }, { 'label': [55], 'rd': '100:12', 'prefix': '2010:1:12::/64' }] self.assertEqual(nlri_list, IPv6MPLSVPN.parse(value=nlri_hex))
def test_withdraw_parse(self): nlri_hex = b'\x98\x80\x00\x00\x00\x00\x00\x64\x00\x00\x00\x0c\x20\x10\x00\x00\x00\x12\x00' \ b'\x04\x98\x80\x00\x00\x00\x00\x00\x64\x00\x00\x00\x0c\x20\x10\x00\x01\x00\x12\x00\x00' nlri_list = [{ 'label': [524288], 'rd': '100:12', 'prefix': '2010:0:12:4::/64' }, { 'label': [524288], 'rd': '100:12', 'prefix': '2010:1:12::/64' }] self.assertEqual(nlri_list, IPv6MPLSVPN.parse(value=nlri_hex, iswithdraw=True))
def parse(cls, value): try: afi, safi, nexthop_length = struct.unpack('!HBB', value[0:4]) nexthop_bin = value[4:4 + nexthop_length] nlri_bin = value[5 + nexthop_length:] except Exception: # error when lenght is wrong raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=repr(value)) # Address Family IPv4 if afi == afn.AFNUM_INET: if safi == safn.SAFNUM_LAB_VPNUNICAST: # MPLS VPN # parse nexthop rd_bin = nexthop_bin[0:8] rd_type = struct.unpack('!H', rd_bin[0:2])[0] rd_value_bin = rd_bin[2:] if rd_type == 0: asn, an = struct.unpack('!HI', rd_value_bin) ipv4 = str( netaddr.IPAddress( int(binascii.b2a_hex(nexthop_bin[8:]), 16))) nexthop = {'rd': '%s:%s' % (asn, an), 'str': ipv4} # TODO(xiaoquwl) for other RD type decoding else: nexthop = repr(nexthop_bin[8:]) # parse nlri nlri = IPv4MPLSVPN.parse(nlri_bin) return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri) elif safi == safn.SAFNUM_FSPEC_RULE: # if nlri length is greater than 240 bytes, it is encoded over 2 bytes if len(nlri_bin) >= 240: nlri_bin = nlri_bin[2:] else: nlri_bin = nlri_bin[1:] nlri = IPv4FlowSpec.parse(nlri_bin) return dict(afi_safi=(afi, safi), nexthop=nexthop_bin, nlri=nlri) else: nlri = repr(nlri_bin) # # Address Family IPv6 elif afi == afn.AFNUM_INET6: # IPv6 unicast if safi == safn.SAFNUM_UNICAST: # decode nexthop # RFC 2545 # The value of the Length of Next Hop Network Address field on a # MP_REACH_NLRI attribute shall be set to 16, when only a global # address is present, or 32 if a link-local address is also included in # the Next Hop field. # # The link-local address shall be included in the Next Hop field if and # only if the BGP speaker shares a common subnet with the entity # identified by the global IPv6 address carried in the Network Address # of Next Hop field and the peer the route is being advertised to. nexthop_addrlen = 16 has_link_local = False nexthop = str( netaddr.IPAddress( int(binascii.b2a_hex(nexthop_bin[:nexthop_addrlen]), 16))) if len(nexthop_bin) == 2 * nexthop_addrlen: # has link local address has_link_local = True linklocal_nexthop = str( netaddr.IPAddress( int( binascii.b2a_hex( nexthop_bin[nexthop_addrlen:]), 16))) nlri = IPv6Unicast.parse(nlri_bin) if has_link_local: return dict(afi_safi=(afi, safi), nexthop=nexthop, linklocal_nexthop=linklocal_nexthop, nlri=nlri) else: return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri) elif safi == safn.SAFNUM_LAB_VPNUNICAST: # IPv6 MPLS VPN # parse nexthop rd_bin = nexthop_bin[0:8] rd_type = struct.unpack('!H', rd_bin[0:2])[0] rd_value_bin = rd_bin[2:] if rd_type == 0: asn, an = struct.unpack('!HI', rd_value_bin) ipv6 = str( netaddr.IPAddress( int(binascii.b2a_hex(nexthop_bin[8:]), 16))) nexthop = {'rd': '%s:%s' % (asn, an), 'str': ipv6} # TODO(xiaoquwl) for other RD type decoding else: nexthop = repr(nexthop_bin[8:]) # parse nlri nlri = IPv6MPLSVPN.parse(nlri_bin) return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri) else: return dict(afi_safi=(afi, safi), nexthop=nexthop_bin, nlri=nlri_bin) # for l2vpn elif afi == afn.AFNUM_L2VPN: if safi == safn.SAFNUM_EVPN: nexthop = str( netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin), 16))) nlri = EVPN.parse(nlri_bin) return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri) else: nlri = repr(nlri_bin) else: nlri = repr(nlri_bin) return dict(afi_safi=(afi, safi), nexthop=nexthop_bin, nlri=nlri_bin)
def parse(cls, value): try: afi, safi, nexthop_length = struct.unpack('!HBB', value[0:4]) nexthop_bin = value[4:4 + nexthop_length] nlri_bin = value[5 + nexthop_length:] except Exception: # error when lenght is wrong raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=repr(value)) # Address Family IPv4 if afi == afn.AFNUM_INET: if safi == safn.SAFNUM_LAB_VPNUNICAST: # MPLS VPN # parse nexthop rd_bin = nexthop_bin[0:8] rd_type = struct.unpack('!H', rd_bin[0:2])[0] rd_value_bin = rd_bin[2:] if rd_type == 0: asn, an = struct.unpack('!HI', rd_value_bin) ipv4 = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin[8:]), 16))) nexthop = {'rd': '%s:%s' % (asn, an), 'str': ipv4} # TODO(xiaoquwl) for other RD type decoding else: nexthop = repr(nexthop_bin[8:]) # parse nlri nlri = IPv4MPLSVPN.parse(nlri_bin) return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri) elif safi == safn.SAFNUM_FSPEC_RULE: # if nlri length is greater than 240 bytes, it is encoded over 2 bytes nlri_list = [] while nlri_bin: length = ord(nlri_bin[0]) if length >> 4 == 0xf and len(nlri_bin) > 2: length = struct.unpack('!H', nlri_bin[:2])[0] nlri_tmp = nlri_bin[2: length + 2] nlri_bin = nlri_bin[length + 2:] else: nlri_tmp = nlri_bin[1: length + 1] nlri_bin = nlri_bin[length + 1:] nlri = IPv4FlowSpec.parse(nlri_tmp) if nlri: nlri_list.append(nlri) if nexthop_bin: nexthop = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin), 16))) else: nexthop = '' return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri_list) else: nlri = repr(nlri_bin) # # Address Family IPv6 elif afi == afn.AFNUM_INET6: # IPv6 unicast if safi == safn.SAFNUM_UNICAST: # decode nexthop # RFC 2545 # The value of the Length of Next Hop Network Address field on a # MP_REACH_NLRI attribute shall be set to 16, when only a global # address is present, or 32 if a link-local address is also included in # the Next Hop field. # # The link-local address shall be included in the Next Hop field if and # only if the BGP speaker shares a common subnet with the entity # identified by the global IPv6 address carried in the Network Address # of Next Hop field and the peer the route is being advertised to. nexthop_addrlen = 16 has_link_local = False nexthop = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin[:nexthop_addrlen]), 16))) if len(nexthop_bin) == 2 * nexthop_addrlen: # has link local address has_link_local = True linklocal_nexthop = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin[nexthop_addrlen:]), 16))) nlri = IPv6Unicast.parse(nlri_bin) if has_link_local: return dict(afi_safi=(afi, safi), nexthop=nexthop, linklocal_nexthop=linklocal_nexthop, nlri=nlri) else: return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri) elif safi == safn.SAFNUM_LAB_VPNUNICAST: # IPv6 MPLS VPN # parse nexthop rd_bin = nexthop_bin[0:8] rd_type = struct.unpack('!H', rd_bin[0:2])[0] rd_value_bin = rd_bin[2:] if rd_type == 0: asn, an = struct.unpack('!HI', rd_value_bin) ipv6 = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin[8:]), 16))) nexthop = {'rd': '%s:%s' % (asn, an), 'str': ipv6} # TODO(xiaoquwl) for other RD type decoding else: nexthop = repr(nexthop_bin[8:]) # parse nlri nlri = IPv6MPLSVPN.parse(nlri_bin) return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri) else: return dict(afi_safi=(afi, safi), nexthop=nexthop_bin, nlri=nlri_bin) # for l2vpn elif afi == afn.AFNUM_L2VPN: if safi == safn.SAFNUM_EVPN: nexthop = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin), 16))) nlri = EVPN.parse(nlri_bin) return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri) else: nlri = repr(nlri_bin) else: nlri = repr(nlri_bin) return dict(afi_safi=(afi, safi), nexthop=nexthop_bin, nlri=nlri_bin)