Пример #1
0
    def parse(cls, value, asn4=False):
        """
        Parse AS PATH attributes.
        :param asn4: 4 bytes asn or not
        :param value: raw binary balue
        """
        # Loop over all path segments
        aspath = []
        while len(value) > 0:
            seg_type, length = struct.unpack('!BB', value[:2])
            if seg_type not in [
                    cls.AS_SET, cls.AS_SEQUENCE, cls.AS_CONFED_SEQUENCE,
                    cls.AS_CONFED_SET
            ]:
                raise excep.UpdateMessageError(
                    sub_error=bgp_cons.ERR_MSG_UPDATE_MALFORMED_ASPATH,
                    data=repr(value))
            try:
                if asn4:
                    segment = list(
                        struct.unpack('!%dI' % length,
                                      value[2:2 + length * 4]))
                    value = value[2 + length * 4:]

                else:
                    segment = list(
                        struct.unpack('!%dH' % length,
                                      value[2:2 + length * 2]))
                    value = value[2 + length * 2:]
            except Exception:
                raise excep.UpdateMessageError(
                    sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data='')
            aspath.append((seg_type, segment))
        return aspath
Пример #2
0
    def parse(cls, value, asn4=False):

        """
        Parse Aggregator attributes.
        :param value: raw binary value
        :param asn4: support 4 bytes asn or not
        """

        if not asn4:
            try:
                asn = struct.unpack('!H', value[:2])[0]
                aggregator = str(netaddr.IPAddress(struct.unpack('!I', value[2:])[0]))
            except Exception:
                raise excep.UpdateMessageError(
                    sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN,
                    data=value)
        else:
            # 4 bytes ASN
            try:
                asn = struct.unpack('!I', value[:4])[0]
                aggregator = str(netaddr.IPAddress(struct.unpack('!I', value[4:])[0]))
            except Exception:
                raise excep.UpdateMessageError(
                    sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN,
                    data=value)

        return asn, aggregator
Пример #3
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))
Пример #4
0
 def construct(cls, value):
     """
     encode BGP nexthop attribute.
     :param value: ipv4 format string like 1.1.1.1
     """
     try:
         if netaddr.IPAddress(value).version == 4:
             ip_addr_raw = netaddr.IPAddress(value).packed
             return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \
                 + struct.pack('!B', len(ip_addr_raw)) + ip_addr_raw
         else:
             raise excep.UpdateMessageError(
                 sub_error=bgp_cons.ERR_MSG_UPDATE_INVALID_NEXTHOP,
                 data=value)
     except Exception:
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_INVALID_NEXTHOP, data=value)
Пример #5
0
 def parse(cls, value):
     """
     Parse originator id
     :param value:
     """
     if len(value) != 4:
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)
     return str(netaddr.IPAddress(int(binascii.b2a_hex(value[0:4]), 16)))
Пример #6
0
 def parse(cls, value):
     """
     parse BGP med attributes
     :param value: raw binary value
     """
     try:
         return struct.unpack('!I', value)[0]
     except:
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)
Пример #7
0
 def parse(cls, value):
     """
     parse bgp ATOMIC_AGGREGATE attribute
     :param value:
     """
     if not value:
         return value
     else:
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_OPTIONAL_ATTR, data=value)
Пример #8
0
 def construct(cls, value):
     """
     encode BGP med attributes
     :param value:
     """
     try:
         return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \
             + struct.pack('!B', 4) + struct.pack('!I', value)
     except Exception:
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data='')
Пример #9
0
 def construct(cls, value):
     """
     construct a origin attribute
     :param value: 0,1,2
     """
     if value not in [cls.IGP, cls.EGP, cls.INCOMPLETE]:
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_INVALID_ORIGIN, data='')
     length = 1
     return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \
         + struct.pack('!B', length) + struct.pack('!B', value)
