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 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_construct_in_mul_eth_tag(self): data_hex = b'\x03\x11\x00\x01\xac\x10\x00\x01\x17\x10\x00\x00\x00\x64\x20\xc0\xa8\x00\x01' data_list = [{ 'type': bgp_cons.BGPNLRI_EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG, 'value': { 'rd': '172.16.0.1:5904', 'eth_tag_id': 100, 'ip': '192.168.0.1' } }] self.assertEqual(data_hex, EVPN.construct(data_list))
def test_construct_eth_segment(self): data_hex = b'\x04\x17\x00\x01\xac\x10\x00\x01\x17\x10\x00\x00' \ b'\x00\x00\x00\x00\x00\x00\x00\x00\x20\xc0\xa8\x00\x01' data_list = [{ 'type': bgp_cons.BGPNLRI_EVPN_ETHERNET_SEGMENT, 'value': { 'rd': '172.16.0.1:5904', 'esi': 0, 'ip': '192.168.0.1' } }] self.assertEqual(data_hex, EVPN.construct(data_list))
def test_construct_eth_auto_dis(self): data_hex = b'\x01\x19\x00\x01\x01\x01\x01\x01\x80\x63\x00\x00\x00' \ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x64\x00\x00\xa1' data_list = [{ 'type': bgp_cons.BGPNLRI_EVPN_ETHERNET_AUTO_DISCOVERY, 'value': { 'rd': '1.1.1.1:32867', 'esi': 0, 'eth_tag_id': 100, 'label': [10] } }] self.assertEqual(data_hex, EVPN.construct(data_list))
def test_construct_ip_route_prefix_v4(self): data_hex = b'\x05\x22\x00\x02\x00\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \ b'\x00\x00\x00\x01\x18\x01\x01\x01\x00\x01\x01\x01\x01\x00\x00\xa1' data_list = [{ 'type': 5, 'value': { 'esi': 0, 'eth_tag_id': 1, 'gateway': '1.1.1.1', 'label': [10], 'prefix': '1.1.1.0/24', 'rd': '65536:2'}}] self.assertEqual(data_hex, EVPN.construct(data_list))
def test_construct_mac_ip_adv(self): data_hex = b'\x02\x25\x00\x01\xac\x11\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \ b'\x00\x00\x00\x6c\x30\x00\x11\x22\x33\x44\x55\x20\x0b\x0b\x0b\x01\x00\x00\x00' data_list = [{ 'type': bgp_cons.BGPNLRI_EVPN_MAC_IP_ADVERTISEMENT, 'value': { 'rd': '172.17.0.3:2', 'mac': '00-11-22-33-44-55', 'eth_tag_id': 108, 'esi': 0, 'ip': '11.11.11.1', 'label': [0]} }] self.assertEqual(data_hex, EVPN.construct(data_list))
def test_construct_ip_route_prefix_v6(self): data_hex = b'\x05' \ b'\x3a' \ b'\x00\x02\x00\x01\x00\x00\x00\x02' \ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \ b'\x00\x00\x00\x01' \ b'\x40' \ b'\x20\x01\x32\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' \ b'\x20\x01\x32\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' \ b'\x00\x00\xa1' data_list = [{ 'type': 5, 'value': { 'esi': 0, 'eth_tag_id': 1, 'gateway': '2001:3232::1', 'label': [10], 'prefix': '2001:3232::1/64', 'rd': '65536:2'}}] self.assertEqual(data_hex, EVPN.construct(data_list))
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 construct(cls, value): """Construct a attribute :param value: python dictionary {'afi_safi': (1,128), 'nexthop': {}, 'nlri': [] """ afi, safi = value['afi_safi'] if afi == afn.AFNUM_INET: if safi == safn.SAFNUM_LAB_VPNUNICAST: # MPLS VPN nexthop_hex = cls.construct_mpls_vpn_nexthop(value['nexthop']) nlri_hex = IPv4MPLSVPN.construct(value['nlri']) attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) +\ struct.pack('!B', len(nexthop_hex)) + nexthop_hex + b'\x00' + nlri_hex return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value elif safi == safn.SAFNUM_FSPEC_RULE: # BGP Flow spec try: try: nexthop = netaddr.IPAddress(value['nexthop']).packed except netaddr.core.AddrFormatError: nexthop = '' nlri = IPv4FlowSpec.construct(value=value['nlri']) if nlri: attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + \ struct.pack('!B', len(nexthop)) + nexthop + b'\x00' + nlri return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value except Exception as e: raise excep.ConstructAttributeFailed( reason='failed to construct attributes: %s' % e, data=value) else: raise excep.ConstructAttributeFailed( reason='unsupport this sub address family', data=value) # ipv6 unicast elif afi == afn.AFNUM_INET6: if safi == safn.SAFNUM_LAB_VPNUNICAST: # MPLS VPN nexthop_hex = cls.construct_mpls_vpn_nexthop(value['nexthop']) nlri_hex = IPv6MPLSVPN.construct(value['nlri']) attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) +\ struct.pack('!B', len(nexthop_hex)) + nexthop_hex + b'\x00' + nlri_hex return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value elif safi == safn.SAFNUM_UNICAST: nexthop_len = 16 nexthop_bin = netaddr.IPAddress(value['nexthop']).packed if value.get('linklocal_nexthop'): nexthop_len *= 2 nexthop_bin += netaddr.IPAddress( value['linklocal_nexthop']).packed nlri_bin = IPv6Unicast.construct(nlri_list=value['nlri']) attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + struct.pack('!B', nexthop_len) + \ nexthop_bin + b'\x00' + nlri_bin return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID)\ + struct.pack('!B', len(attr_value)) + attr_value # for l2vpn elif afi == afn.AFNUM_L2VPN: if safi == safn.SAFNUM_EVPN: nexthop_bin = netaddr.IPAddress(value['nexthop']).packed nlri_bin = EVPN.construct(nlri_list=value['nlri']) attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + struct.pack('!B', len(nexthop_bin)) + \ nexthop_bin + b'\x00' + nlri_bin return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID)\ + struct.pack('!B', len(attr_value)) + attr_value else: raise excep.ConstructAttributeFailed( reason='unsupport this sub address family', data=value)
def construct(cls, value): """Construct a attribute :param value: python dictionary {'afi_safi': (1,128), 'withdraw': [] """ afi, safi = value['afi_safi'] if afi == afn.AFNUM_INET: if safi == safn.SAFNUM_LAB_VPNUNICAST: # MPLS VPN nlri = IPv4MPLSVPN.construct(value['withdraw'], iswithdraw=True) if nlri: attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + nlri return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value else: return None elif safi == safn.SAFNUM_FSPEC_RULE: try: nlri_list = value.get('withdraw') or [] if not nlri_list: return None nlri_hex = b'' for nlri in nlri_list: nlri_hex += IPv4FlowSpec.construct(value=nlri) attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + nlri_hex return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value except Exception: raise excep.ConstructAttributeFailed( reason='failed to construct attributes', data=value ) else: raise excep.ConstructAttributeFailed( reason='unsupport this sub address family', data=value) elif afi == afn.AFNUM_INET6: if safi == safn.SAFNUM_UNICAST: nlri = IPv6Unicast.construct(nlri_list=value['withdraw']) if nlri: attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + nlri return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value elif safi == safn.SAFNUM_LAB_VPNUNICAST: nlri = IPv6MPLSVPN.construct(value=value['withdraw'], iswithdraw=True) if nlri: attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + nlri return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value else: return None # for l2vpn elif afi == afn.AFNUM_L2VPN: # for evpn if safi == safn.SAFNUM_EVPN: nlri = EVPN.construct(nlri_list=value['withdraw']) if nlri: attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + nlri return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value else: return None else: raise excep.ConstructAttributeFailed( reason='unsupport this sub address family', data=value)
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)
def construct(cls, value): """Construct a attribute :param value: python dictionary {'afi_safi': (1,128), 'nexthop': {}, 'nlri': [] """ afi, safi = value['afi_safi'] if afi == afn.AFNUM_INET: if safi == safn.SAFNUM_LAB_VPNUNICAST: # MPLS VPN nexthop_hex = cls.construct_mpls_vpn_nexthop(value['nexthop']) nlri_hex = IPv4MPLSVPN.construct(value['nlri']) attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) +\ struct.pack('!B', len(nexthop_hex)) + nexthop_hex + b'\x00' + nlri_hex return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value elif safi == safn.SAFNUM_FSPEC_RULE: # BGP Flow spec try: try: nexthop = netaddr.IPAddress(value['nexthop']).packed except netaddr.core.AddrFormatError: nexthop = '' nlri_hex = b'' for nlri in value['nlri']: nlri_hex += IPv4FlowSpec.construct(value=nlri) if nlri_hex: attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + \ struct.pack('!B', len(nexthop)) + nexthop + b'\x00' + nlri_hex return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value except Exception as e: raise excep.ConstructAttributeFailed( reason='failed to construct attributes: %s' % e, data=value ) else: raise excep.ConstructAttributeFailed( reason='unsupport this sub address family', data=value) # ipv6 unicast elif afi == afn.AFNUM_INET6: if safi == safn.SAFNUM_LAB_VPNUNICAST: # MPLS VPN nexthop_hex = cls.construct_mpls_vpn_nexthop(value['nexthop']) nlri_hex = IPv6MPLSVPN.construct(value['nlri']) attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) +\ struct.pack('!B', len(nexthop_hex)) + nexthop_hex + b'\x00' + nlri_hex return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \ + struct.pack('!B', len(attr_value)) + attr_value elif safi == safn.SAFNUM_UNICAST: nexthop_len = 16 nexthop_bin = netaddr.IPAddress(value['nexthop']).packed if value.get('linklocal_nexthop'): nexthop_len *= 2 nexthop_bin += netaddr.IPAddress(value['linklocal_nexthop']).packed nlri_bin = IPv6Unicast.construct(nlri_list=value['nlri']) attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + struct.pack('!B', nexthop_len) + \ nexthop_bin + b'\x00' + nlri_bin return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID)\ + struct.pack('!B', len(attr_value)) + attr_value # for l2vpn elif afi == afn.AFNUM_L2VPN: if safi == safn.SAFNUM_EVPN: nexthop_bin = netaddr.IPAddress(value['nexthop']).packed nlri_bin = EVPN.construct(nlri_list=value['nlri']) attr_value = struct.pack('!H', afi) + struct.pack('!B', safi) + struct.pack('!B', len(nexthop_bin)) + \ nexthop_bin + b'\x00' + nlri_bin return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID)\ + struct.pack('!B', len(attr_value)) + attr_value else: raise excep.ConstructAttributeFailed( reason='unsupport this sub address family', data=value)
def construct_attributes(attr_dict, asn4=False): """ construts BGP Update attirubte. :param attr_dict: bgp attribute dictionary :param asn4: support 4 bytes asn or not """ attr_raw_hex = b'' for type_code, value in attr_dict.items(): if type_code == bgp_cons.BGPTYPE_ORIGIN: origin_hex = Origin.construct(value=value) attr_raw_hex += origin_hex elif type_code == bgp_cons.BGPTYPE_AS_PATH: aspath_hex = ASPath.construct(value=value, asn4=asn4) attr_raw_hex += aspath_hex elif type_code == bgp_cons.BGPTYPE_NEXT_HOP: nexthop_hex = NextHop.construct(value=value) attr_raw_hex += nexthop_hex elif type_code == bgp_cons.BGPTYPE_MULTI_EXIT_DISC: med_hex = MED.construct(value=value) attr_raw_hex += med_hex elif type_code == bgp_cons.BGPTYPE_LOCAL_PREF: localpre_hex = LocalPreference.construct(value=value) attr_raw_hex += localpre_hex elif type_code == bgp_cons.BGPTYPE_ATOMIC_AGGREGATE: atomicaggregate_hex = AtomicAggregate.construct(value=value) attr_raw_hex += atomicaggregate_hex elif type_code == bgp_cons.BGPTYPE_AGGREGATOR: aggregator_hex = Aggregator.construct(value=value, asn4=asn4) attr_raw_hex += aggregator_hex elif type_code == bgp_cons.BGPTYPE_COMMUNITIES: community_hex = Community.construct(value=value) attr_raw_hex += community_hex elif type_code == bgp_cons.BGPTYPE_ORIGINATOR_ID: originatorid_hex = OriginatorID.construct(value=value) attr_raw_hex += originatorid_hex elif type_code == bgp_cons.BGPTYPE_CLUSTER_LIST: clusterlist_hex = ClusterList.construct(value=value) attr_raw_hex += clusterlist_hex elif type_code == bgp_cons.BGPTYPE_MP_REACH_NLRI: mpreach_hex = MpReachNLRI().construct(value=value) attr_raw_hex += mpreach_hex elif type_code == bgp_cons.BGPTYPE_MP_UNREACH_NLRI: mpunreach_hex = MpUnReachNLRI.construct(value=value) attr_raw_hex += mpunreach_hex elif type_code == bgp_cons.BGPTYPE_EXTENDED_COMMUNITY: community_ext_hex = ExtCommunity.construct(value=value) attr_raw_hex += community_ext_hex elif type_code == bgp_cons.BGPTYPE_PMSI_TUNNEL: evpn_overlay = EVPN.signal_evpn_overlay(attr_dict) attr_raw_hex += PMSITunnel.construct(value=value, evpn_overlay=evpn_overlay) elif type_code == bgp_cons.BGPTYPE_TUNNEL_ENCAPS_ATTR: tunnelencap_hex = TunnelEncaps.construct(value=value) attr_raw_hex += tunnelencap_hex elif type_code == bgp_cons.BGPTYPE_LARGE_COMMUNITY: large_community_ext_hex = LargeCommunity.construct(value=value) attr_raw_hex += large_community_ext_hex return attr_raw_hex
def parse_attributes(data, asn4=False): """ Parses an RFC4271 encoded blob of BGP attributes into a list :param data: :param asn4: support 4 bytes asn or not :return: """ attributes = {} postfix = data bgpls_pro_id = None bgpls_attr = None while len(postfix) > 0: try: flags, type_code = struct.unpack('!BB', postfix[:2]) if flags & AttributeFlag.EXTENDED_LENGTH: attr_len = struct.unpack('!H', postfix[2:4])[0] attr_value = postfix[4:4 + attr_len] postfix = postfix[4 + attr_len:] # Next attribute else: # standard 1-octet length if isinstance(postfix[2], int): attr_len = postfix[2] else: attr_len = ord(postfix[2]) attr_value = postfix[3:3 + attr_len] postfix = postfix[3 + attr_len:] # Next attribute except Exception as e: LOG.error(e) error_str = traceback.format_exc() LOG.debug(error_str) raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_MALFORMED_ATTR_LIST, data='') if type_code == bgp_cons.BGPTYPE_ORIGIN: decode_value = Origin.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_AS_PATH: decode_value = ASPath.parse(value=attr_value, asn4=asn4) elif type_code == bgp_cons.BGPTYPE_NEXT_HOP: decode_value = NextHop.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_MULTI_EXIT_DISC: decode_value = MED.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_LOCAL_PREF: decode_value = LocalPreference.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_ATOMIC_AGGREGATE: decode_value = AtomicAggregate.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_AGGREGATOR: decode_value = Aggregator.parse(value=attr_value, asn4=asn4) elif type_code == bgp_cons.BGPTYPE_COMMUNITIES: decode_value = Community.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_ORIGINATOR_ID: decode_value = OriginatorID.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_CLUSTER_LIST: decode_value = ClusterList.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_NEW_AS_PATH: decode_value = ASPath.parse(value=attr_value, asn4=True) elif type_code == bgp_cons.BGPTYPE_NEW_AGGREGATOR: decode_value = Aggregator.parse(value=attr_value, asn4=True) elif type_code == bgp_cons.BGPTYPE_LARGE_COMMUNITY: decode_value = LargeCommunity.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_MP_REACH_NLRI: decode_value = MpReachNLRI.parse(value=attr_value) if decode_value['nlri'][0] and type( decode_value['nlri'][0]) is dict: if decode_value['nlri'][0].get("protocol_id"): bgpls_pro_id = decode_value['nlri'][0]["protocol_id"] elif type_code == bgp_cons.BGPTYPE_MP_UNREACH_NLRI: decode_value = MpUnReachNLRI.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_EXTENDED_COMMUNITY: decode_value = ExtCommunity.parse(value=attr_value) elif type_code == bgp_cons.BGPTYPE_PMSI_TUNNEL: decode_value = PMSITunnel.parse(value=attr_value) pmsi_hex = attr_value elif type_code == bgp_cons.BGPTYPE_LINK_STATE: if bgpls_pro_id: attributes.update( LinkState.unpack(bgpls_pro_id=bgpls_pro_id, data=attr_value).dict()) else: bgpls_attr = attr_value continue else: decode_value = binascii.b2a_hex(attr_value) attributes[type_code] = decode_value if bgpls_attr: attributes.update( LinkState.unpack(bgpls_pro_id=bgpls_pro_id, data=attr_value).dict()) evpn_overlay = EVPN.signal_evpn_overlay(attributes) if evpn_overlay['evpn'] and evpn_overlay['encap_ec']: if bgp_cons.BGPTYPE_PMSI_TUNNEL in attributes: attributes[bgp_cons.BGPTYPE_PMSI_TUNNEL] = PMSITunnel.parse( value=pmsi_hex, evpn_overlay=evpn_overlay) return attributes