summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--bgpd/bgp_updgrp_adv.c2
-rw-r--r--bgpd/bgp_vty.c222
-rw-r--r--bgpd/bgpd.c31
-rw-r--r--bgpd/bgpd.h59
-rwxr-xr-xbuildtest.sh2
-rw-r--r--configure.ac27
-rw-r--r--doc/developer/building-frr-for-centos6.rst1
-rw-r--r--doc/developer/building-frr-for-centos7.rst1
-rw-r--r--doc/developer/building-frr-for-centos8.rst1
-rw-r--r--doc/developer/building-frr-for-debian8.rst1
-rw-r--r--doc/developer/building-frr-for-debian9.rst1
-rw-r--r--doc/developer/building-frr-for-netbsd6.rst1
-rw-r--r--doc/developer/building-frr-for-netbsd7.rst1
-rw-r--r--doc/developer/include-compile.rst1
-rw-r--r--doc/developer/topotests.rst1
-rw-r--r--doc/user/basic.rst37
-rw-r--r--doc/user/bgp.rst70
-rw-r--r--doc/user/installation.rst24
-rw-r--r--doc/user/ipv6.rst5
-rw-r--r--doc/user/ospf6d.rst14
-rw-r--r--doc/user/ospfd.rst4
-rw-r--r--doc/user/zebra.rst7
-rw-r--r--isisd/isis_cli.c4
-rw-r--r--isisd/isis_nb_config.c131
-rw-r--r--isisd/isis_zebra.c5
-rw-r--r--lib/command.c39
-rw-r--r--lib/routemap.h5
-rw-r--r--lib/subdir.am3
-rw-r--r--lib/thread.c184
-rw-r--r--lib/thread.h11
-rw-r--r--lib/vty.c54
-rw-r--r--lib/zclient.c16
-rw-r--r--lib/zclient.h3
-rw-r--r--ospf6d/ospf6_asbr.c31
-rw-r--r--ospf6d/ospf6_asbr.h1
-rw-r--r--ospf6d/ospf6_interface.c6
-rw-r--r--ospf6d/ospf6_interface.h1
-rw-r--r--ospf6d/ospf6_lsa.c2
-rw-r--r--ospf6d/ospf6_message.c7
-rw-r--r--ospf6d/ospf6_top.c87
-rw-r--r--ospf6d/ospf6_top.h1
-rw-r--r--ospf6d/ospf6d.c1
-rw-r--r--ospf6d/subdir.am1
-rw-r--r--ospfd/ospf_interface.c7
-rw-r--r--ospfd/ospf_zebra.c5
-rw-r--r--pathd/pathd.c2
-rw-r--r--python/xrelfo.py6
-rw-r--r--tests/topotests/bgp_default_afi_safi/__init__.py (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/__init__.py)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r1/bgpd.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/bgpd.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r1/zebra.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/zebra.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r2/bgpd.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/bgpd.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r2/zebra.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/zebra.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r3/bgpd.conf5
-rw-r--r--tests/topotests/bgp_default_afi_safi/r3/zebra.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/zebra.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r4/bgpd.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/bgpd.conf)1
-rw-r--r--tests/topotests/bgp_default_afi_safi/r4/zebra.conf6
-rw-r--r--tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/test_bgp-default-ipv4-ipv6-unicast.py)43
-rw-r--r--tests/topotests/bgp_route_map/test_route_map_topo1.py103
-rw-r--r--vtysh/vtysh.c4
-rw-r--r--zebra/main.c1
-rw-r--r--zebra/rib.h18
-rw-r--r--zebra/rtadv.c409
-rw-r--r--zebra/rtadv.h3
-rw-r--r--zebra/zebra_router.c2
-rw-r--r--zebra/zebra_router.h3
-rw-r--r--zebra/zebra_vrf.c2
67 files changed, 1227 insertions, 502 deletions
diff --git a/Makefile.am b/Makefile.am
index a38029dcfa..8c9d7df77c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -109,8 +109,6 @@ CLEANFILES =
DISTCLEANFILES =
SUFFIXES =
-examplesdir = $(exampledir)
-
bin_PROGRAMS =
sbin_PROGRAMS =
sbin_SCRIPTS =
@@ -122,7 +120,6 @@ lib_LTLIBRARIES =
module_LTLIBRARIES =
pkginclude_HEADERS =
nodist_pkginclude_HEADERS =
-dist_examples_DATA =
dist_yangmodels_DATA =
man_MANS =
vtysh_scan =
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 4dd7597e5f..18829aa747 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -839,6 +839,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
bgp_dest_get_prefix(dest), &tmp_pi);
if (ret == RMAP_DENYMATCH) {
+ /* The aspath belongs to 'attr' */
+ tmp_attr.aspath = NULL;
bgp_attr_flush(&tmp_attr);
continue;
} else {
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index de4f5a59b6..e713894eb1 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -470,6 +470,74 @@ int argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index,
return ret;
}
+/*
+ * Convert an afi_t/safi_t pair to matching BGP_DEFAULT_AF* flag.
+ *
+ * afi
+ * address-family identifier
+ *
+ * safi
+ * subsequent address-family identifier
+ *
+ * Returns:
+ * default_af string corresponding to the supplied afi/safi pair.
+ * If afi/safi is invalid or if flag for afi/safi doesn't exist,
+ * return -1.
+ */
+static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi)
+{
+ switch (afi) {
+ case AFI_IP:
+ switch (safi) {
+ case SAFI_UNICAST:
+ return "ipv4-unicast";
+ case SAFI_MULTICAST:
+ return "ipv4-multicast";
+ case SAFI_MPLS_VPN:
+ return "ipv4-vpn";
+ case SAFI_ENCAP:
+ return "ipv4-encap";
+ case SAFI_LABELED_UNICAST:
+ return "ipv4-labeled-unicast";
+ case SAFI_FLOWSPEC:
+ return "ipv4-flowspec";
+ default:
+ return "unknown-afi/safi";
+ }
+ break;
+ case AFI_IP6:
+ switch (safi) {
+ case SAFI_UNICAST:
+ return "ipv6-unicast";
+ case SAFI_MULTICAST:
+ return "ipv6-multicast";
+ case SAFI_MPLS_VPN:
+ return "ipv6-vpn";
+ case SAFI_ENCAP:
+ return "ipv6-encap";
+ case SAFI_LABELED_UNICAST:
+ return "ipv6-labeled-unicast";
+ case SAFI_FLOWSPEC:
+ return "ipv6-flowspec";
+ default:
+ return "unknown-afi/safi";
+ }
+ break;
+ case AFI_L2VPN:
+ switch (safi) {
+ case SAFI_EVPN:
+ return "l2vpn-evpn";
+ default:
+ return "unknown-afi/safi";
+ }
+ case AFI_UNSPEC:
+ case AFI_MAX:
+ return "unknown-afi/safi";
+ }
+ /* all AFIs are accounted for above, so this shouldn't happen */
+ return "unknown-afi/safi";
+}
+
int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
enum bgp_instance_type inst_type)
{
@@ -3741,52 +3809,60 @@ DEFPY (no_bgp_bestpath_bw,
return CMD_SUCCESS;
}
-/* "no bgp default ipv6-unicast". */
-DEFUN(no_bgp_default_ipv6_unicast, no_bgp_default_ipv6_unicast_cmd,
- "no bgp default ipv6-unicast", NO_STR
+DEFPY(bgp_default_afi_safi, bgp_default_afi_safi_cmd,
+ "[no] bgp default <ipv4-unicast|"
+ "ipv4-multicast|"
+ "ipv4-vpn|"
+ "ipv4-labeled-unicast|"
+ "ipv4-flowspec|"
+ "ipv6-unicast|"
+ "ipv6-multicast|"
+ "ipv6-vpn|"
+ "ipv6-labeled-unicast|"
+ "ipv6-flowspec|"
+ "l2vpn-evpn>$afi_safi",
+ NO_STR
"BGP specific commands\n"
"Configure BGP defaults\n"
- "Activate ipv6-unicast for a peer by default\n")
+ "Activate ipv4-unicast for a peer by default\n"
+ "Activate ipv4-multicast for a peer by default\n"
+ "Activate ipv4-vpn for a peer by default\n"
+ "Activate ipv4-labeled-unicast for a peer by default\n"
+ "Activate ipv4-flowspec for a peer by default\n"
+ "Activate ipv6-unicast for a peer by default\n"
+ "Activate ipv6-multicast for a peer by default\n"
+ "Activate ipv6-vpn for a peer by default\n"
+ "Activate ipv6-labeled-unicast for a peer by default\n"
+ "Activate ipv6-flowspec for a peer by default\n"
+ "Activate l2vpn-evpn for a peer by default\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- UNSET_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6);
- return CMD_SUCCESS;
-}
+ char afi_safi_str[strlen(afi_safi) + 1];
+ char *afi_safi_str_tok;
-DEFUN(bgp_default_ipv6_unicast, bgp_default_ipv6_unicast_cmd,
- "bgp default ipv6-unicast",
- "BGP specific commands\n"
- "Configure BGP defaults\n"
- "Activate ipv6-unicast for a peer by default\n")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- SET_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6);
- return CMD_SUCCESS;
-}
+ strlcpy(afi_safi_str, afi_safi, sizeof(afi_safi_str));
+ char *afi_str = strtok_r(afi_safi_str, "-", &afi_safi_str_tok);
+ char *safi_str = strtok_r(NULL, "-", &afi_safi_str_tok);
+ afi_t afi = bgp_vty_afi_from_str(afi_str);
+ safi_t safi;
-/* "no bgp default ipv4-unicast". */
-DEFUN (no_bgp_default_ipv4_unicast,
- no_bgp_default_ipv4_unicast_cmd,
- "no bgp default ipv4-unicast",
- NO_STR
- "BGP specific commands\n"
- "Configure BGP defaults\n"
- "Activate ipv4-unicast for a peer by default\n")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- SET_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4);
- return CMD_SUCCESS;
-}
+ if (strmatch(safi_str, "labeled"))
+ safi = bgp_vty_safi_from_str("labeled-unicast");
+ else
+ safi = bgp_vty_safi_from_str(safi_str);
+
+ if (no)
+ bgp->default_af[afi][safi] = false;
+ else {
+ if ((safi == SAFI_LABELED_UNICAST
+ && bgp->default_af[afi][SAFI_UNICAST])
+ || (safi == SAFI_UNICAST
+ && bgp->default_af[afi][SAFI_LABELED_UNICAST]))
+ bgp_vty_return(vty, BGP_ERR_PEER_SAFI_CONFLICT);
+ else
+ bgp->default_af[afi][safi] = true;
+ }
-DEFUN (bgp_default_ipv4_unicast,
- bgp_default_ipv4_unicast_cmd,
- "bgp default ipv4-unicast",
- "BGP specific commands\n"
- "Configure BGP defaults\n"
- "Activate ipv4-unicast for a peer by default\n")
-{
- VTY_DECLVAR_CONTEXT(bgp, bgp);
- UNSET_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4);
return CMD_SUCCESS;
}
@@ -17436,41 +17512,14 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
}
} else {
if (peer->afc[afi][safi]) {
- if ((afi == AFI_IP || afi == AFI_IP6)
- && safi == SAFI_UNICAST) {
- if (afi == AFI_IP
- && CHECK_FLAG(bgp->flags,
- BGP_FLAG_NO_DEFAULT_IPV4)) {
- vty_out(vty, " neighbor %s activate\n",
- addr);
- } else if (afi == AFI_IP6
- && !CHECK_FLAG(
- bgp->flags,
- BGP_FLAG_DEFAULT_IPV6)) {
- vty_out(vty, " neighbor %s activate\n",
- addr);
- }
- } else {
+ if (safi == SAFI_ENCAP)
+ vty_out(vty, " neighbor %s activate\n", addr);
+ else if (!bgp->default_af[afi][safi])
vty_out(vty, " neighbor %s activate\n", addr);
- }
} else {
- if ((afi == AFI_IP || afi == AFI_IP6)
- && safi == SAFI_UNICAST) {
- if (afi == AFI_IP
- && !CHECK_FLAG(bgp->flags,
- BGP_FLAG_NO_DEFAULT_IPV4)) {
- vty_out(vty,
- " no neighbor %s activate\n",
- addr);
- } else if (afi == AFI_IP6
- && CHECK_FLAG(
- bgp->flags,
- BGP_FLAG_DEFAULT_IPV6)) {
- vty_out(vty,
- " no neighbor %s activate\n",
- addr);
- }
- }
+ if (bgp->default_af[afi][safi])
+ vty_out(vty, " no neighbor %s activate\n",
+ addr);
}
}
@@ -17796,6 +17845,8 @@ int bgp_config_write(struct vty *vty)
struct peer *peer;
struct listnode *node, *nnode;
struct listnode *mnode, *mnnode;
+ afi_t afi;
+ safi_t safi;
if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
vty_out(vty, "bgp route-map delay-timer %u\n",
@@ -17886,13 +17937,17 @@ int bgp_config_write(struct vty *vty)
? ""
: "no ");
- /* BGP default ipv4-unicast. */
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4))
- vty_out(vty, " no bgp default ipv4-unicast\n");
-
- /* BGP default ipv6-unicast. */
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6))
- vty_out(vty, " bgp default ipv6-unicast\n");
+ /* BGP default <afi>-<safi> */
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (afi == AFI_IP && safi == SAFI_UNICAST) {
+ if (!bgp->default_af[afi][safi])
+ vty_out(vty, " no bgp default %s\n",
+ get_bgp_default_af_flag(afi,
+ safi));
+ } else if (bgp->default_af[afi][safi])
+ vty_out(vty, " bgp default %s\n",
+ get_bgp_default_af_flag(afi, safi));
+ }
/* BGP default local-preference. */
if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF)
@@ -18586,13 +18641,8 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_bestpath_bw_cmd);
install_element(BGP_NODE, &no_bgp_bestpath_bw_cmd);
- /* "no bgp default ipv4-unicast" commands. */
- install_element(BGP_NODE, &no_bgp_default_ipv4_unicast_cmd);
- install_element(BGP_NODE, &bgp_default_ipv4_unicast_cmd);
-
- /* "no bgp default ipv6-unicast" commands. */
- install_element(BGP_NODE, &no_bgp_default_ipv6_unicast_cmd);
- install_element(BGP_NODE, &bgp_default_ipv6_unicast_cmd);
+ /* "no bgp default <afi>-<safi>" commands. */
+ install_element(BGP_NODE, &bgp_default_afi_safi_cmd);
/* "bgp network import-check" commands. */
install_element(BGP_NODE, &bgp_network_import_check_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 49562e5874..95cfb205e9 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1776,22 +1776,15 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
- /* If address family is IPv4 and `bgp default ipv4-unicast` (default),
- * then activate the neighbor for this AF.
- * If address family is IPv6 and `bgp default ipv6-unicast`
- * (non-default), then activate the neighbor for this AF.
+ /* If 'bgp default <afi>-<safi>' is configured, then activate the
+ * neighbor for the corresponding address family. IPv4 Unicast is
+ * the only address family enabled by default without expliict
+ * configuration.
*/
FOREACH_AFI_SAFI (afi, safi) {
- if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) {
- if ((afi == AFI_IP
- && !CHECK_FLAG(bgp->flags,
- BGP_FLAG_NO_DEFAULT_IPV4))
- || (afi == AFI_IP6
- && CHECK_FLAG(bgp->flags,
- BGP_FLAG_DEFAULT_IPV6))) {
- peer->afc[afi][safi] = 1;
- peer_af_create(peer, afi, safi);
- }
+ if (bgp->default_af[afi][safi]) {
+ peer->afc[afi][safi] = 1;
+ peer_af_create(peer, afi, safi);
}
}
@@ -2585,6 +2578,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name)
{
struct peer_group *group;
afi_t afi;
+ safi_t safi;
group = peer_group_lookup(bgp, name);
if (group)
@@ -2598,10 +2592,10 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name)
for (afi = AFI_IP; afi < AFI_MAX; afi++)
group->listen_range[afi] = list_new();
group->conf = peer_new(bgp);
- if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4))
- group->conf->afc[AFI_IP][SAFI_UNICAST] = 1;
- if (CHECK_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6))
- group->conf->afc[AFI_IP6][SAFI_UNICAST] = 1;
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (bgp->default_af[afi][safi])
+ group->conf->afc[afi][safi] = 1;
+ }
XFREE(MTYPE_BGP_PEER_HOST, group->conf->host);
group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name);
group->conf->group = group;
@@ -3244,6 +3238,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
atomic_store_explicit(&bgp->rpkt_quanta, BGP_READ_PACKET_MAX,
memory_order_relaxed);
bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
+ bgp->default_af[AFI_IP][SAFI_UNICAST] = true;
QOBJ_REG(bgp, bgp);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 776f4b0a21..d2e8cce997 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -464,38 +464,41 @@ struct bgp {
#define BGP_FLAG_DETERMINISTIC_MED (1 << 1)
#define BGP_FLAG_MED_MISSING_AS_WORST (1 << 2)
#define BGP_FLAG_MED_CONFED (1 << 3)
-#define BGP_FLAG_NO_DEFAULT_IPV4 (1 << 4)
-#define BGP_FLAG_NO_CLIENT_TO_CLIENT (1 << 5)
-#define BGP_FLAG_COMPARE_ROUTER_ID (1 << 7)
-#define BGP_FLAG_ASPATH_IGNORE (1 << 8)
-#define BGP_FLAG_IMPORT_CHECK (1 << 9)
-#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1 << 10)
-#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 11)
+#define BGP_FLAG_NO_CLIENT_TO_CLIENT (1 << 4)
+#define BGP_FLAG_COMPARE_ROUTER_ID (1 << 5)
+#define BGP_FLAG_ASPATH_IGNORE (1 << 6)
+#define BGP_FLAG_IMPORT_CHECK (1 << 7)
+#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1 << 8)
+#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 9)
/* This flag is set when we have full BGP Graceful-Restart mode enable */
-#define BGP_FLAG_GRACEFUL_RESTART (1 << 12)
-
-#define BGP_FLAG_ASPATH_CONFED (1 << 13)
-#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14)
-#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 15)
-#define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1 << 16)
-#define BGP_FLAG_MULTIPATH_RELAX_AS_SET (1 << 17)
-#define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 18)
-#define BGP_FLAG_SHOW_HOSTNAME (1 << 19)
-#define BGP_FLAG_GR_PRESERVE_FWD (1 << 20)
-#define BGP_FLAG_GRACEFUL_SHUTDOWN (1 << 21)
-#define BGP_FLAG_DELETE_IN_PROGRESS (1 << 22)
-#define BGP_FLAG_SELECT_DEFER_DISABLE (1 << 23)
-#define BGP_FLAG_GR_DISABLE_EOR (1 << 24)
-#define BGP_FLAG_EBGP_REQUIRES_POLICY (1 << 25)
-#define BGP_FLAG_SHOW_NEXTHOP_HOSTNAME (1 << 26)
+#define BGP_FLAG_GRACEFUL_RESTART (1 << 10)
+
+#define BGP_FLAG_ASPATH_CONFED (1 << 11)
+#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 12)
+#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 13)
+#define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1 << 14)
+#define BGP_FLAG_MULTIPATH_RELAX_AS_SET (1 << 15)
+#define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 16)
+#define BGP_FLAG_SHOW_HOSTNAME (1 << 17)
+#define BGP_FLAG_GR_PRESERVE_FWD (1 << 18)
+#define BGP_FLAG_GRACEFUL_SHUTDOWN (1 << 19)
+#define BGP_FLAG_DELETE_IN_PROGRESS (1 << 20)
+#define BGP_FLAG_SELECT_DEFER_DISABLE (1 << 21)
+#define BGP_FLAG_GR_DISABLE_EOR (1 << 22)
+#define BGP_FLAG_EBGP_REQUIRES_POLICY (1 << 23)
+#define BGP_FLAG_SHOW_NEXTHOP_HOSTNAME (1 << 24)
/* This flag is set if the instance is in administrative shutdown */
-#define BGP_FLAG_SHUTDOWN (1 << 27)
-#define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 28)
-#define BGP_FLAG_SUPPRESS_DUPLICATES (1 << 29)
-#define BGP_FLAG_DEFAULT_IPV6 (1 << 30)
-#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1 << 31)
+#define BGP_FLAG_SHUTDOWN (1 << 25)
+#define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 26)
+#define BGP_FLAG_SUPPRESS_DUPLICATES (1 << 27)
+#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1 << 29)
+
+ /* BGP default address-families.
+ * New peers inherit enabled afi/safis from bgp instance.
+ */
+ uint16_t default_af[AFI_MAX][SAFI_MAX];
enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
[BGP_GLOBAL_GR_EVENT_CMD];
diff --git a/buildtest.sh b/buildtest.sh
index b4b02d10bf..eeae82fc44 100755
--- a/buildtest.sh
+++ b/buildtest.sh
@@ -4,7 +4,7 @@
# builds some git commit of FRR in some different configurations
# usage: buildtest.sh [commit [configurations...]]
-basecfg="--prefix=/usr --enable-user=frr --enable-group=frr --enable-vty-group=frr --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/frr --enable-exampledir=/etc/frr/samples --localstatedir=/var/run/frr --libdir=/usr/lib64/frr --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-pimd --enable-werror"
+basecfg="--prefix=/usr --enable-user=frr --enable-group=frr --enable-vty-group=frr --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/frr --localstatedir=/var/run/frr --libdir=/usr/lib64/frr --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-pimd --enable-werror"
configs_base="gcc|$basecfg"
diff --git a/configure.ac b/configure.ac
index 96bacc9ed4..0ea209bbfa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -114,15 +114,6 @@ AC_PATH_PROG([PERL], [perl])
PKG_PROG_PKG_CONFIG
dnl default is to match previous behavior
-exampledir=${sysconfdir}
-AC_ARG_ENABLE([exampledir],
- AS_HELP_STRING([--enable-exampledir],
- [specify alternate directory for examples]),
- exampledir="$enableval",)
-dnl XXX add --exampledir to autoconf standard directory list somehow
-AC_SUBST([exampledir])
-
-dnl default is to match previous behavior
pkgsrcrcdir=""
AC_ARG_ENABLE([pkgsrcrcdir],
AS_HELP_STRING([--enable-pkgsrcrcdir],
@@ -663,8 +654,6 @@ AC_ARG_ENABLE([irdp],
AS_HELP_STRING([--disable-irdp], [disable IRDP server support in zebra (enabled by default if supported)]))
AC_ARG_ENABLE([capabilities],
AS_HELP_STRING([--disable-capabilities], [disable using POSIX capabilities]))
-AC_ARG_ENABLE([rusage],
- AS_HELP_STRING([--disable-rusage], [disable using getrusage]))
AC_ARG_ENABLE([gcc_ultra_verbose],
AS_HELP_STRING([--enable-gcc-ultra-verbose], [enable ultra verbose GCC warnings]))
AC_ARG_ENABLE([backtrace],
@@ -794,7 +783,6 @@ fi
if test "$enable_datacenter" = "yes" ; then
AC_DEFINE([HAVE_DATACENTER], [1], [Compile extensions for a DataCenter])
- AC_MSG_WARN([The --enable-datacenter compile time option is deprecated. Please modify the init script to pass -F datacenter to the daemons instead.])
DFLT_NAME="datacenter"
else
DFLT_NAME="traditional"
@@ -2241,6 +2229,10 @@ AC_CHECK_DECL([CLOCK_MONOTONIC],
AC_DEFINE([HAVE_CLOCK_MONOTONIC], [1], [Have monotonic clock])
], [AC_MSG_RESULT([no])], [FRR_INCLUDES])
+AC_CHECK_DECL([CLOCK_THREAD_CPUTIME_ID], [
+ AC_DEFINE([HAVE_CLOCK_THREAD_CPUTIME_ID], [1], [Have cpu-time clock])
+], [AC_MSG_RESULT([no])], [FRR_INCLUDES])
+
AC_SEARCH_LIBS([clock_nanosleep], [rt], [
AC_DEFINE([HAVE_CLOCK_NANOSLEEP], [1], [Have clock_nanosleep()])
])
@@ -2693,7 +2685,6 @@ make : ${MAKE-make}
linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM}
state file directory : ${frr_statedir}
config file directory : `eval echo \`echo ${sysconfdir}\``
-example directory : `eval echo \`echo ${exampledir}\``
module directory : ${CFG_MODULE}
script directory : ${CFG_SCRIPT}
user to run as : ${enable_user}
@@ -2707,6 +2698,16 @@ vici socket path : ${vici_socket}
The above user and group must have read/write access to the state file
directory and to the config files in the config file directory."
+if test -n "$enable_datacenter"; then
+ AC_MSG_WARN([The --enable-datacenter compile time option is deprecated. Please modify the init script to pass -F datacenter to the daemons instead.])
+fi
+if test -n "$enable_time_check"; then
+ AC_MSG_WARN([The --enable-time-check compile time option is deprecated. Please use the service cputime-stats configuration option instead.])
+fi
+if test -n "$enable_cpu_time"; then
+ AC_MSG_WARN([The --enable-cpu-time compile time option is deprecated. Please use the service cputime-warning NNN configuration option instead.])
+fi
+
if test "$enable_doc" != "no" -a "$frr_py_mod_sphinx" = "false"; then
AC_MSG_WARN([sphinx is missing but required to build documentation])
fi
diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst
index 5d3be492de..7a7af42119 100644
--- a/doc/developer/building-frr-for-centos6.rst
+++ b/doc/developer/building-frr-for-centos6.rst
@@ -172,7 +172,6 @@ an example.)
--enable-user=frr \
--enable-group=frr \
--enable-vty-group=frrvty \
- --disable-exampledir \
--disable-ldpd \
--enable-fpm \
--with-pkg-git-version \
diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst
index 8d0aea943c..93b9993a38 100644
--- a/doc/developer/building-frr-for-centos7.rst
+++ b/doc/developer/building-frr-for-centos7.rst
@@ -67,7 +67,6 @@ an example.)
--enable-group=frr \
--enable-vty-group=frrvty \
--enable-systemd=yes \
- --disable-exampledir \
--disable-ldpd \
--enable-fpm \
--with-pkg-git-version \
diff --git a/doc/developer/building-frr-for-centos8.rst b/doc/developer/building-frr-for-centos8.rst
index 77fe489358..65c93286b7 100644
--- a/doc/developer/building-frr-for-centos8.rst
+++ b/doc/developer/building-frr-for-centos8.rst
@@ -60,7 +60,6 @@ an example.)
--enable-group=frr \
--enable-vty-group=frrvty \
--enable-systemd=yes \
- --disable-exampledir \
--disable-ldpd \
--enable-fpm \
--with-pkg-git-version \
diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst
index 51dd07c42a..475e0303fc 100644
--- a/doc/developer/building-frr-for-debian8.rst
+++ b/doc/developer/building-frr-for-debian8.rst
@@ -57,7 +57,6 @@ an example.)
cd frr
./bootstrap.sh
./configure \
- --enable-exampledir=/usr/share/doc/frr/examples/ \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr \
--sysconfdir=/etc/frr \
diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst
index 919b010314..1981127b3d 100644
--- a/doc/developer/building-frr-for-debian9.rst
+++ b/doc/developer/building-frr-for-debian9.rst
@@ -44,7 +44,6 @@ an example.)
cd frr
./bootstrap.sh
./configure \
- --enable-exampledir=/usr/share/doc/frr/examples/ \
--localstatedir=/var/opt/frr \
--sbindir=/usr/lib/frr \
--sysconfdir=/etc/frr \
diff --git a/doc/developer/building-frr-for-netbsd6.rst b/doc/developer/building-frr-for-netbsd6.rst
index e50d11130a..a78f8b3c2f 100644
--- a/doc/developer/building-frr-for-netbsd6.rst
+++ b/doc/developer/building-frr-for-netbsd6.rst
@@ -64,7 +64,6 @@ an example)
export CPPFLAGS="-I/usr/pkg/include"
./configure \
--sysconfdir=/usr/pkg/etc/frr \
- --enable-exampledir=/usr/pkg/share/examples/frr \
--enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \
--localstatedir=/var/run/frr \
--enable-multipath=64 \
diff --git a/doc/developer/building-frr-for-netbsd7.rst b/doc/developer/building-frr-for-netbsd7.rst
index 32d1145edc..a52ece19a1 100644
--- a/doc/developer/building-frr-for-netbsd7.rst
+++ b/doc/developer/building-frr-for-netbsd7.rst
@@ -55,7 +55,6 @@ an example)
export CPPFLAGS="-I/usr/pkg/include"
./configure \
--sysconfdir=/usr/pkg/etc/frr \
- --enable-exampledir=/usr/pkg/share/examples/frr \
--enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \
--localstatedir=/var/run/frr \
--enable-multipath=64 \
diff --git a/doc/developer/include-compile.rst b/doc/developer/include-compile.rst
index 0ff0ae3ffe..d9fa260221 100644
--- a/doc/developer/include-compile.rst
+++ b/doc/developer/include-compile.rst
@@ -15,7 +15,6 @@ obtained by running ``./configure -h``. The options shown below are examples.
./configure \
--prefix=/usr \
--includedir=\${prefix}/include \
- --enable-exampledir=\${prefix}/share/doc/frr/examples \
--bindir=\${prefix}/bin \
--sbindir=\${prefix}/lib/frr \
--libdir=\${prefix}/lib/frr \
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index ba03aa9045..18317cd33c 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -221,7 +221,6 @@ for ``master`` branch:
--prefix=/usr/lib/frr --sysconfdir=/etc/frr \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr --bindir=/usr/lib/frr \
- --enable-exampledir=/usr/lib/frr/examples \
--with-moduledir=/usr/lib/frr/modules \
--enable-multipath=0 --enable-rtadv \
--enable-tcp-zebra --enable-fpm --enable-pimd \
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 6a0249f316..16708adb50 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -66,10 +66,6 @@ Basic Config Commands
Set domainname of the router. It is only for current ``vtysh``, it will not
be saved to any configuration file even with ``write file``.
-.. clicmd:: domainname DOMAINNAME
-
- Set domainname of the router.
-
.. clicmd:: password PASSWORD
Set password for vty interface. The ``no`` form of the command deletes the
@@ -80,6 +76,39 @@ Basic Config Commands
Set enable password. The ``no`` form of the command deletes the enable
password.
+.. clicmd:: service cputime-stats
+
+ Collect CPU usage statistics for individual FRR event handlers and CLI
+ commands. This is enabled by default and can be disabled if the extra
+ overhead causes a noticeable slowdown on your system.
+
+ Disabling these statistics will also make the
+ :clicmd:`service cputime-warning (1-4294967295)` limit non-functional.
+
+.. clicmd:: service cputime-warning (1-4294967295)
+
+ Warn if the CPU usage of an event handler or CLI command exceeds the
+ specified limit (in milliseconds.) Such warnings are generally indicative
+ of some routine in FRR mistakenly blocking/hogging the processing loop and
+ should be reported as a FRR bug.
+
+ The default limit is 5 seconds (i.e. 5000), but this can be changed by the
+ deprecated ``--enable-time-check=...`` compile-time option.
+
+ This command has no effect if :clicmd:`service cputime-stats` is disabled.
+
+.. clicmd:: service walltime-warning (1-4294967295)
+
+ Warn if the total wallclock time spent handling an event or executing a CLI
+ command exceeds the specified limit (in milliseconds.) This includes time
+ spent waiting for I/O or other tasks executing and may produce excessive
+ warnings if the system is overloaded. (This may still be useful to
+ provide an immediate sign that FRR is not operating correctly due to
+ externally caused starvation.)
+
+ The default limit is 5 seconds as above, including the same deprecated
+ ``--enable-time-check=...`` compile-time option.
+
.. clicmd:: log trap LEVEL
These commands are deprecated and are present only for historical
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 7f23f7a633..b5950538dd 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1597,16 +1597,67 @@ Configuring Peers
.. clicmd:: bgp default ipv4-unicast
- This command allows the user to specify that v4 peering is turned
- on by default or not. This command defaults to on and is not displayed.
+ This command allows the user to specify that the IPv4 Unicast address
+ family is turned on by default or not. This command defaults to on
+ and is not displayed.
The `no bgp default ipv4-unicast` form of the command is displayed.
+.. clicmd:: bgp default ipv4-multicast
+
+ This command allows the user to specify that the IPv4 Multicast address
+ family is turned on by default or not. This command defaults to off
+ and is not displayed.
+ The `bgp default ipv4-multicast` form of the command is displayed.
+
+.. clicmd:: bgp default ipv4-vpn
+
+ This command allows the user to specify that the IPv4 MPLS VPN address
+ family is turned on by default or not. This command defaults to off
+ and is not displayed.
+ The `bgp default ipv4-vpn` form of the command is displayed.
+
+.. clicmd:: bgp default ipv4-flowspec
+
+ This command allows the user to specify that the IPv4 Flowspec address
+ family is turned on by default or not. This command defaults to off
+ and is not displayed.
+ The `bgp default ipv4-flowspec` form of the command is displayed.
+
.. clicmd:: bgp default ipv6-unicast
- This command allows the user to specify that v6 peering is turned
- on by default or not. This command defaults to off and is not displayed.
+ This command allows the user to specify that the IPv6 Unicast address
+ family is turned on by default or not. This command defaults to off
+ and is not displayed.
The `bgp default ipv6-unicast` form of the command is displayed.
+.. clicmd:: bgp default ipv6-multicast
+
+ This command allows the user to specify that the IPv6 Multicast address
+ family is turned on by default or not. This command defaults to off
+ and is not displayed.
+ The `bgp default ipv6-multicast` form of the command is displayed.
+
+.. clicmd:: bgp default ipv6-vpn
+
+ This command allows the user to specify that the IPv6 MPLS VPN address
+ family is turned on by default or not. This command defaults to off
+ and is not displayed.
+ The `bgp default ipv6-vpn` form of the command is displayed.
+
+.. clicmd:: bgp default ipv6-flowspec
+
+ This command allows the user to specify that the IPv6 Flowspec address
+ family is turned on by default or not. This command defaults to off
+ and is not displayed.
+ The `bgp default ipv6-flowspec` form of the command is displayed.
+
+.. clicmd:: bgp default l2vpn-evpn
+
+ This command allows the user to specify that the L2VPN EVPN address
+ family is turned on by default or not. This command defaults to off
+ and is not displayed.
+ The `bgp default l2vpn-evpn` form of the command is displayed.
+
.. clicmd:: bgp default show-hostname
This command shows the hostname of the peer in certain BGP commands
@@ -2727,10 +2778,12 @@ Host1 MAC/IP as type-2 route which is used to resolve host1 gateway IP.
PE2 receives this type-5 route and imports it into the vrf based on route
targets. BGP prefix imported into the vrf uses gateway IP as its BGP nexthop.
This route is installed into zebra if following conditions are satisfied:
+
1. Gateway IP nexthop is L3 reachable.
2. PE2 has received EVPN type-2 route with IP field set to gateway IP.
Topology requirements:
+
1. This feature is supported for asymmetric routing model only. While
sending packets to SN1, ingress PE (PE2) performs routing and
egress PE (PE1) performs only bridging.
@@ -2749,8 +2802,7 @@ route with gateway IP.
1. CLI to add gateway IP while generating EVPN type-5 route from a BGP IPv4/IPv6
prefix:
-.. index:: advertise <ipv4|ipv6> unicast [gateway-ip]
-.. clicmd:: [no] advertise <ipv4|ipv6> unicast [gateway-ip]
+.. clicmd:: advertise <ipv4|ipv6> unicast [gateway-ip]
When this CLI is configured for a BGP vrf under L2VPN EVPN address family, EVPN
type-5 routes are generated for BGP prefixes in the vrf. Nexthop of the BGP
@@ -2761,8 +2813,7 @@ routes are generated without overlay index.
2. Add gateway IP to EVPN type-5 route using a route-map:
-.. index:: set evpn gateway-ip <ipv4|ipv6> <addr>
-.. clicmd:: [no] set evpn gateway-ip <ipv4|ipv6> <addr>
+.. clicmd:: set evpn gateway-ip <ipv4|ipv6> <addr>
When route-map with above set clause is applied as outbound policy in BGP, it
will set the gateway-ip in EVPN type-5 NLRI.
@@ -2786,8 +2837,7 @@ A PE that receives a type-5 route with gateway IP overlay index should have
"enable-resolve-overlay-index" configuration enabled to recursively resolve the
overlay index nexthop and install the prefix into zebra.
-.. index:: enable-resolve-overlay-index
-.. clicmd:: [no] enable-resolve-overlay-index
+.. clicmd:: enable-resolve-overlay-index
Example configuration:
diff --git a/doc/user/installation.rst b/doc/user/installation.rst
index f7e45a6231..63254555d9 100644
--- a/doc/user/installation.rst
+++ b/doc/user/installation.rst
@@ -199,6 +199,10 @@ options from the list below.
.. option:: --enable-datacenter
+ This option is deprecated as it is superseded by the `-F` (profile) command
+ line option which allows adjusting the setting at startup rather than
+ compile time.
+
Enable system defaults to work as if in a Data Center. See defaults.h
for what is changed by this configure option.
@@ -343,20 +347,17 @@ options from the list below.
.. option:: --enable-time-check XXX
- When this is enabled with a XXX value in microseconds, any thread that
- runs for over this value will cause a warning to be issued to the log.
- If you do not specify any value or don't include this option then
- the default time is 5 seconds. If --disable-time-check is specified
- then no warning is issued for any thread run length.
+ This option is deprecated as it was replaced by the
+ :clicmd:`service cputime-stats` CLI command, which may be adjusted at
+ runtime rather than being a compile-time setting. See there for further
+ detail.
.. option:: --disable-cpu-time
- Disable cpu process accounting, this command also disables the `show thread cpu`
- command. If this option is disabled, --enable-time-check is ignored. This
- disabling of cpu time effectively means that the getrusage call is skipped.
- Since this is a process switch into the kernel, systems with high FRR
- load might see improvement in behavior. Be aware that `show thread cpu`
- is considered a good data gathering tool from the perspective of developers.
+ This option is deprecated as it was replaced by the
+ :clicmd:`service cputime-warning NNN` CLI command, which may be adjusted at
+ runtime rather than being a compile-time setting. See there for further
+ detail.
.. option:: --enable-pcreposix
@@ -561,7 +562,6 @@ the options you chose:
./configure \
--prefix=/usr \
- --enable-exampledir=/usr/share/doc/frr/examples/ \
--localstatedir=/var/run/frr \
--sbindir=/usr/lib/frr \
--sysconfdir=/etc/frr \
diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst
index 089fae39b1..4f01061e7b 100644
--- a/doc/user/ipv6.rst
+++ b/doc/user/ipv6.rst
@@ -17,6 +17,11 @@ no longer possible.
Router Advertisement
====================
+.. clicmd:: show ipv6 nd ra-interfaces [vrf <VRFNAME|all>]
+
+ Show configured route advertisement interfaces. VRF subcommand only
+ applicable for netns-based vrfs.
+
.. clicmd:: ipv6 nd suppress-ra
Don't send router advertisement messages. The ``no`` form of this command
diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst
index 7c01b6f136..04ee1643d8 100644
--- a/doc/user/ospf6d.rst
+++ b/doc/user/ospf6d.rst
@@ -77,20 +77,26 @@ OSPF6 router
of packets to process before returning. The default value of this parameter
is 20.
+.. clicmd:: clear ipv6 ospf6 process [vrf NAME]
+
+ This command clears up the database and routing tables and resets the
+ neighborship by restarting the interface state machine. This will be
+ helpful when there is a change in router-id and if user wants the router-id
+ change to take effect, user can use this cli instead of restarting the
+ ospf6d daemon.
.. _ospf6-area:
OSPF6 area
==========
-.. index:: [no] area A.B.C.D nssa
-.. clicmd:: [no] area A.B.C.D nssa
+.. clicmd:: area A.B.C.D nssa
NSSA Support in OSPFv3
=======================
The configuration of NSSA areas in OSPFv3 is supported using the CLI command
-area A.B.C.D nssa in ospf6 router configuration mode.
+``area A.B.C.D nssa`` in ospf6 router configuration mode.
The following functionalities are implemented as per RFC 3101:
1. Advertising Type-7 LSA into NSSA area when external route is redistributed
@@ -98,7 +104,7 @@ The following functionalities are implemented as per RFC 3101:
2. Processing Type-7 LSA received from neighbor and installing route in the
route table
3. Support for NSSA ABR functionality which is generating Type-5 LSA when
- backbone area is configured. Currently translation od TYpe-7 LSA to Type-5 LSA
+ backbone area is configured. Currently translation of Type-7 LSA to Type-5 LSA
is enabled by default.
4. Support for NSSA Translator functionality when there are multiple NSSA ABR
in an area
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 692ce8c1b2..8d67ec865f 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -80,11 +80,13 @@ Routers
To start OSPF process you have to specify the OSPF router.
-.. clicmd:: router ospf [(1-65535)] vrf NAME
+.. clicmd:: router ospf [{(1-65535)|vrf NAME}]
Enable or disable the OSPF process.
+ Multiple instances don't support `vrf NAME`.
+
.. clicmd:: ospf router-id A.B.C.D
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index ee9da63445..3654801100 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -647,7 +647,6 @@ FRR's cli or frr.conf or zebra.conf. This section shows how
to configure SRv6 on FRR. Of course SRv6 can be used as standalone,
and this section also helps that case.
-.. index:: show segment-routing srv6 locator [json]
.. clicmd:: show segment-routing srv6 locator [json]
This command dump SRv6-locator configured on zebra. SRv6-locator is used
@@ -666,7 +665,6 @@ and this section also helps that case.
loc1 1 2001:db8:1:1::/64 Up
loc2 2 2001:db8:2:2::/64 Up
-.. index:: show segment-routing srv6 locator NAME detail [json]
.. clicmd:: show segment-routing srv6 locator NAME detail [json]
As shown in the example, by specifying the name of the locator, you
@@ -696,29 +694,24 @@ and this section also helps that case.
Chunks:
- prefix: 2001:db8:2:2::/64, owner: sharp
-.. index:: segment-routing
.. clicmd:: segment-routing
Move from configure mode to segment-routing node.
-.. index:: srv6
.. clicmd:: srv6
Move from segment-routing node to srv6 node.
-.. index:: locators
.. clicmd:: locators
Move from srv6 node to locator node. In this locator node, user can
configure detailed settings such as the actual srv6 locator.
-.. index:: locator NAME
.. clicmd:: locator NAME
Create a new locator. If the name of an existing locator is specified,
move to specified locator's configuration node to change the settings it.
-.. index:: prefix X:X::X:X/M [function-bits-length 32]
.. clicmd:: prefix X:X::X:X/M [function-bits-length 32]
Set the ipv6 prefix block of the locator. SRv6 locator is defined by
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 366d544d1f..ef86d47b22 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -1196,7 +1196,7 @@ DEFPY_YANG(no_isis_mpls_te_on, no_isis_mpls_te_on_cmd, "no mpls-te [on]",
void cli_show_isis_mpls_te(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- vty_out(vty, " mpls-te on\n");
+ vty_out(vty, " mpls-te on\n");
}
/*
@@ -1229,7 +1229,7 @@ DEFPY_YANG(no_isis_mpls_te_router_addr, no_isis_mpls_te_router_addr_cmd,
void cli_show_isis_mpls_te_router_addr(struct vty *vty, struct lyd_node *dnode,
bool show_defaults)
{
- vty_out(vty, " mpls-te router-address %s\n",
+ vty_out(vty, " mpls-te router-address %s\n",
yang_dnode_get_string(dnode, NULL));
}
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 2622c5b51b..4a01c728f0 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -111,6 +111,28 @@ int isis_instance_is_type_modify(struct nb_cb_modify_args *args)
return NB_OK;
}
+struct sysid_iter {
+ struct area_addr *addr;
+ bool same;
+};
+
+static int sysid_iter_cb(const struct lyd_node *dnode, void *arg)
+{
+ struct sysid_iter *iter = arg;
+ struct area_addr addr;
+ const char *net;
+
+ net = yang_dnode_get_string(dnode, NULL);
+ addr.addr_len = dotformat2buff(addr.area_addr, net);
+
+ if (memcmp(GETSYSID(iter->addr), GETSYSID((&addr)), ISIS_SYS_ID_LEN)) {
+ iter->same = false;
+ return YANG_ITER_STOP;
+ }
+
+ return YANG_ITER_CONTINUE;
+}
+
/*
* XPath: /frr-isisd:isis/instance/area-address
*/
@@ -119,14 +141,12 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
struct isis_area *area;
struct area_addr addr, *addrr = NULL, *addrp = NULL;
struct listnode *node;
+ struct sysid_iter iter;
uint8_t buff[255];
const char *net_title = yang_dnode_get_string(args->dnode, NULL);
switch (args->event) {
case NB_EV_VALIDATE:
- area = nb_running_get_entry(args->dnode, NULL, false);
- if (area == NULL)
- return NB_ERR_VALIDATION;
addr.addr_len = dotformat2buff(buff, net_title);
memcpy(addr.area_addr, buff, addr.addr_len);
if (addr.area_addr[addr.addr_len - 1] != 0) {
@@ -135,15 +155,18 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
"nsel byte (last byte) in area address must be 0");
return NB_ERR_VALIDATION;
}
- if (area->isis->sysid_set) {
- /* Check that the SystemID portions match */
- if (memcmp(area->isis->sysid, GETSYSID((&addr)),
- ISIS_SYS_ID_LEN)) {
- snprintf(
- args->errmsg, args->errmsg_len,
- "System ID must not change when defining additional area addresses");
- return NB_ERR_VALIDATION;
- }
+
+ iter.addr = &addr;
+ iter.same = true;
+
+ yang_dnode_iterate(sysid_iter_cb, &iter, args->dnode,
+ "../area-address");
+
+ if (!iter.same) {
+ snprintf(
+ args->errmsg, args->errmsg_len,
+ "System ID must not change when defining additional area addresses");
+ return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
@@ -2360,14 +2383,14 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_n_flag_clear_modify(
int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args)
{
struct isis_area *area;
+ const char *vrfname;
switch (args->event) {
case NB_EV_VALIDATE:
- area = nb_running_get_entry(args->dnode, NULL, false);
- if (area == NULL || area->isis == NULL)
- return NB_ERR_VALIDATION;
+ vrfname = yang_dnode_get_string(
+ lyd_parent(lyd_parent(args->dnode)), "./vrf");
- if (area->isis->vrf_id != VRF_DEFAULT) {
+ if (strcmp(vrfname, VRF_DEFAULT_NAME)) {
snprintf(args->errmsg, args->errmsg_len,
"LDP-Sync only runs on Default VRF");
return NB_ERR_VALIDATION;
@@ -2404,14 +2427,15 @@ int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args)
{
struct isis_area *area;
uint16_t holddown;
+ const char *vrfname;
switch (args->event) {
case NB_EV_VALIDATE:
- area = nb_running_get_entry(args->dnode, NULL, false);
- if (area == NULL || area->isis == NULL)
- return NB_ERR_VALIDATION;
+ vrfname = yang_dnode_get_string(
+ lyd_parent(lyd_parent(lyd_parent(args->dnode))),
+ "./vrf");
- if (area->isis->vrf_id != VRF_DEFAULT) {
+ if (strcmp(vrfname, VRF_DEFAULT_NAME)) {
snprintf(args->errmsg, args->errmsg_len,
"LDP-Sync only runs on Default VRF");
return NB_ERR_VALIDATION;
@@ -3180,26 +3204,14 @@ int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args)
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
bool ldp_sync_enable;
- struct interface *ifp;
+ const char *vrfname;
switch (args->event) {
case NB_EV_VALIDATE:
- ifp = nb_running_get_entry(
- lyd_parent(lyd_parent(lyd_parent(args->dnode))), NULL,
- false);
- if (ifp == NULL)
- return NB_ERR_VALIDATION;
- if (if_is_loopback(ifp)) {
- snprintf(args->errmsg, args->errmsg_len,
- "LDP-Sync does not run on loopback interface");
- return NB_ERR_VALIDATION;
- }
-
- circuit = nb_running_get_entry(args->dnode, NULL, false);
- if (circuit == NULL || circuit->area == NULL)
- break;
-
- if (circuit->isis->vrf_id != VRF_DEFAULT) {
+ vrfname = yang_dnode_get_string(
+ lyd_parent(lyd_parent(lyd_parent(args->dnode))),
+ "./vrf");
+ if (strcmp(vrfname, VRF_DEFAULT_NAME)) {
snprintf(args->errmsg, args->errmsg_len,
"LDP-Sync only runs on Default VRF");
return NB_ERR_VALIDATION;
@@ -3236,27 +3248,14 @@ int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args)
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
uint16_t holddown;
- struct interface *ifp;
+ const char *vrfname;
switch (args->event) {
case NB_EV_VALIDATE:
-
- ifp = nb_running_get_entry(
- lyd_parent(lyd_parent(lyd_parent(args->dnode))), NULL,
- false);
- if (ifp == NULL)
- return NB_ERR_VALIDATION;
- if (if_is_loopback(ifp)) {
- snprintf(args->errmsg, args->errmsg_len,
- "LDP-Sync does not run on loopback interface");
- return NB_ERR_VALIDATION;
- }
-
- circuit = nb_running_get_entry(args->dnode, NULL, false);
- if (circuit == NULL || circuit->area == NULL)
- break;
-
- if (circuit->isis->vrf_id != VRF_DEFAULT) {
+ vrfname = yang_dnode_get_string(
+ lyd_parent(lyd_parent(lyd_parent(args->dnode))),
+ "./vrf");
+ if (strcmp(vrfname, VRF_DEFAULT_NAME)) {
snprintf(args->errmsg, args->errmsg_len,
"LDP-Sync only runs on Default VRF");
return NB_ERR_VALIDATION;
@@ -3282,26 +3281,14 @@ int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args)
{
struct isis_circuit *circuit;
struct ldp_sync_info *ldp_sync_info;
- struct interface *ifp;
+ const char *vrfname;
switch (args->event) {
case NB_EV_VALIDATE:
- ifp = nb_running_get_entry(
- lyd_parent(lyd_parent(lyd_parent(args->dnode))), NULL,
- false);
- if (ifp == NULL)
- return NB_ERR_VALIDATION;
- if (if_is_loopback(ifp)) {
- snprintf(args->errmsg, args->errmsg_len,
- "LDP-Sync does not run on loopback interface");
- return NB_ERR_VALIDATION;
- }
-
- circuit = nb_running_get_entry(args->dnode, NULL, false);
- if (circuit == NULL || circuit->area == NULL)
- break;
-
- if (circuit->isis->vrf_id != VRF_DEFAULT) {
+ vrfname = yang_dnode_get_string(
+ lyd_parent(lyd_parent(lyd_parent(args->dnode))),
+ "./vrf");
+ if (strcmp(vrfname, VRF_DEFAULT_NAME)) {
snprintf(args->errmsg, args->errmsg_len,
"LDP-Sync only runs on Default VRF");
return NB_ERR_VALIDATION;
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 0142e30b2b..2c05cb8277 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -145,10 +145,11 @@ static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
+ bool changed = false;
- ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id);
+ ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id, &changed);
- if (ifp == NULL)
+ if (ifp == NULL || !changed)
return 0;
/* Update TE TLV */
diff --git a/lib/command.c b/lib/command.c
index 7be54907ed..560d4a09f8 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -255,6 +255,9 @@ static bool cmd_hash_cmp(const void *a, const void *b)
/* Install top node of command vector. */
void install_node(struct cmd_node *node)
{
+#define CMD_HASH_STR_SIZE 256
+ char hash_name[CMD_HASH_STR_SIZE];
+
vector_set_index(cmdvec, node->node, node);
node->cmdgraph = graph_new();
node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
@@ -263,8 +266,10 @@ void install_node(struct cmd_node *node)
cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
graph_new_node(node->cmdgraph, token,
(void (*)(void *)) & cmd_token_del);
- node->cmd_hash = hash_create_size(16, cmd_hash_key, cmd_hash_cmp,
- "Command Hash");
+
+ snprintf(hash_name, sizeof(hash_name), "Command Hash: %s", node->name);
+ node->cmd_hash =
+ hash_create_size(16, cmd_hash_key, cmd_hash_cmp, hash_name);
}
/* Return prompt character of specified node. */
@@ -434,6 +439,36 @@ static int config_write_host(struct vty *vty)
}
log_config_write(vty);
+ /* print disable always, but enable only if default is flipped
+ * => prep for future removal of compile-time knob
+ */
+ if (!cputime_enabled)
+ vty_out(vty, "no service cputime-stats\n");
+#ifdef EXCLUDE_CPU_TIME
+ else
+ vty_out(vty, "service cputime-stats\n");
+#endif
+
+ if (!cputime_threshold)
+ vty_out(vty, "no service cputime-warning\n");
+#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000
+ else /* again, always print non-default */
+#else
+ else if (cputime_threshold != 5000000)
+#endif
+ vty_out(vty, "service cputime-warning %lu\n",
+ cputime_threshold);
+
+ if (!walltime_threshold)
+ vty_out(vty, "no service walltime-warning\n");
+#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000
+ else /* again, always print non-default */
+#else
+ else if (walltime_threshold != 5000000)
+#endif
+ vty_out(vty, "service walltime-warning %lu\n",
+ walltime_threshold);
+
if (host.advanced)
vty_out(vty, "service advanced-vty\n");
diff --git a/lib/routemap.h b/lib/routemap.h
index 4d76ae1536..4a40ec08b9 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -194,6 +194,11 @@ struct route_map_index {
};
DECLARE_QOBJ_TYPE(route_map_index);
+/* route map maximum length. Not strictly the maximum xpath length but cannot be
+ * greater
+ */
+#define RMAP_NAME_MAXLEN XPATH_MAXLEN
+
/* Route map list structure. */
struct route_map {
/* Name of route map. */
diff --git a/lib/subdir.am b/lib/subdir.am
index 4015c67ea8..90301d800a 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -168,6 +168,7 @@ clippy_scan += \
lib/northbound_cli.c \
lib/plist.c \
lib/routemap_cli.c \
+ lib/thread.c \
lib/vty.c \
# end
@@ -463,7 +464,7 @@ endif
SUFFIXES += .xref
%.xref: % $(CLIPPY)
- $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py $(XRELFO_FLAGS) -o $@ $<
+ $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py $(WERROR) $(XRELFO_FLAGS) -o $@ $<
# dependencies added in python/makefile.py
frr.xref:
diff --git a/lib/thread.c b/lib/thread.c
index 3af89fad5a..835aa38115 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -90,7 +90,22 @@ static struct list *masters;
static void thread_free(struct thread_master *master, struct thread *thread);
+#ifndef EXCLUDE_CPU_TIME
+#define EXCLUDE_CPU_TIME 0
+#endif
+#ifndef CONSUMED_TIME_CHECK
+#define CONSUMED_TIME_CHECK 0
+#endif
+
+bool cputime_enabled = !EXCLUDE_CPU_TIME;
+unsigned long cputime_threshold = CONSUMED_TIME_CHECK;
+unsigned long walltime_threshold = CONSUMED_TIME_CHECK;
+
/* CLI start ---------------------------------------------------------------- */
+#ifndef VTYSH_EXTRACT_PL
+#include "lib/thread_clippy.c"
+#endif
+
static unsigned int cpu_record_hash_key(const struct cpu_thread_history *a)
{
int size = sizeof(a->func);
@@ -120,7 +135,6 @@ static void cpu_record_hash_free(void *a)
XFREE(MTYPE_THREAD_STATS, hist);
}
-#ifndef EXCLUDE_CPU_TIME
static void vty_out_cpu_thread_history(struct vty *vty,
struct cpu_thread_history *a)
{
@@ -187,6 +201,14 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
struct thread_master *m;
struct listnode *ln;
+ if (!cputime_enabled)
+ vty_out(vty,
+ "\n"
+ "Collecting CPU time statistics is currently disabled. Following statistics\n"
+ "will be zero or may display data from when collection was enabled. Use the\n"
+ " \"service cputime-stats\" command to start collecting data.\n"
+ "\nCounters and wallclock times are always maintained and should be accurate.\n");
+
memset(&tmp, 0, sizeof(tmp));
tmp.funcname = "TOTAL";
tmp.types = filter;
@@ -236,7 +258,6 @@ static void cpu_record_print(struct vty *vty, uint8_t filter)
if (tmp.total_calls > 0)
vty_out_cpu_thread_history(vty, &tmp);
}
-#endif
static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[])
{
@@ -306,7 +327,6 @@ static uint8_t parse_filter(const char *filterstr)
return filter;
}
-#ifndef EXCLUDE_CPU_TIME
DEFUN_NOSH (show_thread_cpu,
show_thread_cpu_cmd,
"show thread cpu [FILTER]",
@@ -331,7 +351,61 @@ DEFUN_NOSH (show_thread_cpu,
cpu_record_print(vty, filter);
return CMD_SUCCESS;
}
-#endif
+
+DEFPY (service_cputime_stats,
+ service_cputime_stats_cmd,
+ "[no] service cputime-stats",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "Collect CPU usage statistics\n")
+{
+ cputime_enabled = !no;
+ return CMD_SUCCESS;
+}
+
+DEFPY (service_cputime_warning,
+ service_cputime_warning_cmd,
+ "[no] service cputime-warning (1-4294967295)",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "Warn for tasks exceeding CPU usage threshold\n"
+ "Warning threshold in milliseconds\n")
+{
+ if (no)
+ cputime_threshold = 0;
+ else
+ cputime_threshold = cputime_warning * 1000;
+ return CMD_SUCCESS;
+}
+
+ALIAS (service_cputime_warning,
+ no_service_cputime_warning_cmd,
+ "no service cputime-warning",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "Warn for tasks exceeding CPU usage threshold\n")
+
+DEFPY (service_walltime_warning,
+ service_walltime_warning_cmd,
+ "[no] service walltime-warning (1-4294967295)",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "Warn for tasks exceeding total wallclock threshold\n"
+ "Warning threshold in milliseconds\n")
+{
+ if (no)
+ walltime_threshold = 0;
+ else
+ walltime_threshold = walltime_warning * 1000;
+ return CMD_SUCCESS;
+}
+
+ALIAS (service_walltime_warning,
+ no_service_walltime_warning_cmd,
+ "no service walltime-warning",
+ NO_STR
+ "Set up miscellaneous service\n"
+ "Warn for tasks exceeding total wallclock threshold\n")
static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
{
@@ -421,11 +495,15 @@ DEFUN (clear_thread_cpu,
void thread_cmd_init(void)
{
-#ifndef EXCLUDE_CPU_TIME
install_element(VIEW_NODE, &show_thread_cpu_cmd);
-#endif
install_element(VIEW_NODE, &show_thread_poll_cmd);
install_element(ENABLE_NODE, &clear_thread_cpu_cmd);
+
+ install_element(CONFIG_NODE, &service_cputime_stats_cmd);
+ install_element(CONFIG_NODE, &service_cputime_warning_cmd);
+ install_element(CONFIG_NODE, &no_service_cputime_warning_cmd);
+ install_element(CONFIG_NODE, &service_walltime_warning_cmd);
+ install_element(CONFIG_NODE, &no_service_walltime_warning_cmd);
}
/* CLI end ------------------------------------------------------------------ */
@@ -1743,9 +1821,14 @@ static unsigned long timeval_elapsed(struct timeval a, struct timeval b)
unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start,
unsigned long *cputime)
{
+#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
+ *cputime = (now->cpu.tv_sec - start->cpu.tv_sec) * TIMER_SECOND_MICRO
+ + (now->cpu.tv_nsec - start->cpu.tv_nsec) / 1000;
+#else
/* This is 'user + sys' time. */
*cputime = timeval_elapsed(now->cpu.ru_utime, start->cpu.ru_utime)
+ timeval_elapsed(now->cpu.ru_stime, start->cpu.ru_stime);
+#endif
return timeval_elapsed(now->real, start->real);
}
@@ -1778,13 +1861,23 @@ void thread_set_yield_time(struct thread *thread, unsigned long yield_time)
void thread_getrusage(RUSAGE_T *r)
{
+ monotime(&r->real);
+ if (!cputime_enabled) {
+ memset(&r->cpu, 0, sizeof(r->cpu));
+ return;
+ }
+
+#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
+ /* not currently implemented in Linux's vDSO, but maybe at some point
+ * in the future?
+ */
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &r->cpu);
+#else /* !HAVE_CLOCK_THREAD_CPUTIME_ID */
#if defined RUSAGE_THREAD
#define FRR_RUSAGE RUSAGE_THREAD
#else
#define FRR_RUSAGE RUSAGE_SELF
#endif
- monotime(&r->real);
-#ifndef EXCLUDE_CPU_TIME
getrusage(FRR_RUSAGE, &(r->cpu));
#endif
}
@@ -1802,13 +1895,14 @@ void thread_getrusage(RUSAGE_T *r)
*/
void thread_call(struct thread *thread)
{
-#ifndef EXCLUDE_CPU_TIME
- _Atomic unsigned long realtime, cputime;
- unsigned long exp;
- unsigned long helper;
-#endif
RUSAGE_T before, after;
+ /* if the thread being called is the CLI, it may change cputime_enabled
+ * ("service cputime-stats" command), which can result in nonsensical
+ * and very confusing warnings
+ */
+ bool cputime_enabled_here = cputime_enabled;
+
if (thread->master->ready_run_loop)
before = thread->master->last_getrusage;
else
@@ -1828,43 +1922,45 @@ void thread_call(struct thread *thread)
GETRUSAGE(&after);
thread->master->last_getrusage = after;
-#ifndef EXCLUDE_CPU_TIME
- realtime = thread_consumed_time(&after, &before, &helper);
- cputime = helper;
+ unsigned long walltime, cputime;
+ unsigned long exp;
+
+ walltime = thread_consumed_time(&after, &before, &cputime);
- /* update realtime */
- atomic_fetch_add_explicit(&thread->hist->real.total, realtime,
+ /* update walltime */
+ atomic_fetch_add_explicit(&thread->hist->real.total, walltime,
memory_order_seq_cst);
exp = atomic_load_explicit(&thread->hist->real.max,
memory_order_seq_cst);
- while (exp < realtime
+ while (exp < walltime
&& !atomic_compare_exchange_weak_explicit(
- &thread->hist->real.max, &exp, realtime,
- memory_order_seq_cst, memory_order_seq_cst))
+ &thread->hist->real.max, &exp, walltime,
+ memory_order_seq_cst, memory_order_seq_cst))
;
- /* update cputime */
- atomic_fetch_add_explicit(&thread->hist->cpu.total, cputime,
- memory_order_seq_cst);
- exp = atomic_load_explicit(&thread->hist->cpu.max,
- memory_order_seq_cst);
- while (exp < cputime
- && !atomic_compare_exchange_weak_explicit(
- &thread->hist->cpu.max, &exp, cputime,
- memory_order_seq_cst, memory_order_seq_cst))
- ;
+ if (cputime_enabled_here && cputime_enabled) {
+ /* update cputime */
+ atomic_fetch_add_explicit(&thread->hist->cpu.total, cputime,
+ memory_order_seq_cst);
+ exp = atomic_load_explicit(&thread->hist->cpu.max,
+ memory_order_seq_cst);
+ while (exp < cputime
+ && !atomic_compare_exchange_weak_explicit(
+ &thread->hist->cpu.max, &exp, cputime,
+ memory_order_seq_cst, memory_order_seq_cst))
+ ;
+ }
atomic_fetch_add_explicit(&thread->hist->total_calls, 1,
memory_order_seq_cst);
atomic_fetch_or_explicit(&thread->hist->types, 1 << thread->add_type,
memory_order_seq_cst);
-#ifdef CONSUMED_TIME_CHECK
- if (cputime > CONSUMED_TIME_CHECK) {
+ if (cputime_enabled_here && cputime_enabled && cputime_threshold
+ && cputime > cputime_threshold) {
/*
- * We have a CPU Hog on our hands. The time FRR
- * has spent doing actual work ( not sleeping )
- * is greater than 5 seconds.
+ * We have a CPU Hog on our hands. The time FRR has spent
+ * doing actual work (not sleeping) is greater than 5 seconds.
* Whinge about it now, so we're aware this is yet another task
* to fix.
*/
@@ -1874,13 +1970,13 @@ void thread_call(struct thread *thread)
EC_LIB_SLOW_THREAD_CPU,
"CPU HOG: task %s (%lx) ran for %lums (cpu time %lums)",
thread->xref->funcname, (unsigned long)thread->func,
- realtime / 1000, cputime / 1000);
- } else if (realtime > CONSUMED_TIME_CHECK) {
+ walltime / 1000, cputime / 1000);
+
+ } else if (walltime_threshold && walltime > walltime_threshold) {
/*
- * The runtime for a task is greater than 5 seconds, but
- * the cpu time is under 5 seconds. Let's whine
- * about this because this could imply some sort of
- * scheduling issue.
+ * The runtime for a task is greater than 5 seconds, but the
+ * cpu time is under 5 seconds. Let's whine about this because
+ * this could imply some sort of scheduling issue.
*/
atomic_fetch_add_explicit(&thread->hist->total_wall_warn,
1, memory_order_seq_cst);
@@ -1888,10 +1984,8 @@ void thread_call(struct thread *thread)
EC_LIB_SLOW_THREAD_WALL,
"STARVATION: task %s (%lx) ran for %lums (cpu time %lums)",
thread->xref->funcname, (unsigned long)thread->func,
- realtime / 1000, cputime / 1000);
+ walltime / 1000, cputime / 1000);
}
-#endif /* CONSUMED_TIME_CHECK */
-#endif /* Exclude CPU Time */
}
/* Execute thread */
diff --git a/lib/thread.h b/lib/thread.h
index fee728dbf9..abd94ff4f0 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -33,8 +33,19 @@
extern "C" {
#endif
+extern bool cputime_enabled;
+extern unsigned long cputime_threshold;
+/* capturing wallclock time is always enabled since it is fast (reading
+ * hardware TSC w/o syscalls)
+ */
+extern unsigned long walltime_threshold;
+
struct rusage_t {
+#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID
+ struct timespec cpu;
+#else
struct rusage cpu;
+#endif
struct timeval real;
};
#define RUSAGE_T struct rusage_t
diff --git a/lib/vty.c b/lib/vty.c
index 50d116c564..f64ab83847 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -502,37 +502,37 @@ static int vty_command(struct vty *vty, char *buf)
zlog_notice("%s%s", prompt_str, buf);
}
-#ifdef CONSUMED_TIME_CHECK
- {
- RUSAGE_T before;
- RUSAGE_T after;
- unsigned long realtime, cputime;
+ RUSAGE_T before;
+ RUSAGE_T after;
+ unsigned long walltime, cputime;
- GETRUSAGE(&before);
-#endif /* CONSUMED_TIME_CHECK */
+ /* cmd_execute() may change cputime_enabled if we're executing the
+ * "service cputime-stats" command, which can result in nonsensical
+ * and very confusing warnings
+ */
+ bool cputime_enabled_here = cputime_enabled;
- ret = cmd_execute(vty, buf, NULL, 0);
+ GETRUSAGE(&before);
- /* Get the name of the protocol if any */
- protocolname = frr_protoname;
+ ret = cmd_execute(vty, buf, NULL, 0);
-#ifdef CONSUMED_TIME_CHECK
- GETRUSAGE(&after);
- realtime = thread_consumed_time(&after, &before, &cputime);
- if (cputime > CONSUMED_TIME_CHECK) {
- /* Warn about CPU hog that must be fixed. */
- flog_warn(
- EC_LIB_SLOW_THREAD_CPU,
- "CPU HOG: command took %lums (cpu time %lums): %s",
- realtime / 1000, cputime / 1000, buf);
- } else if (realtime > CONSUMED_TIME_CHECK) {
- flog_warn(
- EC_LIB_SLOW_THREAD_WALL,
- "STARVATION: command took %lums (cpu time %lums): %s",
- realtime / 1000, cputime / 1000, buf);
- }
- }
-#endif /* CONSUMED_TIME_CHECK */
+ GETRUSAGE(&after);
+
+ walltime = thread_consumed_time(&after, &before, &cputime);
+
+ if (cputime_enabled_here && cputime_enabled && cputime_threshold
+ && cputime > cputime_threshold)
+ /* Warn about CPU hog that must be fixed. */
+ flog_warn(EC_LIB_SLOW_THREAD_CPU,
+ "CPU HOG: command took %lums (cpu time %lums): %s",
+ walltime / 1000, cputime / 1000, buf);
+ else if (walltime_threshold && walltime > walltime_threshold)
+ flog_warn(EC_LIB_SLOW_THREAD_WALL,
+ "STARVATION: command took %lums (cpu time %lums): %s",
+ walltime / 1000, cputime / 1000, buf);
+
+ /* Get the name of the protocol if any */
+ protocolname = frr_protoname;
if (ret != CMD_SUCCESS)
switch (ret) {
diff --git a/lib/zclient.c b/lib/zclient.c
index 4a70881b57..ffae1332af 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -2269,10 +2269,13 @@ stream_failure:
}
struct interface *zebra_interface_link_params_read(struct stream *s,
- vrf_id_t vrf_id)
+ vrf_id_t vrf_id,
+ bool *changed)
{
struct if_link_params *iflp;
+ struct if_link_params iflp_copy;
ifindex_t ifindex;
+ bool params_changed = false;
STREAM_GETL(s, ifindex);
@@ -2285,12 +2288,23 @@ struct interface *zebra_interface_link_params_read(struct stream *s,
return NULL;
}
+ if (ifp->link_params == NULL)
+ params_changed = true;
+
if ((iflp = if_link_params_get(ifp)) == NULL)
return NULL;
+ memcpy(&iflp_copy, iflp, sizeof(iflp_copy));
+
if (link_params_set_value(s, iflp) != 0)
goto stream_failure;
+ if (memcmp(&iflp_copy, iflp, sizeof(iflp_copy)))
+ params_changed = true;
+
+ if (changed)
+ *changed = params_changed;
+
return ifp;
stream_failure:
diff --git a/lib/zclient.h b/lib/zclient.h
index 48de3425be..a25c5800b7 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -1043,7 +1043,8 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s,
extern int zebra_router_id_update_read(struct stream *s, struct prefix *rid);
extern struct interface *zebra_interface_link_params_read(struct stream *s,
- vrf_id_t vrf_id);
+ vrf_id_t vrf_id,
+ bool *changed);
extern size_t zebra_interface_link_params_write(struct stream *,
struct interface *);
extern enum zclient_send_status
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index ba355a347e..d7307fe375 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -2478,7 +2478,7 @@ void ospf6_asbr_init(void)
install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);
}
-void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6)
+void ospf6_asbr_redistribute_disable(struct ospf6 *ospf6)
{
int type;
struct ospf6_redist *red;
@@ -2500,6 +2500,35 @@ void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6)
}
}
+void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6)
+{
+ int type;
+ struct ospf6_redist *red;
+ char buf[RMAP_NAME_MAXLEN];
+
+ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) {
+ buf[0] = '\0';
+ if (type == ZEBRA_ROUTE_OSPF6)
+ continue;
+ red = ospf6_redist_lookup(ospf6, type, 0);
+ if (!red)
+ continue;
+
+ if (type == DEFAULT_ROUTE) {
+ ospf6_redistribute_default_set(
+ ospf6, ospf6->default_originate);
+ continue;
+ }
+ if (ROUTEMAP_NAME(red))
+ strlcpy(buf, ROUTEMAP_NAME(red), sizeof(buf));
+
+ ospf6_asbr_redistribute_unset(ospf6, red, type);
+ if (buf[0])
+ ospf6_asbr_routemap_set(red, buf);
+ ospf6_asbr_redistribute_set(ospf6, type);
+ }
+}
+
void ospf6_asbr_terminate(void)
{
/* Cleanup route maps */
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 418c157f36..8f2135ef30 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -93,6 +93,7 @@ extern int ospf6_redistribute_config_write(struct vty *vty,
struct ospf6 *ospf6);
extern void ospf6_asbr_init(void);
+extern void ospf6_asbr_redistribute_disable(struct ospf6 *ospf6);
extern void ospf6_asbr_redistribute_reset(struct ospf6 *ospf6);
extern void ospf6_asbr_terminate(void);
extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *);
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 553967e2e3..1e75fc60f6 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -2695,7 +2695,7 @@ void ospf6_interface_init(void)
}
/* Clear the specified interface structure */
-static void ospf6_interface_clear(struct vty *vty, struct interface *ifp)
+void ospf6_interface_clear(struct interface *ifp)
{
struct ospf6_interface *oi;
@@ -2733,7 +2733,7 @@ DEFUN (clear_ipv6_ospf6_interface,
if (argc == 4) /* Clear all the ospfv3 interfaces. */
{
FOR_ALL_INTERFACES (vrf, ifp)
- ospf6_interface_clear(vty, ifp);
+ ospf6_interface_clear(ifp);
} else /* Interface name is specified. */
{
if ((ifp = if_lookup_by_name(argv[idx_ifname]->arg,
@@ -2743,7 +2743,7 @@ DEFUN (clear_ipv6_ospf6_interface,
argv[idx_ifname]->arg);
return CMD_WARNING;
}
- ospf6_interface_clear(vty, ifp);
+ ospf6_interface_clear(ifp);
}
return CMD_SUCCESS;
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index 530efc3bd2..c9cd74b691 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -213,6 +213,7 @@ extern int backup_seen(struct thread *);
extern int neighbor_change(struct thread *);
extern void ospf6_interface_init(void);
+extern void ospf6_interface_clear(struct interface *ifp);
extern void install_element_ospf6_clear_interface(void);
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index d627194252..bab5fdaae8 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -659,7 +659,7 @@ void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
adv_router);
json_object_int_add(json_obj, "lsSequenceNumber",
(unsigned long)ntohl(lsa->header->seqnum));
- json_object_int_add(json_obj, "checkSum",
+ json_object_int_add(json_obj, "checksum",
ntohs(lsa->header->checksum));
json_object_int_add(json_obj, "length",
ntohs(lsa->header->length));
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 5f23aab80a..817e5372ea 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -1709,6 +1709,13 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6)
return OSPF6_READ_CONTINUE;
}
+ /*
+ * Drop packet destined to another VRF.
+ * This happens when raw_l3mdev_accept is set to 1.
+ */
+ if (ospf6->vrf_id != oi->interface->vrf_id)
+ return OSPF6_READ_CONTINUE;
+
oh = (struct ospf6_header *)recvbuf;
if (ospf6_rxpacket_examin(oi, oh, len) != MSG_OK)
return OSPF6_READ_CONTINUE;
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 6cea5032bd..057f89797a 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -63,6 +63,10 @@ FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES,
{ .val_bool = false },
);
+#ifndef VTYSH_EXTRACT_PL
+#include "ospf6d/ospf6_top_clippy.c"
+#endif
+
/* global ospf6d variable */
static struct ospf6_master ospf6_master;
struct ospf6_master *om6;
@@ -512,7 +516,7 @@ static void ospf6_disable(struct ospf6 *o)
/* XXX: This also changes persistent settings */
/* Unregister redistribution */
- ospf6_asbr_redistribute_reset(o);
+ ospf6_asbr_redistribute_disable(o);
ospf6_lsdb_remove_all(o->lsdb);
ospf6_route_remove_all(o->route_table);
@@ -649,6 +653,78 @@ DEFUN(no_router_ospf6, no_router_ospf6_cmd, "no router ospf6 [vrf NAME]",
return CMD_SUCCESS;
}
+static void ospf6_db_clear(struct ospf6 *ospf6)
+{
+ struct ospf6_interface *oi;
+ struct interface *ifp;
+ struct vrf *vrf = vrf_lookup_by_id(ospf6->vrf_id);
+ struct listnode *node, *nnode;
+ struct ospf6_area *oa;
+
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ if (if_is_operative(ifp) && ifp->info != NULL) {
+ oi = (struct ospf6_interface *)ifp->info;
+ ospf6_lsdb_remove_all(oi->lsdb);
+ ospf6_lsdb_remove_all(oi->lsdb_self);
+ ospf6_lsdb_remove_all(oi->lsupdate_list);
+ ospf6_lsdb_remove_all(oi->lsack_list);
+ }
+ }
+
+ for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
+ ospf6_lsdb_remove_all(oa->lsdb);
+ ospf6_lsdb_remove_all(oa->lsdb_self);
+
+ ospf6_spf_table_finish(oa->spf_table);
+ ospf6_route_remove_all(oa->route_table);
+ }
+
+ ospf6_lsdb_remove_all(ospf6->lsdb);
+ ospf6_lsdb_remove_all(ospf6->lsdb_self);
+ ospf6_route_remove_all(ospf6->route_table);
+ ospf6_route_remove_all(ospf6->brouter_table);
+}
+
+static void ospf6_process_reset(struct ospf6 *ospf6)
+{
+ struct interface *ifp;
+ struct vrf *vrf = vrf_lookup_by_id(ospf6->vrf_id);
+
+ ospf6_flush_self_originated_lsas_now(ospf6);
+ ospf6->inst_shutdown = 0;
+ ospf6_db_clear(ospf6);
+
+ ospf6_router_id_update(ospf6);
+
+ ospf6_asbr_redistribute_reset(ospf6);
+ FOR_ALL_INTERFACES (vrf, ifp)
+ ospf6_interface_clear(ifp);
+}
+
+DEFPY (clear_router_ospf6,
+ clear_router_ospf6_cmd,
+ "clear ipv6 ospf6 process [vrf NAME$name]",
+ CLEAR_STR
+ IP6_STR
+ OSPF6_STR
+ "Reset OSPF Process\n"
+ VRF_CMD_HELP_STR)
+{
+ struct ospf6 *ospf6;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+
+ if (name != NULL)
+ vrf_name = name;
+
+ ospf6 = ospf6_lookup_by_vrf_name(vrf_name);
+ if (ospf6 == NULL)
+ vty_out(vty, "OSPFv3 is not configured\n");
+ else
+ ospf6_process_reset(ospf6);
+
+ return CMD_SUCCESS;
+}
+
/* change Router_ID commands. */
DEFUN(ospf6_router_id,
ospf6_router_id_cmd,
@@ -679,7 +755,7 @@ DEFUN(ospf6_router_id,
for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
if (oa->full_nbrs) {
vty_out(vty,
- "For this router-id change to take effect, save config and restart ospf6d\n");
+ "For this router-id change to take effect, run the \"clear ipv6 ospf6 process\" command\n");
return CMD_SUCCESS;
}
}
@@ -705,7 +781,7 @@ DEFUN(no_ospf6_router_id,
for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
if (oa->full_nbrs) {
vty_out(vty,
- "For this router-id change to take effect, save config and restart ospf6d\n");
+ "For this router-id change to take effect, run the \"clear ipv6 ospf6 process\" command\n");
return CMD_SUCCESS;
}
}
@@ -1708,6 +1784,11 @@ static struct cmd_node ospf6_node = {
.config_write = config_write_ospf6,
};
+void install_element_ospf6_clear_process(void)
+{
+ install_element(ENABLE_NODE, &clear_router_ospf6_cmd);
+}
+
/* Install ospf related commands. */
void ospf6_top_init(void)
{
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
index 5b739ac76b..51df4b6b8e 100644
--- a/ospf6d/ospf6_top.h
+++ b/ospf6d/ospf6_top.h
@@ -173,6 +173,7 @@ extern struct ospf6_master *om6;
/* prototypes */
extern void ospf6_master_init(struct thread_master *master);
+extern void install_element_ospf6_clear_process(void);
extern void ospf6_top_init(void);
extern void ospf6_delete(struct ospf6 *o);
extern void ospf6_router_id_update(struct ospf6 *ospf6);
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
index 65f0aa664e..fb6ac4402a 100644
--- a/ospf6d/ospf6d.c
+++ b/ospf6d/ospf6d.c
@@ -1425,6 +1425,7 @@ void ospf6_init(struct thread_master *master)
install_element_ospf6_debug_flood();
install_element_ospf6_debug_nssa();
+ install_element_ospf6_clear_process();
install_element_ospf6_clear_interface();
install_element(ENABLE_NODE, &show_debugging_ospf6_cmd);
diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am
index 2e1891be71..2b7bce5392 100644
--- a/ospf6d/subdir.am
+++ b/ospf6d/subdir.am
@@ -88,6 +88,7 @@ ospf6d_ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la
clippy_scan += \
+ ospf6d/ospf6_top.c \
ospf6d/ospf6_asbr.c \
# end
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index b4e318d1d1..b3aba247df 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -50,6 +50,7 @@
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_ldp_sync.h"
#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_te.h"
DEFINE_QOBJ_TYPE(ospf_interface);
DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd));
@@ -1354,6 +1355,9 @@ static int ospf_ifp_create(struct interface *ifp)
ospf_if_update(ospf, ifp);
+ if (HAS_LINK_PARAMS(ifp))
+ ospf_mpls_te_update_if(ifp);
+
hook_call(ospf_if_update, ifp);
return 0;
@@ -1392,6 +1396,9 @@ static int ospf_ifp_up(struct interface *ifp)
ospf_if_up(oi);
}
+ if (HAS_LINK_PARAMS(ifp))
+ ospf_mpls_te_update_if(ifp);
+
return 0;
}
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 5853b506f8..df112edc68 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -163,10 +163,11 @@ static int ospf_interface_address_delete(ZAPI_CALLBACK_ARGS)
static int ospf_interface_link_params(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
+ bool changed = false;
- ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id);
+ ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id, &changed);
- if (ifp == NULL)
+ if (ifp == NULL || !changed)
return 0;
/* Update TE TLV */
diff --git a/pathd/pathd.c b/pathd/pathd.c
index 022813a497..90b8727284 100644
--- a/pathd/pathd.c
+++ b/pathd/pathd.c
@@ -666,7 +666,7 @@ struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
candidate->preference = preference;
candidate->policy = policy;
candidate->type = SRTE_CANDIDATE_TYPE_UNDEFINED;
- candidate->discriminator = rand();
+ candidate->discriminator = frr_weak_random();
candidate->protocol_origin = origin;
if (originator != NULL) {
strlcpy(candidate->originator, originator,
diff --git a/python/xrelfo.py b/python/xrelfo.py
index 0ecd008579..17262da8d9 100644
--- a/python/xrelfo.py
+++ b/python/xrelfo.py
@@ -357,6 +357,7 @@ def main():
argp.add_argument('--out-by-file', type=str, help='write by-file JSON output')
argp.add_argument('-Wlog-format', action='store_const', const=True)
argp.add_argument('-Wlog-args', action='store_const', const=True)
+ argp.add_argument('-Werror', action='store_const', const=True)
argp.add_argument('--profile', action='store_const', const=True)
argp.add_argument('binaries', metavar='BINARY', nargs='+', type=str, help='files to read (ELF files or libtool objects)')
args = argp.parse_args()
@@ -380,9 +381,12 @@ def _main(args):
traceback.print_exc()
for option in dir(args):
- if option.startswith('W'):
+ if option.startswith('W') and option != 'Werror':
checks = sorted(xrelfo.check(args))
sys.stderr.write(''.join([c[-1] for c in checks]))
+
+ if args.Werror and len(checks) > 0:
+ errors += 1
break
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/__init__.py b/tests/topotests/bgp_default_afi_safi/__init__.py
index e69de29bb2..e69de29bb2 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/__init__.py
+++ b/tests/topotests/bgp_default_afi_safi/__init__.py
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/bgpd.conf b/tests/topotests/bgp_default_afi_safi/r1/bgpd.conf
index bf39152ea8..bf39152ea8 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/bgpd.conf
+++ b/tests/topotests/bgp_default_afi_safi/r1/bgpd.conf
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/zebra.conf b/tests/topotests/bgp_default_afi_safi/r1/zebra.conf
index 697765168d..697765168d 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/zebra.conf
+++ b/tests/topotests/bgp_default_afi_safi/r1/zebra.conf
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/bgpd.conf b/tests/topotests/bgp_default_afi_safi/r2/bgpd.conf
index abbd1b86fa..abbd1b86fa 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/bgpd.conf
+++ b/tests/topotests/bgp_default_afi_safi/r2/bgpd.conf
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/zebra.conf b/tests/topotests/bgp_default_afi_safi/r2/zebra.conf
index 606c17bec9..606c17bec9 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/zebra.conf
+++ b/tests/topotests/bgp_default_afi_safi/r2/zebra.conf
diff --git a/tests/topotests/bgp_default_afi_safi/r3/bgpd.conf b/tests/topotests/bgp_default_afi_safi/r3/bgpd.conf
new file mode 100644
index 0000000000..f3ec3f06c5
--- /dev/null
+++ b/tests/topotests/bgp_default_afi_safi/r3/bgpd.conf
@@ -0,0 +1,5 @@
+!
+router bgp 65001
+ no bgp default ipv4-unicast
+ bgp default l2vpn-evpn
+!
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/zebra.conf b/tests/topotests/bgp_default_afi_safi/r3/zebra.conf
index e9fdfb70c5..e9fdfb70c5 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/zebra.conf
+++ b/tests/topotests/bgp_default_afi_safi/r3/zebra.conf
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/bgpd.conf b/tests/topotests/bgp_default_afi_safi/r4/bgpd.conf
index a405c047ca..8a6af55ee7 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/bgpd.conf
+++ b/tests/topotests/bgp_default_afi_safi/r4/bgpd.conf
@@ -1,4 +1,5 @@
!
router bgp 65001
bgp default ipv6-unicast
+ bgp default l2vpn-evpn
!
diff --git a/tests/topotests/bgp_default_afi_safi/r4/zebra.conf b/tests/topotests/bgp_default_afi_safi/r4/zebra.conf
new file mode 100644
index 0000000000..e9fdfb70c5
--- /dev/null
+++ b/tests/topotests/bgp_default_afi_safi/r4/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r3-eth0
+ ip address 192.168.255.3/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/test_bgp-default-ipv4-ipv6-unicast.py b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py
index f9aa94fd14..28117b7fe4 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/test_bgp-default-ipv4-ipv6-unicast.py
+++ b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py
@@ -20,12 +20,13 @@
#
"""
-Test if `bgp default ipv4-unicast` and `bgp default ipv6-unicast`
-commands work as expected.
+Test if `bgp default ipv4-unicast`, `bgp default ipv6-unicast`
+and `bgp default l2vpn-evpn` commands work as expected.
STEP 1: 'Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only'
STEP 2: 'Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only'
-STEP 3: 'Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families'
+STEP 3: 'Check if neighbor 192.168.255.254 is enabled for l2vpn evpn address-family only'
+STEP 4: 'Check if neighbor 192.168.255.254 is enabled for ipv4/ipv6 unicast and l2vpn evpn address-families'
"""
import os
@@ -98,7 +99,7 @@ def test_bgp_default_ipv4_ipv6_unicast():
output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp summary json"))
- if "ipv4Unicast" in output and "ipv6Unicast" not in output:
+ if len(output.keys()) == 1 and "ipv4Unicast" in output:
return True
return False
@@ -113,28 +114,48 @@ def test_bgp_default_ipv4_ipv6_unicast():
output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp summary json"))
- if "ipv4Unicast" not in output and "ipv6Unicast" in output:
+ if len(output.keys()) == 1 and "ipv6Unicast" in output:
return True
return False
assert _bgp_neighbor_ipv6_af_only() == True
- step(
- "Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families"
- )
+ step("Check if neighbor 192.168.255.254 is enabled for evpn address-family only")
- def _bgp_neighbor_ipv4_and_ipv6_af():
+ def _bgp_neighbor_evpn_af_only():
tgen.gears["r3"].vtysh_cmd(
"conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
)
output = json.loads(tgen.gears["r3"].vtysh_cmd("show bgp summary json"))
- if "ipv4Unicast" in output and "ipv6Unicast" in output:
+ if len(output.keys()) == 1 and "l2VpnEvpn" in output:
+ return True
+ return False
+
+ assert _bgp_neighbor_evpn_af_only() == True
+
+ step(
+ "Check if neighbor 192.168.255.254 is enabled for ipv4/ipv6 unicast and evpn address-families"
+ )
+
+ def _bgp_neighbor_ipv4_ipv6_and_evpn_af():
+ tgen.gears["r4"].vtysh_cmd(
+ "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+ )
+
+ output = json.loads(tgen.gears["r4"].vtysh_cmd("show bgp summary json"))
+
+ if (
+ len(output.keys()) == 3
+ and "ipv4Unicast" in output
+ and "ipv6Unicast" in output
+ and "l2VpnEvpn" in output
+ ):
return True
return False
- assert _bgp_neighbor_ipv4_and_ipv6_af() == True
+ assert _bgp_neighbor_ipv4_ipv6_and_evpn_af() == True
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_route_map/test_route_map_topo1.py b/tests/topotests/bgp_route_map/test_route_map_topo1.py
index 0158e24d31..74172501db 100644
--- a/tests/topotests/bgp_route_map/test_route_map_topo1.py
+++ b/tests/topotests/bgp_route_map/test_route_map_topo1.py
@@ -20,47 +20,6 @@
# OF THIS SOFTWARE.
#
-#################################
-# TOPOLOGY
-#################################
-"""
-
- +-------+
- +------- | R2 |
- | +-------+
- | |
- +-------+ |
- | R1 | |
- +-------+ |
- | |
- | +-------+ +-------+
- +---------- | R3 |----------| R4 |
- +-------+ +-------+
-
-"""
-
-#################################
-# TEST SUMMARY
-#################################
-"""
-Following tests are covered to test route-map functionality:
-TC_34:
- Verify if route-maps is applied in both inbound and
- outbound direction to same neighbor/interface.
-TC_36:
- Test permit/deny statements operation in route-maps with a
- permutation and combination of permit/deny in prefix-lists
-TC_35:
- Test multiple sequence numbers in a single route-map for different
- match/set clauses.
-TC_37:
- Test add/remove route-maps with multiple set
- clauses and without any match statement.(Set only)
-TC_38:
- Test add/remove route-maps with multiple match
- clauses and without any set statement.(Match only)
-"""
-
import sys
import json
import time
@@ -91,6 +50,7 @@ from lib.common_config import (
create_bgp_community_lists,
interface_status,
create_route_maps,
+ create_static_routes,
create_prefix_lists,
verify_route_maps,
check_address_types,
@@ -107,6 +67,46 @@ from lib.bgp import (
)
from lib.topojson import build_topo_from_json, build_config_from_json
+#################################
+# TOPOLOGY
+#################################
+"""
+
+ +-------+
+ +------- | R2 |
+ | +-------+
+ | |
+ +-------+ |
+ | R1 | |
+ +-------+ |
+ | |
+ | +-------+ +-------+
+ +---------- | R3 |----------| R4 |
+ +-------+ +-------+
+
+"""
+
+#################################
+# TEST SUMMARY
+#################################
+"""
+Following tests are covered to test route-map functionality:
+TC_34:
+ Verify if route-maps is applied in both inbound and
+ outbound direction to same neighbor/interface.
+TC_36:
+ Test permit/deny statements operation in route-maps with a
+ permutation and combination of permit/deny in prefix-lists
+TC_35:
+ Test multiple sequence numbers in a single route-map for different
+ match/set clauses.
+TC_37:
+ Test add/remove route-maps with multiple set
+ clauses and without any match statement.(Set only)
+TC_38:
+ Test add/remove route-maps with multiple match
+ clauses and without any set statement.(Match only)
+"""
# Global variables
bgp_convergence = False
@@ -475,8 +475,8 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request):
result = verify_rib(
tgen, adt, dut, input_dict_2, protocol=protocol, expected=False
)
- assert result is not True, "Testcase {} : Failed \n"
- "routes are not present in rib \n Error: {}".format(tc_name, result)
+ assert result is not True, ("Testcase {} : Failed \n"
+ "routes are not present in rib \n Error: {}".format(tc_name, result))
logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
@@ -495,8 +495,8 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request):
result = verify_rib(
tgen, adt, dut, input_dict, protocol=protocol, expected=False
)
- assert result is not True, "Testcase {} : Failed \n "
- "routes are not present in rib \n Error: {}".format(tc_name, result)
+ assert result is not True, ("Testcase {} : Failed \n "
+ "routes are not present in rib \n Error: {}".format(tc_name, result))
logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
@@ -687,14 +687,17 @@ def test_route_map_with_action_values_combination_of_prefix_action_p0(
}
# tgen.mininet_cli()
- result = verify_rib(
- tgen, adt, dut, input_dict_2, protocol=protocol, expected=False
- )
if "deny" in [prefix_action, rmap_action]:
- assert result is not True, "Testcase {} : Failed \n "
- "Routes are still present \n Error: {}".format(tc_name, result)
+ result = verify_rib(
+ tgen, adt, dut, input_dict_2, protocol=protocol, expected=False
+ )
+ assert result is not True, ("Testcase {} : Failed \n "
+ "Routes are still present \n Error: {}".format(tc_name, result))
logger.info("Expected behaviour: {}".format(result))
else:
+ result = verify_rib(
+ tgen, adt, dut, input_dict_2, protocol=protocol
+ )
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 41b7bc8a10..507c6ce882 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -2851,7 +2851,6 @@ DEFUN (vtysh_show_poll,
return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n");
}
-#ifndef EXCLUDE_CPU_TIME
DEFUN (vtysh_show_thread,
vtysh_show_thread_cmd,
"show thread cpu [FILTER]",
@@ -2862,7 +2861,6 @@ DEFUN (vtysh_show_thread,
{
return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n");
}
-#endif
DEFUN (vtysh_show_work_queues,
vtysh_show_work_queues_cmd,
@@ -4567,9 +4565,7 @@ void vtysh_init_vty(void)
install_element(VIEW_NODE, &vtysh_show_modules_cmd);
install_element(VIEW_NODE, &vtysh_show_work_queues_cmd);
install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd);
-#ifndef EXCLUDE_CPU_TIME
install_element(VIEW_NODE, &vtysh_show_thread_cmd);
-#endif
install_element(VIEW_NODE, &vtysh_show_poll_cmd);
/* Logging */
diff --git a/zebra/main.c b/zebra/main.c
index e36af51005..bded50149f 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -186,7 +186,6 @@ static void sigint(void)
work_queue_free_and_null(&zrouter.lsp_process_q);
vrf_terminate();
- rtadv_terminate();
ns_walk_func(zebra_ns_early_shutdown, NULL, NULL);
zebra_ns_notify_close();
diff --git a/zebra/rib.h b/zebra/rib.h
index 957f38602a..b7ffb9ce8d 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -288,16 +288,30 @@ DECLARE_LIST(re_list, struct route_entry, next);
#define RNODE_NEXT_RE(rn, re) RE_DEST_NEXT_ROUTE(rib_dest_from_rnode(rn), re)
#if defined(HAVE_RTADV)
+PREDECL_SORTLIST_UNIQ(adv_if_list);
/* Structure which hold status of router advertisement. */
struct rtadv {
int sock;
- int adv_if_count;
- int adv_msec_if_count;
+ struct adv_if_list_head adv_if;
+ struct adv_if_list_head adv_msec_if;
struct thread *ra_read;
struct thread *ra_timer;
};
+
+/* adv list node */
+struct adv_if {
+ char name[INTERFACE_NAMSIZ];
+ struct adv_if_list_item list_item;
+};
+
+static int adv_if_cmp(const struct adv_if *a, const struct adv_if *b)
+{
+ return if_cmp_name_func(a->name, b->name);
+}
+
+DECLARE_SORTLIST_UNIQ(adv_if_list, struct adv_if, list_item, adv_if_cmp);
#endif /* HAVE_RTADV */
/*
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 1e06b3e0e9..8cb0223a46 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -54,6 +54,7 @@ extern struct zebra_privs_t zserv_privs;
#endif
DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix");
+DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface");
#ifdef OPEN_BSD
#include <netinet/icmp6.h>
@@ -92,11 +93,13 @@ static void rtadv_event(struct zebra_vrf *, enum rtadv_event, int);
static int if_join_all_router(int, struct interface *);
static int if_leave_all_router(int, struct interface *);
-static int rtadv_get_socket(struct zebra_vrf *zvrf)
+static struct zebra_vrf *rtadv_interface_get_zvrf(const struct interface *ifp)
{
- if (zvrf->rtadv.sock > 0)
- return zvrf->rtadv.sock;
- return zrouter.rtadv_sock;
+ /* We use the default vrf for rtadv handling except in netns */
+ if (!vrf_is_backend_netns())
+ return vrf_info_lookup(VRF_DEFAULT);
+
+ return vrf_info_lookup(ifp->vrf_id);
}
static int rtadv_increment_received(struct zebra_vrf *zvrf, ifindex_t *ifindex)
@@ -480,7 +483,7 @@ static int rtadv_timer(struct thread *thread)
int period;
zvrf->rtadv.ra_timer = NULL;
- if (zvrf->rtadv.adv_msec_if_count == 0) {
+ if (adv_if_list_count(&zvrf->rtadv.adv_msec_if) == 0) {
period = 1000; /* 1 s */
rtadv_event(zvrf, RTADV_TIMER, 1 /* 1 s */);
} else {
@@ -520,8 +523,8 @@ static int rtadv_timer(struct thread *thread)
ifp->ifindex);
}
- rtadv_send_packet(rtadv_get_socket(zvrf),
- ifp, RA_ENABLE);
+ rtadv_send_packet(zvrf->rtadv.sock, ifp,
+ RA_ENABLE);
} else {
zif->rtadv.AdvIntervalTimer -= period;
if (zif->rtadv.AdvIntervalTimer <= 0) {
@@ -534,8 +537,8 @@ static int rtadv_timer(struct thread *thread)
zif->rtadv
.MaxRtrAdvInterval;
rtadv_send_packet(
- rtadv_get_socket(zvrf),
- ifp, RA_ENABLE);
+ zvrf->rtadv.sock, ifp,
+ RA_ENABLE);
}
}
}
@@ -546,9 +549,10 @@ static int rtadv_timer(struct thread *thread)
static void rtadv_process_solicit(struct interface *ifp)
{
- struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
+ struct zebra_vrf *zvrf;
struct zebra_if *zif;
+ zvrf = rtadv_interface_get_zvrf(ifp);
assert(zvrf);
zif = ifp->info;
@@ -565,7 +569,7 @@ static void rtadv_process_solicit(struct interface *ifp)
if ((zif->rtadv.UseFastRexmit)
|| (zif->rtadv.AdvIntervalTimer <=
(zif->rtadv.MaxRtrAdvInterval - MIN_DELAY_BETWEEN_RAS))) {
- rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_ENABLE);
+ rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_ENABLE);
zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
} else
zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS;
@@ -788,7 +792,7 @@ static int rtadv_read(struct thread *thread)
zvrf->rtadv.ra_read = NULL;
/* Register myself. */
- rtadv_event(zvrf, RTADV_READ, sock);
+ rtadv_event(zvrf, RTADV_READ, 0);
len = rtadv_recv_packet(zvrf, sock, buf, sizeof(buf), &from, &ifindex,
&hoplimit);
@@ -862,6 +866,201 @@ static int rtadv_make_socket(ns_id_t ns_id)
return sock;
}
+static struct adv_if *adv_if_new(const char *name)
+{
+ struct adv_if *new;
+
+ new = XCALLOC(MTYPE_ADV_IF, sizeof(struct adv_if));
+
+ strlcpy(new->name, name, sizeof(new->name));
+
+ return new;
+}
+
+static void adv_if_free(struct adv_if *adv_if)
+{
+ XFREE(MTYPE_ADV_IF, adv_if);
+}
+
+static bool adv_if_is_empty_internal(const struct adv_if_list_head *adv_if_head)
+{
+ return adv_if_list_count(adv_if_head) ? false : true;
+}
+
+static struct adv_if *adv_if_add_internal(struct adv_if_list_head *adv_if_head,
+ const char *name)
+{
+ struct adv_if adv_if_lookup = {};
+ struct adv_if *adv_if = NULL;
+
+ strlcpy(adv_if_lookup.name, name, sizeof(adv_if_lookup.name));
+ adv_if = adv_if_list_find(adv_if_head, &adv_if_lookup);
+
+ if (adv_if != NULL)
+ return adv_if;
+
+ adv_if = adv_if_new(adv_if_lookup.name);
+ adv_if_list_add(adv_if_head, adv_if);
+
+ return NULL;
+}
+
+static struct adv_if *adv_if_del_internal(struct adv_if_list_head *adv_if_head,
+ const char *name)
+{
+ struct adv_if adv_if_lookup = {};
+ struct adv_if *adv_if = NULL;
+
+ strlcpy(adv_if_lookup.name, name, sizeof(adv_if_lookup.name));
+ adv_if = adv_if_list_find(adv_if_head, &adv_if_lookup);
+
+ if (adv_if == NULL)
+ return NULL;
+
+ adv_if_list_del(adv_if_head, adv_if);
+
+ return adv_if;
+}
+
+static void adv_if_clean_internal(struct adv_if_list_head *adv_if_head)
+{
+ struct adv_if *node = NULL;
+
+ if (!adv_if_is_empty_internal(adv_if_head)) {
+ frr_each_safe (adv_if_list, adv_if_head, node) {
+ adv_if_list_del(adv_if_head, node);
+ adv_if_free(node);
+ }
+ }
+
+ adv_if_list_fini(adv_if_head);
+}
+
+
+/*
+ * Add to list. On Success, return NULL, otherwise return already existing
+ * adv_if.
+ */
+static struct adv_if *adv_if_add(struct zebra_vrf *zvrf, const char *name)
+{
+ struct adv_if *adv_if = NULL;
+
+ adv_if = adv_if_add_internal(&zvrf->rtadv.adv_if, name);
+
+ if (adv_if != NULL)
+ return adv_if;
+
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
+ adv_if_list_count(&zvrf->rtadv.adv_if));
+ }
+
+ return NULL;
+}
+
+/*
+ * Del from list. On Success, return the adv_if, otherwise return NULL. Caller
+ * frees.
+ */
+static struct adv_if *adv_if_del(struct zebra_vrf *zvrf, const char *name)
+{
+ struct adv_if *adv_if = NULL;
+
+ adv_if = adv_if_del_internal(&zvrf->rtadv.adv_if, name);
+
+ if (adv_if == NULL)
+ return NULL;
+
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
+ adv_if_list_count(&zvrf->rtadv.adv_if));
+ }
+
+ return adv_if;
+}
+
+/*
+ * Add to list. On Success, return NULL, otherwise return already existing
+ * adv_if.
+ */
+static struct adv_if *adv_msec_if_add(struct zebra_vrf *zvrf, const char *name)
+{
+ struct adv_if *adv_if = NULL;
+
+ adv_if = adv_if_add_internal(&zvrf->rtadv.adv_msec_if, name);
+
+ if (adv_if != NULL)
+ return adv_if;
+
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
+ adv_if_list_count(&zvrf->rtadv.adv_msec_if));
+ }
+
+ return NULL;
+}
+
+/*
+ * Del from list. On Success, return the adv_if, otherwise return NULL. Caller
+ * frees.
+ */
+static struct adv_if *adv_msec_if_del(struct zebra_vrf *zvrf, const char *name)
+{
+ struct adv_if *adv_if = NULL;
+
+ adv_if = adv_if_del_internal(&zvrf->rtadv.adv_msec_if, name);
+
+ if (adv_if == NULL)
+ return NULL;
+
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
+ VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
+ adv_if_list_count(&zvrf->rtadv.adv_msec_if));
+ }
+
+ return adv_if;
+}
+
+/* Clean adv_if list, called on vrf terminate */
+static void adv_if_clean(struct zebra_vrf *zvrf)
+{
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s: %s:%u count: %zu -> 0", __func__,
+ VRF_LOGNAME(vrf), zvrf_id(zvrf),
+ adv_if_list_count(&zvrf->rtadv.adv_if));
+ }
+
+ adv_if_clean_internal(&zvrf->rtadv.adv_if);
+}
+
+/* Clean adv_msec_if list, called on vrf terminate */
+static void adv_msec_if_clean(struct zebra_vrf *zvrf)
+{
+ if (IS_ZEBRA_DEBUG_EVENT) {
+ struct vrf *vrf = zvrf->vrf;
+
+ zlog_debug("%s: %s:%u count: %zu -> 0", __func__,
+ VRF_LOGNAME(vrf), zvrf_id(zvrf),
+ adv_if_list_count(&zvrf->rtadv.adv_msec_if));
+ }
+
+ adv_if_clean_internal(&zvrf->rtadv.adv_msec_if);
+}
+
static struct rtadv_prefix *rtadv_prefix_new(void)
{
return XCALLOC(MTYPE_RTADV_PREFIX, sizeof(struct rtadv_prefix));
@@ -1006,30 +1205,34 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp,
{
struct zebra_if *zif;
struct zebra_vrf *zvrf;
+ struct adv_if *adv_if = NULL;
zif = ifp->info;
- zvrf = vrf_info_lookup(ifp->vrf_id);
+
+ zvrf = rtadv_interface_get_zvrf(ifp);
if (status == RA_SUPPRESS) {
/* RA is currently enabled */
if (zif->rtadv.AdvSendAdvertisements) {
- rtadv_send_packet(rtadv_get_socket(zvrf), ifp,
- RA_SUPPRESS);
+ rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_SUPPRESS);
zif->rtadv.AdvSendAdvertisements = 0;
zif->rtadv.AdvIntervalTimer = 0;
- zvrf->rtadv.adv_if_count--;
- if_leave_all_router(rtadv_get_socket(zvrf), ifp);
+ adv_if = adv_if_del(zvrf, ifp->name);
+ if (adv_if == NULL)
+ return; /* Nothing to delete */
+
+ adv_if_free(adv_if);
+
+ if_leave_all_router(zvrf->rtadv.sock, ifp);
- if (zvrf->rtadv.adv_if_count == 0)
+ if (adv_if_list_count(&zvrf->rtadv.adv_if) == 0)
rtadv_event(zvrf, RTADV_STOP, 0);
}
} else {
if (!zif->rtadv.AdvSendAdvertisements) {
zif->rtadv.AdvSendAdvertisements = 1;
zif->rtadv.AdvIntervalTimer = 0;
- zvrf->rtadv.adv_if_count++;
-
if ((zif->rtadv.MaxRtrAdvInterval >= 1000)
&& zif->rtadv.UseFastRexmit) {
/*
@@ -1041,11 +1244,14 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp,
RTADV_NUM_FAST_REXMITS;
}
- if_join_all_router(rtadv_get_socket(zvrf), ifp);
+ adv_if = adv_if_add(zvrf, ifp->name);
+ if (adv_if != NULL)
+ return; /* Alread added */
+
+ if_join_all_router(zvrf->rtadv.sock, ifp);
- if (zvrf->rtadv.adv_if_count == 1)
- rtadv_event(zvrf, RTADV_START,
- rtadv_get_socket(zvrf));
+ if (adv_if_list_count(&zvrf->rtadv.adv_if) == 1)
+ rtadv_event(zvrf, RTADV_START, 0);
}
}
}
@@ -1092,7 +1298,7 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
zebra_route_string(client->proto));
return;
}
- if (ifp->vrf_id != zvrf_id(zvrf)) {
+ if (vrf_is_backend_netns() && ifp->vrf_id != zvrf_id(zvrf)) {
struct vrf *vrf = zvrf->vrf;
zlog_debug(
@@ -1136,10 +1342,10 @@ void rtadv_stop_ra(struct interface *ifp)
struct zebra_vrf *zvrf;
zif = ifp->info;
- zvrf = vrf_info_lookup(ifp->vrf_id);
+ zvrf = rtadv_interface_get_zvrf(ifp);
if (zif->rtadv.AdvSendAdvertisements)
- rtadv_send_packet(rtadv_get_socket(zvrf), ifp, RA_SUPPRESS);
+ rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_SUPPRESS);
}
/*
@@ -1179,6 +1385,76 @@ void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS)
zebra_interface_radv_set(client, hdr, msg, zvrf, 1);
}
+static void show_zvrf_rtadv_adv_if_helper(struct vty *vty,
+ struct adv_if_list_head *adv_if_head)
+{
+ struct adv_if *node = NULL;
+
+ if (!adv_if_is_empty_internal(adv_if_head)) {
+ frr_each (adv_if_list, adv_if_head, node) {
+ vty_out(vty, " %s\n", node->name);
+ }
+ }
+
+ vty_out(vty, "\n");
+}
+
+static void show_zvrf_rtadv_helper(struct vty *vty, struct zebra_vrf *zvrf)
+{
+ vty_out(vty, "VRF: %s\n", zvrf_name(zvrf));
+ vty_out(vty, " Interfaces:\n");
+ show_zvrf_rtadv_adv_if_helper(vty, &zvrf->rtadv.adv_if);
+
+ vty_out(vty, " Interfaces(msec):\n");
+ show_zvrf_rtadv_adv_if_helper(vty, &zvrf->rtadv.adv_msec_if);
+}
+
+DEFPY(show_ipv6_nd_ra_if, show_ipv6_nd_ra_if_cmd,
+ "show ipv6 nd ra-interfaces [vrf<NAME$vrf_name|all$vrf_all>]",
+ SHOW_STR IP6_STR
+ "Neighbor discovery\n"
+ "Route Advertisement Interfaces\n" VRF_FULL_CMD_HELP_STR)
+{
+ struct zebra_vrf *zvrf = NULL;
+
+ if (!vrf_is_backend_netns() && (vrf_name || vrf_all)) {
+ vty_out(vty,
+ "%% VRF subcommand only applicable for netns-based vrfs.\n");
+ return CMD_WARNING;
+ }
+
+ if (vrf_all) {
+ struct vrf *vrf;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf->info;
+ if (!zvrf)
+ continue;
+
+ show_zvrf_rtadv_helper(vty, zvrf);
+ }
+
+ return CMD_SUCCESS;
+ }
+
+ if (vrf_name)
+ zvrf = zebra_vrf_lookup_by_name(vrf_name);
+ else
+ zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
+
+ if (!zvrf) {
+ vty_out(vty, "%% VRF '%s' specified does not exist\n",
+ vrf_name);
+ return CMD_WARNING;
+ }
+
+ show_zvrf_rtadv_helper(vty, zvrf);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (ipv6_nd_ra_fast_retrans,
ipv6_nd_ra_fast_retrans_cmd,
"ipv6 nd ra-fast-retrans",
@@ -1379,8 +1655,9 @@ DEFUN (ipv6_nd_ra_interval_msec,
unsigned interval;
struct zebra_if *zif = ifp->info;
struct zebra_vrf *zvrf;
+ struct adv_if *adv_if;
- zvrf = vrf_info_lookup(ifp->vrf_id);
+ zvrf = rtadv_interface_get_zvrf(ifp);
interval = strtoul(argv[idx_number]->arg, NULL, 10);
if ((zif->rtadv.AdvDefaultLifetime != -1
@@ -1390,11 +1667,14 @@ DEFUN (ipv6_nd_ra_interval_msec,
return CMD_WARNING_CONFIG_FAILED;
}
- if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zvrf->rtadv.adv_msec_if_count--;
+ if (zif->rtadv.MaxRtrAdvInterval % 1000) {
+ adv_if = adv_msec_if_del(zvrf, ifp->name);
+ if (adv_if != NULL)
+ adv_if_free(adv_if);
+ }
if (interval % 1000)
- zvrf->rtadv.adv_msec_if_count++;
+ (void)adv_msec_if_add(zvrf, ifp->name);
SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
zif->rtadv.MaxRtrAdvInterval = interval;
@@ -1417,8 +1697,9 @@ DEFUN (ipv6_nd_ra_interval,
unsigned interval;
struct zebra_if *zif = ifp->info;
struct zebra_vrf *zvrf;
+ struct adv_if *adv_if;
- zvrf = vrf_info_lookup(ifp->vrf_id);
+ zvrf = rtadv_interface_get_zvrf(ifp);
interval = strtoul(argv[idx_number]->arg, NULL, 10);
if ((zif->rtadv.AdvDefaultLifetime != -1
@@ -1428,8 +1709,11 @@ DEFUN (ipv6_nd_ra_interval,
return CMD_WARNING_CONFIG_FAILED;
}
- if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zvrf->rtadv.adv_msec_if_count--;
+ if (zif->rtadv.MaxRtrAdvInterval % 1000) {
+ adv_if = adv_msec_if_del(zvrf, ifp->name);
+ if (adv_if != NULL)
+ adv_if_free(adv_if);
+ }
/* convert to milliseconds */
interval = interval * 1000;
@@ -1456,11 +1740,15 @@ DEFUN (no_ipv6_nd_ra_interval,
VTY_DECLVAR_CONTEXT(interface, ifp);
struct zebra_if *zif = ifp->info;
struct zebra_vrf *zvrf = NULL;
+ struct adv_if *adv_if;
- zvrf = vrf_info_lookup(ifp->vrf_id);
+ zvrf = rtadv_interface_get_zvrf(ifp);
- if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zvrf->rtadv.adv_msec_if_count--;
+ if (zif->rtadv.MaxRtrAdvInterval % 1000) {
+ adv_if = adv_msec_if_del(zvrf, ifp->name);
+ if (adv_if != NULL)
+ adv_if_free(adv_if);
+ }
UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
@@ -2451,7 +2739,7 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
{
- struct rtadv *rtadv = &zvrf->rtadv;
+ struct rtadv *rtadv;
if (IS_ZEBRA_DEBUG_EVENT) {
struct vrf *vrf = zvrf->vrf;
@@ -2460,9 +2748,11 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
VRF_LOGNAME(vrf), event, val);
}
+ rtadv = &zvrf->rtadv;
+
switch (event) {
case RTADV_START:
- thread_add_read(zrouter.master, rtadv_read, zvrf, val,
+ thread_add_read(zrouter.master, rtadv_read, zvrf, rtadv->sock,
&rtadv->ra_read);
thread_add_event(zrouter.master, rtadv_timer, zvrf, 0,
&rtadv->ra_timer);
@@ -2480,7 +2770,7 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
&rtadv->ra_timer);
break;
case RTADV_READ:
- thread_add_read(zrouter.master, rtadv_read, zvrf, val,
+ thread_add_read(zrouter.master, rtadv_read, zvrf, rtadv->sock,
&rtadv->ra_read);
break;
default:
@@ -2489,37 +2779,27 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
return;
}
-void rtadv_init(struct zebra_vrf *zvrf)
+void rtadv_vrf_init(struct zebra_vrf *zvrf)
{
- if (vrf_is_backend_netns()) {
- zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id);
- zrouter.rtadv_sock = -1;
- } else {
- zvrf->rtadv.sock = -1;
- if (zrouter.rtadv_sock < 0)
- zrouter.rtadv_sock =
- rtadv_make_socket(zvrf->zns->ns_id);
- }
+ if (!vrf_is_backend_netns() && (zvrf_id(zvrf) != VRF_DEFAULT))
+ return;
+
+ zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id);
}
void rtadv_vrf_terminate(struct zebra_vrf *zvrf)
{
+ if (!vrf_is_backend_netns() && (zvrf_id(zvrf) != VRF_DEFAULT))
+ return;
+
rtadv_event(zvrf, RTADV_STOP, 0);
if (zvrf->rtadv.sock >= 0) {
close(zvrf->rtadv.sock);
zvrf->rtadv.sock = -1;
}
- zvrf->rtadv.adv_if_count = 0;
- zvrf->rtadv.adv_msec_if_count = 0;
-}
-
-void rtadv_terminate(void)
-{
- if (zrouter.rtadv_sock >= 0) {
- close(zrouter.rtadv_sock);
- zrouter.rtadv_sock = -1;
- }
+ adv_if_clean(zvrf);
+ adv_msec_if_clean(zvrf);
}
void rtadv_cmd_init(void)
@@ -2527,6 +2807,8 @@ void rtadv_cmd_init(void)
hook_register(zebra_if_extra_info, nd_dump_vty);
hook_register(zebra_if_config_wr, rtadv_config_write);
+ install_element(VIEW_NODE, &show_ipv6_nd_ra_if_cmd);
+
install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd);
install_element(INTERFACE_NODE, &no_ipv6_nd_ra_fast_retrans_cmd);
install_element(INTERFACE_NODE, &ipv6_nd_ra_retrans_interval_cmd);
@@ -2629,14 +2911,11 @@ static int if_leave_all_router(int sock, struct interface *ifp)
}
#else
-void rtadv_init(struct zebra_vrf *zvrf)
-{
- /* Empty.*/;
-}
-void rtadv_terminate(void)
+void rtadv_vrf_init(struct zebra_vrf *zvrf)
{
/* Empty.*/;
}
+
void rtadv_cmd_init(void)
{
/* Empty.*/;
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index d7a1ccfb29..7b71ee45a2 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -152,9 +152,8 @@ enum ipv6_nd_suppress_ra_status {
RA_SUPPRESS,
};
-extern void rtadv_init(struct zebra_vrf *zvrf);
+extern void rtadv_vrf_init(struct zebra_vrf *zvrf);
extern void rtadv_vrf_terminate(struct zebra_vrf *zvrf);
-extern void rtadv_terminate(void);
extern void rtadv_stop_ra(struct interface *ifp);
extern void rtadv_stop_ra_all(void);
extern void rtadv_cmd_init(void);
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index 5a00f3155d..d930f59866 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -268,8 +268,6 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack)
zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS;
- zrouter.rtadv_sock = -1;
-
zebra_vxlan_init();
zebra_mlag_init();
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index 08c5fcaf8d..408f9cbee5 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -162,9 +162,6 @@ struct zebra_router {
struct hash *iptable_hash;
- /* used if vrf backend is not network namespace */
- int rtadv_sock;
-
/* A sequence number used for tracking routes */
_Atomic uint32_t sequence_num;
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index a0c63e4202..2430b51989 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -131,7 +131,7 @@ static int zebra_vrf_enable(struct vrf *vrf)
else
zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
#if defined(HAVE_RTADV)
- rtadv_init(zvrf);
+ rtadv_vrf_init(zvrf);
#endif
/* Inform clients that the VRF is now active. This is an