Ejemplo n.º 1
0
    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))
Ejemplo n.º 2
0
    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))
Ejemplo n.º 3
0
 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))
Ejemplo n.º 4
0
 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))
Ejemplo n.º 5
0
 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))
Ejemplo n.º 6
0
 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))
Ejemplo n.º 7
0
 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))
Ejemplo n.º 8
0
 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))
Ejemplo n.º 9
0
 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))
Ejemplo n.º 10
0
 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))
Ejemplo n.º 11
0
 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))
Ejemplo n.º 12
0
 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))
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
    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)
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
    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)
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
    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
Ejemplo n.º 19
0
    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
Ejemplo n.º 20
0
    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)