From 1840384bae2a0ab4d79781bda300ce8f54313d3b Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 14 Oct 2019 18:02:22 +0200 Subject: [PATCH] bgpd: flowspec code support for ipv6 until now, the assumption was done in bgp flowspec code that the information contained was an ipv4 flowspec prefix. now that it is possible to handle ipv4 or ipv6 flowspec prefixes, that information is stored in prefix_flowspec attribute. Also, some unlocking is done in order to process ipv4 and ipv6 flowspec entries. Signed-off-by: Philippe Guibert --- bgpd/bgp_debug.c | 3 ++- bgpd/bgp_flowspec.c | 17 ++++++++--------- bgpd/bgp_flowspec.h | 3 ++- bgpd/bgp_flowspec_util.c | 28 ++++++++++++++++++++-------- bgpd/bgp_flowspec_util.h | 8 +++++--- bgpd/bgp_flowspec_vty.c | 15 ++++++++++++--- bgpd/bgp_nht.c | 2 +- bgpd/bgp_pbr.c | 7 +++---- bgpd/bgp_pbr.h | 1 + bgpd/bgp_route.c | 4 +++- bgpd/bgp_routemap.c | 6 +++++- 11 files changed, 62 insertions(+), 32 deletions(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 255a7f238b..e9d7c9e8aa 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -2692,7 +2692,8 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, bgp_fs_nlri_get_string((unsigned char *)fs->prefix.ptr, fs->prefix.prefixlen, return_string, - NLRI_STRING_FORMAT_DEBUG, NULL); + NLRI_STRING_FORMAT_DEBUG, NULL, + family2afi(fs->prefix.family)); snprintf(str, size, "FS %s Match{%s}", afi2str(afi), return_string); } else diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c index 17c41636de..03fc1f52c3 100644 --- a/bgpd/bgp_flowspec.c +++ b/bgpd/bgp_flowspec.c @@ -33,7 +33,8 @@ #include "bgpd/bgp_debug.h" #include "bgpd/bgp_errors.h" -static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len) +static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len, + afi_t afi) { uint32_t offset = 0; int type; @@ -48,7 +49,8 @@ static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len) ret = bgp_flowspec_ip_address( BGP_FLOWSPEC_VALIDATE_ONLY, nlri_content + offset, - len - offset, NULL, &error); + len - offset, NULL, &error, + afi); break; case FLOWSPEC_IP_PROTOCOL: case FLOWSPEC_PORT: @@ -103,11 +105,6 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, afi = packet->afi; safi = packet->safi; - if (afi == AFI_IP6) { - flog_err(EC_LIB_DEVELOPMENT, "BGP flowspec IPv6 not supported"); - return BGP_NLRI_PARSE_ERROR_FLOWSPEC_IPV6_NOT_SUPPORTED; - } - if (packet->length >= FLOWSPEC_NLRI_SIZELIMIT_EXTENDED) { flog_err(EC_BGP_FLOWSPEC_PACKET, "BGP flowspec nlri length maximum reached (%u)", @@ -137,7 +134,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, psize); return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; } - if (bgp_fs_nlri_validate(pnt, psize) < 0) { + if (bgp_fs_nlri_validate(pnt, psize, afi) < 0) { flog_err( EC_BGP_FLOWSPEC_PACKET, "Bad flowspec format or NLRI options not supported"); @@ -147,6 +144,7 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, p.prefixlen = 0; /* Flowspec encoding is in bytes */ p.u.prefix_flowspec.prefixlen = psize; + p.u.prefix_flowspec.family = afi2family(afi); temp = XCALLOC(MTYPE_TMP, psize); memcpy(temp, pnt, psize); p.u.prefix_flowspec.ptr = (uintptr_t) temp; @@ -161,7 +159,8 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr, p.u.prefix_flowspec.ptr, p.u.prefix_flowspec.prefixlen, return_string, - NLRI_STRING_FORMAT_MIN, NULL); + NLRI_STRING_FORMAT_MIN, NULL, + afi); snprintf(ec_string, sizeof(ec_string), "EC{none}"); if (attr && attr->ecommunity) { diff --git a/bgpd/bgp_flowspec.h b/bgpd/bgp_flowspec.h index 94c571f2fc..d1a59a672d 100644 --- a/bgpd/bgp_flowspec.h +++ b/bgpd/bgp_flowspec.h @@ -41,7 +41,8 @@ extern int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, extern void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, char *return_string, int format, - json_object *json_path); + json_object *json_path, + afi_t afi); extern void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, struct bgp_path_info *path, int display, diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c index 764d2f87ae..0e879e8168 100644 --- a/bgpd/bgp_flowspec_util.c +++ b/bgpd/bgp_flowspec_util.c @@ -76,6 +76,7 @@ static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content, int len, return ret; } + bool bgp_flowspec_contains_prefix(const struct prefix *pfs, struct prefix *input, int prefix_check) { @@ -84,6 +85,7 @@ bool bgp_flowspec_contains_prefix(const struct prefix *pfs, int ret = 0, error = 0; uint8_t *nlri_content = (uint8_t *)pfs->u.prefix_flowspec.ptr; size_t len = pfs->u.prefix_flowspec.prefixlen; + afi_t afi = family2afi(pfs->u.prefix_flowspec.family); struct prefix compare; error = 0; @@ -98,7 +100,8 @@ bool bgp_flowspec_contains_prefix(const struct prefix *pfs, BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE, nlri_content+offset, len - offset, - &compare, &error); + &compare, &error, + afi); if (ret <= 0) break; if (prefix_check && @@ -158,7 +161,8 @@ bool bgp_flowspec_contains_prefix(const struct prefix *pfs, int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type, uint8_t *nlri_ptr, uint32_t max_len, - void *result, int *error) + void *result, int *error, + afi_t afi) { char *display = (char *)result; /* for return_string */ struct prefix *prefix = (struct prefix *)result; @@ -417,7 +421,8 @@ int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type, } int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, - struct bgp_pbr_entry_main *bpem) + struct bgp_pbr_entry_main *bpem, + afi_t afi) { int offset = 0, error = 0; struct prefix *prefix; @@ -444,7 +449,8 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE, nlri_content + offset, len - offset, - prefix, &error); + prefix, &error, + afi); if (error < 0) flog_err(EC_BGP_FLOWSPEC_PACKET, "%s: flowspec_ip_address error %d", @@ -599,7 +605,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, /* return 1 if FS entry invalid or no NH IP */ bool bgp_flowspec_get_first_nh(struct bgp *bgp, struct bgp_path_info *pi, - struct prefix *p) + struct prefix *p, afi_t afi) { struct bgp_pbr_entry_main api; int i; @@ -615,9 +621,15 @@ bool bgp_flowspec_get_first_nh(struct bgp *bgp, struct bgp_path_info *pi, api_action = &api.actions[i]; if (api_action->action != ACTION_REDIRECT_IP) continue; - p->family = AF_INET; - p->prefixlen = IPV4_MAX_BITLEN; - p->u.prefix4 = api_action->u.zr.redirect_ip_v4; + p->family = afi2family(afi); + if (afi == AFI_IP) { + p->prefixlen = IPV4_MAX_BITLEN; + p->u.prefix4 = api_action->u.zr.redirect_ip_v4; + } else { + p->prefixlen = IPV6_MAX_BITLEN; + memcpy(&p->u.prefix6, &api_action->u.zr.redirect_ip_v6, + sizeof(struct in6_addr)); + } return false; } return true; diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h index 0e78c7a53c..26d919d7d2 100644 --- a/bgpd/bgp_flowspec_util.h +++ b/bgpd/bgp_flowspec_util.h @@ -39,7 +39,8 @@ extern int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type, 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); + void *result, int *error, + afi_t afi); extern int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type, uint8_t *nlri_ptr, @@ -48,13 +49,14 @@ extern int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type, struct bgp_pbr_entry_main; extern int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len, - struct bgp_pbr_entry_main *bpem); + struct bgp_pbr_entry_main *bpem, + afi_t afi); extern bool bgp_flowspec_contains_prefix(const struct prefix *pfs, struct prefix *input, int prefix_check); extern bool bgp_flowspec_get_first_nh(struct bgp *bgp, struct bgp_path_info *pi, - struct prefix *nh); + struct prefix *nh, afi_t afi); #endif /* _FRR_BGP_FLOWSPEC_UTIL_H */ diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index e309fa948e..5703d86be3 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -93,7 +93,8 @@ static const struct message bgp_flowspec_display_min[] = { */ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, char *return_string, int format, - json_object *json_path) + json_object *json_path, + afi_t afi) { uint32_t offset = 0; int type; @@ -127,7 +128,8 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len, type_util, nlri_content+offset, len - offset, - local_string, &error); + local_string, &error, + afi); if (ret <= 0) break; if (json_path) { @@ -263,7 +265,12 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, json_object *json_ecom_path = NULL; json_object *json_time_path = NULL; char timebuf[BGP_UPTIME_LEN]; + struct bgp_dest *dest = NULL; + if (path) + dest = path->net; + if (dest) + bgp_dest_get_bgp_table_info(dest); /* Print prefix */ if (p != NULL) { if (p->family != AF_FLOWSPEC) @@ -282,7 +289,9 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p, p->u.prefix_flowspec.prefixlen, return_string, display, - json_nlri_path); + json_nlri_path, + family2afi(p->u.prefix_flowspec + .family)); if (display == NLRI_STRING_FORMAT_LARGE) vty_out(vty, "%s", return_string); else if (display == NLRI_STRING_FORMAT_DEBUG) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index a74b5f91ac..a780fb7347 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -544,7 +544,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) if (!pi->peer) return -1; return bgp_flowspec_get_first_nh(pi->peer->bgp, - pi, p); + pi, p, afi); } memset(p, 0, sizeof(struct prefix)); switch (afi) { diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 7c3e8cd70e..38b1ae4da9 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -668,6 +668,7 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api) } /* return -1 if build or validation failed */ + int bgp_pbr_build_and_validate_entry(const struct prefix *p, struct bgp_path_info *path, struct bgp_pbr_entry_main *api) @@ -679,13 +680,13 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p, struct bgp_pbr_entry_action *api_action; struct prefix *src = NULL, *dst = NULL; int valid_prefix = 0; - afi_t afi = AFI_IP; struct bgp_pbr_entry_action *api_action_redirect_ip = NULL; bool discard_action_found = false; + afi_t afi = family2afi(p->u.prefix_flowspec.family); /* extract match from flowspec entries */ ret = bgp_flowspec_match_rules_fill((uint8_t *)p->u.prefix_flowspec.ptr, - p->u.prefix_flowspec.prefixlen, api); + p->u.prefix_flowspec.prefixlen, api, afi); if (ret < 0) return -1; /* extract actiosn from flowspec ecom list */ @@ -2598,8 +2599,6 @@ void bgp_pbr_update_entry(struct bgp *bgp, const struct prefix *p, { struct bgp_pbr_entry_main api; - if (afi == AFI_IP6) - return; /* IPv6 not supported */ if (safi != SAFI_FLOWSPEC) return; /* not supported */ /* Make Zebra API structure. */ diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h index 043853a157..52bb3b5410 100644 --- a/bgpd/bgp_pbr.h +++ b/bgpd/bgp_pbr.h @@ -79,6 +79,7 @@ struct bgp_pbr_entry_action { vrf_id_t redirect_vrf; struct _pbr_redirect_ip { struct in_addr redirect_ip_v4; + struct in6_addr redirect_ip_v6; uint8_t duplicate; } zr; uint8_t marking_dscp; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3a627b4486..eefff4bef8 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10008,11 +10008,13 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, if (dest_p->family == AF_FLOWSPEC) { char retstr[BGP_FLOWSPEC_STRING_DISPLAY_MAX]; + bgp_fs_nlri_get_string( (unsigned char *) dest_p->u.prefix_flowspec.ptr, dest_p->u.prefix_flowspec.prefixlen, - retstr, NLRI_STRING_FORMAT_MIN, NULL); + retstr, NLRI_STRING_FORMAT_MIN, NULL, + family2afi(dest_p->u.prefix_flowspec.family)); if (first) vty_out(vty, "\"%s/%d\": ", retstr, dest_p->u.prefix_flowspec diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 97153cfb72..5644daba62 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -594,10 +594,14 @@ route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist, memset(&api, 0, sizeof(api)); + if (family2afi(p->u.prefix_flowspec.family) != afi) + return RMAP_NOMATCH; + /* extract match from flowspec entries */ ret = bgp_flowspec_match_rules_fill( (uint8_t *)p->u.prefix_flowspec.ptr, - p->u.prefix_flowspec.prefixlen, &api); + p->u.prefix_flowspec.prefixlen, &api, + afi); if (ret < 0) return RMAP_NOMATCH; if (api.match_bitmask & PREFIX_DST_PRESENT || -- 2.39.5