From 11c700e90cd5036dcfc8514693206c704e1724fc Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 7 Dec 2023 17:19:30 +0100 Subject: [PATCH 1/2] zebra: rework zebra_nhg_proto_add() parameters This small rework prepares next commit. Signed-off-by: Philippe Guibert --- zebra/zebra_nhg.c | 12 +++++++++--- zebra/zebra_nhg.h | 6 ++---- zebra/zebra_rib.c | 5 +---- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 9e3aa8bc5c8e..ff117d348cd2 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -3356,8 +3356,7 @@ bool zebra_nhg_proto_nexthops_only(void) } /* Add NHE from upper level proto */ -struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, - uint16_t instance, uint32_t session, +struct nhg_hash_entry *zebra_nhg_proto_add(struct nhg_hash_entry *nhe, struct nexthop_group *nhg, afi_t afi) { struct nhg_hash_entry lookup; @@ -3365,7 +3364,14 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, struct nhg_connected *rb_node_dep = NULL; struct nexthop *newhop; bool replace = false; - int ret = 0; + int ret = 0, type; + uint32_t id, session; + uint16_t instance; + + id = nhe->id; + type = nhe->type; + session = nhe->zapi_session; + instance = nhe->zapi_instance; if (!nhg->nexthop) { if (IS_ZEBRA_DEBUG_NHG) diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 4eddecb73d6e..ccdb34e8f5ba 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -322,10 +322,8 @@ zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi); * * Returns allocated NHE on success, otherwise NULL. */ -struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type, - uint16_t instance, uint32_t session, - struct nexthop_group *nhg, - afi_t afi); +struct nhg_hash_entry *zebra_nhg_proto_add(struct nhg_hash_entry *nhe, + struct nexthop_group *nhg, afi_t afi); /* * Del NHE. diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 4b5f81a3df51..6b03761a584d 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2580,10 +2580,7 @@ static void process_subq_nhg(struct listnode *lnode) ZAPI_NHG_REMOVE_FAIL); } else { - newnhe = zebra_nhg_proto_add(nhe->id, nhe->type, - nhe->zapi_instance, - nhe->zapi_session, - &nhe->nhg, 0); + newnhe = zebra_nhg_proto_add(nhe, &nhe->nhg, 0); /* Report error to daemon via ZAPI */ if (newnhe == NULL) From 1aa88fa54d3b725dfff635e8e08ebcb75bb28dcf Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Fri, 8 Dec 2023 22:09:13 +0100 Subject: [PATCH 2/2] 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. Maintain the flag unset by default. 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..09e7e683657f 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, type, 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);