Пример #10
0
 def construct(cls, value):
     """
     construct a ORIGINATOR_ID path attribute
     :param value: ipv4 format string
     """
     try:
         return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \
             + struct.pack('!B', 4) + netaddr.IPAddress(value).packed
     except Exception:
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)
Пример #11
0
    def construct(cls, value):
        """construct a ATOMIC_AGGREGATE path attribute
        :param value:
        """

        if value:
            raise excep.UpdateMessageError(
                sub_error=bgp_cons.ERR_MSG_UPDATE_OPTIONAL_ATTR, data='')
        else:
            value = 0
        return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \
            + struct.pack('!B', value)
Пример #12
0
 def parse(cls, value):
     """
     parse bgp ATOMIC_AGGREGATE attribute
     :param value:
     """
     if not value:
         # return value
         # return str(value, encoding="utf-8")
         return bytes.decode(value)
     else:
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_OPTIONAL_ATTR, data=value)
Пример #13
0
 def parse(cls, value):
     """
     Parse BGP nexthop.
     :param value: raw binary value
     """
     if len(value) % 4 == 0:
         next_hop = str(
             netaddr.IPAddress(int(binascii.b2a_hex(value[0:4]), 16)))
         return next_hop
     else:
         # Error process
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)
Пример #14
0
 def parse(cls, value):
     """
     Error process:
     (1) the falgs of the ORIGIN attribute must be "well-know,transitive"
     (2) If the ORIGIN attribute has an undefined value, then the Error Sub-code
     MUST be set to Invalid Origin Attribute. The Data field MUST contain the
     unrecognized attribute (type,length, and vlaue)
     :param value: raw binary value
     """
     orgin = ord(value[0:1])
     if orgin not in [cls.IGP, cls.EGP, cls.INCOMPLETE]:
         raise excep.UpdateMessageError(
             sub_error=bgp_cons.ERR_MSG_UPDATE_INVALID_ORIGIN, data=value)
     return orgin
Пример #15
0
    def parse_prefix_list(data, addpath=False):
        """
        Parses an RFC4271 encoded blob of BGP prefixes into a list

        :param data: hex data
        :param addpath: support addpath or not
        :return: prefix_list
        """
        prefixes = []
        postfix = data
        while len(postfix) > 0:
            # for python2 and python3
            if addpath:
                path_id = struct.unpack('!I', postfix[0:4])[0]
                postfix = postfix[4:]
            if isinstance(postfix[0], int):
                prefix_len = postfix[0]
            else:
                prefix_len = ord(postfix[0])
            if prefix_len > 32:
                LOG.warning('Prefix Length larger than 32')
                raise excep.UpdateMessageError(
                    sub_error=bgp_cons.ERR_MSG_UPDATE_INVALID_NETWORK_FIELD,
                    data=repr(data))
            octet_len, remainder = int(prefix_len / 8), prefix_len % 8
            if remainder > 0:
                # prefix length doesn't fall on octet boundary
                octet_len += 1
            tmp = postfix[1:octet_len + 1]
            # for python2 and python3
            if isinstance(postfix[0], int):
                prefix_data = [i for i in tmp]
            else:
                prefix_data = [ord(i) for i in tmp]
            # Zero the remaining bits in the last octet if it didn't fall
            # on an octet boundary
            if remainder > 0:
                prefix_data[-1] &= 255 << (8 - remainder)
            prefix_data = prefix_data + list(str(0)) * 4
            prefix = "%s.%s.%s.%s" % (tuple(
                prefix_data[0:4])) + '/' + str(prefix_len)
            if not addpath:
                prefixes.append(prefix)
            else:
                prefixes.append({'prefix': prefix, 'path_id': path_id})
            # Next prefix
            postfix = postfix[octet_len + 1:]

        return prefixes
Пример #16
0
    def parse(cls, value):

        """
        Parse culster list
        :param value
        """
        cluster_list = []
        if len(value) % 4 != 0:
            raise excep.UpdateMessageError(
                sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN,
                data=repr(value))
        while value:
            cluster_list.append(str(netaddr.IPAddress(struct.unpack('!I', value[0:4])[0])))
            value = value[4:]
        return cluster_list
