From 0789eb69e5b4b1d0b9040cea79cd047ce77b9406 Mon Sep 17 00:00:00 2001 From: Kantesh Mundaragi Date: Tue, 24 Aug 2021 07:53:29 -0700 Subject: [PATCH] bgpd: VRF-Lite fix nexthop type Description: Change is intended for fixing the following issues related to vrf route leaking: Routes with special nexthops i.e. blackhole/sink routes when imported, are not programmed into the FIB and corresponding nexthop is set as 'inactive', nexthop interface as 'unknown'. While importing/leaking routes between VRFs, in case of special nexthop(ipv4/ipv6) once bgp announces route(s) to zebra, nexthop type is incorrectly set as NEXTHOP_TYPE_IPV6_IFINDEX/NEXTHOP_TYPE_IFINDEX i.e. directly connected even though we are not able to resolve through an interface. This leads to nexthop_active_check marking nexthop !NEXTHOP_FLAG_ACTIVE. Unable to find the active nexthop(s), route is not programmed into the FIB. Whenever BGP leaks routes, set the correct nexthop type, so that route gets resolved and correctly programmed into the FIB, in the imported vrf. Co-authored-by: Kantesh Mundaragi Signed-off-by: Iqra Siddiqui --- bgpd/bgp_attr.c | 6 +++++- bgpd/bgp_attr.h | 6 ++++++ bgpd/bgp_route.c | 7 +++++-- bgpd/bgp_route.h | 5 +++-- bgpd/bgp_zebra.c | 33 ++++++++++++++++++++++----------- lib/nexthop.c | 5 +++-- lib/nexthop.h | 3 ++- tests/lib/test_nexthop.c | 6 +++--- zebra/zapi_msg.c | 3 ++- zebra/zebra_vty.c | 14 +++++++------- 10 files changed, 58 insertions(+), 30 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f1c953f21d..eeb0ac5c6a 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -691,6 +691,8 @@ unsigned int attrhash_key_make(const void *p) key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key); MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance); MIX(attr->rmap_table_id); + MIX(attr->nh_type); + MIX(attr->bh_type); return key; } @@ -747,7 +749,9 @@ bool attrhash_cmp(const void *p1, const void *p2) && attr1->distance == attr2->distance && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn) && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) - && attr1->srte_color == attr2->srte_color) + && attr1->srte_color == attr2->srte_color + && attr1->nh_type == attr2->nh_type + && attr1->bh_type == attr2->bh_type) return true; } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index a583581030..6c49cf509f 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -307,6 +307,12 @@ struct attr { /* EVPN DF preference and algorithm for DF election on local ESs */ uint16_t df_pref; uint8_t df_alg; + + /* Nexthop type */ + enum nexthop_types_t nh_type; + + /* If NEXTHOP_TYPE_BLACKHOLE, then blackhole type */ + enum blackhole_type bh_type; }; /* rmap_change_flags definition */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b164d710a5..db0ee58e72 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -8066,8 +8066,9 @@ DEFPY(aggregate_addressv6, aggregate_addressv6_cmd, void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, const union g_addr *nexthop, ifindex_t ifindex, enum nexthop_types_t nhtype, uint8_t distance, - uint32_t metric, uint8_t type, - unsigned short instance, route_tag_t tag) + enum blackhole_type bhtype, uint32_t metric, + uint8_t type, unsigned short instance, + route_tag_t tag) { struct bgp_path_info *new; struct bgp_path_info *bpi; @@ -8109,8 +8110,10 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; break; } + attr.bh_type = bhtype; break; } + attr.nh_type = nhtype; attr.nh_ifindex = ifindex; attr.med = metric; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 75da2723e6..d052a3f408 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -642,8 +642,9 @@ extern bool bgp_maximum_prefix_overflow(struct peer *, afi_t, safi_t, int); extern void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, const union g_addr *nexthop, ifindex_t ifindex, enum nexthop_types_t nhtype, uint8_t distance, - uint32_t metric, uint8_t type, - unsigned short instance, route_tag_t tag); + enum blackhole_type bhtype, uint32_t metric, + uint8_t type, unsigned short instance, + route_tag_t tag); extern void bgp_redistribute_delete(struct bgp *, struct prefix *, uint8_t, unsigned short); extern void bgp_redistribute_withdraw(struct bgp *, afi_t, int, unsigned short); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5ef49e5108..b0d0c844f3 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -472,8 +472,9 @@ static int bgp_interface_vrf_update(ZAPI_CALLBACK_ARGS) static int zebra_read_route(ZAPI_CALLBACK_ARGS) { enum nexthop_types_t nhtype; + enum blackhole_type bhtype = BLACKHOLE_UNSPEC; struct zapi_route api; - union g_addr nexthop; + union g_addr nexthop = {}; ifindex_t ifindex; int add, i; struct bgp *bgp; @@ -494,10 +495,16 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6)) return 0; - nexthop = api.nexthops[0].gate; ifindex = api.nexthops[0].ifindex; nhtype = api.nexthops[0].type; + /* api_nh structure has union of gate and bh_type */ + if (nhtype == NEXTHOP_TYPE_BLACKHOLE) { + /* bh_type is only applicable if NEXTHOP_TYPE_BLACKHOLE*/ + bhtype = api.nexthops[0].bh_type; + } else + nexthop = api.nexthops[0].gate; + add = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD); if (add) { /* @@ -517,8 +524,8 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) /* Now perform the add/update. */ bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex, - nhtype, api.distance, api.metric, api.type, - api.instance, api.tag); + nhtype, bhtype, api.distance, api.metric, + api.type, api.instance, api.tag); } else { bgp_redistribute_delete(bgp, &api.prefix, api.type, api.instance); @@ -1076,8 +1083,10 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, * a VRF (which are programmed as onlink on l3-vni SVI) as well as * connected routes leaked into a VRF. */ - if (is_evpn) { - + if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) { + api_nh->type = attr->nh_type; + api_nh->bh_type = attr->bh_type; + } else if (is_evpn) { /* * If the nexthop is EVPN overlay index gateway IP, * treat the nexthop as NEXTHOP_TYPE_IPV4 @@ -1090,8 +1099,7 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK); api_nh->ifindex = nh_bgp->l3vni_svi_ifindex; } - } else if (nh_othervrf && - api_nh->gate.ipv4.s_addr == INADDR_ANY) { + } else if (nh_othervrf && api_nh->gate.ipv4.s_addr == INADDR_ANY) { api_nh->type = NEXTHOP_TYPE_IFINDEX; api_nh->ifindex = attr->nh_ifindex; } else @@ -1113,8 +1121,10 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, attr = pi->attr; api_nh->vrf_id = nh_bgp->vrf_id; - if (is_evpn) { - + if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) { + api_nh->type = attr->nh_type; + api_nh->bh_type = attr->bh_type; + } else if (is_evpn) { /* * If the nexthop is EVPN overlay index gateway IP, * treat the nexthop as NEXTHOP_TYPE_IPV4 @@ -1169,7 +1179,8 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, api_nh->ifindex = 0; } } - if (nexthop) + /* api_nh structure has union of gate and bh_type */ + if (nexthop && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) api_nh->gate.ipv6 = *nexthop; return true; diff --git a/lib/nexthop.c b/lib/nexthop.c index 23e3a2b733..98409c76c5 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -519,12 +519,13 @@ struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6, return nexthop; } -struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type) +struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type, + vrf_id_t nh_vrf_id) { struct nexthop *nexthop; nexthop = nexthop_new(); - nexthop->vrf_id = VRF_DEFAULT; + nexthop->vrf_id = nh_vrf_id; nexthop->type = NEXTHOP_TYPE_BLACKHOLE; nexthop->bh_type = bh_type; diff --git a/lib/nexthop.h b/lib/nexthop.h index dd65509aec..320b46315e 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -182,7 +182,8 @@ struct nexthop *nexthop_from_ipv6(const struct in6_addr *ipv6, vrf_id_t vrf_id); struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6, ifindex_t ifindex, vrf_id_t vrf_id); -struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type); +struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type, + vrf_id_t nh_vrf_id); /* * Hash a nexthop. Suitable for use with hash tables. diff --git a/tests/lib/test_nexthop.c b/tests/lib/test_nexthop.c index 659d207b4e..7cf687dffe 100644 --- a/tests/lib/test_nexthop.c +++ b/tests/lib/test_nexthop.c @@ -112,15 +112,15 @@ static void test_run_first(void) nexthop_free(nh2); /* Blackhole */ - nh1 = nexthop_from_blackhole(BLACKHOLE_REJECT); - nh2 = nexthop_from_blackhole(BLACKHOLE_REJECT); + nh1 = nexthop_from_blackhole(BLACKHOLE_REJECT, 0); + nh2 = nexthop_from_blackhole(BLACKHOLE_REJECT, 0); ret = nexthop_cmp_basic(nh1, nh2); assert(ret == 0); nexthop_free(nh2); - nh2 = nexthop_from_blackhole(BLACKHOLE_NULL); + nh2 = nexthop_from_blackhole(BLACKHOLE_NULL, 0); ret = nexthop_cmp_basic(nh1, nh2); assert(ret != 0); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 6666b3525e..549a1c9c2e 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1611,7 +1611,8 @@ static struct nexthop *nexthop_from_zapi(const struct zapi_nexthop *api_nh, zlog_debug("%s: nh blackhole %d", __func__, api_nh->bh_type); - nexthop = nexthop_from_blackhole(api_nh->bh_type); + nexthop = + nexthop_from_blackhole(api_nh->bh_type, api_nh->vrf_id); break; } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index b204b30ca7..1c8a1ad09a 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -357,9 +357,11 @@ static void show_nexthop_detail_helper(struct vty *vty, break; } - if ((re->vrf_id != nexthop->vrf_id) - && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) - vty_out(vty, "(vrf %s)", vrf_id_to_name(nexthop->vrf_id)); + if (re->vrf_id != nexthop->vrf_id) { + struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); + + vty_out(vty, "(vrf %s)", VRF_LOGNAME(vrf)); + } if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) vty_out(vty, " (duplicate nexthop removed)"); @@ -607,8 +609,7 @@ static void show_route_nexthop_helper(struct vty *vty, break; } - if ((re == NULL || (nexthop->vrf_id != re->vrf_id)) - && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) + if ((re == NULL || (nexthop->vrf_id != re->vrf_id))) vty_out(vty, " (vrf %s)", vrf_id_to_name(nexthop->vrf_id)); if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) @@ -780,8 +781,7 @@ static void show_nexthop_json_helper(json_object *json_nexthop, break; } - if ((nexthop->vrf_id != re->vrf_id) - && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) + if (nexthop->vrf_id != re->vrf_id) json_object_string_add(json_nexthop, "vrf", vrf_id_to_name(nexthop->vrf_id));