From c77981de5a7094d9fcc90ef8f6773c46aafb355e Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 8 Dec 2023 22:09:13 +0100 Subject: [PATCH] zebra, lib: add recursive support for protocol nhid In sharpd, configuring a nexthop-group with an IP nexthop that is not directly connected does not create a NHG context in zebra: > ubuntu2204(config)# interface loop1 > ubuntu2204(config-if)# ip address 192.0.2.1/24 > ubuntu2204(config-if)# exi > ubuntu2204(config)# ip route 192.168.0.0/24 192.0.2.100 > ubuntu2204(config)# nexthop-group ABCD > ubuntu2204(config-nh-group)# nexthop 192.168.0.100 > 2024/01/17 16:36:23 SHARP: [Y2G2F-ZTW6M] nhg_add: nhg 181818169 not sent: no valid nexthops > ubuntu2204(config-nh-group)# do show nexthop-group rib 181818169 > Nexthop Group ID: 181818169 does not exist Nexthops with an undefined interface index are neither handled in ZEBRA, nor in SHARPD. On the other hand, if we had created a route pointing to the same nexthop (by using ZEBRA_ROUTE_ADD zapi), the next-hop would have been installed, thanks to the ALLOW_RECURSION flag embedded in the zapi_route structure. Add the support for recursivity in nexthop groups by introducing a flags attribute in the nexthop group structure. Define the NEXTHOP_GROUP_ALLOW_RECURSION value, which will be used by ZEBRA to check for the next-hop group recursivity. This flag is not used by default. This flag control is mandatory, as the recursivity may not be allowed by protocols like eBGP single-hop. Signed-off-by: Philippe Guibert --- lib/nexthop_group.h | 4 ++++ lib/zclient.c | 2 ++ lib/zclient.h | 3 +++ sharpd/sharp_zebra.c | 1 + zebra/zapi_msg.c | 3 +++ zebra/zebra_nhg.c | 25 ++++++++++++++++++------- 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 822a35439cc0..7476d533737f 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -34,6 +34,10 @@ struct nexthop_group { struct nexthop *nexthop; struct nhg_resilience nhgr; + + /* nexthop group flags */ +#define NEXTHOP_GROUP_ALLOW_RECURSION (1 << 1) + uint8_t flags; }; struct nexthop_group *nexthop_group_new(void); diff --git a/lib/zclient.c b/lib/zclient.c index 2a7d2a8c5bc1..124241be7738 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1173,6 +1173,8 @@ static int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg) stream_putl(s, api_nhg->resilience.idle_timer); stream_putl(s, api_nhg->resilience.unbalanced_timer); + stream_putc(s, api_nhg->flags); + if (cmd == ZEBRA_NHG_ADD) { /* Nexthops */ zapi_nexthop_group_sort(api_nhg->nexthops, diff --git a/lib/zclient.h b/lib/zclient.h index 8d7faeb223d5..0ca4b31c868e 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -486,6 +486,9 @@ struct zapi_nhg { uint16_t backup_nexthop_num; struct zapi_nexthop backup_nexthops[MULTIPATH_NUM]; + + /* nexthop group flags */ + uint8_t flags; }; /* diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index cbfa0d1cccec..9048d7309fe1 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -539,6 +539,7 @@ void nhg_add(uint32_t id, const struct nexthop_group *nhg, api_nhg.id = id; + api_nhg.flags = nhg->flags; api_nhg.resilience = nhg->nhgr; for (ALL_NEXTHOPS_PTR(nhg, nh)) { diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 761eafeb1375..1b3bcd1a2b8d 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1895,6 +1895,8 @@ static int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg) STREAM_GETL(s, api_nhg->resilience.idle_timer); STREAM_GETL(s, api_nhg->resilience.unbalanced_timer); + STREAM_GETC(s, api_nhg->flags); + /* Nexthops */ STREAM_GETW(s, api_nhg->nexthop_num); @@ -2013,6 +2015,7 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS) nhe = zebra_nhg_alloc(); nhe->id = api_nhg.id; nhe->type = api_nhg.proto; + nhe->nhg.flags = api_nhg.flags; nhe->zapi_instance = client->instance; nhe->zapi_session = client->session_id; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index ff117d348cd2..2daf6f84a375 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2346,8 +2346,10 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe, * if specified) - i.e., we cannot have a nexthop NH1 is * resolved by a route NH1. The exception is if the route is a * host route. + * This control will not work by using nexthop groups, and will + * have to be handled at protocol level */ - if (prefix_same(&rn->p, top)) + if (top && prefix_same(&rn->p, top)) if (((afi == AFI_IP) && (rn->p.prefixlen != IPV4_MAX_BITLEN)) || ((afi == AFI_IP6) @@ -3365,7 +3367,7 @@ struct nhg_hash_entry *zebra_nhg_proto_add(struct nhg_hash_entry *nhe, struct nexthop *newhop; bool replace = false; int ret = 0, type; - uint32_t id, session; + uint32_t id, session, api_message = 0; uint16_t instance; id = nhe->id; @@ -3413,14 +3415,23 @@ struct nhg_hash_entry *zebra_nhg_proto_add(struct nhg_hash_entry *nhe, return NULL; } - if (!newhop->ifindex) { + if (!newhop->ifindex && + !CHECK_FLAG(nhg->flags, NEXTHOP_GROUP_ALLOW_RECURSION)) { if (IS_ZEBRA_DEBUG_NHG) - zlog_debug( - "%s: id %u, nexthop without ifindex is not supported", - __func__, id); + zlog_debug("%s: id %u, nexthop without ifindex and allow-recursion is not supported", + __func__, id); return NULL; } - SET_FLAG(newhop->flags, NEXTHOP_FLAG_ACTIVE); + + /* Check that the route may be recursively resolved */ + if (CHECK_FLAG(nhg->flags, NEXTHOP_GROUP_ALLOW_RECURSION)) + api_message = ZEBRA_FLAG_ALLOW_RECURSION; + + if (nexthop_active(newhop, nhe, NULL, 0, api_message, NULL, + newhop->vrf_id)) + SET_FLAG(newhop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG(newhop->flags, NEXTHOP_FLAG_ACTIVE); } zebra_nhe_init(&lookup, afi, nhg->nexthop);