Пример #17
0
    def construct(cls, value):

        """
        construct a CLUSTER_LIST path attribute
        :param value:
        """
        cluster_raw = b''
        try:
            for cluster in value:
                cluster_raw += netaddr.IPAddress(cluster).packed
            return struct.pack("!B", cls.FLAG) + struct.pack('!B', cls.ID) \
                + struct.pack("!B", len(cluster_raw)) + cluster_raw
        except Exception:
            raise excep.UpdateMessageError(
                sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN,
                data=struct.pack('B', cls.FLAG))
Пример #18
0
    def construct(cls, value, asn4=False):
        """
        Construct AS PATH.
        :param asn4: 4byte asn
        :param value:
        """
        # value example
        # [(2, [3257, 31027, 34848, 21465])], or [(3, [64606]), (2, [64624, 65515])]

        as_path_raw = b''
        for segment in value:
            as_seg_raw = b''
            seg_type = segment[0]
            as_path_list = segment[1]
            if seg_type not in [
                    cls.AS_SET, cls.AS_SEQUENCE, cls.AS_CONFED_SET,
                    cls.AS_CONFED_SEQUENCE
            ]:
                assert excep.UpdateMessageError(
                    sub_error=bgp_cons.ERR_MSG_UPDATE_MALFORMED_ASPATH,
                    data='')

            if asn4:
                #  4 bytes asn encode
                as_count = 0
                for asn in as_path_list:
                    as_count += 1
                    as_seg_raw += struct.pack('!I', asn)
            else:
                # 2 bytes asn encode
                as_count = 0
                for asn in as_path_list:
                    as_count += 1
                    as_seg_raw += struct.pack('!H', asn)

            as_path_raw += struct.pack('!B', seg_type) + struct.pack(
                '!B', as_count) + as_seg_raw

        flags = cls.FLAG
        if len(as_path_raw) > 255:
            flags += AttributeFlag.EXTENDED_LENGTH
            return struct.pack('!B', flags) + struct.pack('!B', cls.ID) \
                + struct.pack('!H', len(as_path_raw)) + as_path_raw
        else:
            return struct.pack('!B', flags) + struct.pack('!B', cls.ID) \
                + struct.pack('!B', len(as_path_raw)) + as_path_raw
Пример #19
0
    def construct(cls, value):
        """
        construct a LARGE COMMUNITY path attribute
        :param value:
        """
        large_community_hex = b''
        for large_community in value:
            try:
                value = large_community.split(':')
                for sub_value in value:
                    large_community_hex += struct.pack('!I', int(sub_value))
            except Exception:
                raise excep.UpdateMessageError(
                    sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)

        return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \
            + struct.pack('!B', len(large_community_hex)) + large_community_hex
Пример #20
0
    def construct(cls, value, asn4=False):

        """
        Construct aggregator.
        :param value:
        :param asn4:
        """
        try:
            if asn4:
                agg_raw = struct.pack('!I', value[0]) + netaddr.IPAddress(value[1]).packed
            else:
                agg_raw = struct.pack('!H', value[0]) + netaddr.IPAddress(value[1]).packed

            return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \
                + struct.pack('!B', len(agg_raw)) + agg_raw
        except Exception:
            raise excep.UpdateMessageError(
                sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN,
                data=value)
Пример #21
0
 def parse(cls, value):
     """
     parse BGP large community.
     :param value:
     """
     large_community = []
     if value:
         try:
             length = len(value) / 4
             value_list = list(struct.unpack('!%di' % length, value))
             while value_list:
                 large_community.append(
                     "%s:%s:%s" %
                     (value_list[0], value_list[1], value_list[2]))
                 value_list = value_list[3:]
         except Exception:
             raise excep.UpdateMessageError(
                 sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)
     return large_community
