From: Ryoga Saito Date: Tue, 17 Aug 2021 10:22:33 +0000 (+0000) Subject: bgpd: fix parser of srv6 infomation X-Git-Tag: base_8.1~39^2~8 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=73604f82177a01f44001960ad03693d7a6228bd2;p=matthieu%2Ffrr.git bgpd: fix parser of srv6 infomation bgpd couldn't parse SRv6 SID Information Sub-TLV correctly. draft-ietf-bess-srv6-services-07 also defines SRv6 SID Structure Sub-Sub-TLV. This patch adds the parser for SRv6 SID Structure Sub-Sub-TLV. Signed-off-by: Ryoga Saito --- diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index c4d159afd0..1ee92198dd 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2524,6 +2524,152 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */ return 0; } + +/* SRv6 Service Data Sub-Sub-TLV attribute + * draft-ietf-bess-srv6-services-07 + */ +static bgp_attr_parse_ret_t +bgp_attr_srv6_service_data(struct bgp_attr_parser_args *args) +{ + struct peer *const peer = args->peer; + uint8_t type, loc_block_len, loc_node_len, func_len, arg_len, + transposition_len, transposition_offset; + uint16_t length; + size_t headersz = sizeof(type) + sizeof(length); + + if (STREAM_READABLE(peer->curr) < headersz) { + flog_err( + EC_BGP_ATTR_LEN, + "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)", + headersz, STREAM_READABLE(peer->curr)); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + + type = stream_getc(peer->curr); + length = stream_getw(peer->curr); + + if (STREAM_READABLE(peer->curr) < length) { + flog_err( + EC_BGP_ATTR_LEN, + "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)", + length, STREAM_READABLE(peer->curr)); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + + if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE) { + loc_block_len = stream_getc(peer->curr); + loc_node_len = stream_getc(peer->curr); + func_len = stream_getc(peer->curr); + arg_len = stream_getc(peer->curr); + transposition_len = stream_getc(peer->curr); + transposition_offset = stream_getc(peer->curr); + + /* Log SRv6 Service Data Sub-Sub-TLV */ + if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) { + zlog_debug( + "%s: srv6-l3-srv-data loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u, transposition-len=%u, transposition-offset=%u", + __func__, loc_block_len, loc_node_len, func_len, + arg_len, transposition_len, + transposition_offset); + } + } + + else { + if (bgp_debug_update(peer, NULL, NULL, 1)) + zlog_debug( + "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped", + peer->host, type); + + stream_forward_getp(peer->curr, length); + } + + return BGP_ATTR_PARSE_PROCEED; +} + +/* SRv6 Service Sub-TLV attribute + * draft-ietf-bess-srv6-services-07 + */ +static bgp_attr_parse_ret_t +bgp_attr_srv6_service(struct bgp_attr_parser_args *args) +{ + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + struct in6_addr ipv6_sid; + uint8_t type, sid_flags; + uint16_t length, endpoint_behavior; + size_t headersz = sizeof(type) + sizeof(length); + char buf[BUFSIZ]; + + if (STREAM_READABLE(peer->curr) < headersz) { + flog_err( + EC_BGP_ATTR_LEN, + "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)", + headersz, STREAM_READABLE(peer->curr)); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + + type = stream_getc(peer->curr); + length = stream_getw(peer->curr); + + if (STREAM_READABLE(peer->curr) < length) { + flog_err( + EC_BGP_ATTR_LEN, + "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)", + length, STREAM_READABLE(peer->curr)); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + + if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO) { + stream_getc(peer->curr); + stream_get(&ipv6_sid, peer->curr, sizeof(ipv6_sid)); + sid_flags = stream_getc(peer->curr); + endpoint_behavior = stream_getw(peer->curr); + stream_getc(peer->curr); + + /* Log SRv6 Service Sub-TLV */ + if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) { + inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf)); + zlog_debug( + "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x", + __func__, buf, sid_flags, endpoint_behavior); + } + + /* Configure from Info */ + if (attr->srv6_l3vpn) { + flog_err(EC_BGP_ATTRIBUTE_REPEATED, + "Prefix SID SRv6 L3VPN field repeated"); + return bgp_attr_malformed( + args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total); + } + attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, + sizeof(struct bgp_attr_srv6_l3vpn)); + attr->srv6_l3vpn->sid_flags = sid_flags; + attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior; + sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid); + attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn); + + // Sub-Sub-TLV found + if (length > BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) + return bgp_attr_srv6_service_data(args); + } + + /* Placeholder code for unsupported type */ + else { + if (bgp_debug_update(peer, NULL, NULL, 1)) + zlog_debug( + "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped", + peer->host, type); + + stream_forward_getp(peer->curr, length); + } + + return BGP_ATTR_PARSE_PROCEED; +} + /* * Read an individual SID value returning how much data we have read * Returns 0 if there was an error that needs to be passed up the stack @@ -2539,7 +2685,6 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length, uint32_t srgb_range; int srgb_count; uint8_t sid_type, sid_flags; - uint16_t endpoint_behavior; char buf[BUFSIZ]; if (type == BGP_PREFIX_SID_LABEL_INDEX) { @@ -2694,45 +2839,20 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length, /* Placeholder code for the SRv6 L3 Service type */ else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) { - if (STREAM_READABLE(peer->curr) < length - || length != BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH) { - flog_err(EC_BGP_ATTR_LEN, - "Prefix SID SRv6 L3-Service length is %hu instead of %u", - length, BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH); + if (STREAM_READABLE(peer->curr) < length) { + flog_err( + EC_BGP_ATTR_LEN, + "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain", + length, STREAM_READABLE(peer->curr)); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } - /* Parse L3-SERVICE Sub-TLV */ - stream_getc(peer->curr); /* reserved */ - stream_get(&ipv6_sid, peer->curr, - sizeof(ipv6_sid)); /* sid_value */ - sid_flags = stream_getc(peer->curr); /* sid_flags */ - endpoint_behavior = stream_getw(peer->curr); /* endpoint */ - stream_getc(peer->curr); /* reserved */ - - /* Log L3-SERVICE Sub-TLV */ - if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) { - inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf)); - zlog_debug( - "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x", - __func__, buf, sid_flags, endpoint_behavior); - } + /* ignore reserved */ + stream_getc(peer->curr); - /* Configure from Info */ - if (attr->srv6_l3vpn) { - flog_err(EC_BGP_ATTRIBUTE_REPEATED, - "Prefix SID SRv6 L3VPN field repeated"); - return bgp_attr_malformed( - args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total); - } - attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, - sizeof(struct bgp_attr_srv6_l3vpn)); - attr->srv6_l3vpn->sid_flags = sid_flags; - attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior; - sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid); - attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn); + return bgp_attr_srv6_service(args); } /* Placeholder code for Unsupported TLV */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index d76b2d5005..7eb1c8cf0e 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -76,6 +76,9 @@ #define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO 1 #define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH 21 +/* SRv6 Service Data Sub-Sub-TLV types */ +#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE 1 + #define BGP_ATTR_NH_AFI(afi, attr) \ ((afi != AFI_L2VPN) ? afi : \ ((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) ? AFI_IP : AFI_IP6))