From 8f2421871071160ad5c856d6c389a3f7d17a2325 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 17 Oct 2019 16:11:57 +0200 Subject: [PATCH] bgpd: support for flowspec interface list per address-family in addition to ipv4 flowspec, ipv6 flowspec address family can configure its own list of interfaces to monitor. this permits filtering the policy routing only on some interfaces. Signed-off-by: Philippe Guibert --- bgpd/bgp_ecommunity.c | 19 ++++++++++--------- bgpd/bgp_flowspec_vty.c | 33 ++++++++++++++++++++++++--------- bgpd/bgp_pbr.c | 9 ++++++--- bgpd/bgp_pbr.h | 2 ++ bgpd/bgp_zebra.c | 21 +++++++++++++-------- 5 files changed, 55 insertions(+), 29 deletions(-) diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 9a987ad1e7..f45fa2bed5 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -195,8 +195,7 @@ ecommunity_uniq_sort_internal(struct ecommunity *ecom, new->unit_size = ecom_size; for (i = 0; i < ecom->size; i++) { - eval = (void *)(ecom->val - + (i * ecom_size)); + eval = (void *)(ecom->val + (i * ecom_size)); ecommunity_add_val_internal(new, eval, false, false, ecom_size); } return new; @@ -549,20 +548,24 @@ static const char *ecommunity_gettoken(const char *str, limit = endptr = strrchr(p, ':'); if (!endptr) goto error; + endptr++; as = strtoul(endptr, &endptr, 10); if (*endptr != '\0' || as == BGP_AS4_MAX) goto error; + memcpy(buf, p, (limit - p)); buf[limit - p] = '\0'; ret = inet_pton(AF_INET6, buf, &ip6); if (ret == 0) goto error; + ecomm_type = ECOMMUNITY_ENCODE_TRANS_EXP; if (ecommunity_encode_internal(ecomm_type, - ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6, - 1, 0, NULL, &ip6, as, eval_ptr)) + ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6, + 1, 0, NULL, &ip6, as, eval_ptr)) goto error; + *token = ecommunity_token_val6; while (isdigit((int)*p) || *p == ':' || *p == '.') { p++; @@ -667,8 +670,7 @@ static struct ecommunity *ecommunity_str2com_internal(const char *str, int type, case ecommunity_token_val: if (keyword_included) { if (!keyword) { - if (ecom) - ecommunity_free(&ecom); + ecommunity_free(&ecom); return NULL; } keyword = 0; @@ -682,8 +684,7 @@ static struct ecommunity *ecommunity_str2com_internal(const char *str, int type, case ecommunity_token_val6: if (keyword_included) { if (!keyword) { - if (ecom) - ecommunity_free(&ecom); + ecommunity_free(&ecom); return NULL; } keyword = 0; @@ -1039,7 +1040,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) sub_type = *pnt++; if (sub_type == ECOMMUNITY_ROUTE_TARGET) { - char buf[64]; + char buf[ECOMMUNITY_STRLEN]; memset(buf, 0, sizeof(buf)); ecommunity_rt_soo_str_internal(buf, sizeof(buf), diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index b4bec75f0a..cc6d1ed457 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -509,10 +509,17 @@ int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp, struct bgp_pbr_interface_head *head; bool bgp_pbr_interface_any; - if (!bgp_pbr_cfg || safi != SAFI_FLOWSPEC || afi != AFI_IP) + if (!bgp_pbr_cfg || safi != SAFI_FLOWSPEC) return 0; - head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); - bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv4; + if (afi == AFI_IP) { + head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); + bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv4; + } else if (afi == AFI_IP6) { + head = &(bgp_pbr_cfg->ifaces_by_name_ipv6); + bgp_pbr_interface_any = bgp_pbr_cfg->pbr_interface_any_ipv6; + } else { + return 0; + } if (!RB_EMPTY(bgp_pbr_interface_head, head) || !bgp_pbr_interface_any) declare_node = true; @@ -523,7 +530,8 @@ int bgp_fs_config_write_pbr(struct vty *vty, struct bgp *bgp, } static int bgp_fs_local_install_interface(struct bgp *bgp, - const char *no, const char *ifname) + const char *no, const char *ifname, + afi_t afi) { struct bgp_pbr_interface *pbr_if; struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg; @@ -532,14 +540,19 @@ static int bgp_fs_local_install_interface(struct bgp *bgp, if (!bgp_pbr_cfg) return CMD_SUCCESS; - head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); - bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv4); + if (afi == AFI_IP) { + head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); + bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv4); + } else { + head = &(bgp_pbr_cfg->ifaces_by_name_ipv6); + bgp_pbr_interface_any = &(bgp_pbr_cfg->pbr_interface_any_ipv6); + } if (no) { if (!ifname) { if (*bgp_pbr_interface_any) { *bgp_pbr_interface_any = false; /* remove all other interface list */ - bgp_pbr_reset(bgp, AFI_IP); + bgp_pbr_reset(bgp, afi); } return CMD_SUCCESS; } @@ -563,7 +576,7 @@ static int bgp_fs_local_install_interface(struct bgp *bgp, if (!*bgp_pbr_interface_any) { /* remove all other interface list */ - bgp_pbr_reset(bgp, AFI_IP); + bgp_pbr_reset(bgp, afi); *bgp_pbr_interface_any = true; } } @@ -583,7 +596,8 @@ DEFUN (bgp_fs_local_install_ifname, char *ifname = argv_find(argv, argc, "INTERFACE", &idx) ? argv[idx]->arg : NULL; - return bgp_fs_local_install_interface(bgp, no, ifname); + return bgp_fs_local_install_interface(bgp, no, ifname, + bgp_node_afi(vty)); } extern int bgp_flowspec_display_match_per_ip(afi_t afi, struct bgp_table *rib, @@ -621,4 +635,5 @@ void bgp_flowspec_vty_init(void) install_element(ENABLE_NODE, &no_debug_bgp_flowspec_cmd); install_element(CONFIG_NODE, &no_debug_bgp_flowspec_cmd); install_element(BGP_FLOWSPECV4_NODE, &bgp_fs_local_install_ifname_cmd); + install_element(BGP_FLOWSPECV6_NODE, &bgp_fs_local_install_ifname_cmd); } diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index dd01ba3e35..552f6a51fe 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -1388,6 +1388,7 @@ void bgp_pbr_cleanup(struct bgp *bgp) if (bgp->bgp_pbr_cfg == NULL) return; bgp_pbr_reset(bgp, AFI_IP); + bgp_pbr_reset(bgp, AFI_IP6); XFREE(MTYPE_PBR, bgp->bgp_pbr_cfg); } @@ -2935,10 +2936,12 @@ void bgp_pbr_reset(struct bgp *bgp, afi_t afi) struct bgp_pbr_interface_head *head; struct bgp_pbr_interface *pbr_if; - if (!bgp_pbr_cfg || afi != AFI_IP) + if (!bgp_pbr_cfg) return; - head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); - + if (afi == AFI_IP) + head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); + else + head = &(bgp_pbr_cfg->ifaces_by_name_ipv6); while (!RB_EMPTY(bgp_pbr_interface_head, head)) { pbr_if = RB_ROOT(bgp_pbr_interface_head, head); RB_REMOVE(bgp_pbr_interface_head, head, pbr_if); diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h index 9d6360094c..dc2bb7260e 100644 --- a/bgpd/bgp_pbr.h +++ b/bgpd/bgp_pbr.h @@ -159,6 +159,8 @@ extern int bgp_pbr_interface_compare(const struct bgp_pbr_interface *a, struct bgp_pbr_config { struct bgp_pbr_interface_head ifaces_by_name_ipv4; bool pbr_interface_any_ipv4; + struct bgp_pbr_interface_head ifaces_by_name_ipv6; + bool pbr_interface_any_ipv6; }; extern struct bgp_pbr_config *bgp_pbr_cfg; diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 73ce990724..dba114f86a 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2984,7 +2984,8 @@ void bgp_send_pbr_ipset_entry_match(struct bgp_pbr_match_entry *pbrime, pbrime->install_in_progress = true; } -static void bgp_encode_pbr_interface_list(struct bgp *bgp, struct stream *s) +static void bgp_encode_pbr_interface_list(struct bgp *bgp, struct stream *s, + uint8_t family) { struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg; struct bgp_pbr_interface_head *head; @@ -2993,8 +2994,10 @@ static void bgp_encode_pbr_interface_list(struct bgp *bgp, struct stream *s) if (!bgp_pbr_cfg) return; - head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); - + if (family == AF_INET) + head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); + else + head = &(bgp_pbr_cfg->ifaces_by_name_ipv6); RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) { ifp = if_lookup_by_name(pbr_if->name, bgp->vrf_id); if (ifp) @@ -3002,7 +3005,7 @@ static void bgp_encode_pbr_interface_list(struct bgp *bgp, struct stream *s) } } -static int bgp_pbr_get_ifnumber(struct bgp *bgp) +static int bgp_pbr_get_ifnumber(struct bgp *bgp, uint8_t family) { struct bgp_pbr_config *bgp_pbr_cfg = bgp->bgp_pbr_cfg; struct bgp_pbr_interface_head *head; @@ -3011,8 +3014,10 @@ static int bgp_pbr_get_ifnumber(struct bgp *bgp) if (!bgp_pbr_cfg) return 0; - head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); - + if (family == AF_INET) + head = &(bgp_pbr_cfg->ifaces_by_name_ipv4); + else + head = &(bgp_pbr_cfg->ifaces_by_name_ipv6); RB_FOREACH (pbr_if, bgp_pbr_interface_head, head) { if (if_lookup_by_name(pbr_if->name, bgp->vrf_id)) cnt++; @@ -3043,10 +3048,10 @@ void bgp_send_pbr_iptable(struct bgp_pbr_action *pba, VRF_DEFAULT); bgp_encode_pbr_iptable_match(s, pba, pbm); - nb_interface = bgp_pbr_get_ifnumber(pba->bgp); + nb_interface = bgp_pbr_get_ifnumber(pba->bgp, pbm->family); stream_putl(s, nb_interface); if (nb_interface) - bgp_encode_pbr_interface_list(pba->bgp, s); + bgp_encode_pbr_interface_list(pba->bgp, s, pbm->family); stream_putw_at(s, 0, stream_get_endp(s)); ret = zclient_send_message(zclient); if (install) { -- 2.39.5