Пример #22
0
    def parse(cls, value):

        try:
            afi, safi, nexthop_length = struct.unpack('!HBB', value[0:4])
            nexthop_data = value[4:4 + nexthop_length]
            nlri_data = 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))
        if afi == afn.AFNUM_INET:
            if safi == safn.SAFNUM_LAB_VPNUNICAST:
                nlri = IPv4MPLSVPN.parse(nlri_data)

        return {
            'afi_safi': (afi, safi),
            'nexthop': nexthop_data,
            'nlri': nlri
        }
Пример #23
0
    def construct(cls, value):
        """
        construct a COMMUNITY path attribute
        :param value:
        """
        community_hex = b''
        for community in value:
            if community.upper() in bgp_cons.WELL_KNOW_COMMUNITY_STR_2_INT:
                value = bgp_cons.WELL_KNOW_COMMUNITY_STR_2_INT[
                    community.upper()]
                community_hex += struct.pack('!I', value)
            else:
                try:
                    value = community.split(':')
                    value = int(value[0]) * 16 * 16 * 16 * 16 + int(value[1])
                    community_hex += struct.pack('!I', value)
                except Exception:
                    raise excep.UpdateMessageError(
                        sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)

        return struct.pack('!B', cls.FLAG) + struct.pack('!B', cls.ID) \
            + struct.pack('!B', len(community_hex)) + community_hex
Пример #24
0
 def parse(cls, value):
     """
     parse BGP community.
     :param value:
     """
     community = []
     if value:
         try:
             length = len(value) / 2
             value_list = list(struct.unpack('!%dH' % length, value))
             while value_list:
                 value_type = value_list[
                     0] * 16 * 16 * 16 * 16 + value_list[1]
                 if value_type in bgp_cons.WELL_KNOW_COMMUNITY_INT_2_STR:
                     community.append(
                         bgp_cons.WELL_KNOW_COMMUNITY_INT_2_STR[value_type])
                 else:
                     community.append("%s:%s" %
                                      (value_list[0], value_list[1]))
                 value_list = value_list[2:]
         except Exception:
             raise excep.UpdateMessageError(
                 sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)
     return community
