diff options
author | Philippe Guibert <philippe.guibert@6wind.com> | 2019-10-16 08:42:30 +0200 |
---|---|---|
committer | Philippe Guibert <philippe.guibert@6wind.com> | 2020-08-21 13:37:08 +0200 |
commit | 9cec4121623c18eb5d826420e2078e2a78242362 (patch) | |
tree | 345c4ced2b1c8a527dc8dd11e7a2b2e0c2c71599 | |
parent | bgpd: flowspec code support for ipv6 (diff) | |
download | frr-9cec4121623c18eb5d826420e2078e2a78242362.tar.xz frr-9cec4121623c18eb5d826420e2078e2a78242362.zip |
bgpd: ipv6 flowspec address decoding and validation
as per [0], ipv6 adress format introduces an ipv6 offset that needs to
be extracted too. The change include the validation, decoding for
further usage with policy-routing and decoding for dumping.
[0] https://tools.ietf.org/html/draft-ietf-idr-flow-spec-v6-09
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
-rw-r--r-- | bgpd/bgp_flowspec.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_flowspec_util.c | 48 | ||||
-rw-r--r-- | bgpd/bgp_flowspec_util.h | 2 | ||||
-rw-r--r-- | bgpd/bgp_flowspec_vty.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_pbr.c | 290 | ||||
-rw-r--r-- | bgpd/bgp_pbr.h | 2 |
6 files changed, 241 insertions, 105 deletions
diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index 03fc1f52c..19db1159c 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -50,7 +50,7 @@ static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len, BGP_FLOWSPEC_VALIDATE_ONLY, nlri_content + offset, len - offset, NULL, &error, - afi); + afi, NULL); break; case FLOWSPEC_IP_PROTOCOL: case FLOWSPEC_PORT: diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c index 0e879e816..2dd35696d 100644 --- a/bgpd/bgp_flowspec_util.c +++ b/bgpd/bgp_flowspec_util.c @@ -101,7 +101,7 @@ bool bgp_flowspec_contains_prefix(const struct prefix *pfs, nlri_content+offset, len - offset, &compare, &error, - afi); + afi, NULL); if (ret <= 0) break; if (prefix_check && @@ -162,13 +162,15 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type, uint8_t *nlri_ptr, uint32_t max_len, void *result, int *error, - afi_t afi) + afi_t afi, + uint8_t *ipv6_offset) { char *display = (char *)result; /* for return_string */ struct prefix *prefix = (struct prefix *)result; uint32_t offset = 0; struct prefix prefix_local; int psize; + uint8_t prefix_offset = 0; *error = 0; memset(&prefix_local, 0, sizeof(struct prefix)); @@ -176,8 +178,13 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type, prefix_local.prefixlen = nlri_ptr[offset]; psize = PSIZE(prefix_local.prefixlen); offset++; - /* TODO Flowspec IPv6 Support */ - prefix_local.family = AF_INET; + prefix_local.family = afi2family(afi); + if (prefix_local.family == AF_INET6) { + prefix_offset = nlri_ptr[offset]; + if (ipv6_offset) + *ipv6_offset = prefix_offset; + offset++; + } /* Prefix length check. */ if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8) *error = -1; @@ -193,11 +200,28 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type, offset += psize; switch (type) { case BGP_FLOWSPEC_RETURN_STRING: - prefix2str(&prefix_local, display, - BGP_FLOWSPEC_STRING_DISPLAY_MAX); + if (prefix_local.family == AF_INET6) { + char str[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; + int ret; + + prefix2str(&prefix_local, str, + BGP_FLOWSPEC_STRING_DISPLAY_MAX); + ret = snprintf(display, BGP_FLOWSPEC_STRING_DISPLAY_MAX, + "%s/off %u", + str, prefix_offset); + if (ret < 0) { + *error = -1; + break; + } + } else + prefix2str(&prefix_local, display, + BGP_FLOWSPEC_STRING_DISPLAY_MAX); break; case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE: - PREFIX_COPY_IPV4(prefix, &prefix_local) + if (prefix_local.family == AF_INET) + PREFIX_COPY_IPV4(prefix, &prefix_local) + else + PREFIX_COPY_IPV6(prefix, &prefix_local) break; case BGP_FLOWSPEC_VALIDATE_ONLY: default: @@ -430,6 +454,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, uint8_t *match_num; uint8_t bitmask = 0; int ret = 0, type; + uint8_t *prefix_offset; while (offset < len - 1 && error >= 0) { type = nlri_content[offset]; @@ -441,16 +466,18 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, if (type == FLOWSPEC_DEST_PREFIX) { bitmask |= PREFIX_DST_PRESENT; prefix = &bpem->dst_prefix; + prefix_offset = &bpem->dst_prefix_offset; } else { bitmask |= PREFIX_SRC_PRESENT; prefix = &bpem->src_prefix; + prefix_offset = &bpem->src_prefix_offset; } ret = bgp_flowspec_ip_address( BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE, nlri_content + offset, len - offset, prefix, &error, - afi); + afi, prefix_offset); if (error < 0) flog_err(EC_BGP_FLOWSPEC_PACKET, "%s: flowspec_ip_address error %d", @@ -462,6 +489,11 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, if (prefix->family == AF_INET && prefix->u.prefix4.s_addr == INADDR_ANY) bpem->match_bitmask_iprule |= bitmask; + else if (prefix->family == AF_INET6 + && !memcmp(&prefix->u.prefix6, + &in6addr_any, + sizeof(struct in6_addr))) + bpem->match_bitmask_iprule |= bitmask; else bpem->match_bitmask |= bitmask; } diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h index 26d919d7d..6cc4854d7 100644 --- a/bgpd/bgp_flowspec_util.h +++ b/bgpd/bgp_flowspec_util.h @@ -40,7 +40,7 @@ extern int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type, uint8_t *nlri_ptr, uint32_t max_len, void *result, int *error, - afi_t afi); + afi_t afi, uint8_t *ipv6_offset); extern int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type, uint8_t *nlri_ptr, diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 5703d86be..d3e95b123 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -129,7 +129,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, nlri_content+offset, len - offset, local_string, &error, - afi); + afi, NULL); if (ret <= 0) break; if (json_path) { diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 38b1ae4da..c20bade97 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -168,35 +168,61 @@ static int bgp_pbr_match_walkcb(struct hash_bucket *bucket, void *arg) return HASHWALK_CONTINUE; } -static int sprintf_bgp_pbr_match_val(char *str, struct bgp_pbr_match_val *mval, - const char *prepend) +static int snprintf_bgp_pbr_match_val(char *str, int len, struct bgp_pbr_match_val *mval, + const char *prepend) { char *ptr = str; + int delta; - if (prepend) - ptr += sprintf(ptr, "%s", prepend); - else { - if (mval->unary_operator & OPERATOR_UNARY_OR) - ptr += sprintf(ptr, ", or "); - if (mval->unary_operator & OPERATOR_UNARY_AND) - ptr += sprintf(ptr, ", and "); - } - if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN) - ptr += sprintf(ptr, "<"); - if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN) - ptr += sprintf(ptr, ">"); - if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO) - ptr += sprintf(ptr, "="); - if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH) - ptr += sprintf(ptr, "match"); - ptr += sprintf(ptr, " %u", mval->value); + if (prepend) { + delta = snprintf(ptr, len, "%s", prepend); + ptr += delta; + len -= delta; + } else { + if (mval->unary_operator & OPERATOR_UNARY_OR) { + delta = snprintf(ptr, len, ", or "); + ptr += delta; + len -= delta; + } + if (mval->unary_operator & OPERATOR_UNARY_AND) { + delta = snprintf(ptr, len, ", and "); + ptr += delta; + len -= delta; + } + } + if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN) { + delta = snprintf(ptr, len, "<"); + ptr += delta; + len -= delta; + } + if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN) { + delta = snprintf(ptr, len, ">"); + ptr += delta; + len -= delta; + } + if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO) { + delta = snprintf(ptr, len, "="); + ptr += delta; + len -= delta; + } + if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH) { + delta = snprintf(ptr, len, "match"); + ptr += delta; + len -= delta; + } + ptr += snprintf(ptr, len, " %u", mval->value); return (int)(ptr - str); } -#define INCREMENT_DISPLAY(_ptr, _cnt) do { \ - if (_cnt) \ - (_ptr) += sprintf((_ptr), "; "); \ - _cnt++; \ +#define INCREMENT_DISPLAY(_ptr, _cnt, _len) do { \ + int sn_delta; \ + \ + if (_cnt) { \ + sn_delta = snprintf((_ptr), (_len), "; ");\ + (_len) -= sn_delta; \ + (_ptr) += sn_delta; \ + } \ + (_cnt)++; \ } while (0) /* this structure can be used for port range, @@ -1275,132 +1301,208 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api) char *ptr = return_string; char buff[64]; int nb_items = 0; + int delta, len = sizeof(return_string); - ptr += sprintf(ptr, "MATCH : "); + delta = snprintf(ptr, sizeof(return_string), "MATCH : "); + len -= delta; + ptr += delta; if (api->match_bitmask & PREFIX_SRC_PRESENT) { struct prefix *p = &(api->src_prefix); - ptr += sprintf(ptr, "@src %s", prefix2str(p, buff, 64)); - INCREMENT_DISPLAY(ptr, nb_items); + if (api->src_prefix_offset) + delta = snprintf(ptr, len, "@src %s/off%u", + prefix2str(p, buff, 64), + api->src_prefix_offset); + else + delta = snprintf(ptr, len, "@src %s", + prefix2str(p, buff, 64)); + len -= delta; + ptr += delta; + INCREMENT_DISPLAY(ptr, nb_items, len); } if (api->match_bitmask & PREFIX_DST_PRESENT) { struct prefix *p = &(api->dst_prefix); - INCREMENT_DISPLAY(ptr, nb_items); - ptr += sprintf(ptr, "@dst %s", prefix2str(p, buff, 64)); + INCREMENT_DISPLAY(ptr, nb_items, len); + if (api->dst_prefix_offset) + delta = snprintf(ptr, len, "@dst %s/off%u", + prefix2str(p, buff, 64), + api->dst_prefix_offset); + else + delta = snprintf(ptr, len, "@dst %s", prefix2str(p, buff, 64)); + len -= delta; + ptr += delta; } if (api->match_protocol_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_protocol_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->protocol[i], - i > 0 ? NULL : "@proto "); + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_protocol_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->protocol[i], + i > 0 ? NULL : "@proto "); + len -= delta; + ptr += delta; + } if (api->match_src_port_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_src_port_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->src_port[i], - i > 0 ? NULL : "@srcport "); + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_src_port_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->src_port[i], + i > 0 ? NULL : "@srcport "); + len -= delta; + ptr += delta; + } if (api->match_dst_port_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_dst_port_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->dst_port[i], - i > 0 ? NULL : "@dstport "); + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_dst_port_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dst_port[i], + i > 0 ? NULL : "@dstport "); + len -= delta; + ptr += delta; + } if (api->match_port_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_port_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->port[i], - i > 0 ? NULL : "@port "); + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_port_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->port[i], + i > 0 ? NULL : "@port "); + len -= delta; + ptr += delta; + } if (api->match_icmp_type_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_icmp_type_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->icmp_type[i], - i > 0 ? NULL : "@icmptype "); + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_icmp_type_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_type[i], + i > 0 ? NULL : "@icmptype "); + len -= delta; + ptr += delta; + } if (api->match_icmp_code_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_icmp_code_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->icmp_code[i], - i > 0 ? NULL : "@icmpcode "); + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_icmp_code_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_code[i], + i > 0 ? NULL : "@icmpcode "); + len -= delta; + ptr += delta; + } if (api->match_packet_length_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_packet_length_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->packet_length[i], - i > 0 ? NULL : "@plen "); + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_packet_length_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->packet_length[i], + i > 0 ? NULL : "@plen "); + len -= delta; + ptr += delta; + } if (api->match_dscp_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_dscp_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->dscp[i], - i > 0 ? NULL : "@dscp "); + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_dscp_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dscp[i], + i > 0 ? NULL : "@dscp "); + len -= delta; + ptr += delta; + } if (api->match_tcpflags_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_tcpflags_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->tcpflags[i], - i > 0 ? NULL : "@tcpflags "); + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_tcpflags_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->tcpflags[i], + i > 0 ? NULL : "@tcpflags "); + len -= delta; + ptr += delta; + } if (api->match_fragment_num) - INCREMENT_DISPLAY(ptr, nb_items); - for (i = 0; i < api->match_fragment_num; i++) - ptr += sprintf_bgp_pbr_match_val(ptr, &api->fragment[i], - i > 0 ? NULL : "@fragment "); - if (!nb_items) + INCREMENT_DISPLAY(ptr, nb_items, len); + for (i = 0; i < api->match_fragment_num; i++) { + delta = snprintf_bgp_pbr_match_val(ptr, len, &api->fragment[i], + i > 0 ? NULL : "@fragment "); + len -= delta; + ptr += delta; + } + + len = sizeof(return_string); + if (!nb_items) { ptr = return_string; - else - ptr += sprintf(ptr, "; "); - if (api->action_num) - ptr += sprintf(ptr, "SET : "); + } else { + len -= (ptr - return_string); + delta = snprintf(ptr, len, "; "); + len -= delta; + ptr += delta; + } + if (api->action_num) { + delta = snprintf(ptr, len, "SET : "); + len -= delta; + ptr += delta; + } nb_items = 0; for (i = 0; i < api->action_num; i++) { switch (api->actions[i].action) { case ACTION_TRAFFICRATE: - INCREMENT_DISPLAY(ptr, nb_items); - ptr += sprintf(ptr, "@set rate %f", - api->actions[i].u.r.rate); + INCREMENT_DISPLAY(ptr, nb_items, len); + delta = snprintf(ptr, len, "@set rate %f", + api->actions[i].u.r.rate); + len -= delta; + ptr += delta; break; case ACTION_TRAFFIC_ACTION: - INCREMENT_DISPLAY(ptr, nb_items); - ptr += sprintf(ptr, "@action "); + INCREMENT_DISPLAY(ptr, nb_items, len); + delta = snprintf(ptr, len, "@action "); + len -= delta; + ptr += delta; if (api->actions[i].u.za.filter - & TRAFFIC_ACTION_TERMINATE) - ptr += sprintf(ptr, - " terminate (apply filter(s))"); + & TRAFFIC_ACTION_TERMINATE) { + delta = snprintf(ptr, len, + " terminate (apply filter(s))"); + len -= delta; + ptr += delta; + } if (api->actions[i].u.za.filter - & TRAFFIC_ACTION_DISTRIBUTE) - ptr += sprintf(ptr, " distribute"); + & TRAFFIC_ACTION_DISTRIBUTE) { + delta = snprintf(ptr, len, " distribute"); + len -= delta; + ptr += delta; + } if (api->actions[i].u.za.filter - & TRAFFIC_ACTION_SAMPLE) - ptr += sprintf(ptr, " sample"); + & TRAFFIC_ACTION_SAMPLE) { + delta = snprintf(ptr, len, " sample"); + len -= delta; + ptr += delta; + } break; case ACTION_REDIRECT_IP: - INCREMENT_DISPLAY(ptr, nb_items); char local_buff[INET_ADDRSTRLEN]; + INCREMENT_DISPLAY(ptr, nb_items, len); if (inet_ntop(AF_INET, &api->actions[i].u.zr.redirect_ip_v4, local_buff, INET_ADDRSTRLEN) != NULL) - ptr += sprintf(ptr, + delta = snprintf(ptr, len, "@redirect ip nh %s", local_buff); + len -= delta; + ptr += delta; break; case ACTION_REDIRECT: { struct vrf *vrf; vrf = vrf_lookup_by_id(api->actions[i].u.redirect_vrf); - INCREMENT_DISPLAY(ptr, nb_items); - ptr += sprintf(ptr, "@redirect vrf %s(%u)", - VRF_LOGNAME(vrf), - api->actions[i].u.redirect_vrf); + INCREMENT_DISPLAY(ptr, nb_items, len); + delta = snprintf(ptr, len, "@redirect vrf %s(%u)", + VRF_LOGNAME(vrf), + api->actions[i].u.redirect_vrf); + len -= delta; + ptr += delta; break; } case ACTION_MARKING: - INCREMENT_DISPLAY(ptr, nb_items); - ptr += sprintf(ptr, "@set dscp %u", - api->actions[i].u.marking_dscp); + INCREMENT_DISPLAY(ptr, nb_items, len); + delta = snprintf(ptr, len, "@set dscp %u", + api->actions[i].u.marking_dscp); + len -= delta; + ptr += delta; break; default: break; diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h index 52bb3b541..ff771f88d 100644 --- a/bgpd/bgp_pbr.h +++ b/bgpd/bgp_pbr.h @@ -118,6 +118,8 @@ struct bgp_pbr_entry_main { struct prefix src_prefix; struct prefix dst_prefix; + uint8_t src_prefix_offset; + uint8_t dst_prefix_offset; #define PROTOCOL_UDP 17 #define PROTOCOL_TCP 6 |