diff options
40 files changed, 412 insertions, 134 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); } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 2d1fc103bc..cc9b2c7bb4 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1199,6 +1199,8 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, struct stream *s; iana_afi_t pkt_afi = IANA_AFI_IPV4; iana_safi_t pkt_safi = IANA_SAFI_UNICAST; + unsigned long cap_len; + uint16_t len; /* Convert AFI, SAFI to values for packet. */ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); @@ -1209,7 +1211,41 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, bgp_packet_set_marker(s, BGP_MSG_CAPABILITY); /* Encode MP_EXT capability. */ - if (capability_code == CAPABILITY_CODE_MP) { + switch (capability_code) { + case CAPABILITY_CODE_SOFT_VERSION: + SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV); + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_SOFT_VERSION); + cap_len = stream_get_endp(s); + stream_putc(s, 0); /* Capability Length */ + + /* The Capability Length SHOULD be no greater than 64. + * This is the limit to allow other capabilities as much + * space as they require. + */ + const char *soft_version = cmd_software_version_get(); + + len = strlen(soft_version); + if (len > BGP_MAX_SOFT_VERSION) + len = BGP_MAX_SOFT_VERSION; + + stream_putc(s, len); + stream_put(s, soft_version, len); + + /* Software Version capability Len. */ + len = stream_get_endp(s) - cap_len - 1; + stream_putc_at(s, cap_len, len); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s Software Version for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + break; + case CAPABILITY_CODE_MP: stream_putc(s, action); stream_putc(s, CAPABILITY_CODE_MP); stream_putc(s, CAPABILITY_CODE_MP_LEN); @@ -1224,6 +1260,22 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); + break; + case CAPABILITY_CODE_REFRESH: + case CAPABILITY_CODE_ORF: + case CAPABILITY_CODE_RESTART: + case CAPABILITY_CODE_AS4: + case CAPABILITY_CODE_DYNAMIC: + case CAPABILITY_CODE_ADDPATH: + case CAPABILITY_CODE_ENHANCED_RR: + case CAPABILITY_CODE_LLGR: + case CAPABILITY_CODE_FQDN: + case CAPABILITY_CODE_ENHE: + case CAPABILITY_CODE_EXT_MESSAGE: + case CAPABILITY_CODE_ROLE: + break; + default: + break; } /* Set packet size. */ @@ -1735,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); @@ -2698,6 +2753,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, afi_t afi; iana_safi_t pkt_safi; safi_t safi; + char soft_version[BGP_MAX_SOFT_VERSION + 1] = {}; end = pnt + length; @@ -2728,14 +2784,6 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, "%s CAPABILITY has action: %d, code: %u, length %u", peer->host, action, hdr->code, hdr->length); - if (hdr->length < sizeof(struct capability_mp_data)) { - zlog_info( - "%pBP Capability structure is not properly filled out, expected at least %zu bytes but header length specified is %d", - peer, sizeof(struct capability_mp_data), - hdr->length); - return BGP_Stop; - } - /* Capability length check. */ if ((pnt + hdr->length + 3) > end) { zlog_info("%s Capability length error", peer->host); @@ -2744,20 +2792,42 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, return BGP_Stop; } - /* Fetch structure to the byte stream. */ - memcpy(&mpc, pnt + 3, sizeof(struct capability_mp_data)); - pnt += hdr->length + 3; + /* Ignore capability when override-capability is set. */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) + continue; + + switch (hdr->code) { + case CAPABILITY_CODE_SOFT_VERSION: + if (action == CAPABILITY_ACTION_SET) { + SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); + + memcpy(&soft_version, pnt + 3, hdr->length); + soft_version[hdr->length] = '\0'; + + XFREE(MTYPE_BGP_SOFT_VERSION, + peer->soft_version); + peer->soft_version = + XSTRDUP(MTYPE_BGP_SOFT_VERSION, + soft_version); + } else { + UNSET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV); + XFREE(MTYPE_BGP_SOFT_VERSION, + peer->soft_version); + } + break; + case CAPABILITY_CODE_MP: + if (hdr->length < sizeof(struct capability_mp_data)) { + zlog_info("%pBP Capability structure is not properly filled out, expected at least %zu bytes but header length specified is %d", + peer, + sizeof(struct capability_mp_data), + hdr->length); + return BGP_Stop; + } - /* We know MP Capability Code. */ - if (hdr->code == CAPABILITY_CODE_MP) { + memcpy(&mpc, pnt + 3, sizeof(struct capability_mp_data)); pkt_afi = ntohs(mpc.afi); pkt_safi = mpc.safi; - /* Ignore capability when override-capability is set. */ - if (CHECK_FLAG(peer->flags, - PEER_FLAG_OVERRIDE_CAPABILITY)) - continue; - /* Convert AFI, SAFI to internal values. */ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { @@ -2797,12 +2867,29 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, else return BGP_Stop; } - } else { + break; + case CAPABILITY_CODE_REFRESH: + case CAPABILITY_CODE_ORF: + case CAPABILITY_CODE_RESTART: + case CAPABILITY_CODE_AS4: + case CAPABILITY_CODE_DYNAMIC: + case CAPABILITY_CODE_ADDPATH: + case CAPABILITY_CODE_ENHANCED_RR: + case CAPABILITY_CODE_LLGR: + case CAPABILITY_CODE_FQDN: + case CAPABILITY_CODE_ENHE: + case CAPABILITY_CODE_EXT_MESSAGE: + case CAPABILITY_CODE_ROLE: + break; + default: flog_warn( EC_BGP_UNRECOGNIZED_CAPABILITY, "%s unrecognized capability code: %d - ignored", peer->host, hdr->code); + break; } + + pnt += hdr->length + 3; } /* No FSM action necessary */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 4f773f21a5..591e0c3969 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5725,17 +5725,29 @@ DEFPY(neighbor_capability_software_version, "Advertise Software Version capability to the peer\n") { struct peer *peer; + int ret; peer = peer_and_group_lookup_vty(vty, neighbor); - if (peer && peer->conf_if) - return CMD_SUCCESS; + if (!peer) + return CMD_WARNING_CONFIG_FAILED; if (no) - return peer_flag_unset_vty(vty, neighbor, - PEER_FLAG_CAPABILITY_SOFT_VERSION); + ret = peer_flag_unset_vty(vty, neighbor, + PEER_FLAG_CAPABILITY_SOFT_VERSION); else - return peer_flag_set_vty(vty, neighbor, - PEER_FLAG_CAPABILITY_SOFT_VERSION); + ret = peer_flag_set_vty(vty, neighbor, + PEER_FLAG_CAPABILITY_SOFT_VERSION); + + if (peer_established(peer)) { + if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && + CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_SOFT_VERSION, + no ? CAPABILITY_ACTION_UNSET + : CAPABILITY_ACTION_SET); + } + + return ret; } static int peer_af_flag_modify_vty(struct vty *vty, const char *peer_str, 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.c b/bgpd/bgpd.c index 84890da8c1..b72e75d12e 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4449,7 +4449,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_PORT, 0, peer_change_reset}, {PEER_FLAG_AIGP, 0, peer_change_none}, {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none}, - {PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_reset}, + {PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_none}, {0, 0, 0}}; static const struct peer_flag_action peer_af_flag_action_list[] = { 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/tests/topotests/babel_topo1/r3/babeld.conf b/tests/topotests/babel_topo1/r3/babeld.conf index bfda3622dd..e10e5aaacc 100644 --- a/tests/topotests/babel_topo1/r3/babeld.conf +++ b/tests/topotests/babel_topo1/r3/babeld.conf @@ -14,4 +14,3 @@ router babel network r3-eth1 redistribute ipv4 connected redistribute ipv4 static - redistirbute ipv6 connected diff --git a/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf index ce36494604..72238ccd40 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf @@ -27,6 +27,5 @@ interface eth-rt3 ! router ospf ospf router-id 1.1.1.1 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf index a8ca564e4e..c5f4262a8f 100644 --- a/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf @@ -25,6 +25,5 @@ interface eth-rt5 ! router ospf ospf router-id 2.2.2.2 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf index 0404994c09..e487bdd7c0 100644 --- a/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf @@ -25,6 +25,5 @@ interface eth-rt4 ! router ospf ospf router-id 3.3.3.3 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf index 6b8ab3704f..560904e75d 100644 --- a/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf @@ -24,6 +24,5 @@ interface eth-rt5 ! router ospf ospf router-id 4.4.4.4 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf index 043432ec3d..77f5445286 100644 --- a/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf @@ -24,6 +24,5 @@ interface eth-rt4 ! router ospf ospf router-id 5.5.5.5 - passive interface lo router-info area 0.0.0.0 ! diff --git a/tests/topotests/bgp_addpath_best_selected/r5/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r5/bgpd.conf index 0396cc07b4..f36e2bddd7 100644 --- a/tests/topotests/bgp_addpath_best_selected/r5/bgpd.conf +++ b/tests/topotests/bgp_addpath_best_selected/r5/bgpd.conf @@ -1,5 +1,5 @@ router bgp 65005 - timers 3 10 + timers bgp 3 10 no bgp ebgp-requires-policy neighbor 192.168.2.2 remote-as external neighbor 192.168.2.2 timers connect 5 diff --git a/tests/topotests/bgp_addpath_best_selected/r6/bgpd.conf b/tests/topotests/bgp_addpath_best_selected/r6/bgpd.conf index d9e77b66d6..0d83ef868a 100644 --- a/tests/topotests/bgp_addpath_best_selected/r6/bgpd.conf +++ b/tests/topotests/bgp_addpath_best_selected/r6/bgpd.conf @@ -1,5 +1,5 @@ router bgp 65006 - timers 3 10 + timers bgp 3 10 no bgp ebgp-requires-policy neighbor 192.168.2.2 remote-as external neighbor 192.168.2.2 timers connect 5 diff --git a/tests/topotests/bgp_dynamic_capability/__init__.py b/tests/topotests/bgp_dynamic_capability/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/__init__.py diff --git a/tests/topotests/bgp_dynamic_capability/r1/bgpd.conf b/tests/topotests/bgp_dynamic_capability/r1/bgpd.conf new file mode 100644 index 0000000000..113936df4c --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/r1/bgpd.conf @@ -0,0 +1,10 @@ +! +!debug bgp neighbor +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.2 capability dynamic +! diff --git a/tests/topotests/bgp_dynamic_capability/r1/zebra.conf b/tests/topotests/bgp_dynamic_capability/r1/zebra.conf new file mode 100644 index 0000000000..b29940f46a --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/r1/zebra.conf @@ -0,0 +1,4 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bgp_dynamic_capability/r2/bgpd.conf b/tests/topotests/bgp_dynamic_capability/r2/bgpd.conf new file mode 100644 index 0000000000..587b241a90 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/r2/bgpd.conf @@ -0,0 +1,10 @@ +! +!debug bgp neighbor +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + neighbor 192.168.1.1 capability dynamic +! diff --git a/tests/topotests/bgp_dynamic_capability/r2/zebra.conf b/tests/topotests/bgp_dynamic_capability/r2/zebra.conf new file mode 100644 index 0000000000..cffe827363 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/r2/zebra.conf @@ -0,0 +1,4 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py new file mode 100644 index 0000000000..a375993af4 --- /dev/null +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2023 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +""" +Test if software version capability is exchanged dynamically. +""" + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.bgpd + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dynamic_capability(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "softwareVersion": { + "advertisedSoftwareVersion": None, + "receivedSoftwareVersion": None, + }, + }, + "connectionsEstablished": 1, + "connectionsDropped": 0, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + step("Enable software version capability and check if it's exchanged dynamically") + + r1.vtysh_cmd( + """ + configure terminal + router bgp + neighbor 192.168.1.2 capability software-version + """ + ) + + r2.vtysh_cmd( + """ + configure terminal + router bgp + neighbor 192.168.1.1 capability software-version + """ + ) + + def _bgp_check_if_session_not_reset(): + def _bgp_software_version(): + try: + versions = output["192.168.1.2"]["neighborCapabilities"][ + "softwareVersion" + ] + adv = versions["advertisedSoftwareVersion"] + rcv = versions["receivedSoftwareVersion"] + + if not adv and not rcv: + return "" + + pattern = "FRRouting/\\d.+" + if re.search(pattern, adv) and re.search(pattern, rcv): + return adv, rcv + except: + return "" + + output = json.loads(r1.vtysh_cmd("show bgp neighbor json")) + adv, rcv = _bgp_software_version() + expected = { + "192.168.1.2": { + "bgpState": "Established", + "neighborCapabilities": { + "dynamic": "advertisedAndReceived", + "softwareVersion": { + "advertisedSoftwareVersion": adv, + "receivedSoftwareVersion": rcv, + }, + }, + "connectionsEstablished": 1, + "connectionsDropped": 0, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_session_not_reset, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "Session was reset after enabling software version capability" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/PE1/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/PE1/bgpd.conf index f839443025..e4d20b9a50 100644 --- a/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/PE1/bgpd.conf +++ b/tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/PE1/bgpd.conf @@ -1,5 +1,5 @@ router bgp 65000 - timers 3 9 + timers bgp 3 9 bgp router-id 10.10.10.10 no bgp default ipv4-unicast neighbor 10.30.30.30 remote-as 65000 diff --git a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf index 39ac8ca69c..9fb2bd6835 100644 --- a/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf +++ b/tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf @@ -1,5 +1,5 @@ router bgp 65000 - timers 3 9 + timers bgp 3 9 bgp router-id 10.10.10.10 no bgp default ipv4-unicast neighbor 10.30.30.30 remote-as 65000 diff --git a/tests/topotests/bgp_evpn_vxlan_topo1/PE1/bgpd.conf b/tests/topotests/bgp_evpn_vxlan_topo1/PE1/bgpd.conf index 991a1e7e56..dbbfc82db9 100644 --- a/tests/topotests/bgp_evpn_vxlan_topo1/PE1/bgpd.conf +++ b/tests/topotests/bgp_evpn_vxlan_topo1/PE1/bgpd.conf @@ -1,5 +1,5 @@ router bgp 65000 - timers 3 9 + timers bgp 3 9 bgp router-id 10.10.10.10 no bgp default ipv4-unicast neighbor 10.30.30.30 remote-as 65000 diff --git a/tests/topotests/bgp_update_delay/r2/zebra.conf b/tests/topotests/bgp_update_delay/r2/zebra.conf index 420f00d974..1fcedaaf72 100644 --- a/tests/topotests/bgp_update_delay/r2/zebra.conf +++ b/tests/topotests/bgp_update_delay/r2/zebra.conf @@ -12,9 +12,5 @@ interface r2-eth3 ip address 192.168.252.1/30 vrf vrf1 ! -auto vrf1 -iface vrf1 - vrf-table auto -! ip forwarding ! diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf b/tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf deleted file mode 100644 index 233a6473b3..0000000000 --- a/tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf +++ /dev/null @@ -1,14 +0,0 @@ -interface r1-eth0 - ip router isis 1 - isis circuit-type level-1 -! -interface lo - ip router isis 1 - isis passive -! -router isis 1 - is-type level-1 - net 49.0002.0000.1994.00 - segment-routing on - segment-routing prefix 192.0.2.1/32 index 11 -! diff --git a/tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf b/tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf deleted file mode 100644 index 547d10f2bc..0000000000 --- a/tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf +++ /dev/null @@ -1,14 +0,0 @@ -interface r2-eth0 - ip router isis 1 - isis circuit-type level-1 -! -interface lo - ip router isis 1 - isis passive -! -router isis 1 - is-type level-1 - net 49.0002.0000.1995.00 - segment-routing on - segment-routing prefix 192.0.2.2/32 index 22 -! diff --git a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py index f665040f7f..f2865fec9e 100644 --- a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py +++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py @@ -120,9 +120,6 @@ def setup_module(mod): router.load_config( TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) ) - router.load_config( - TopoRouter.RD_ISIS, os.path.join(CWD, "{}/bgpd.conf".format(rname)) - ) # Initialize all routers. tgen.start_router() diff --git a/tests/topotests/config_timing/r1/zebra.conf b/tests/topotests/config_timing/r1/zebra.conf index 46fd965034..b4dc338b8d 100644 --- a/tests/topotests/config_timing/r1/zebra.conf +++ b/tests/topotests/config_timing/r1/zebra.conf @@ -4,10 +4,8 @@ ip prefix-list ANY permit 0.0.0.0/0 le 32 ipv6 prefix-list ANY seq 10 permit any route-map RM-NONE4 deny 10 -exit-route-map route-map RM-NONE6 deny 10 -exit-route-map interface r1-eth0 ip address 100.0.0.1/24 diff --git a/tests/topotests/cspf_topo1/r1/sharpd.conf b/tests/topotests/cspf_topo1/r1/sharpd.conf index 272eac944e..465034f150 100644 --- a/tests/topotests/cspf_topo1/r1/sharpd.conf +++ b/tests/topotests/cspf_topo1/r1/sharpd.conf @@ -1,3 +1,2 @@ ! -import-te ! diff --git a/tests/topotests/isis_snmp/r1/ldpd.conf b/tests/topotests/isis_snmp/r1/ldpd.conf index 5b1cbfebc9..64f51fce27 100644 --- a/tests/topotests/isis_snmp/r1/ldpd.conf +++ b/tests/topotests/isis_snmp/r1/ldpd.conf @@ -5,7 +5,6 @@ log file ldpd.log ! debug mpls ldp event ! debug mpls ldp errors ! debug mpls ldp sync -agentx ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf index 8a9b4eb124..aa9438b78e 100644 --- a/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf +++ b/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf @@ -1,4 +1,3 @@ -:assword 1 hostname rt1 log file ospf6d.log log commands 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"); |