Пример #25
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)
Пример #26
0
    def parse(cls, value):

        """
        Each Extended Community is encoded as an 8-octet quantity, as
        follows:
        - Type Field : 1 or 2 octets
        - Value Field : Remaining octets
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        | Type high | Type low(*) |                                     |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Value                         |
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        Parse Extended Community attributes.
        :param value : value
        """
        # devide every ext community
        if len(value) % 8 != 0:
            raise excep.UpdateMessageError(
                sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN,
                data=value)

        ext_community = []
        while value:
            comm_type, subtype = struct.unpack('!BB', value[0:2])
            value_tmp = value[2:8]

            comm_code = comm_type * 256 + subtype

            # Route Target
            if comm_code == bgp_cons.BGP_EXT_COM_RT_0:
                # Route Target, Format AS(2bytes):AN(4bytes)
                asn, an = struct.unpack('!HI', value_tmp)
                ext_community.append([bgp_cons.BGP_EXT_COM_RT_0, '%s:%s' % (asn, an)])

            elif comm_code == bgp_cons.BGP_EXT_COM_RT_1:
                # Route Target,Format IPv4 address(4bytes):AN(2bytes)
                ipv4 = str(netaddr.IPAddress(struct.unpack('!I', value_tmp[0:4])[0]))
                an = struct.unpack('!H', value_tmp[4:])[0]
                ext_community.append([bgp_cons.BGP_EXT_COM_RT_1, '%s:%s' % (ipv4, an)])

            elif comm_code == bgp_cons.BGP_EXT_COM_RT_2:
                # Route Target,Format AS(4bytes):AN(2bytes)
                asn, an = struct.unpack('!IH', value_tmp)
                ext_community.append([bgp_cons.BGP_EXT_COM_RT_2, '%s:%s' % (asn, an)])

            # Route Origin
            elif comm_code == bgp_cons.BGP_EXT_COM_RO_0:
                # Route Origin,Format AS(2bytes):AN(4bytes)
                asn, an = struct.unpack('!HI', value_tmp)
                ext_community.append([bgp_cons.BGP_EXT_COM_RO_0, '%s:%s' % (asn, an)])

            elif comm_code == bgp_cons.BGP_EXT_COM_RO_1:
                # Route Origin,Format IP address:AN(2bytes)
                ipv4 = str(netaddr.IPAddress(struct.unpack('!I', value_tmp[0:4])[0]))
                an = struct.unpack('!H', value_tmp[4:])[0]
                ext_community.append([bgp_cons.BGP_EXT_COM_RO_1, '%s:%s' % (ipv4, an)])

            elif comm_code == bgp_cons.BGP_EXT_COM_RO_2:
                # Route Origin,Format AS(2bytes):AN(4bytes)
                asn, an = struct.unpack('!IH', value_tmp)
                ext_community.append([bgp_cons.BGP_EXT_COM_RO_2, '%s:%s' % (asn, an)])

            # BGP Flow spec
            elif comm_code == bgp_cons.BGP_EXT_REDIRECT_NH:
                ipv4 = str(netaddr.IPAddress(int(binascii.b2a_hex(value_tmp[0:4]), 16)))
                copy_flag = struct.unpack('!H', value_tmp[4:])[0]
                ext_community.append([bgp_cons.BGP_EXT_REDIRECT_NH, ipv4, copy_flag])
            elif comm_code == bgp_cons.BGP_EXT_TRA_RATE:
                asn, rate = struct.unpack('!Hf', value_tmp)
                ext_community.append([bgp_cons.BGP_EXT_TRA_RATE, '%s:%s' % (asn, int(rate))])

            elif comm_code == bgp_cons.BGP_EXT_TRA_ACTION:
                bit_value = parse_bit(value_tmp[-1])
                ext_community.append([bgp_cons.BGP_EXT_TRA_ACTION, {'S': bit_value['6'], 'T': bit_value['7']}])
            elif comm_code == bgp_cons.BGP_EXT_REDIRECT_VRF:
                asn, an = struct.unpack('!HI', value_tmp)
                ext_community.append([bgp_cons.BGP_EXT_REDIRECT_VRF, '%s:%s' % (asn, an)])
            elif comm_code == bgp_cons.BGP_EXT_TRA_MARK:
                mark = struct.unpack('!B', value_tmp[-1])[0]
                ext_community.append([bgp_cons.BGP_EXT_TRA_MARK, mark])

            # Transitive Opaque
            elif comm_code == bgp_cons.BGP_EXT_COM_ENCAP:
                ext_community.append([bgp_cons.BGP_EXT_COM_ENCAP, struct.unpack('!I', value_tmp[2:])[0]])
            # EVPN
            elif comm_code == bgp_cons.BGP_EXT_COM_EVPN_ES_IMPORT:
                mac = str(netaddr.EUI(int(binascii.b2a_hex(value_tmp), 16)))
                ext_community.append([comm_code, mac])
            elif comm_code == bgp_cons.BGP_EXT_COM_EVPN_MAC_MOBIL:
                flag = ord(value_tmp[0:1])
                seq = struct.unpack('!I', value_tmp[2:])[0]
                ext_community.append([comm_code, flag, seq])
            elif comm_code == bgp_cons.BGP_EXT_COM_EVPN_ESI_MPLS_LABEL:
                flag = ord(value_tmp[0:1])
                label = struct.unpack('!L', b'\00'+value_tmp[3:])[0]
                label >>= 4
                ext_community.append([comm_code, flag, label])
            elif comm_code == bgp_cons.BGP_EXT_COM_EVPN_ROUTE_MAC:
                ext_community.append([comm_code, str(netaddr.EUI(int(binascii.b2a_hex(value_tmp), 16)))])
            else:
                ext_community.append([bgp_cons.BGP_EXT_COM_UNKNOW, repr(value_tmp)])
                LOG.warn('unknow bgp extended community, type=%s, value=%s', comm_code, repr(value_tmp))

            value = value[8:]

        return ext_community
