From 1f5611c06d1c243b42279748788f0627793ead9c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Mon, 24 Jul 2023 11:16:53 -0400 Subject: [PATCH 1/6] zebra: Allow zebra cli to accept v6 routes with v4 nexthops add --v6-with-v4-nexthop cli to zebra to allow operator to specify that this functionality is allowed. Signed-off-by: Donald Sharp --- zebra/main.c | 63 ++++++++++++++++++++++++-------------------- zebra/zebra_router.c | 5 ++-- zebra/zebra_router.h | 4 ++- zebra/zebra_vty.c | 3 +++ 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/zebra/main.c b/zebra/main.c index bd4623be55..aeb9739c13 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -71,22 +71,25 @@ uint32_t rcvbufsize = 128 * 1024; #define OPTION_V6_RR_SEMANTICS 2000 #define OPTION_ASIC_OFFLOAD 2001 +#define OPTION_V6_WITH_V4_NEXTHOP 2002 /* Command line options. */ const struct option longopts[] = { - {"batch", no_argument, NULL, 'b'}, - {"allow_delete", no_argument, NULL, 'a'}, - {"socket", required_argument, NULL, 'z'}, - {"ecmp", required_argument, NULL, 'e'}, - {"retain", no_argument, NULL, 'r'}, - {"graceful_restart", required_argument, NULL, 'K'}, - {"asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD}, + { "batch", no_argument, NULL, 'b' }, + { "allow_delete", no_argument, NULL, 'a' }, + { "socket", required_argument, NULL, 'z' }, + { "ecmp", required_argument, NULL, 'e' }, + { "retain", no_argument, NULL, 'r' }, + { "graceful_restart", required_argument, NULL, 'K' }, + { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, + { "v6-with-v4-nexthops", no_argument, NULL, OPTION_V6_WITH_V4_NEXTHOP }, #ifdef HAVE_NETLINK - {"vrfwnetns", no_argument, NULL, 'n'}, - {"nl-bufsize", required_argument, NULL, 's'}, - {"v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS}, + { "vrfwnetns", no_argument, NULL, 'n' }, + { "nl-bufsize", required_argument, NULL, 's' }, + { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - {0}}; + { 0 } +}; zebra_capabilities_t _caps_p[] = {ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, @@ -287,6 +290,7 @@ int main(int argc, char **argv) struct sockaddr_storage dummy; socklen_t dummylen; bool asic_offload = false; + bool v6_with_v4_nexthop = false; bool notify_on_ack = true; graceful_restart = 0; @@ -294,26 +298,26 @@ int main(int argc, char **argv) frr_preinit(&zebra_di, argc, argv); - frr_opt_add( - "baz:e:rK:s:" + frr_opt_add("baz:e:rK:s:" #ifdef HAVE_NETLINK - "n" + "n" #endif - , - longopts, - " -b, --batch Runs in batch mode\n" - " -a, --allow_delete Allow other processes to delete zebra routes\n" - " -z, --socket Set path of zebra socket\n" - " -e, --ecmp Specify ECMP to use.\n" - " -r, --retain When program terminates, retain added route by zebra.\n" - " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" - " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" + , + longopts, + " -b, --batch Runs in batch mode\n" + " -a, --allow_delete Allow other processes to delete zebra routes\n" + " -z, --socket Set path of zebra socket\n" + " -e, --ecmp Specify ECMP to use.\n" + " -r, --retain When program terminates, retain added route by zebra.\n" + " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" + " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" + " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops" #ifdef HAVE_NETLINK - " -s, --nl-bufsize Set netlink receive buffer size\n" - " -n, --vrfwnetns Use NetNS as VRF backend\n" - " --v6-rr-semantics Use v6 RR semantics\n" + " -s, --nl-bufsize Set netlink receive buffer size\n" + " -n, --vrfwnetns Use NetNS as VRF backend\n" + " --v6-rr-semantics Use v6 RR semantics\n" #else - " -s, Set kernel socket receive buffer size\n" + " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ ); @@ -383,6 +387,9 @@ int main(int argc, char **argv) notify_on_ack = true; asic_offload = true; break; + case OPTION_V6_WITH_V4_NEXTHOP: + v6_with_v4_nexthop = true; + break; #endif /* HAVE_NETLINK */ default: frr_help_exit(1); @@ -392,7 +399,7 @@ int main(int argc, char **argv) zrouter.master = frr_init(); /* Zebra related initialize. */ - zebra_router_init(asic_offload, notify_on_ack); + zebra_router_init(asic_offload, notify_on_ack, v6_with_v4_nexthop); zserv_init(); rib_init(); zebra_if_init(); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 1b3e31ee42..4caaf8a9e2 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -255,7 +255,8 @@ bool zebra_router_notify_on_ack(void) return !zrouter.asic_offloaded || zrouter.notify_on_ack; } -void zebra_router_init(bool asic_offload, bool notify_on_ack) +void zebra_router_init(bool asic_offload, bool notify_on_ack, + bool v6_with_v4_nexthop) { zrouter.sequence_num = 0; @@ -310,7 +311,7 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) zrouter.asic_offloaded = asic_offload; zrouter.notify_on_ack = notify_on_ack; - + zrouter.v6_with_v4_nexthop = v6_with_v4_nexthop; /* * If you start using asic_notification_nexthop_control * come talk to the FRR community about what you are doing diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index a7f0f135f9..bd86cfb495 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -207,6 +207,7 @@ struct zebra_router { */ bool asic_offloaded; bool notify_on_ack; + bool v6_with_v4_nexthop; /* * If the asic is notifying us about successful nexthop @@ -237,7 +238,8 @@ struct zebra_router { extern struct zebra_router zrouter; extern uint32_t rcvbufsize; -extern void zebra_router_init(bool asic_offload, bool notify_on_ack); +extern void zebra_router_init(bool asic_offload, bool notify_on_ack, + bool v6_with_v4_nexthop); extern void zebra_router_cleanup(void); extern void zebra_router_terminate(void); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 291c2eb7e0..1a123ba5c2 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -4033,6 +4033,9 @@ DEFUN (show_zebra, ttable_add_row(table, "VRF|Not Available"); #endif + ttable_add_row(table, "v6 with v4 nexthop|%s", + zrouter.v6_with_v4_nexthop ? "Used" : "Unavaliable"); + ttable_add_row(table, "ASIC offload|%s", zrouter.asic_offloaded ? "Used" : "Unavailable"); From 68f52d7a0c235928e631e2c2a8e7504b42df45a7 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 2 Aug 2023 20:56:35 -0400 Subject: [PATCH 2/6] lib, zebra: Send up whether or not v6_with_v4_nexthops are supported After Zebra knows it's capability surrounding v6 with v4 nexthops have it send this ability up to interested parties. Signed-off-by: Donald Sharp --- lib/zclient.c | 1 + lib/zclient.h | 1 + zebra/zapi_msg.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/zclient.c b/lib/zclient.c index c36bcc6e2e..294a78feb0 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -3876,6 +3876,7 @@ static int zclient_capability_decode(ZAPI_CALLBACK_ARGS) cap.mpls_enabled = !!mpls_enabled; STREAM_GETL(s, cap.ecmp); STREAM_GETC(s, cap.role); + STREAM_GETC(s, cap.v6_with_v4_nexthop); if (zclient->zebra_capabilities) (*zclient->zebra_capabilities)(&cap); diff --git a/lib/zclient.h b/lib/zclient.h index 316dd4cd68..42c5a5fdac 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -274,6 +274,7 @@ struct zclient_capabilities { uint32_t ecmp; bool mpls_enabled; enum mlag_role role; + bool v6_with_v4_nexthop; }; /* Graceful Restart Capabilities message */ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 2fc696c4e1..e9c243217a 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -2319,7 +2319,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) stream_putc(s, mpls_enabled); stream_putl(s, zrouter.multipath_num); stream_putc(s, zebra_mlag_get_role()); - + stream_putc(s, zrouter.v6_with_v4_nexthop); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } From 052debc3eedceed9b3a3183fe70120dcd58a535f Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 2 Aug 2023 21:08:43 -0400 Subject: [PATCH 3/6] bgpd: Have bgp notice the zebra ability to use v6_with_v4_nexthops Store the data. Signed-off-by: Donald Sharp --- bgpd/bgp_zebra.c | 6 ++++++ bgpd/bgpd.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index becd99167f..8ff6b63e05 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3455,6 +3455,11 @@ static bool bgp_zebra_label_manager_connect(void) return true; } +static void bgp_zebra_capabilities(struct zclient_capabilities *cap) +{ + bm->v6_with_v4_nexthops = cap->v6_with_v4_nexthop; +} + void bgp_zebra_init(struct event_loop *master, unsigned short instance) { struct zclient_options options = zclient_options_default; @@ -3470,6 +3475,7 @@ void bgp_zebra_init(struct event_loop *master, unsigned short instance) array_size(bgp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); zclient->zebra_connected = bgp_zebra_connected; + zclient->zebra_capabilities = bgp_zebra_capabilities; zclient->instance = instance; /* Initialize special zclient for synchronous message exchanges. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 5e467bb873..67ee8aa138 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -168,6 +168,8 @@ struct bgp_master { struct event *t_bgp_sync_label_manager; struct event *t_bgp_start_label_manager; + bool v6_with_v4_nexthops; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp_master); From 95002ded3edc5694c7826558ed40b9dd0188c78c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 2 Aug 2023 21:15:02 -0400 Subject: [PATCH 4/6] bgpd: Do not allow a peer to come up on v6 if we have no ability to route Modify bgp to not allow a v6 peer to come up if the v6 afi is negotiated and the outgoing interface has no v6 address as well as zebra does not support the v6 with v4 nexthop capabilities that some dataplanes allow. Signed-off-by: Donald Sharp --- bgpd/bgp_packet.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 2d1fc103bc..3e3e1b9431 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1735,11 +1735,14 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) || peer->afc_nego[AFI_IP6][SAFI_MULTICAST] || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_ENCAP]) { - if (IN6_IS_ADDR_UNSPECIFIED(&peer->nexthop.v6_global)) { -#if defined(HAVE_CUMULUS) - zlog_warn("%s: No local IPv6 address, BGP routing may not work", - peer->host); -#endif + if (IN6_IS_ADDR_UNSPECIFIED(&peer->nexthop.v6_global) && + !bm->v6_with_v4_nexthops) { + flog_err(EC_BGP_SND_FAIL, +"%s: No local IPv6 address, and zebra does not support V6 routing with v4 nexthops, BGP routing for V6 will not work", + peer->host); + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); + return BGP_Stop; } } peer->rtt = sockopt_tcp_rtt(peer->fd); From 0435b31bb8ed55377f83d0e19bc085abc3c71b44 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 3 Aug 2023 08:14:08 -0400 Subject: [PATCH 5/6] bgpd: Allow bgp to specify if it will allow v6 routing with v4 nexthops Add a `--v6-with-v4-nexthop` cli to bgp to allow it to peer with neighbors in the configuration where the interface has no v6 addresses at all and there is a v4 address that is usable as a v4 address embedded in a v6 address. Signed-off-by: Donald Sharp --- bgpd/bgp_main.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 074059c146..11917c6c4a 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -57,15 +57,17 @@ /* bgpd options, we use GNU getopt library. */ static const struct option longopts[] = { - {"bgp_port", required_argument, NULL, 'p'}, - {"listenon", required_argument, NULL, 'l'}, - {"no_kernel", no_argument, NULL, 'n'}, - {"skip_runas", no_argument, NULL, 'S'}, - {"ecmp", required_argument, NULL, 'e'}, - {"int_num", required_argument, NULL, 'I'}, - {"no_zebra", no_argument, NULL, 'Z'}, - {"socket_size", required_argument, NULL, 's'}, - {0}}; + { "bgp_port", required_argument, NULL, 'p' }, + { "listenon", required_argument, NULL, 'l' }, + { "no_kernel", no_argument, NULL, 'n' }, + { "skip_runas", no_argument, NULL, 'S' }, + { "ecmp", required_argument, NULL, 'e' }, + { "int_num", required_argument, NULL, 'I' }, + { "no_zebra", no_argument, NULL, 'Z' }, + { "socket_size", required_argument, NULL, 's' }, + { "v6-with-v4-nexthops", no_argument, NULL, 'v' }, + { 0 } +}; /* signal definitions */ void sighup(void); @@ -387,16 +389,16 @@ int main(int argc, char **argv) addresses->cmp = (int (*)(void *, void *))strcmp; frr_preinit(&bgpd_di, argc, argv); - frr_opt_add( - "p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts, - " -p, --bgp_port Set BGP listen port number (0 means do not listen).\n" - " -l, --listenon Listen on specified address (implies -n)\n" - " -n, --no_kernel Do not install route to kernel.\n" - " -Z, --no_zebra Do not communicate with Zebra.\n" - " -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n" - " -e, --ecmp Specify ECMP to use.\n" - " -I, --int_num Set instance number (label-manager)\n" - " -s, --socket_size Set BGP peer socket send buffer size\n"); + frr_opt_add("p:l:SnZe:I:s:" DEPRECATED_OPTIONS, longopts, + " -p, --bgp_port Set BGP listen port number (0 means do not listen).\n" + " -l, --listenon Listen on specified address (implies -n)\n" + " -n, --no_kernel Do not install route to kernel.\n" + " -Z, --no_zebra Do not communicate with Zebra.\n" + " -S, --skip_runas Skip capabilities checks, and changing user and group IDs.\n" + " -e, --ecmp Specify ECMP to use.\n" + " -I, --int_num Set instance number (label-manager)\n" + " -s, --socket_size Set BGP peer socket send buffer size\n" + " , --v6-with-v4-nexthop Allow BGP to form v6 neighbors using v4 nexthops\n"); /* Command line argument treatment. */ while (1) { @@ -458,6 +460,9 @@ int main(int argc, char **argv) case 's': buffer_size = atoi(optarg); break; + case 'v': + bm->v6_with_v4_nexthops = true; + break; default: frr_help_exit(1); } From 6f6b7e170614fab61c4d92cdfb415a03b260aa8e Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 3 Aug 2023 08:57:55 -0400 Subject: [PATCH 6/6] doc: Add --v6-with-v4-nexthops documentation Signed-off-by: Donald Sharp --- doc/user/bgp.rst | 9 +++++++++ doc/user/zebra.rst | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index ad8f913355..09173ab2f5 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -86,6 +86,15 @@ be specified (:ref:`common-invocation-options`). be done to see if this is helping or not at the scale you are running at. +.. option:: --v6-with-v4-nexthops + + Allow BGP to peer in the V6 afi, when the interface only has v4 addresses. + This allows bgp to install the v6 routes with a v6 nexthop that has the + v4 address encoded in the nexthop. Zebra's equivalent option currently + overrides the bgp setting. This setting is only really usable when + the operator has turned off communication to zebra and is running bgpd + as a complete standalone process. + LABEL MANAGER ------------- diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index d7e768b710..32de3e908f 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -87,6 +87,13 @@ Besides the common invocation options (:ref:`common-invocation-options`), the Allow zebra to modify the default receive buffer size to SIZE in bytes. Under \*BSD only the -s option is available. +.. option:: --v6-with-v4-nexthops + + Signal to zebra that v6 routes with v4 nexthops are accepted + by the underlying dataplane. This will be communicated to + the upper level daemons that can install v6 routes with v4 + nexthops. + .. _interface-commands: Configuration Addresses behaviour