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); } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 7c2c6f616b..cc9b2c7bb4 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1787,11 +1787,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); 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); 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 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/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/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); } 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");