summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_main.c43
-rw-r--r--bgpd/bgp_packet.c137
-rw-r--r--bgpd/bgp_vty.c24
-rw-r--r--bgpd/bgp_zebra.c6
-rw-r--r--bgpd/bgpd.c2
-rw-r--r--bgpd/bgpd.h2
-rw-r--r--doc/user/bgp.rst9
-rw-r--r--doc/user/zebra.rst7
-rw-r--r--lib/zclient.c1
-rw-r--r--lib/zclient.h1
-rw-r--r--tests/topotests/babel_topo1/r3/babeld.conf1
-rw-r--r--tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf1
-rw-r--r--tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf1
-rw-r--r--tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf1
-rw-r--r--tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf1
-rw-r--r--tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf1
-rw-r--r--tests/topotests/bgp_addpath_best_selected/r5/bgpd.conf2
-rw-r--r--tests/topotests/bgp_addpath_best_selected/r6/bgpd.conf2
-rw-r--r--tests/topotests/bgp_dynamic_capability/__init__.py0
-rw-r--r--tests/topotests/bgp_dynamic_capability/r1/bgpd.conf10
-rw-r--r--tests/topotests/bgp_dynamic_capability/r1/zebra.conf4
-rw-r--r--tests/topotests/bgp_dynamic_capability/r2/bgpd.conf10
-rw-r--r--tests/topotests/bgp_dynamic_capability/r2/zebra.conf4
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py153
-rw-r--r--tests/topotests/bgp_evpn_vxlan_macvrf_soo_topo1/PE1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_evpn_vxlan_svd_topo1/PE1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_evpn_vxlan_topo1/PE1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_update_delay/r2/zebra.conf4
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf14
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf14
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py3
-rw-r--r--tests/topotests/config_timing/r1/zebra.conf2
-rw-r--r--tests/topotests/cspf_topo1/r1/sharpd.conf1
-rw-r--r--tests/topotests/isis_snmp/r1/ldpd.conf1
-rw-r--r--tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf1
-rw-r--r--zebra/main.c63
-rw-r--r--zebra/zapi_msg.c2
-rw-r--r--zebra/zebra_router.c5
-rw-r--r--zebra/zebra_router.h4
-rw-r--r--zebra/zebra_vty.c3
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");