Пример #27
0
    def parse(cls, value):
        """
        Each Extended Community is encoded as an 8-octet quantity, as
        follows:
        - Type Field : 1 or 2 octets
        - Value Field : Remaining octets
        0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        | Type high | Type low(*) |                                     |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Value                         |
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        Parse Extended Community attributes.
        :param value : value
        """
        # devide every ext community
        if len(value) % 8 != 0:
            raise excep.UpdateMessageError(
                sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=value)

        ext_community = []
        while value:
            comm_type, subtype = struct.unpack('!BB', value[0:2])
            value_tmp = value[2:8]

            comm_code = comm_type * 256 + subtype

            # Route Target
            if comm_code == bgp_cons.BGP_EXT_COM_RT_0:
                # Route Target, Format AS(2bytes):AN(4bytes)
                asn, an = struct.unpack('!HI', value_tmp)
                ext_community.append(
                    (bgp_cons.BGP_EXT_COM_RT_0, '%s:%s' % (asn, an)))

            elif comm_code == bgp_cons.BGP_EXT_COM_RT_1:
                # Route Target,Format IPv4 address(4bytes):AN(2bytes)
                ipv4 = str(
                    netaddr.IPAddress(struct.unpack('!I', value_tmp[0:4])[0]))
                an = struct.unpack('!H', value_tmp[4:])[0]
                ext_community.append(
                    (bgp_cons.BGP_EXT_COM_RT_1, '%s:%s' % (ipv4, an)))

            elif comm_code == bgp_cons.BGP_EXT_COM_RT_2:
                # Route Target,Format AS(4bytes):AN(2bytes)
                asn, an = struct.unpack('!IH', value_tmp)
                ext_community.append(
                    (bgp_cons.BGP_EXT_COM_RT_2, '%s:%s' % (asn, an)))

            # Route Origin
            elif comm_code == bgp_cons.BGP_EXT_COM_RO_0:
                # Route Origin,Format AS(2bytes):AN(4bytes)
                asn, an = struct.unpack('!HI', value_tmp)
                ext_community.append(
                    (bgp_cons.BGP_EXT_COM_RO_0, '%s:%s' % (asn, an)))

            elif comm_code == bgp_cons.BGP_EXT_COM_RO_1:
                # Route Origin,Format IP address:AN(2bytes)
                ipv4 = str(
                    netaddr.IPAddress(struct.unpack('!I', value_tmp[0:4])[0]))
                an = struct.unpack('!H', value_tmp[4:])[0]
                ext_community.append(
                    (bgp_cons.BGP_EXT_COM_RO_1, '%s:%s' % (ipv4, an)))

            elif comm_code == bgp_cons.BGP_EXT_COM_RO_2:
                # Route Origin,Format AS(2bytes):AN(4bytes)
                asn, an = struct.unpack('!IH', value_tmp)
                ext_community.append(
                    (bgp_cons.BGP_EXT_COM_RO_2, '%s:%s' % (asn, an)))

            else:
                ext_community.append(
                    (bgp_cons.BGP_EXT_COM_UNKNOW, repr(value_tmp)))
                LOG.warn('unknow bgp extended community, type=%s, value=%s',
                         comm_code, repr(value_tmp))

            value = value[8:]

        return ext_community
Пример #28
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
        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_LINK_STATE:
                decode_value = LinkState.parse(value=attr_value).dict()[29]

            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_MP_REACH_NLRI:
                decode_value = MpReachNLRI.parse(value=attr_value)

            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)
            else:
                decode_value = binascii.b2a_hex(attr_value)
            attributes[type_code] = decode_value

        return attributes
Пример #29
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