summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd.c8
-rw-r--r--bfdd/bfdd.c2
-rw-r--r--bfdd/bfdd_cli.c6
-rw-r--r--bfdd/bfdd_nb_config.c22
-rw-r--r--bgpd/bgp_packet.c17
-rw-r--r--bgpd/bgp_route.c20
-rw-r--r--bgpd/bgpd.c20
-rwxr-xr-xconfigure.ac64
-rw-r--r--debian/README.Debian6
-rw-r--r--debian/compat2
-rw-r--r--debian/control127
-rw-r--r--debian/frr-doc.install16
-rw-r--r--debian/frr.dirs2
-rw-r--r--debian/frr.docs2
-rw-r--r--debian/frr.install16
-rw-r--r--debian/frr.tmpfile2
-rw-r--r--debian/gbp.conf4
-rwxr-xr-xdebian/rules6
-rw-r--r--debian/source/format2
-rw-r--r--debian/tests/control7
-rw-r--r--debian/watch3
-rw-r--r--doc/user/pbr.rst2
-rw-r--r--isisd/isis_adjacency.c34
-rw-r--r--lib/hash.h3
-rw-r--r--lib/log.c5
-rw-r--r--lib/nexthop_group.c42
-rw-r--r--lib/route_types.txt2
-rw-r--r--lib/zclient.c95
-rw-r--r--lib/zclient.h56
-rw-r--r--pbrd/pbr_map.c13
-rw-r--r--pbrd/pbr_zebra.c8
-rw-r--r--pbrd/pbr_zebra.h2
-rw-r--r--ripd/ripd.c7
-rw-r--r--ripngd/ripngd.c7
-rw-r--r--sharpd/sharp_globals.h1
-rw-r--r--sharpd/sharp_main.c3
-rw-r--r--sharpd/sharp_nht.c158
-rw-r--r--sharpd/sharp_nht.h6
-rw-r--r--sharpd/sharp_vty.c5
-rw-r--r--sharpd/sharp_zebra.c104
-rw-r--r--sharpd/sharp_zebra.h7
-rw-r--r--tests/subdir.am8
-rw-r--r--[-rwxr-xr-x]tests/topotests/all-protocol-startup/test_all_protocol_startup.py214
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py0
-rw-r--r--tests/topotests/bgp-evpn-mh/test_evpn_mh.py4
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-route-map/test_route_map_topo1.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-route-map/test_route_map_topo2.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py0
-rw-r--r--tests/topotests/eigrp-topo1/test_eigrp_topo1.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py0
-rw-r--r--[-rwxr-xr-x]tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py4
-rw-r--r--tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py4
-rw-r--r--[-rwxr-xr-x]tests/topotests/ldp-topo1/test_ldp_topo1.py0
-rw-r--r--tests/topotests/lib/bgp.py13
-rw-r--r--tests/topotests/lib/common_config.py34
-rw-r--r--tests/topotests/lib/ltemplate.py8
-rw-r--r--[-rwxr-xr-x]tests/topotests/lib/lutil.py38
-rw-r--r--tests/topotests/lib/ospf.py12
-rw-r--r--tests/topotests/lib/topogen.py21
-rw-r--r--tests/topotests/lib/topojson.py2
-rw-r--r--tests/topotests/lib/topolog.py2
-rw-r--r--tests/topotests/lib/topotest.py15
-rw-r--r--tests/topotests/ospf-topo2/test_ospf_topo2.py22
-rw-r--r--tests/topotests/pbr-topo1/test_pbr_topo1.py20
-rw-r--r--[-rwxr-xr-x]tests/topotests/rip-topo1/test_rip_topo1.py8
-rw-r--r--[-rwxr-xr-x]tests/topotests/ripng-topo1/test_ripng_topo1.py0
-rw-r--r--vtysh/vtysh.c649
-rw-r--r--yang/frr-bfdd.yang15
-rw-r--r--yang/frr-bgp-common-structure.yang6
-rw-r--r--yang/frr-bgp-common.yang20
-rw-r--r--yang/frr-bgp-types.yang4
-rw-r--r--yang/frr-eigrpd.yang14
-rw-r--r--yang/frr-isisd.yang16
-rw-r--r--yang/frr-nexthop.yang6
-rw-r--r--yang/frr-ospfd.yang10
-rw-r--r--yang/frr-ripd.yang20
-rw-r--r--yang/frr-ripngd.yang16
-rw-r--r--yang/frr-routing.yang2
-rw-r--r--yang/frr-test-module.yang4
-rw-r--r--yang/frr-zebra.yang2
-rw-r--r--zebra/rib.h4
-rw-r--r--zebra/rt_netlink.c71
-rw-r--r--zebra/zapi_msg.c512
-rw-r--r--zebra/zapi_msg.h2
-rw-r--r--zebra/zebra_dplane.c43
-rw-r--r--zebra/zebra_dplane.h1
-rw-r--r--zebra/zebra_nhg.c511
-rw-r--r--zebra/zebra_nhg.h72
-rw-r--r--zebra/zebra_rib.c31
-rw-r--r--zebra/zebra_vty.c20
-rw-r--r--zebra/zebra_vxlan.c9
-rw-r--r--zebra/zserv.c8
106 files changed, 2407 insertions, 1008 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index c16912060c..57e5909f57 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -2158,6 +2158,7 @@ void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf)
if (yang_module_find("frr-bfdd") && bs->key.vrfname[0]) {
struct lyd_node *bfd_dnode;
char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32];
+ char oldpath[XPATH_MAXLEN], newpath[XPATH_MAXLEN];
char addr_buf[INET6_ADDRSTRLEN];
int slen;
@@ -2178,14 +2179,19 @@ void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf)
"[interface='%s']", bs->key.ifname);
else
slen += snprintf(xpath + slen, sizeof(xpath) - slen,
- "[interface='']");
+ "[interface='*']");
snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']/vrf",
bs->key.vrfname);
bfd_dnode = yang_dnode_get(running_config->dnode, xpath,
bs->key.vrfname);
if (bfd_dnode) {
+ yang_dnode_get_path(bfd_dnode->parent, oldpath,
+ sizeof(oldpath));
yang_dnode_change_leaf(bfd_dnode, vrf->name);
+ yang_dnode_get_path(bfd_dnode->parent, newpath,
+ sizeof(newpath));
+ nb_running_move_tree(oldpath, newpath);
running_config->version++;
}
}
diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c
index 6b8f2c5d46..098e7a289e 100644
--- a/bfdd/bfdd.c
+++ b/bfdd/bfdd.c
@@ -21,6 +21,8 @@
#include <zebra.h>
#include "filter.h"
+#include "if.h"
+#include "vrf.h"
#include "bfd.h"
#include "bfdd_nb.h"
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index d115684b1c..ddec83397d 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -127,7 +127,7 @@ DEFPY_YANG_NOSH(
"[interface='%s']", ifname);
else
slen += snprintf(xpath + slen, sizeof(xpath) - slen,
- "[interface='']");
+ "[interface='*']");
if (vrf)
snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf);
else
@@ -185,7 +185,7 @@ DEFPY_YANG(
"[interface='%s']", ifname);
else
slen += snprintf(xpath + slen, sizeof(xpath) - slen,
- "[interface='']");
+ "[interface='*']");
if (vrf)
snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']", vrf);
else
@@ -218,7 +218,7 @@ static void _bfd_cli_show_peer(struct vty *vty, struct lyd_node *dnode,
if (strcmp(vrf, VRF_DEFAULT_NAME))
vty_out(vty, " vrf %s", vrf);
- if (ifname[0])
+ if (strcmp(ifname, "*"))
vty_out(vty, " interface %s", ifname);
vty_out(vty, "\n");
diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c
index 0046bc625b..fe6a0b7905 100644
--- a/bfdd/bfdd_nb_config.c
+++ b/bfdd/bfdd_nb_config.c
@@ -45,11 +45,11 @@ static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode,
if (yang_dnode_exists(dnode, "./source-addr"))
strtosa(yang_dnode_get_string(dnode, "./source-addr"), &lsa);
- /* Get optional interface and vrf names. */
- if (yang_dnode_exists(dnode, "./interface"))
- ifname = yang_dnode_get_string(dnode, "./interface");
- if (yang_dnode_exists(dnode, "./vrf"))
- vrfname = yang_dnode_get_string(dnode, "./vrf");
+ ifname = yang_dnode_get_string(dnode, "./interface");
+ vrfname = yang_dnode_get_string(dnode, "./vrf");
+
+ if (strcmp(ifname, "*") == 0)
+ ifname = NULL;
/* Generate the corresponding key. */
gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname);
@@ -72,18 +72,10 @@ static int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
*/
yang_dnode_get_prefix(&p, dnode, "./dest-addr");
- /*
- * To support old FRR versions we must allow empty
- * interface to be specified, however that should
- * change in the future.
- */
- if (yang_dnode_exists(dnode, "./interface"))
- ifname = yang_dnode_get_string(dnode, "./interface");
- else
- ifname = "";
+ ifname = yang_dnode_get_string(dnode, "./interface");
if (p.family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)
- && strlen(ifname) == 0) {
+ && strcmp(ifname, "*") == 0) {
zlog_warn(
"%s: when using link-local you must specify an interface.",
__func__);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index ee3580edf1..6c077878b5 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1319,11 +1319,18 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
else
peer->v_holdtime = send_holdtime;
- if ((CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
- && (peer->keepalive < peer->v_holdtime / 3))
- peer->v_keepalive = peer->keepalive;
- else
- peer->v_keepalive = peer->v_holdtime / 3;
+ /* Set effective keepalive to 1/3 the effective holdtime.
+ * Use configured keeplive when < effective keepalive.
+ */
+ peer->v_keepalive = peer->v_holdtime / 3;
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) {
+ if (peer->keepalive && peer->keepalive < peer->v_keepalive)
+ peer->v_keepalive = peer->keepalive;
+ } else {
+ if (peer->bgp->default_keepalive
+ && peer->bgp->default_keepalive < peer->v_keepalive)
+ peer->v_keepalive = peer->bgp->default_keepalive;
+ }
/* Open option part parse. */
if (optlen != 0) {
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 174c11fd34..15c1df8473 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -3340,14 +3340,20 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
(type == ZEBRA_ROUTE_BGP && stype == BGP_ROUTE_STATIC) ? true
: false;
- /* Only validated for unicast and multicast currently. */
- /* Also valid for EVPN where the nexthop is an IP address. */
- if (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != SAFI_EVPN)
+ /*
+ * Only validated for unicast and multicast currently.
+ * Also valid for EVPN where the nexthop is an IP address.
+ * If we are a bgp static route being checked then there is
+ * no need to check to see if the nexthop is martian as
+ * that it should be ok.
+ */
+ if (is_bgp_static_route ||
+ (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != SAFI_EVPN))
return false;
/* If NEXT_HOP is present, validate it. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
- if ((attr->nexthop.s_addr == INADDR_ANY && !is_bgp_static_route)
+ if (attr->nexthop.s_addr == INADDR_ANY
|| IPV4_CLASS_DE(ntohl(attr->nexthop.s_addr))
|| bgp_nexthop_self(bgp, afi, type, stype, attr, dest))
return true;
@@ -3366,8 +3372,7 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
switch (attr->mp_nexthop_len) {
case BGP_ATTR_NHLEN_IPV4:
case BGP_ATTR_NHLEN_VPNV4:
- ret = ((attr->mp_nexthop_global_in.s_addr == INADDR_ANY
- && !is_bgp_static_route)
+ ret = (attr->mp_nexthop_global_in.s_addr == INADDR_ANY
|| IPV4_CLASS_DE(
ntohl(attr->mp_nexthop_global_in.s_addr))
|| bgp_nexthop_self(bgp, afi, type, stype, attr,
@@ -3376,9 +3381,8 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
case BGP_ATTR_NHLEN_IPV6_GLOBAL:
case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
- ret = ((IN6_IS_ADDR_UNSPECIFIED(
+ ret = (IN6_IS_ADDR_UNSPECIFIED(
&attr->mp_nexthop_global)
- && !is_bgp_static_route)
|| IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global)
|| IN6_IS_ADDR_MULTICAST(
&attr->mp_nexthop_global)
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 84d4aeb1e6..4260970541 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -336,7 +336,15 @@ void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id)
bgp->name_pretty,
bgp->vrf_id,
inet_ntoa(*addr));
- bgp_router_id_set(bgp, addr, false);
+ /*
+ * if old router-id was 0x0, set flag
+ * to use this new value
+ */
+ bgp_router_id_set(bgp, addr,
+ (bgp->router_id.s_addr
+ == INADDR_ANY)
+ ? true
+ : false);
}
}
}
@@ -359,7 +367,15 @@ void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id)
bgp->name_pretty,
bgp->vrf_id,
inet_ntoa(*addr));
- bgp_router_id_set(bgp, addr, false);
+ /*
+ * if old router-id was 0x0, set flag
+ * to use this new value
+ */
+ bgp_router_id_set(bgp, addr,
+ (bgp->router_id.s_addr
+ == INADDR_ANY)
+ ? true
+ : false);
}
}
diff --git a/configure.ac b/configure.ac
index d75637c0a7..3cc74c4110 100755
--- a/configure.ac
+++ b/configure.ac
@@ -542,7 +542,7 @@ AC_ARG_ENABLE([fabricd],
AC_ARG_ENABLE([vrrpd],
AS_HELP_STRING([--disable-vrrpd], [do not build vrrpd]))
AC_ARG_ENABLE([bgp-announce],
- AS_HELP_STRING([--disable-bgp-announce,], [turn off BGP route announcement]))
+ AS_HELP_STRING([--disable-bgp-announce], [turn off BGP route announcement]))
AC_ARG_ENABLE([bgp-vnc],
AS_HELP_STRING([--disable-bgp-vnc],[turn off BGP VNC support]))
AC_ARG_ENABLE([bgp-bmp],
@@ -593,7 +593,7 @@ AC_ARG_ENABLE([rusage],
AC_ARG_ENABLE([gcc_ultra_verbose],
AS_HELP_STRING([--enable-gcc-ultra-verbose], [enable ultra verbose GCC warnings]))
AC_ARG_ENABLE([backtrace],
- AS_HELP_STRING([--disable-backtrace,], [disable crash backtraces (default autodetect)]))
+ AS_HELP_STRING([--disable-backtrace], [disable crash backtraces (default autodetect)]))
AC_ARG_ENABLE([time-check],
AS_HELP_STRING([--disable-time-check], [disable slow thread warning messages]))
AC_ARG_ENABLE([cpu-time],
@@ -1561,10 +1561,70 @@ dnl --------------------
dnl Daemon disable check
dnl --------------------
+AS_IF([test "$enable_bgpd" != "no"], [
+ AC_DEFINE([HAVE_BGPD], [1], [bgpd])
+])
+
+AS_IF([test "$enable_ripd" != "no"], [
+ AC_DEFINE([HAVE_RIPD], [1], [ripd])
+])
+
+AS_IF([test "$enable_ripngd" != "no"], [
+ AC_DEFINE([HAVE_RIPNGD], [1], [ripngd])
+])
+
+AS_IF([test "$enable_ospfd" != "no"], [
+ AC_DEFINE([HAVE_OSPFD], [1], [ospfd])
+])
+
+AS_IF([test "$enable_ospf6d" != "no"], [
+ AC_DEFINE([HAVE_OSPF6D], [1], [ospf6d])
+])
+
AS_IF([test "$enable_ldpd" != "no"], [
AC_DEFINE([HAVE_LDPD], [1], [ldpd])
])
+AS_IF([test "$enable_nhrpd" != "no"], [
+ AC_DEFINE([HAVE_NHRPD], [1], [nhrpd])
+])
+
+AS_IF([test "$enable_eigrpd" != "no"], [
+ AC_DEFINE([HAVE_EIGRPD], [1], [eigrpd])
+])
+
+AS_IF([test "$enable_babeld" != "no"], [
+ AC_DEFINE([HAVE_BABELD], [1], [babeld])
+])
+
+AS_IF([test "$enable_isisd" != "no"], [
+ AC_DEFINE([HAVE_ISISD], [1], [isisd])
+])
+
+AS_IF([test "$enable_pimd" != "no"], [
+ AC_DEFINE([HAVE_PIMD], [1], [pimd])
+])
+
+AS_IF([test "$enable_pbrd" != "no"], [
+ AC_DEFINE([HAVE_PBRD], [1], [pbrd])
+])
+
+AS_IF([test "$enable_sharpd" = "yes"], [
+ AC_DEFINE([HAVE_SHARPD], [1], [sharpd])
+])
+
+AS_IF([test "$enable_staticd" != "no"], [
+ AC_DEFINE([HAVE_STATICD], [1], [staticd])
+])
+
+AS_IF([test "$enable_fabricd" != "no"], [
+ AC_DEFINE([HAVE_FABRICD], [1], [fabricd])
+])
+
+AS_IF([test "$enable_vrrpd" != "no"], [
+ AC_DEFINE([HAVE_VRRPD], [1], [vrrpd])
+])
+
if test "$enable_bfdd" = "no"; then
AC_DEFINE([HAVE_BFDD], [0], [bfdd])
BFDD=""
diff --git a/debian/README.Debian b/debian/README.Debian
index 01b9213ae4..a23a0efcac 100644
--- a/debian/README.Debian
+++ b/debian/README.Debian
@@ -31,10 +31,6 @@ The following Build Profiles have been added:
controls whether the RPKI module is built.
Will be enabled by default at some point, adds some extra dependencies.
-- pkg.frr.nosnmp (pkg.frr.snmp)
- controls whether the SNMP module is built, see below for license issues.
- Will remain default-off as long as the license issue persists.
-
- pkg.frr.nosystemd
Disables both systemd unit file installation as well as watchfrr sd_notify
support at startup. Removes libsystemd dependency.
@@ -108,3 +104,5 @@ See message #4525 from 2005-05-09 in the quagga-users mailing list.
Check /etc/pam.d/frr, it probably denies access to your user. The passwords
configured in /etc/frr/frr.conf are only for telnet access.
+
+ -- Ondřej Surý <Ondřej Surý <ondrej@debian.org>>, Fri, 3 Jul 2020 12:39:42 +0200
diff --git a/debian/compat b/debian/compat
index ec635144f6..f599e28b8a 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-9
+10
diff --git a/debian/control b/debian/control
index fca6956760..4aaa9f21bf 100644
--- a/debian/control
+++ b/debian/control
@@ -2,64 +2,63 @@ Source: frr
Section: net
Priority: optional
Maintainer: David Lamparter <equinox-debian@diac24.net>
-Uploaders: FRRouting-dev <dev@lists.frrouting.org>
-Build-Depends:
- autotools-dev,
- bison,
- chrpath,
- debhelper (>= 9),
- debhelper (>= 9.20160709) <!pkg.frr.nosystemd> | dh-systemd <!pkg.frr.nosystemd>,
- dh-autoreconf,
- flex,
- gawk,
- install-info,
- libc-ares-dev,
- libcap-dev,
- libjson-c-dev | libjson0-dev,
- libpam0g-dev | libpam-dev,
- libpcre3-dev,
- libpython3-dev,
- libreadline-dev,
- librtr-dev <!pkg.frr.nortrlib>,
- libsnmp-dev,
- libssh-dev <!pkg.frr.nortrlib>,
- libsystemd-dev <!pkg.frr.nosystemd>,
- libyang-dev (>= 1.0.184),
- pkg-config,
- python3,
- python3-dev,
- python3-sphinx,
- python3-pytest <!nocheck>,
- texinfo (>= 4.7)
-Standards-Version: 4.4.1
+Uploaders: FRRouting-dev <dev@lists.frrouting.org>,
+ Ondřej Surý <ondrej@debian.org>
+Build-Depends: bison,
+ chrpath,
+ debhelper (>= 10~) | dh-systemd,
+ debhelper (>= 9.20150101~),
+ flex,
+ gawk,
+ install-info,
+ libc-ares-dev,
+ libcap-dev,
+ libjson-c-dev | libjson0-dev,
+ libpam0g-dev | libpam-dev,
+ libpcre3-dev,
+ libpython3-dev,
+ libreadline-dev,
+ librtr-dev <!pkg.frr.nortrlib>,
+ libsnmp-dev,
+ libssh-dev <!pkg.frr.nortrlib>,
+ libsystemd-dev <!pkg.frr.nosystemd>,
+ libyang-dev (>= 1.0.184),
+ lsb-base,
+ pkg-config,
+ python3,
+ python3-dev,
+ python3-pytest <!nocheck>,
+ python3-sphinx,
+ texinfo (>= 4.7)
+Standards-Version: 4.5.0.3
Homepage: https://www.frrouting.org/
Vcs-Browser: https://github.com/FRRouting/frr/tree/debian/master
Vcs-Git: https://github.com/FRRouting/frr.git -b debian/master
Package: frr
Architecture: linux-any
-Depends:
- ${misc:Depends},
- ${shlibs:Depends},
- iproute2 | iproute,
- logrotate (>= 3.2-11)
+Depends: iproute2 | iproute,
+ logrotate (>= 3.2-11),
+ lsof,
+ ${misc:Depends},
+ ${shlibs:Depends}
Pre-Depends: adduser
Recommends: frr-pythontools
Suggests: frr-doc
-Conflicts:
- zebra,
- zebra-pj,
- pimd,
- quagga,
- quagga-bgpd,
- quagga-core,
- quagga-isisd,
- quagga-ospf6d,
- quagga-ospfd,
- quagga-pimd,
- quagga-ripd,
- quagga-ripngd
-Replaces: zebra, zebra-pj
+Conflicts: pimd,
+ quagga,
+ quagga-bgpd,
+ quagga-core,
+ quagga-isisd,
+ quagga-ospf6d,
+ quagga-ospfd,
+ quagga-pimd,
+ quagga-ripd,
+ quagga-ripngd,
+ zebra,
+ zebra-pj
+Replaces: zebra,
+ zebra-pj
Description: FRRouting suite of internet protocols (BGP, OSPF, IS-IS, ...)
FRRouting implements the routing protocols commonly used in the
internet and private networks to exchange information between routers.
@@ -77,10 +76,9 @@ Description: FRRouting suite of internet protocols (BGP, OSPF, IS-IS, ...)
Package: frr-snmp
Architecture: linux-any
-Depends:
- ${misc:Depends},
- ${shlibs:Depends},
- frr (= ${binary:Version})
+Depends: frr (= ${binary:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends}
Recommends: snmpd
Description: FRRouting suite - SNMP support
Adds SNMP support to FRR's daemons by attaching to net-snmp's snmpd
@@ -89,10 +87,9 @@ Description: FRRouting suite - SNMP support
Package: frr-rpki-rtrlib
Architecture: linux-any
-Depends:
- ${misc:Depends},
- ${shlibs:Depends},
- frr (= ${binary:Version})
+Depends: frr (= ${binary:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends}
Description: FRRouting suite - BGP RPKI support (rtrlib)
Adds RPKI support to FRR's bgpd, allowing validation of BGP routes
against cryptographic information stored in WHOIS databases. This is
@@ -105,10 +102,9 @@ Package: frr-doc
Section: doc
Architecture: all
Multi-Arch: foreign
-Depends:
- ${misc:Depends},
- libjs-jquery,
- libjs-underscore
+Depends: libjs-jquery,
+ libjs-underscore,
+ ${misc:Depends}
Suggests: frr
Conflicts: quagga-doc
Description: FRRouting suite - user manual
@@ -118,11 +114,10 @@ Description: FRRouting suite - user manual
Package: frr-pythontools
Architecture: all
-Depends:
- ${misc:Depends},
- frr (<< ${source:Upstream-Version}.0-~),
- frr (>= ${source:Version}~),
- python3:any
+Depends: frr (<< ${source:Upstream-Version}.0-~),
+ frr (>= ${source:Version}~),
+ python3:any,
+ ${misc:Depends}
Description: FRRouting suite - Python tools
The FRRouting suite uses a small Python tool to provide configuration
reload functionality, particularly useful when the interactive configuration
diff --git a/debian/frr-doc.install b/debian/frr-doc.install
index c48dc5a8db..a666162122 100644
--- a/debian/frr-doc.install
+++ b/debian/frr-doc.install
@@ -1,10 +1,16 @@
# html docs include RST sources
-usr/share/doc/frr/html
-
# info + images referenced by it
-usr/share/info/
-doc/user/_build/texinfo/*.png usr/share/info
-
# other
README.md usr/share/doc/frr
doc/figures/*.png usr/share/doc/frr
+doc/figures/fig-normal-processing.png usr/share/info
+doc/figures/fig-rs-processing.png usr/share/info
+doc/figures/fig-vnc-commercial-route-reflector.png usr/share/info
+doc/figures/fig-vnc-frr-route-reflector.png usr/share/info
+doc/figures/fig-vnc-gw.png usr/share/info
+doc/figures/fig-vnc-mesh.png usr/share/info
+doc/figures/fig-vnc-redundant-route-reflectors.png usr/share/info
+doc/figures/fig_topologies_full.png usr/share/info
+doc/figures/fig_topologies_rs.png usr/share/info
+usr/share/doc/frr/html
+usr/share/info/
diff --git a/debian/frr.dirs b/debian/frr.dirs
index 4b05c8c907..9e592e370c 100644
--- a/debian/frr.dirs
+++ b/debian/frr.dirs
@@ -1,6 +1,6 @@
-etc/logrotate.d/
etc/frr/
etc/iproute2/rt_protos.d/
+etc/logrotate.d/
usr/share/doc/frr/
usr/share/doc/frr/examples/
usr/share/lintian/overrides/
diff --git a/debian/frr.docs b/debian/frr.docs
index 34dbbd7bc7..220127caa1 100644
--- a/debian/frr.docs
+++ b/debian/frr.docs
@@ -1,2 +1,2 @@
-tools/zebra.el
debian/README.Debian
+tools/zebra.el
diff --git a/debian/frr.install b/debian/frr.install
index e2485fe8b8..cefc3135b2 100644
--- a/debian/frr.install
+++ b/debian/frr.install
@@ -1,20 +1,20 @@
+debian/frr.conf usr/lib/tmpfiles.d
etc/
-usr/bin/vtysh
+tools/frr-reload usr/lib/frr/
usr/bin/mtracebis
+usr/bin/vtysh
usr/lib/*/frr/libfrr.*
usr/lib/*/frr/libfrrcares.*
usr/lib/*/frr/libfrrospfapiclient.*
+usr/lib/*/frr/modules/bgpd_bmp.so
+usr/lib/*/frr/modules/dplane_fpm_nl.so
+usr/lib/*/frr/modules/zebra_cumulus_mlag.so
+usr/lib/*/frr/modules/zebra_fpm.so
+usr/lib/*/frr/modules/zebra_irdp.so
usr/lib/frr/*.sh
usr/lib/frr/*d
usr/lib/frr/watchfrr
usr/lib/frr/zebra
-usr/lib/*/frr/modules/zebra_cumulus_mlag.so
-usr/lib/*/frr/modules/dplane_fpm_nl.so
-usr/lib/*/frr/modules/zebra_irdp.so
-usr/lib/*/frr/modules/zebra_fpm.so
-usr/lib/*/frr/modules/bgpd_bmp.so
usr/share/doc/frr/examples
usr/share/man/
usr/share/yang/
-tools/frr-reload usr/lib/frr/
-debian/frr.conf usr/lib/tmpfiles.d
diff --git a/debian/frr.tmpfile b/debian/frr.tmpfile
new file mode 100644
index 0000000000..dee3cd849a
--- /dev/null
+++ b/debian/frr.tmpfile
@@ -0,0 +1,2 @@
+# Create the /run/frr directory at boot or from systemd-tmpfiles on install
+d /run/frr 0755 frr frr
diff --git a/debian/gbp.conf b/debian/gbp.conf
new file mode 100644
index 0000000000..990c4d226e
--- /dev/null
+++ b/debian/gbp.conf
@@ -0,0 +1,4 @@
+[DEFAULT]
+pristine-tar = False
+debian-branch = master
+upstream-tree=SLOPPY
diff --git a/debian/rules b/debian/rules
index c8550ecb52..6cc03c378a 100755
--- a/debian/rules
+++ b/debian/rules
@@ -22,17 +22,17 @@ else
endif
ifeq ($(filter pkg.frr.nosystemd,$(DEB_BUILD_PROFILES)),)
- DH_WITH_SYSTEMD=systemd,
+ DH_WITHOUT_SYSTEMD=
CONF_SYSTEMD=--enable-systemd=yes
else
- DH_WITH_SYSTEMD=
+ DH_WITHOUT_SYSTEMD=--without=systemd
CONF_SYSTEMD=--enable-systemd=no
endif
export PYTHON=python3
%:
- dh $@ --with=$(DH_WITH_SYSTEMD)autoreconf --parallel
+ dh $@ $(DH_WITHOUT_SYSTEMD)
override_dh_auto_configure:
$(shell dpkg-buildflags --export=sh); \
diff --git a/debian/source/format b/debian/source/format
index af745b310b..163aaf8d82 100644
--- a/debian/source/format
+++ b/debian/source/format
@@ -1 +1 @@
-3.0 (git)
+3.0 (quilt)
diff --git a/debian/tests/control b/debian/tests/control
index 5990a69370..6cb5b02dc1 100644
--- a/debian/tests/control
+++ b/debian/tests/control
@@ -3,9 +3,12 @@ Depends: frr
Restrictions: needs-root, isolation-container
Tests: bgpd-snmp-rpki
-Depends: frr, frr-snmp, frr-rpki-rtrlib
+Depends: frr,
+ frr-rpki-rtrlib,
+ frr-snmp
Restrictions: needs-root, isolation-container
Tests: py-frr-reload
-Depends: frr, frr-pythontools
+Depends: frr,
+ frr-pythontools
Restrictions: needs-root, isolation-container
diff --git a/debian/watch b/debian/watch
index c286392d7e..f17eba4130 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,4 +1,5 @@
version=4
+opts=uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/ \
https://github.com/FRRouting/frr/releases/ \
- download/frr-(?:\d[\d.]*)/frr-(\d[\d.]*)\.tar\.xz debian uupdate
+ .*/frr-(\d\S+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst
index 99ef258cb2..c869c6bc45 100644
--- a/doc/user/pbr.rst
+++ b/doc/user/pbr.rst
@@ -39,7 +39,7 @@ listing of ECMP nexthops used to forward packets for when a pbr-map is matched.
sub-mode where you can specify individual nexthops. To exit this mode type
exit or end as per normal conventions for leaving a sub-mode.
-.. clicmd:: nexthop [A.B.C.D|X:X::X:XX] [interface] [nexthop-vrf NAME] [label LABELS]
+.. clicmd:: nexthop [A.B.C.D|X:X::X:XX] [interface [onlink]] [nexthop-vrf NAME] [label LABELS]
Create a v4 or v6 nexthop. All normal rules for creating nexthops that you
are used to are allowed here. The syntax was intentionally kept the same as
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index f7cdd58f72..5bfbb2cf7e 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -304,7 +304,6 @@ void isis_adj_state_change(struct isis_adjacency **padj,
continue;
if (new_state == ISIS_ADJ_UP) {
circuit->upadjcount[level - 1]++;
- hook_call(isis_adj_state_change_hook, adj);
/* update counter & timers for debugging
* purposes */
adj->last_flap = time(NULL);
@@ -317,7 +316,6 @@ void isis_adj_state_change(struct isis_adjacency **padj,
if (circuit->upadjcount[level - 1] == 0)
isis_tx_queue_clean(circuit->tx_queue);
- hook_call(isis_adj_state_change_hook, adj);
if (new_state == ISIS_ADJ_DOWN)
del = true;
}
@@ -342,7 +340,6 @@ void isis_adj_state_change(struct isis_adjacency **padj,
continue;
if (new_state == ISIS_ADJ_UP) {
circuit->upadjcount[level - 1]++;
- hook_call(isis_adj_state_change_hook, adj);
/* update counter & timers for debugging
* purposes */
@@ -365,13 +362,14 @@ void isis_adj_state_change(struct isis_adjacency **padj,
if (circuit->upadjcount[level - 1] == 0)
isis_tx_queue_clean(circuit->tx_queue);
- hook_call(isis_adj_state_change_hook, adj);
if (new_state == ISIS_ADJ_DOWN)
del = true;
}
}
}
+ hook_call(isis_adj_state_change_hook, adj);
+
if (del) {
isis_delete_adj(adj);
*padj = NULL;
@@ -467,11 +465,15 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
vty_out(vty, "%-3u", adj->level); /* level */
vty_out(vty, "%-13s", adj_state2string(adj->adj_state));
now = time(NULL);
- if (adj->last_upd)
- vty_out(vty, "%-9llu",
- (unsigned long long)adj->last_upd
- + adj->hold_time - now);
- else
+ if (adj->last_upd) {
+ if (adj->last_upd + adj->hold_time
+ < (unsigned long long)now)
+ vty_out(vty, " Expiring");
+ else
+ vty_out(vty, " %-9llu",
+ (unsigned long long)adj->last_upd
+ + adj->hold_time - now);
+ } else
vty_out(vty, "- ");
vty_out(vty, "%-10s", snpa_print(adj->snpa));
vty_out(vty, "\n");
@@ -491,11 +493,15 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
vty_out(vty, ", Level: %u", adj->level); /* level */
vty_out(vty, ", State: %s", adj_state2string(adj->adj_state));
now = time(NULL);
- if (adj->last_upd)
- vty_out(vty, ", Expires in %s",
- time2string(adj->last_upd + adj->hold_time
- - now));
- else
+ if (adj->last_upd) {
+ if (adj->last_upd + adj->hold_time
+ < (unsigned long long)now)
+ vty_out(vty, " Expiring");
+ else
+ vty_out(vty, ", Expires in %s",
+ time2string(adj->last_upd
+ + adj->hold_time - now));
+ } else
vty_out(vty, ", Expires in %s",
time2string(adj->hold_time));
vty_out(vty, "\n");
diff --git a/lib/hash.h b/lib/hash.h
index e7ba3187f5..00953ff3b3 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -236,7 +236,8 @@ extern void *hash_release(struct hash *hash, void *data);
* Iterate over the elements in a hash table.
*
* It is safe to delete items passed to the iteration function from the hash
- * table during iteration. Please note that adding entries to the hash
+ * table during iteration. More than one item cannot be deleted during each
+ * iteration. Please note that adding entries to the hash
* during the walk will cause undefined behavior in that some new entries
* will be walked and some will not. So do not do this.
*
diff --git a/lib/log.c b/lib/log.c
index 4054185019..b629658f75 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -452,7 +452,10 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE),
DESC_ENTRY(ZEBRA_OPAQUE_REGISTER),
DESC_ENTRY(ZEBRA_OPAQUE_UNREGISTER),
- DESC_ENTRY(ZEBRA_NEIGH_DISCOVER)};
+ DESC_ENTRY(ZEBRA_NEIGH_DISCOVER),
+ DESC_ENTRY(ZEBRA_NHG_ADD),
+ DESC_ENTRY(ZEBRA_NHG_DEL),
+ DESC_ENTRY(ZEBRA_NHG_NOTIFY_OWNER)};
#undef DESC_ENTRY
static const struct zebra_desc_table unknown = {0, "unknown", '?'};
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 687cac4062..83905abe43 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -41,6 +41,7 @@ struct nexthop_hold {
char *nhvrf_name;
union sockunion *addr;
char *intf;
+ bool onlink;
char *labels;
uint32_t weight;
char *backup_str;
@@ -560,6 +561,10 @@ static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
if (ret)
return ret;
+ ret = ((int)nh2->onlink) - ((int)nh1->onlink);
+ if (ret)
+ return ret;
+
return nhgc_cmp_helper(nh1->labels, nh2->labels);
}
@@ -673,8 +678,8 @@ DEFPY(no_nexthop_group_backup, no_nexthop_group_backup_cmd,
static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
const char *nhvrf_name,
const union sockunion *addr,
- const char *intf, const char *labels,
- const uint32_t weight,
+ const char *intf, bool onlink,
+ const char *labels, const uint32_t weight,
const char *backup_str)
{
struct nexthop_hold *nh;
@@ -690,6 +695,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
if (labels)
nh->labels = XSTRDUP(MTYPE_TMP, labels);
+ nh->onlink = onlink;
+
nh->weight = weight;
if (backup_str)
@@ -738,9 +745,10 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
*/
static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
const union sockunion *addr,
- const char *intf, const char *name,
- const char *labels, int *lbl_ret,
- uint32_t weight, const char *backup_str)
+ const char *intf, bool onlink,
+ const char *name, const char *labels,
+ int *lbl_ret, uint32_t weight,
+ const char *backup_str)
{
int ret = 0;
struct vrf *vrf;
@@ -764,6 +772,9 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
return false;
}
+ if (onlink)
+ SET_FLAG(nhop->flags, NEXTHOP_FLAG_ONLINK);
+
if (addr) {
if (addr->sa.sa_family == AF_INET) {
nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
@@ -820,15 +831,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
static bool nexthop_group_parse_nhh(struct nexthop *nhop,
const struct nexthop_hold *nhh)
{
- return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf,
- nhh->nhvrf_name, nhh->labels, NULL,
- nhh->weight, nhh->backup_str));
+ return (nexthop_group_parse_nexthop(
+ nhop, nhh->addr, nhh->intf, nhh->onlink, nhh->nhvrf_name,
+ nhh->labels, NULL, nhh->weight, nhh->backup_str));
}
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"[no] nexthop\
<\
- <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
+ <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf [onlink$onlink]]\
|INTERFACE$intf\
>\
[{ \
@@ -842,6 +853,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
"v4 Address\n"
"v6 Address\n"
"Interface to use\n"
+ "Treat nexthop as directly attached to the interface\n"
"Interface to use\n"
"If the nexthop is in a different vrf tell us\n"
"The nexthop-vrf Name\n"
@@ -870,8 +882,9 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
}
}
- legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label,
- &lbl_ret, weight, backup_idx);
+ legal = nexthop_group_parse_nexthop(&nhop, addr, intf, !!onlink,
+ vrf_name, label, &lbl_ret, weight,
+ backup_idx);
if (nhop.type == NEXTHOP_TYPE_IPV6
&& IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
@@ -933,8 +946,8 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
}
/* Save config always */
- nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label,
- weight, backup_idx);
+ nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, !!onlink,
+ label, weight, backup_idx);
if (legal && nhg_hooks.add_nexthop)
nhg_hooks.add_nexthop(nhgc, nh);
@@ -1106,6 +1119,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
if (nh->intf)
vty_out(vty, " %s", nh->intf);
+ if (nh->onlink)
+ vty_out(vty, " onlink");
+
if (nh->nhvrf_name)
vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name);
diff --git a/lib/route_types.txt b/lib/route_types.txt
index b549c11cfc..37cc2fb590 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -84,7 +84,7 @@ ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR"
ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric"
ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP"
-ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group"
+ZEBRA_ROUTE_NHG, zebra, none, '-', 0, 0, 0, "Nexthop Group"
ZEBRA_ROUTE_SRTE, srte, none, '-', 0, 0, 0, "SR-TE"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
diff --git a/lib/zclient.c b/lib/zclient.c
index c5016d22e2..b7d240b4e8 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1017,6 +1017,57 @@ done:
return ret;
}
+int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
+{
+ int i;
+
+ if (cmd != ZEBRA_NHG_DEL && cmd != ZEBRA_NHG_ADD) {
+ flog_err(EC_LIB_ZAPI_ENCODE,
+ "%s: Specified zapi NHG command (%d) doesn't exist\n",
+ __func__, cmd);
+ return -1;
+ }
+
+ stream_reset(s);
+ zclient_create_header(s, cmd, VRF_DEFAULT);
+
+ stream_putw(s, api_nhg->proto);
+ stream_putl(s, api_nhg->id);
+
+ if (cmd == ZEBRA_NHG_ADD) {
+ /* Nexthops */
+ zapi_nexthop_group_sort(api_nhg->nexthops,
+ api_nhg->nexthop_num);
+
+ stream_putw(s, api_nhg->nexthop_num);
+
+ for (i = 0; i < api_nhg->nexthop_num; i++)
+ zapi_nexthop_encode(s, &api_nhg->nexthops[i], 0, 0);
+
+ /* Backup nexthops */
+
+ stream_putw(s, api_nhg->backup_nexthop_num);
+
+ for (i = 0; i < api_nhg->backup_nexthop_num; i++)
+ zapi_nexthop_encode(s, &api_nhg->backup_nexthops[i], 0,
+ 0);
+ }
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return 0;
+}
+
+int zclient_nhg_send(struct zclient *zclient, int cmd, struct zapi_nhg *api_nhg)
+{
+ api_nhg->proto = zclient->redist_default;
+
+ if (zapi_nhg_encode(zclient->obuf, cmd, api_nhg))
+ return -1;
+
+ return zclient_send_message(zclient);
+}
+
int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
{
struct zapi_nexthop *api_nh;
@@ -1058,6 +1109,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
stream_write(s, (uint8_t *)&api->src_prefix.prefix, psize);
}
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NHG))
+ stream_putl(s, api->nhgid);
+
/* Nexthops. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
/* limit the number of nexthops if necessary */
@@ -1171,8 +1225,8 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
/*
* Decode a single zapi nexthop object
*/
-static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
- uint32_t api_flags, uint32_t api_message)
+int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
+ uint32_t api_flags, uint32_t api_message)
{
int i, ret = -1;
@@ -1328,6 +1382,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
}
}
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NHG))
+ STREAM_GETL(s, api->nhgid);
+
/* Nexthops. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
STREAM_GETW(s, api->nexthop_num);
@@ -1432,6 +1489,22 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
return 0;
}
+bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id,
+ enum zapi_nhg_notify_owner *note)
+{
+ uint32_t read_id;
+
+ STREAM_GET(note, s, sizeof(*note));
+ STREAM_GETL(s, read_id);
+
+ *id = read_id;
+
+ return true;
+
+stream_failure:
+ return false;
+}
+
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
uint32_t *tableid,
enum zapi_route_notify_owner *note)
@@ -1582,6 +1655,9 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
znh->ifindex = nh->ifindex;
znh->gate = nh->gate;
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
+ SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
+
if (nh->nh_label && (nh->nh_label->num_labels > 0)) {
/* Validate */
@@ -3733,6 +3809,11 @@ static int zclient_read(struct thread *thread)
(*zclient->rule_notify_owner)(command, zclient, length,
vrf_id);
break;
+ case ZEBRA_NHG_NOTIFY_OWNER:
+ if (zclient->nhg_notify_owner)
+ (*zclient->nhg_notify_owner)(command, zclient, length,
+ vrf_id);
+ break;
case ZEBRA_GET_LABEL_CHUNK:
if (zclient->label_chunk)
(*zclient->label_chunk)(command, zclient, length,
@@ -4001,3 +4082,13 @@ int zclient_send_neigh_discovery_req(struct zclient *zclient,
stream_putw_at(s, 0, stream_get_endp(s));
return zclient_send_message(zclient);
}
+
+/*
+ * Get a starting nhg point for a routing protocol
+ */
+uint32_t zclient_get_nhg_start(uint32_t proto)
+{
+ assert(proto < ZEBRA_ROUTE_MAX);
+
+ return ZEBRA_NHG_PROTO_SPACING * proto;
+}
diff --git a/lib/zclient.h b/lib/zclient.h
index 050877f27a..959a101395 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -209,6 +209,9 @@ typedef enum {
ZEBRA_MLAG_CLIENT_REGISTER,
ZEBRA_MLAG_CLIENT_UNREGISTER,
ZEBRA_MLAG_FORWARD_MSG,
+ ZEBRA_NHG_ADD,
+ ZEBRA_NHG_DEL,
+ ZEBRA_NHG_NOTIFY_OWNER,
ZEBRA_ERROR,
ZEBRA_CLIENT_CAPABILITIES,
ZEBRA_OPAQUE_MESSAGE,
@@ -354,6 +357,7 @@ struct zclient {
int (*mlag_process_up)(void);
int (*mlag_process_down)(void);
int (*mlag_handle_msg)(struct stream *msg, int len);
+ int (*nhg_notify_owner)(ZAPI_CALLBACK_ARGS);
int (*handle_error)(enum zebra_error_types error);
int (*opaque_msg_handler)(ZAPI_CALLBACK_ARGS);
int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS);
@@ -370,6 +374,7 @@ struct zclient {
#define ZAPI_MESSAGE_SRCPFX 0x20
/* Backup nexthops are present */
#define ZAPI_MESSAGE_BACKUP_NEXTHOPS 0x40
+#define ZAPI_MESSAGE_NHG 0x80
/*
* This should only be used by a DAEMON that needs to communicate
@@ -434,6 +439,20 @@ struct zapi_nexthop {
#define ZAPI_NEXTHOP_FLAG_HAS_BACKUP 0x08 /* Nexthop has a backup */
/*
+ * ZAPI Nexthop Group. For use with protocol creation of nexthop groups.
+ */
+struct zapi_nhg {
+ uint16_t proto;
+ uint32_t id;
+
+ uint16_t nexthop_num;
+ struct zapi_nexthop nexthops[MULTIPATH_NUM];
+
+ uint16_t backup_nexthop_num;
+ struct zapi_nexthop backup_nexthops[MULTIPATH_NUM];
+};
+
+/*
* Some of these data structures do not map easily to
* a actual data structure size giving different compilers
* and systems. For those data structures we need
@@ -514,6 +533,8 @@ struct zapi_route {
uint16_t backup_nexthop_num;
struct zapi_nexthop backup_nexthops[MULTIPATH_NUM];
+ uint32_t nhgid;
+
uint8_t distance;
uint32_t metric;
@@ -592,6 +613,13 @@ enum zapi_route_notify_owner {
ZAPI_ROUTE_REMOVE_FAIL,
};
+enum zapi_nhg_notify_owner {
+ ZAPI_NHG_FAIL_INSTALL,
+ ZAPI_NHG_INSTALLED,
+ ZAPI_NHG_REMOVED,
+ ZAPI_NHG_REMOVE_FAIL,
+};
+
enum zapi_rule_notify_owner {
ZAPI_RULE_FAIL_INSTALL,
ZAPI_RULE_INSTALLED,
@@ -671,6 +699,22 @@ struct zclient_options {
extern struct zclient_options zclient_options_default;
+/*
+ * We reserve the top 4 bits for l2-NHG, everything else
+ * is for zebra/proto l3-NHG.
+ *
+ * Each client is going to get it's own nexthop group space
+ * and we'll separate them, we'll figure out where to start based upon
+ * the route_types.h
+ */
+#define ZEBRA_NHG_PROTO_UPPER \
+ ((uint32_t)250000000) /* Bottom 28 bits then rounded down */
+#define ZEBRA_NHG_PROTO_SPACING (ZEBRA_NHG_PROTO_UPPER / ZEBRA_ROUTE_MAX)
+#define ZEBRA_NHG_PROTO_LOWER \
+ (ZEBRA_NHG_PROTO_SPACING * (ZEBRA_ROUTE_CONNECT + 1))
+
+extern uint32_t zclient_get_nhg_start(uint32_t proto);
+
extern struct zclient *zclient_new(struct thread_master *m,
struct zclient_options *opt);
@@ -853,7 +897,11 @@ extern int zclient_send_rnh(struct zclient *zclient, int command,
int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
uint32_t api_flags, uint32_t api_message);
extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *);
-extern int zapi_route_decode(struct stream *, struct zapi_route *);
+extern int zapi_route_decode(struct stream *s, struct zapi_route *api);
+extern int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
+ uint32_t api_flags, uint32_t api_message);
+bool zapi_nhg_notify_decode(struct stream *s, uint32_t *id,
+ enum zapi_nhg_notify_owner *note);
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
uint32_t *tableid,
enum zapi_route_notify_owner *note);
@@ -864,6 +912,12 @@ bool zapi_ipset_notify_decode(struct stream *s,
uint32_t *unique,
enum zapi_ipset_notify_owner *note);
+
+extern int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg);
+extern int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg);
+extern int zclient_nhg_send(struct zclient *zclient, int cmd,
+ struct zapi_nhg *api_nhg);
+
#define ZEBRA_IPSET_NAME_SIZE 32
bool zapi_ipset_entry_notify_decode(struct stream *s,
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index fe2778c877..01caff5b52 100644
--- a/pbrd/pbr_map.c
+++ b/pbrd/pbr_map.c
@@ -721,12 +721,23 @@ void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi)
{
struct listnode *node;
struct pbr_map_sequence *pbrms;
+ bool sent = false;
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
- pbr_send_pbr_map(pbrms, pmi, false, false);
+ if (pbr_send_pbr_map(pbrms, pmi, false, true))
+ sent = true; /* rule removal sent to zebra */
pmi->delete = true;
+
+ /*
+ * If we actually sent something for deletion, wait on zapi callback
+ * before clearing data.
+ */
+ if (sent)
+ return;
+
+ pbr_map_final_interface_deletion(pbrm, pmi);
}
/*
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index 269bd6da8d..8ef675186f 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -549,7 +549,7 @@ static void pbr_encode_pbr_map_sequence(struct stream *s,
stream_put(s, ifp->name, INTERFACE_NAMSIZ);
}
-void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
+bool pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
struct pbr_map_interface *pmi, bool install, bool changed)
{
struct pbr_map *pbrm = pbrms->parent;
@@ -569,10 +569,10 @@ void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
* to delete just return.
*/
if (install && is_installed && !changed)
- return;
+ return false;
if (!install && !is_installed)
- return;
+ return false;
s = zclient->obuf;
stream_reset(s);
@@ -595,4 +595,6 @@ void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
stream_putw_at(s, 0, stream_get_endp(s));
zclient_send_message(zclient);
+
+ return true;
}
diff --git a/pbrd/pbr_zebra.h b/pbrd/pbr_zebra.h
index cc42e21abe..e8f9bff5d9 100644
--- a/pbrd/pbr_zebra.h
+++ b/pbrd/pbr_zebra.h
@@ -35,7 +35,7 @@ extern void route_delete(struct pbr_nexthop_group_cache *pnhgc,
extern void pbr_send_rnh(struct nexthop *nhop, bool reg);
-extern void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
+extern bool pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
struct pbr_map_interface *pmi, bool install,
bool changed);
diff --git a/ripd/ripd.c b/ripd/ripd.c
index ecadf8fb71..bcf73e8f89 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -3667,13 +3667,20 @@ static int rip_vrf_enable(struct vrf *vrf)
*/
if (yang_module_find("frr-ripd") && old_vrf_name) {
struct lyd_node *rip_dnode;
+ char oldpath[XPATH_MAXLEN];
+ char newpath[XPATH_MAXLEN];
rip_dnode = yang_dnode_get(
running_config->dnode,
"/frr-ripd:ripd/instance[vrf='%s']/vrf",
old_vrf_name);
if (rip_dnode) {
+ yang_dnode_get_path(rip_dnode->parent, oldpath,
+ sizeof(oldpath));
yang_dnode_change_leaf(rip_dnode, vrf->name);
+ yang_dnode_get_path(rip_dnode->parent, newpath,
+ sizeof(newpath));
+ nb_running_move_tree(oldpath, newpath);
running_config->version++;
}
}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index bf6c6ff27b..8a7950daf4 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -2791,13 +2791,20 @@ static int ripng_vrf_enable(struct vrf *vrf)
*/
if (yang_module_find("frr-ripngd") && old_vrf_name) {
struct lyd_node *ripng_dnode;
+ char oldpath[XPATH_MAXLEN];
+ char newpath[XPATH_MAXLEN];
ripng_dnode = yang_dnode_get(
running_config->dnode,
"/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
old_vrf_name);
if (ripng_dnode) {
+ yang_dnode_get_path(ripng_dnode->parent, oldpath,
+ sizeof(oldpath));
yang_dnode_change_leaf(ripng_dnode, vrf->name);
+ yang_dnode_get_path(ripng_dnode->parent, newpath,
+ sizeof(newpath));
+ nb_running_move_tree(oldpath, newpath);
running_config->version++;
}
}
diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h
index 8eba57f4dd..0bd47454a9 100644
--- a/sharpd/sharp_globals.h
+++ b/sharpd/sharp_globals.h
@@ -31,6 +31,7 @@ struct sharp_routes {
/* The nexthop info we are using for installation */
struct nexthop nhop;
struct nexthop backup_nhop;
+ uint32_t nhgid;
struct nexthop_group nhop_group;
struct nexthop_group backup_nhop_group;
diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c
index ccf34b10dd..4cd92c7f3d 100644
--- a/sharpd/sharp_main.c
+++ b/sharpd/sharp_main.c
@@ -47,6 +47,7 @@
#include "sharp_zebra.h"
#include "sharp_vty.h"
#include "sharp_globals.h"
+#include "sharp_nht.h"
DEFINE_MGROUP(SHARPD, "sharpd")
@@ -164,7 +165,7 @@ int main(int argc, char **argv, char **envp)
sharp_global_init();
- nexthop_group_init(NULL, NULL, NULL, NULL);
+ sharp_nhgroup_init();
vrf_init(NULL, NULL, NULL, NULL, NULL);
sharp_zebra_init();
diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c
index 174f186863..7484dd3b06 100644
--- a/sharpd/sharp_nht.c
+++ b/sharpd/sharp_nht.c
@@ -25,11 +25,15 @@
#include "nexthop.h"
#include "nexthop_group.h"
#include "vty.h"
+#include "typesafe.h"
+#include "zclient.h"
#include "sharp_nht.h"
#include "sharp_globals.h"
+#include "sharp_zebra.h"
DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker")
+DEFINE_MTYPE_STATIC(SHARPD, NHG, "Nexthop Group")
struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p)
{
@@ -65,3 +69,157 @@ void sharp_nh_tracker_dump(struct vty *vty)
nht->updates);
}
}
+
+PREDECL_RBTREE_UNIQ(sharp_nhg_rb);
+
+struct sharp_nhg {
+ struct sharp_nhg_rb_item mylistitem;
+
+ uint32_t id;
+
+ char name[256];
+
+ bool installed;
+};
+
+static uint32_t nhg_id;
+
+static uint32_t sharp_get_next_nhid(void)
+{
+ zlog_debug("NHG ID assigned: %u", nhg_id);
+ return nhg_id++;
+}
+
+struct sharp_nhg_rb_head nhg_head;
+
+static int sharp_nhg_compare_func(const struct sharp_nhg *a,
+ const struct sharp_nhg *b)
+{
+ return strncmp(a->name, b->name, strlen(a->name));
+}
+
+DECLARE_RBTREE_UNIQ(sharp_nhg_rb, struct sharp_nhg, mylistitem,
+ sharp_nhg_compare_func);
+
+static struct sharp_nhg *sharp_nhgroup_find_id(uint32_t id)
+{
+ struct sharp_nhg *lookup;
+
+ /* Yea its just a for loop, I don't want add complexity
+ * to sharpd with another RB tree for just IDs
+ */
+
+ frr_each (sharp_nhg_rb, &nhg_head, lookup) {
+ if (lookup->id == id)
+ return lookup;
+ }
+
+ return NULL;
+}
+
+static void sharp_nhgroup_add_cb(const char *name)
+{
+ struct sharp_nhg *snhg;
+
+ snhg = XCALLOC(MTYPE_NHG, sizeof(*snhg));
+ snhg->id = sharp_get_next_nhid();
+ strlcpy(snhg->name, name, sizeof(snhg->name));
+
+ sharp_nhg_rb_add(&nhg_head, snhg);
+}
+
+static void sharp_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
+ const struct nexthop *nhop)
+{
+ struct sharp_nhg lookup;
+ struct sharp_nhg *snhg;
+ struct nexthop_group_cmd *bnhgc = NULL;
+
+ strlcpy(lookup.name, nhgc->name, sizeof(lookup.name));
+ snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
+
+ if (nhgc->backup_list_name[0])
+ bnhgc = nhgc_find(nhgc->backup_list_name);
+
+ nhg_add(snhg->id, &nhgc->nhg, (bnhgc ? &bnhgc->nhg : NULL));
+}
+
+static void sharp_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
+ const struct nexthop *nhop)
+{
+ struct sharp_nhg lookup;
+ struct sharp_nhg *snhg;
+ struct nexthop_group_cmd *bnhgc = NULL;
+
+ strlcpy(lookup.name, nhgc->name, sizeof(lookup.name));
+ snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
+
+ if (nhgc->backup_list_name[0])
+ bnhgc = nhgc_find(nhgc->backup_list_name);
+
+ nhg_add(snhg->id, &nhgc->nhg, (bnhgc ? &bnhgc->nhg : NULL));
+}
+
+static void sharp_nhgroup_delete_cb(const char *name)
+{
+ struct sharp_nhg lookup;
+ struct sharp_nhg *snhg;
+
+ strlcpy(lookup.name, name, sizeof(lookup.name));
+ snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
+ if (!snhg)
+ return;
+
+ nhg_del(snhg->id);
+ sharp_nhg_rb_del(&nhg_head, snhg);
+ XFREE(MTYPE_NHG, snhg);
+}
+
+uint32_t sharp_nhgroup_get_id(const char *name)
+{
+ struct sharp_nhg lookup;
+ struct sharp_nhg *snhg;
+
+ strlcpy(lookup.name, name, sizeof(lookup.name));
+ snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
+ if (!snhg)
+ return 0;
+
+ return snhg->id;
+}
+
+void sharp_nhgroup_id_set_installed(uint32_t id, bool installed)
+{
+ struct sharp_nhg *snhg;
+
+ snhg = sharp_nhgroup_find_id(id);
+ if (!snhg) {
+ zlog_debug("%s: nhg %u not found", __func__, id);
+ return;
+ }
+
+ snhg->installed = installed;
+}
+
+bool sharp_nhgroup_id_is_installed(uint32_t id)
+{
+ struct sharp_nhg *snhg;
+
+ snhg = sharp_nhgroup_find_id(id);
+ if (!snhg) {
+ zlog_debug("%s: nhg %u not found", __func__, id);
+ return false;
+ }
+
+ return snhg->installed;
+}
+
+void sharp_nhgroup_init(void)
+{
+ sharp_nhg_rb_init(&nhg_head);
+ nhg_id = zclient_get_nhg_start(ZEBRA_ROUTE_SHARP);
+
+ nexthop_group_init(sharp_nhgroup_add_cb, sharp_nhgroup_add_nexthop_cb,
+ sharp_nhgroup_del_nexthop_cb,
+ sharp_nhgroup_delete_cb);
+}
diff --git a/sharpd/sharp_nht.h b/sharpd/sharp_nht.h
index 0b00774a81..da33502878 100644
--- a/sharpd/sharp_nht.h
+++ b/sharpd/sharp_nht.h
@@ -35,4 +35,10 @@ struct sharp_nh_tracker {
extern struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p);
extern void sharp_nh_tracker_dump(struct vty *vty);
+
+extern uint32_t sharp_nhgroup_get_id(const char *name);
+extern void sharp_nhgroup_id_set_installed(uint32_t id, bool installed);
+extern bool sharp_nhgroup_id_is_installed(uint32_t id);
+
+extern void sharp_nhgroup_init(void);
#endif
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index d390ea8192..d062f027ab 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -192,6 +192,7 @@ DEFPY (install_routes,
struct vrf *vrf;
struct prefix prefix;
uint32_t rts;
+ uint32_t nhgid = 0;
sg.r.total_routes = routes;
sg.r.installed_routes = 0;
@@ -244,6 +245,8 @@ DEFPY (install_routes,
return CMD_WARNING;
}
+ nhgid = sharp_nhgroup_get_id(nexthop_group);
+ sg.r.nhgid = nhgid;
sg.r.nhop_group.nexthop = nhgc->nhg.nexthop;
/* Use group's backup nexthop info if present */
@@ -296,7 +299,7 @@ DEFPY (install_routes,
sg.r.inst = instance;
sg.r.vrf_id = vrf->vrf_id;
rts = routes;
- sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst,
+ sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst, nhgid,
&sg.r.nhop_group, &sg.r.backup_nhop_group,
rts);
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index 08f5a07b7e..d167e8e277 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -217,7 +217,7 @@ int sharp_install_lsps_helper(bool install_p, bool update_p,
}
void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
- uint8_t instance,
+ uint8_t instance, uint32_t nhgid,
const struct nexthop_group *nhg,
const struct nexthop_group *backup_nhg,
uint32_t routes)
@@ -239,7 +239,7 @@ void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
monotime(&sg.r.t_start);
for (i = 0; i < routes; i++) {
- route_add(p, vrf_id, (uint8_t)instance, nhg, backup_nhg);
+ route_add(p, vrf_id, (uint8_t)instance, nhgid, nhg, backup_nhg);
if (v4)
p->u.prefix4.s_addr = htonl(++temp);
else
@@ -288,7 +288,7 @@ static void handle_repeated(bool installed)
if (!installed) {
sg.r.installed_routes = 0;
sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
- &sg.r.nhop_group,
+ sg.r.nhgid, &sg.r.nhop_group,
&sg.r.backup_nhop_group,
sg.r.total_routes);
}
@@ -357,8 +357,58 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label)
zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP);
}
-void route_add(const struct prefix *p, vrf_id_t vrf_id,
- uint8_t instance, const struct nexthop_group *nhg,
+void nhg_add(uint32_t id, const struct nexthop_group *nhg,
+ const struct nexthop_group *backup_nhg)
+{
+ struct zapi_nhg api_nhg = {};
+ struct zapi_nexthop *api_nh;
+ struct nexthop *nh;
+
+ api_nhg.id = id;
+ for (ALL_NEXTHOPS_PTR(nhg, nh)) {
+ if (api_nhg.nexthop_num >= MULTIPATH_NUM) {
+ zlog_warn(
+ "%s: number of nexthops greater than max multipath size, truncating",
+ __func__);
+ break;
+ }
+
+ api_nh = &api_nhg.nexthops[api_nhg.nexthop_num];
+
+ zapi_nexthop_from_nexthop(api_nh, nh);
+ api_nhg.nexthop_num++;
+ }
+
+ if (backup_nhg) {
+ for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
+ if (api_nhg.backup_nexthop_num >= MULTIPATH_NUM) {
+ zlog_warn(
+ "%s: number of backup nexthops greater than max multipath size, truncating",
+ __func__);
+ break;
+ }
+ api_nh = &api_nhg.backup_nexthops
+ [api_nhg.backup_nexthop_num];
+
+ zapi_backup_nexthop_from_nexthop(api_nh, nh);
+ api_nhg.backup_nexthop_num++;
+ }
+ }
+
+ zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg);
+}
+
+void nhg_del(uint32_t id)
+{
+ struct zapi_nhg api_nhg = {};
+
+ api_nhg.id = id;
+
+ zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg);
+}
+
+void route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance,
+ uint32_t nhgid, const struct nexthop_group *nhg,
const struct nexthop_group *backup_nhg)
{
struct zapi_route api;
@@ -376,14 +426,20 @@ void route_add(const struct prefix *p, vrf_id_t vrf_id,
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- for (ALL_NEXTHOPS_PTR(nhg, nh)) {
- api_nh = &api.nexthops[i];
+ /* Only send via ID if nhgroup has been successfully installed */
+ if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_NHG);
+ api.nhgid = nhgid;
+ } else {
+ for (ALL_NEXTHOPS_PTR(nhg, nh)) {
+ api_nh = &api.nexthops[i];
- zapi_nexthop_from_nexthop(api_nh, nh);
+ zapi_nexthop_from_nexthop(api_nh, nh);
- i++;
+ i++;
+ }
+ api.nexthop_num = i;
}
- api.nexthop_num = i;
/* Include backup nexthops, if present */
if (backup_nhg && backup_nhg->nexthop) {
@@ -668,6 +724,33 @@ void sharp_zebra_send_arp(const struct interface *ifp, const struct prefix *p)
zclient_send_neigh_discovery_req(zclient, ifp, p);
}
+static int nhg_notify_owner(ZAPI_CALLBACK_ARGS)
+{
+ enum zapi_nhg_notify_owner note;
+ uint32_t id;
+
+ if (!zapi_nhg_notify_decode(zclient->ibuf, &id, &note))
+ return -1;
+
+ switch (note) {
+ case ZAPI_NHG_INSTALLED:
+ sharp_nhgroup_id_set_installed(id, true);
+ zlog_debug("Installed nhg %u", id);
+ break;
+ case ZAPI_NHG_FAIL_INSTALL:
+ zlog_debug("Failed install of nhg %u", id);
+ break;
+ case ZAPI_NHG_REMOVED:
+ zlog_debug("Removed nhg %u", id);
+ break;
+ case ZAPI_NHG_REMOVE_FAIL:
+ zlog_debug("Failed removal of nhg %u", id);
+ break;
+ }
+
+ return 0;
+}
+
void sharp_zebra_init(void)
{
struct zclient_options opt = {.receive_notify = true};
@@ -684,6 +767,7 @@ void sharp_zebra_init(void)
zclient->route_notify_owner = route_notify_owner;
zclient->nexthop_update = sharp_nexthop_update;
zclient->import_check_update = sharp_nexthop_update;
+ zclient->nhg_notify_owner = nhg_notify_owner;
zclient->redistribute_route_add = sharp_redistribute_route;
zclient->redistribute_route_del = sharp_redistribute_route;
diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h
index 0a44fa694f..4a767ababf 100644
--- a/sharpd/sharp_zebra.h
+++ b/sharpd/sharp_zebra.h
@@ -29,15 +29,18 @@ int sharp_zclient_create(uint32_t session_id);
int sharp_zclient_delete(uint32_t session_id);
extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
+extern void nhg_add(uint32_t id, const struct nexthop_group *nhg,
+ const struct nexthop_group *backup_nhg);
+extern void nhg_del(uint32_t id);
extern void route_add(const struct prefix *p, vrf_id_t, uint8_t instance,
- const struct nexthop_group *nhg,
+ uint32_t nhgid, const struct nexthop_group *nhg,
const struct nexthop_group *backup_nhg);
extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance);
extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id,
bool import, bool watch, bool connected);
extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
- uint8_t instance,
+ uint8_t instance, uint32_t nhgid,
const struct nexthop_group *nhg,
const struct nexthop_group *backup_nhg,
uint32_t routes);
diff --git a/tests/subdir.am b/tests/subdir.am
index 2cdb214f0b..d7318efc72 100644
--- a/tests/subdir.am
+++ b/tests/subdir.am
@@ -12,8 +12,10 @@ TESTS_BGPD = \
tests/bgpd/test_mp_attr \
tests/bgpd/test_mpath \
tests/bgpd/test_bgp_table
+IGNORE_BGPD =
else
TESTS_BGPD =
+IGNORE_BGPD = --ignore=bgpd/
endif
if ISISD
@@ -23,16 +25,20 @@ TESTS_ISISD = \
tests/isisd/test_isis_spf \
tests/isisd/test_isis_vertex_queue \
# end
+IGNORE_ISISD =
else
TESTS_ISISD =
+IGNORE_ISISD = --ignore=isisd/
endif
if OSPF6D
TESTS_OSPF6D = \
tests/ospf6d/test_lsdb \
# end
+IGNORE_OSPF6D =
else
TESTS_OSPF6D =
+IGNORE_OSPF6D = --ignore=ospf6d/
endif
clippy_scan += \
@@ -368,7 +374,7 @@ EXTRA_DIST += \
.PHONY: tests/tests.xml
tests/tests.xml: $(check_PROGRAMS)
- ( cd tests; $(PYTHON) ../$(srcdir)/tests/runtests.py --junitxml=tests.xml -v ../$(srcdir)/tests; )
+ ( cd tests; $(PYTHON) ../$(srcdir)/tests/runtests.py --junitxml=tests.xml -v ../$(srcdir)/tests $(IGNORE_BGPD) $(IGNORE_ISISD) $(IGNORE_OSPF6D); )
check: tests/tests.xml
clean-local: clean-tests
diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
index 2a00398e28..32b219283b 100755..100644
--- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
+++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
@@ -113,8 +113,8 @@ def setup_module(module):
net['r%s' % i].loadConf('ospfd', '%s/r%s/ospfd.conf' % (thisDir, i))
if net['r1'].checkRouterVersion('<', '4.0'):
net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf-pre-v4' % (thisDir, i))
- else:
- net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i))
+ else:
+ net['r%s' % i].loadConf('ospf6d', '%s/r%s/ospf6d.conf' % (thisDir, i))
net['r%s' % i].loadConf('isisd', '%s/r%s/isisd.conf' % (thisDir, i))
net['r%s' % i].loadConf('bgpd', '%s/r%s/bgpd.conf' % (thisDir, i))
if net['r%s' % i].daemon_available('ldpd'):
@@ -374,26 +374,36 @@ def route_get_nhg_id(route_str):
nhg_id = int(match.group(1))
return nhg_id
-def verify_nexthop_group(nhg_id, recursive=False):
+def verify_nexthop_group(nhg_id, recursive=False, ecmp=0):
# Verify NHG is valid/installed
output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id)
match = re.search(r"Valid", output)
assert match is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id
- # If recursive, we need to look at its resolved group
- if recursive:
- match = re.search(r"Depends: \((\d+)\)", output)
- resolved_id = int(match.group(1))
- verify_nexthop_group(resolved_id, False)
+ if ecmp or recursive:
+ match = re.search(r"Depends:.*\n", output)
+ assert match is not None, "Nexthop Group ID=%d has no depends" % nhg_id
+
+ # list of IDs in group
+ depends = re.findall(r"\((\d+)\)", match.group(0))
+
+ if ecmp:
+ assert (len(depends) == ecmp), "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id
+ else:
+ # If recursive, we need to look at its resolved group
+ assert (len(depends) == 1), "Nexthop Group ID=%d should only have one recursive depend" % nhg_id
+ resolved_id = int(depends[0])
+ verify_nexthop_group(resolved_id, False)
+
else:
match = re.search(r"Installed", output)
assert match is not None, "Nexthop Group ID=%d not marked Installed" % nhg_id
-def verify_route_nexthop_group(route_str, recursive=False):
+def verify_route_nexthop_group(route_str, recursive=False, ecmp=0):
# Verify route and that zebra created NHGs for and they are valid/installed
nhg_id = route_get_nhg_id(route_str)
- verify_nexthop_group(nhg_id, recursive)
+ verify_nexthop_group(nhg_id, recursive, ecmp)
def test_nexthop_groups():
global fatal_error
@@ -611,7 +621,7 @@ def test_ospfv2_interfaces():
actual = net['r%s' % i].cmd('vtysh -c "show ip ospf interface" 2> /dev/null').rstrip()
# Mask out Bandwidth portion. They may change..
actual = re.sub(r"BW [0-9]+ Mbit", "BW XX Mbit", actual)
- actual = re.sub(r"ifindex [0-9]", "ifindex X", actual)
+ actual = re.sub(r"ifindex [0-9]", "ifindex X", actual)
# Drop time in next due
actual = re.sub(r"Hello due in [0-9\.]+s", "Hello due in XX.XXXs", actual)
@@ -882,45 +892,45 @@ def test_bgp_ipv4():
print("******************************************\n")
diffresult = {}
for i in range(1, 2):
- success = 0
- for refTableFile in (glob.glob(
- '%s/r%s/show_bgp_ipv4*.ref' % (thisDir, i))):
- if os.path.isfile(refTableFile):
- # Read expected result from file
- expected = open(refTableFile).read().rstrip()
- # Fix newlines (make them all the same)
- expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
-
- # Actual output from router
- actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
- # Remove summary line (changed recently)
- actual = re.sub(r'Total number.*', '', actual)
- actual = re.sub(r'Displayed.*', '', actual)
- actual = actual.rstrip()
- # Fix newlines (make them all the same)
- actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
-
- # Generate Diff
- diff = topotest.get_textdiff(actual, expected,
- title1="actual SHOW BGP IPv4",
- title2="expected SHOW BGP IPv4")
-
- # Empty string if it matches, otherwise diff contains unified diff
- if diff:
- diffresult[refTableFile] = diff
- else:
- success = 1
- print("template %s matched: r%s ok" % (refTableFile, i))
- break
-
- if not success:
- resultstr = 'No template matched.\n'
- for f in diffresult.iterkeys():
- resultstr += (
- 'template %s: r%s failed SHOW BGP IPv4 check:\n%s\n'
- % (f, i, diffresult[f]))
- raise AssertionError(
- "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, resultstr))
+ success = 0
+ for refTableFile in (glob.glob(
+ '%s/r%s/show_bgp_ipv4*.ref' % (thisDir, i))):
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
+
+ # Actual output from router
+ actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv4" 2> /dev/null').rstrip()
+ # Remove summary line (changed recently)
+ actual = re.sub(r'Total number.*', '', actual)
+ actual = re.sub(r'Displayed.*', '', actual)
+ actual = actual.rstrip()
+ # Fix newlines (make them all the same)
+ actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(actual, expected,
+ title1="actual SHOW BGP IPv4",
+ title2="expected SHOW BGP IPv4")
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ diffresult[refTableFile] = diff
+ else:
+ success = 1
+ print("template %s matched: r%s ok" % (refTableFile, i))
+ break
+
+ if not success:
+ resultstr = 'No template matched.\n'
+ for f in diffresult.iterkeys():
+ resultstr += (
+ 'template %s: r%s failed SHOW BGP IPv4 check:\n%s\n'
+ % (f, i, diffresult[f]))
+ raise AssertionError(
+ "SHOW BGP IPv4 failed for router r%s:\n%s" % (i, resultstr))
# Make sure that all daemons are running
for i in range(1, 2):
@@ -945,44 +955,44 @@ def test_bgp_ipv6():
print("******************************************\n")
diffresult = {}
for i in range(1, 2):
- success = 0
- for refTableFile in (glob.glob(
- '%s/r%s/show_bgp_ipv6*.ref' % (thisDir, i))):
- if os.path.isfile(refTableFile):
- # Read expected result from file
- expected = open(refTableFile).read().rstrip()
- # Fix newlines (make them all the same)
- expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
-
- # Actual output from router
- actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
- # Remove summary line (changed recently)
- actual = re.sub(r'Total number.*', '', actual)
- actual = re.sub(r'Displayed.*', '', actual)
- actual = actual.rstrip()
- # Fix newlines (make them all the same)
- actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
-
- # Generate Diff
- diff = topotest.get_textdiff(actual, expected,
- title1="actual SHOW BGP IPv6",
- title2="expected SHOW BGP IPv6")
-
- # Empty string if it matches, otherwise diff contains unified diff
- if diff:
- diffresult[refTableFile] = diff
- else:
- success = 1
- print("template %s matched: r%s ok" % (refTableFile, i))
-
- if not success:
- resultstr = 'No template matched.\n'
- for f in diffresult.iterkeys():
- resultstr += (
- 'template %s: r%s failed SHOW BGP IPv6 check:\n%s\n'
- % (f, i, diffresult[f]))
- raise AssertionError(
- "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, resultstr))
+ success = 0
+ for refTableFile in (glob.glob(
+ '%s/r%s/show_bgp_ipv6*.ref' % (thisDir, i))):
+ if os.path.isfile(refTableFile):
+ # Read expected result from file
+ expected = open(refTableFile).read().rstrip()
+ # Fix newlines (make them all the same)
+ expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
+
+ # Actual output from router
+ actual = net['r%s' % i].cmd('vtysh -c "show bgp ipv6" 2> /dev/null').rstrip()
+ # Remove summary line (changed recently)
+ actual = re.sub(r'Total number.*', '', actual)
+ actual = re.sub(r'Displayed.*', '', actual)
+ actual = actual.rstrip()
+ # Fix newlines (make them all the same)
+ actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(actual, expected,
+ title1="actual SHOW BGP IPv6",
+ title2="expected SHOW BGP IPv6")
+
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ diffresult[refTableFile] = diff
+ else:
+ success = 1
+ print("template %s matched: r%s ok" % (refTableFile, i))
+
+ if not success:
+ resultstr = 'No template matched.\n'
+ for f in diffresult.iterkeys():
+ resultstr += (
+ 'template %s: r%s failed SHOW BGP IPv6 check:\n%s\n'
+ % (f, i, diffresult[f]))
+ raise AssertionError(
+ "SHOW BGP IPv6 failed for router r%s:\n%s" % (i, resultstr))
# Make sure that all daemons are running
for i in range(1, 2):
@@ -1101,6 +1111,34 @@ def test_nexthop_groups_with_route_maps():
net["r1"].cmd('vtysh -c "c t" -c "no route-map NOPE"')
net["r1"].cmd('vtysh -c "c t" -c "no ip prefix-list NOPE seq 5 permit %s/32"' % permit_route_str)
+def test_nexthop_group_replace():
+ global fatal_error
+ global net
+
+ # Skip if previous fatal error condition is raised
+ if (fatal_error != ""):
+ pytest.skip(fatal_error)
+
+ print("\n\n** Verifying Nexthop Groups")
+ print("******************************************\n")
+
+ ### Nexthop Group Tests
+
+ ## 2-Way ECMP Directly Connected
+
+ net["r1"].cmd('vtysh -c "c t" -c "nexthop-group replace" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"')
+
+ # Create with sharpd using nexthop-group
+ net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
+
+ verify_route_nexthop_group("3.3.3.1/32")
+
+ # Change the nexthop group
+ net["r1"].cmd('vtysh -c "c t" -c "nexthop-group replace" -c "no nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.3 r1-eth1 onlink" -c "nexthop 1.1.1.4 r1-eth4 onlink"')
+
+ # Verify it updated. We can just check install and ecmp count here.
+ verify_route_nexthop_group("3.3.3.1/32", False, 3)
+
def test_mpls_interfaces():
global fatal_error
global net
diff --git a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
index 41fa7c0a09..41fa7c0a09 100755..100644
--- a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
+++ b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
index ee50a422a7..9af22c06bd 100644
--- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
+++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
@@ -477,9 +477,9 @@ def check_es(dut):
vtep_ips.append(vtep["vtep_ip"])
if "local" in types:
- result = check_local_es(esi, vtep_ips, dut.name, [])
+ result = check_local_es(esi, vtep_ips, dut.name, [])
else:
- result = check_remote_es(esi, vtep_ips, dut.name, [])
+ result = check_remote_es(esi, vtep_ips, dut.name, [])
if result:
return result
diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
index 607b036c6a..607b036c6a 100755..100644
--- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
+++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
diff --git a/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py b/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py
index 22952f645c..22952f645c 100755..100644
--- a/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py
+++ b/tests/topotests/bgp-prefix-list-topo1/test_prefix_lists.py
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 1aa951edaa..1aa951edaa 100755..100644
--- a/tests/topotests/bgp-route-map/test_route_map_topo1.py
+++ b/tests/topotests/bgp-route-map/test_route_map_topo1.py
diff --git a/tests/topotests/bgp-route-map/test_route_map_topo2.py b/tests/topotests/bgp-route-map/test_route_map_topo2.py
index 3056aa29f3..3056aa29f3 100755..100644
--- a/tests/topotests/bgp-route-map/test_route_map_topo2.py
+++ b/tests/topotests/bgp-route-map/test_route_map_topo2.py
diff --git a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py
index f9d22a3a36..f9d22a3a36 100755..100644
--- a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py
+++ b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py
diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
index 3ad989c601..0d99f23ad9 100755..100644
--- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
+++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
@@ -143,7 +143,7 @@ def setup_module(mod):
logger.info('result: '+output);
router = tgen.gears['r1']
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
if rname == 'r1':
router.load_config(
TopoRouter.RD_ZEBRA,
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
index fdbd317093..fdbd317093 100755..100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
index e1ec0ea81b..e1ec0ea81b 100755..100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
index dc06b7131a..dc06b7131a 100755..100644
--- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
+++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
index bb88e47415..bb88e47415 100755..100644
--- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
+++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
index c15b88d371..c15b88d371 100755..100644
--- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
+++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
index bb13d54019..bb13d54019 100755..100644
--- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
+++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py
index 6344f7bb40..6344f7bb40 100755..100644
--- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py
+++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py
diff --git a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py
index fef6eb71dc..fef6eb71dc 100755..100644
--- a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py
+++ b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py
diff --git a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py
index 0fabd90341..0fabd90341 100755..100644
--- a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py
+++ b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py
index 1947548b3e..1947548b3e 100755..100644
--- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
index 6c106060b8..6c106060b8 100755..100644
--- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
index 70666a3d61..3ce1472ac0 100644
--- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
+++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
@@ -252,7 +252,7 @@ def ip_eigrp_topo(node):
if code not in ["P", "A", "U", "Q", "R", "r", "s"]:
continue
- if not result.has_key(code):
+ if code not in result:
result[code] = {}
# Split network from the rest
diff --git a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py
index e913105e43..e913105e43 100755..100644
--- a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py
+++ b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py
diff --git a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py
index 9e385823fc..c1eb7d68bb 100755..100644
--- a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py
+++ b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py
@@ -26,9 +26,9 @@ Following tests are covered to test EVPN-Type5 functionality:
1. RD verification (manual/auto).
2. RT verification(manual)
3. In an active/standby EVPN implementation, if active DCG goes down,
- secondary takes over.
+ secondary takes over.
4. EVPN routes are advertised/withdrawn, based on VNFs
- advertising/withdrawing IP prefixes.
+ advertising/withdrawing IP prefixes.
5. Route-map operations for EVPN address family.
6. BGP attributes for EVPN address-family.
"""
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
index 65515f22cc..7943b94189 100644
--- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
@@ -210,7 +210,7 @@ def test_isis_linux_route_installation():
dist = platform.dist()
if (dist[1] == "16.04"):
- pytest.skip("Kernel not supported for vrf")
+ pytest.skip("Kernel not supported for vrf")
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
@@ -267,7 +267,7 @@ def test_isis_linux_route6_installation():
dist = platform.dist()
if (dist[1] == "16.04"):
- pytest.skip("Kernel not supported for vrf")
+ pytest.skip("Kernel not supported for vrf")
"Check whether all expected routes are present and installed in the OS"
tgen = get_topogen()
diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py
index 31adeafbf6..31adeafbf6 100755..100644
--- a/tests/topotests/ldp-topo1/test_ldp_topo1.py
+++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index a3d846edbb..72b99eeba8 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -28,6 +28,7 @@ from lib import topotest
from lib.topolog import logger
from lib.topogen import TopoRouter, get_topogen
+from lib.topotest import frr_unicode
# Import common_config to use commomnly used APIs
from lib.common_config import (
@@ -393,7 +394,7 @@ def __create_bgp_unicast_neighbor(
# Generating IPs for verification
network_list = generate_ips(network, no_of_network)
for ip in network_list:
- ip = str(ipaddress.ip_network(unicode(ip)))
+ ip = str(ipaddress.ip_network(frr_unicode(ip)))
cmd = "network {}".format(ip)
if del_action:
@@ -1037,7 +1038,7 @@ def verify_router_id(tgen, topo, input_dict):
logger.info("Checking router %s router-id", router)
show_bgp_json = run_frr_cmd(rnode, "show bgp summary json", isjson=True)
router_id_out = show_bgp_json["ipv4Unicast"]["routerId"]
- router_id_out = ipaddress.IPv4Address(unicode(router_id_out))
+ router_id_out = ipaddress.IPv4Address(frr_unicode(router_id_out))
# Once router-id is deleted, highest interface ip should become
# router-id
@@ -1045,7 +1046,7 @@ def verify_router_id(tgen, topo, input_dict):
router_id = find_interface_with_greater_ip(topo, router)
else:
router_id = input_dict[router]["bgp"]["router_id"]
- router_id = ipaddress.IPv4Address(unicode(router_id))
+ router_id = ipaddress.IPv4Address(frr_unicode(router_id))
if router_id == router_id_out:
logger.info("Found expected router-id %s for router %s", router_id, router)
@@ -2286,7 +2287,7 @@ def verify_best_path_as_per_bgp_attribute(
routes = generate_ips(_network, no_of_ip)
for route in routes:
- route = str(ipaddress.ip_network(unicode(route)))
+ route = str(ipaddress.ip_network(frr_unicode(route)))
if route in sh_ip_bgp_json["routes"]:
route_attributes = sh_ip_bgp_json["routes"][route]
@@ -2604,7 +2605,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
ip_list = generate_ips(network, no_of_ip)
for st_rt in ip_list:
- st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+ st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
if _addr_type != addr_type:
@@ -2742,7 +2743,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
ip_list = generate_ips(network, no_of_network)
for st_rt in ip_list:
- st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+ st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
if _addr_type != addr_type:
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 6dd8d646f3..1fa6d35101 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -31,16 +31,14 @@ from re import search as re_search
from tempfile import mkdtemp
import os
+import io
import sys
-import ConfigParser
import traceback
import socket
import ipaddress
import platform
-
if sys.version_info[0] > 2:
- import io
import configparser
else:
import StringIO
@@ -48,7 +46,7 @@ else:
from lib.topolog import logger, logger_config
from lib.topogen import TopoRouter, get_topogen
-from lib.topotest import interface_set_status, version_cmp
+from lib.topotest import interface_set_status, version_cmp, frr_unicode
FRRCFG_FILE = "frr_json.conf"
FRRCFG_BKUP_FILE = "frr_json_initial.conf"
@@ -638,7 +636,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None):
ll_per_if_count = 0
# Interface ip
- m1 = re_search("inet6 (fe80[:a-fA-F0-9]+[\/0-9]+)", line)
+ m1 = re_search("inet6 (fe80[:a-fA-F0-9]+[/0-9]+)", line)
if m1:
local = m1.group(1)
ll_per_if_count += 1
@@ -700,18 +698,20 @@ def start_topology(tgen, daemon=None):
router_list = tgen.routers()
ROUTER_LIST = sorted(
- router_list.keys(), key=lambda x: int(re_search("\d+", x).group(0))
+ router_list.keys(), key=lambda x: int(re_search("[0-9]+", x).group(0))
)
TMPDIR = os.path.join(LOGDIR, tgen.modname)
+ linux_ver = ''
router_list = tgen.routers()
for rname in ROUTER_LIST:
router = router_list[rname]
# It will help in debugging the failures, will give more details on which
# specific kernel version tests are failing
- linux_ver = router.run("uname -a")
- logger.info("Logging platform related details: \n %s \n", linux_ver)
+ if linux_ver == '':
+ linux_ver = router.run("uname -a")
+ logger.info("Logging platform related details: \n %s \n", linux_ver)
try:
os.chdir(TMPDIR)
@@ -827,7 +827,7 @@ def topo_daemons(tgen, topo):
router_list = tgen.routers()
ROUTER_LIST = sorted(
- router_list.keys(), key=lambda x: int(re_search("\d+", x).group(0))
+ router_list.keys(), key=lambda x: int(re_search("[0-9]+", x).group(0))
)
for rtr in ROUTER_LIST:
@@ -1152,10 +1152,10 @@ def generate_ips(network, no_of_ips):
addr_type = validate_ip_address(start_ip)
if addr_type == "ipv4":
- start_ip = ipaddress.IPv4Address(unicode(start_ip))
+ start_ip = ipaddress.IPv4Address(frr_unicode(start_ip))
step = 2 ** (32 - mask)
if addr_type == "ipv6":
- start_ip = ipaddress.IPv6Address(unicode(start_ip))
+ start_ip = ipaddress.IPv6Address(frr_unicode(start_ip))
step = 2 ** (128 - mask)
next_ip = start_ip
@@ -2667,7 +2667,7 @@ def verify_rib(
nh_found = False
for st_rt in ip_list:
- st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+ st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
if _addr_type != addr_type:
@@ -2863,7 +2863,7 @@ def verify_rib(
nh_found = False
for st_rt in ip_list:
- st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+ st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
if _addr_type != addr_type:
@@ -3012,7 +3012,7 @@ def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
nh_found = False
for st_rt in ip_list:
- st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+ st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
#st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
@@ -3119,7 +3119,7 @@ def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
for st_rt in ip_list:
#st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
- st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+ st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
if _addr_type != addr_type:
@@ -3268,7 +3268,7 @@ def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
nh_found = False
for st_rt in ip_list:
- st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+ st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
if _addr_type != addr_type:
@@ -3373,7 +3373,7 @@ def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
nh_found = False
for st_rt in ip_list:
- st_rt = str(ipaddress.ip_network(unicode(st_rt)))
+ st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
if _addr_type != addr_type:
diff --git a/tests/topotests/lib/ltemplate.py b/tests/topotests/lib/ltemplate.py
index 192c121008..3c93e1ac5c 100644
--- a/tests/topotests/lib/ltemplate.py
+++ b/tests/topotests/lib/ltemplate.py
@@ -157,8 +157,8 @@ def ltemplateTest(script, SkipIfFailed=True, CallOnFail=None, CheckFuncStr=None,
if SkipIfFailed and tgen.routers_have_failure():
pytest.skip(tgen.errors)
if numEntry > 0:
- if not KeepGoing:
- pytest.skip("Have %d errors" % numEntry)
+ if not KeepGoing:
+ pytest.skip("Have %d errors" % numEntry)
if CheckFuncStr != None:
check = eval(CheckFuncStr)
@@ -172,8 +172,8 @@ def ltemplateTest(script, SkipIfFailed=True, CallOnFail=None, CheckFuncStr=None,
if numFail > 0:
luShowFail()
fatal_error = "%d tests failed" % numFail
- if not KeepGoing:
- assert "scripts/cleanup_all.py failed" == "See summary output above", fatal_error
+ if not KeepGoing:
+ assert "scripts/cleanup_all.py failed" == "See summary output above", fatal_error
# Memory leak test template
def test_memory_leak():
diff --git a/tests/topotests/lib/lutil.py b/tests/topotests/lib/lutil.py
index 4ea97a3692..05ed9c007d 100755..100644
--- a/tests/topotests/lib/lutil.py
+++ b/tests/topotests/lib/lutil.py
@@ -204,17 +204,17 @@ Total %-4d %-4d %d\n\
self.log('WARNING: JSON load failed -- confirm command output is in JSON format.')
self.log('COMMAND OUTPUT:%s:' % report)
- # Experiment: can we achieve the same match behavior via DOTALL
- # without converting newlines to spaces?
- out_nl = out
- search_nl = re.search(regexp, out_nl, re.DOTALL);
- self.l_last_nl = search_nl
- # Set up for comparison
- if search_nl != None:
- group_nl = search_nl.group()
- group_nl_converted = " ".join(group_nl.splitlines())
+ # Experiment: can we achieve the same match behavior via DOTALL
+ # without converting newlines to spaces?
+ out_nl = out
+ search_nl = re.search(regexp, out_nl, re.DOTALL);
+ self.l_last_nl = search_nl
+ # Set up for comparison
+ if search_nl != None:
+ group_nl = search_nl.group()
+ group_nl_converted = " ".join(group_nl.splitlines())
else:
- group_nl_converted = None
+ group_nl_converted = None
out = " ".join(out.splitlines())
search = re.search(regexp, out)
@@ -234,9 +234,9 @@ Total %-4d %-4d %d\n\
success = False
level = 5
self.log('found:%s:' % ret, level)
- # Experiment: compare matched strings obtained each way
- if self.l_dotall_experiment and (group_nl_converted != ret):
- self.log('DOTALL experiment: strings differ dotall=[%s] orig=[%s]' % (group_nl_converted, ret), 9)
+ # Experiment: compare matched strings obtained each way
+ if self.l_dotall_experiment and (group_nl_converted != ret):
+ self.log('DOTALL experiment: strings differ dotall=[%s] orig=[%s]' % (group_nl_converted, ret), 9)
if op == 'pass' or op == 'fail':
self.result(target, success, result)
if js != None:
@@ -297,13 +297,13 @@ def luCommand(target, command, regexp='.', op='none', result='', time=10, return
def luLast(usenl=False):
if usenl:
- if LUtil.l_last_nl != None:
- LUtil.log('luLast:%s:' % LUtil.l_last_nl.group(), 7)
- return LUtil.l_last_nl
+ if LUtil.l_last_nl != None:
+ LUtil.log('luLast:%s:' % LUtil.l_last_nl.group(), 7)
+ return LUtil.l_last_nl
else:
- if LUtil.l_last != None:
- LUtil.log('luLast:%s:' % LUtil.l_last.group(), 7)
- return LUtil.l_last
+ if LUtil.l_last != None:
+ LUtil.log('luLast:%s:' % LUtil.l_last.group(), 7)
+ return LUtil.l_last
def luInclude(filename, CallOnFail=None):
tstFile = LUtil.base_script_dir + '/' + filename
diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py
index a2351bf747..9d6b8fa691 100644
--- a/tests/topotests/lib/ospf.py
+++ b/tests/topotests/lib/ospf.py
@@ -23,7 +23,7 @@ import traceback
from time import sleep
from lib.topolog import logger
import ipaddr
-
+from lib.topotest import frr_unicode
# Import common_config to use commomnly used APIs
from lib.common_config import (create_common_configuration,
@@ -516,7 +516,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
logger.debug("Entering lib API: verify_ospf_neighbor()")
result = False
if input_dict:
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if 'ospf' not in topo['routers'][router]:
continue
@@ -584,7 +584,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
return errormsg
continue
else:
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if 'ospf' not in topo['routers'][router]:
continue
@@ -694,7 +694,7 @@ def verify_ospf_rib(tgen, dut, input_dict, next_hop=None,
additional_nexthops_in_required_nhs = []
found_hops = []
for routerInput in input_dict.keys():
- for router, rnode in router_list.iteritems():
+ for router, rnode in router_list.items():
if router != dut:
continue
@@ -739,7 +739,7 @@ def verify_ospf_rib(tgen, dut, input_dict, next_hop=None,
nh_found = False
for st_rt in ip_list:
- st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
+ st_rt = str(ipaddr.IPNetwork(frr_unicode(st_rt)))
_addr_type = validate_ip_address(st_rt)
if _addr_type != 'ipv4':
@@ -927,7 +927,7 @@ def verify_ospf_interface(tgen, topo, dut=None,lan=False, input_dict=None):
logger.debug("Entering lib API: verify_ospf_interface()")
result = False
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if 'ospf' not in topo['routers'][router]:
continue
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index 171a894b35..ffdcb683e7 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -40,6 +40,7 @@ Basic usage instructions:
import os
import sys
+import io
import logging
import json
@@ -97,7 +98,7 @@ tgen_defaults = {
"verbosity": "info",
"frrdir": "/usr/lib/frr",
"routertype": "frr",
- "memleak_path": None,
+ "memleak_path": "",
}
@@ -182,7 +183,7 @@ class Topogen(object):
params["frrdir"] = self.config.get(self.CONFIG_SECTION, "frrdir")
params["memleak_path"] = self.config.get(self.CONFIG_SECTION, "memleak_path")
- if not params.has_key("routertype"):
+ if "routertype" not in params:
params["routertype"] = self.config.get(self.CONFIG_SECTION, "routertype")
self.gears[name] = TopoRouter(self, cls, name, **params)
@@ -360,7 +361,7 @@ class Topogen(object):
memleak_file = os.environ.get("TOPOTESTS_CHECK_MEMLEAK") or self.config.get(
self.CONFIG_SECTION, "memleak_path"
)
- if memleak_file is None:
+ if memleak_file == "" or memleak_file == None:
return False
return True
@@ -586,7 +587,7 @@ class TopoRouter(TopoGear):
self.cls = cls
self.options = {}
self.routertype = params.get("routertype", "frr")
- if not params.has_key("privateDirs"):
+ if "privateDirs" not in params:
params["privateDirs"] = self.PRIVATE_DIRS
self.options["memleak_path"] = params.get("memleak_path", None)
@@ -822,7 +823,7 @@ class TopoRouter(TopoGear):
memleak_file = (
os.environ.get("TOPOTESTS_CHECK_MEMLEAK") or self.options["memleak_path"]
)
- if memleak_file is None:
+ if memleak_file == "" or memleak_file == None:
return
self.stop()
@@ -1011,7 +1012,7 @@ def diagnose_env_linux():
logger.info("Running environment diagnostics")
# Load configuration
- config = configparser.ConfigParser(tgen_defaults)
+ config = configparser.ConfigParser(defaults=tgen_defaults)
pytestini_path = os.path.join(CWD, "../pytest.ini")
config.read(pytestini_path)
@@ -1106,10 +1107,10 @@ def diagnose_env_linux():
# TODO remove me when we start supporting exabgp >= 4
try:
- output = subprocess.check_output(["exabgp", "-v"])
- line = output.split("\n")[0]
- version = line.split(" ")[2]
- if topotest.version_cmp(version, "4") >= 0:
+ p = os.popen("exabgp -v")
+ line = p.readlines()
+ version = line[0].split()
+ if topotest.version_cmp(version[2], "4") >= 0:
logger.warning(
"BGP topologies are still using exabgp version 3, expect failures"
)
diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py
index b3af09aa99..6535918e36 100644
--- a/tests/topotests/lib/topojson.py
+++ b/tests/topotests/lib/topojson.py
@@ -216,7 +216,7 @@ def build_topo_from_json(tgen, topo):
# Physical Interfaces
if "links" in topo['switches'][curSwitch]:
for destRouterLink, data in sorted(
- topo['switches'][curSwitch]['links'].iteritems()):
+ topo['switches'][curSwitch]['links'].items()):
# Loopback interfaces
if "dst_node" in data:
diff --git a/tests/topotests/lib/topolog.py b/tests/topotests/lib/topolog.py
index 0dfa870930..9fde01cca0 100644
--- a/tests/topotests/lib/topolog.py
+++ b/tests/topotests/lib/topolog.py
@@ -93,7 +93,7 @@ class Logger(object):
"""
if log_level is None:
log_level = self.log_level
- if self.loggers.has_key(name):
+ if name in self.loggers:
return self.loggers[name]
nlogger = logging.Logger(name, level=log_level)
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 00bfac4103..a187971e41 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -992,11 +992,11 @@ class Router(Node):
# Backward compatibility:
# Load configuration defaults like topogen.
self.config_defaults = configparser.ConfigParser(
- {
+ defaults = {
"verbosity": "info",
"frrdir": "/usr/lib/frr",
"routertype": "frr",
- "memleak_path": None,
+ "memleak_path": "",
}
)
self.config_defaults.read(
@@ -1525,7 +1525,7 @@ class Router(Node):
for daemon in self.daemons:
if (self.daemons[daemon] == 1) and not (daemon in daemonsRunning):
sys.stderr.write("%s: Daemon %s not running\n" % (self.name, daemon))
- if daemon is "staticd":
+ if daemon == "staticd":
sys.stderr.write(
"You may have a copy of staticd installed but are attempting to test against\n"
)
@@ -1591,7 +1591,7 @@ class Router(Node):
logger.info("{}: running version: {}".format(self.name, self.version))
rversion = self.version
- if rversion is None:
+ if rversion == None:
return False
result = version_cmp(rversion, version)
@@ -1737,3 +1737,10 @@ class LegacySwitch(OVSSwitch):
def __init__(self, name, **params):
OVSSwitch.__init__(self, name, failMode="standalone", **params)
self.switchIP = None
+
+def frr_unicode(s):
+ '''Convert string to unicode, depending on python version'''
+ if sys.version_info[0] > 2:
+ return s
+ else:
+ return unicode(s)
diff --git a/tests/topotests/ospf-topo2/test_ospf_topo2.py b/tests/topotests/ospf-topo2/test_ospf_topo2.py
index 0b6f568462..79e8e6bf58 100644
--- a/tests/topotests/ospf-topo2/test_ospf_topo2.py
+++ b/tests/topotests/ospf-topo2/test_ospf_topo2.py
@@ -86,19 +86,19 @@ def setup_module(mod):
os.path.join(CWD, '{}/ospfd.conf'.format(rname))
)
- # What is this? OSPF Unnumbered depends on the rp_filter
- # being set appropriately( HA! )
- # Effectively we are putting different /32's on the interface
- # the multicast packet delivery is somewhat controlled by
- # the rp_filter. Setting it to '0' allows the OS to pass
- # up the mcast packet not destined for the local routers
- # network.
- topotest.set_sysctl(tgen.net['r1'],
- 'net.ipv4.conf.r1-eth1.rp_filter', 0)
+ # What is this? OSPF Unnumbered depends on the rp_filter
+ # being set appropriately( HA! )
+ # Effectively we are putting different /32's on the interface
+ # the multicast packet delivery is somewhat controlled by
+ # the rp_filter. Setting it to '0' allows the OS to pass
+ # up the mcast packet not destined for the local routers
+ # network.
+ topotest.set_sysctl(tgen.net['r1'],
+ 'net.ipv4.conf.r1-eth1.rp_filter', 0)
topotest.set_sysctl(tgen.net['r1'],
'net.ipv4.conf.all.rp_filter', 0)
- topotest.set_sysctl(tgen.net['r2'],
- 'net.ipv4.conf.r2-eth1.rp_filter', 0)
+ topotest.set_sysctl(tgen.net['r2'],
+ 'net.ipv4.conf.r2-eth1.rp_filter', 0)
topotest.set_sysctl(tgen.net['r2'],
'net.ipv4.conf.all.rp_filter', 0)
diff --git a/tests/topotests/pbr-topo1/test_pbr_topo1.py b/tests/topotests/pbr-topo1/test_pbr_topo1.py
index 9ae4cce360..91979a8f04 100644
--- a/tests/topotests/pbr-topo1/test_pbr_topo1.py
+++ b/tests/topotests/pbr-topo1/test_pbr_topo1.py
@@ -88,8 +88,8 @@ def setup_module(module):
krel = platform.release()
if topotest.version_cmp(krel, "4.10") < 0:
- tgen.errors = "Newer kernel than 4.9 needed for pbr tests"
- pytest.skip(tgen.errors)
+ tgen.errors = "Newer kernel than 4.9 needed for pbr tests"
+ pytest.skip(tgen.errors)
router_list = tgen.routers()
for rname, router in router_list.items():
@@ -150,8 +150,8 @@ def test_pbr_data():
test_func = partial(topotest.router_json_cmp, router, "show pbr interface json", expected)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"show pbr interface" mismatches on {}'.format(router.name)
- if result is not None:
- gather_pbr_data_on_error(router)
+ if result is not None:
+ gather_pbr_data_on_error(router)
assert result is None, assertmsg
map_file = "{}/{}/pbr-map.json".format(CWD, router.name)
@@ -164,8 +164,8 @@ def test_pbr_data():
test_func = partial(topotest.router_json_cmp, router, "show pbr map json", expected)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"show pbr map" mismatches on {}'.format(router.name)
- if result is not None:
- gather_pbr_data_on_error(router)
+ if result is not None:
+ gather_pbr_data_on_error(router)
assert result is None, assertmsg
nexthop_file = "{}/{}/pbr-nexthop-groups.json".format(CWD, router.name)
@@ -178,8 +178,8 @@ def test_pbr_data():
test_func = partial(topotest.router_json_cmp, router, "show pbr nexthop-groups json", expected)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"show pbr nexthop-groups" mismatches on {}'.format(router.name)
- if result is not None:
- gather_pbr_data_on_error(router)
+ if result is not None:
+ gather_pbr_data_on_error(router)
assert result is None, assertmsg
def test_pbr_flap():
@@ -215,8 +215,8 @@ def test_pbr_flap():
test_func = partial(topotest.router_json_cmp, router, "show pbr interface json", expected)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assertmsg = '"show pbr interface" mismatches on {}'.format(router.name)
- if result is not None:
- gather_pbr_data_on_error(router)
+ if result is not None:
+ gather_pbr_data_on_error(router)
assert result is None, assertmsg
diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py
index 7ff18ba524..de11b78824 100755..100644
--- a/tests/topotests/rip-topo1/test_rip_topo1.py
+++ b/tests/topotests/rip-topo1/test_rip_topo1.py
@@ -91,11 +91,11 @@ class NetworkTopo(Topo):
switch[4] = self.addSwitch("sw4", cls=topotest.LegacySwitch)
self.addLink(switch[4], router[3], intfName2="r3-eth0")
- switch[5] = self.addSwitch("sw5", cls=topotest.LegacySwitch)
- self.addLink(switch[5], router[1], intfName2="r1-eth2")
+ switch[5] = self.addSwitch("sw5", cls=topotest.LegacySwitch)
+ self.addLink(switch[5], router[1], intfName2="r1-eth2")
- switch[6] = self.addSwitch("sw6", cls=topotest.LegacySwitch)
- self.addLink(switch[6], router[1], intfName2="r1-eth3")
+ switch[6] = self.addSwitch("sw6", cls=topotest.LegacySwitch)
+ self.addLink(switch[6], router[1], intfName2="r1-eth3")
#####################################################
diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py
index 2976cdefe4..2976cdefe4 100755..100644
--- a/tests/topotests/ripng-topo1/test_ripng_topo1.py
+++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 4edbb7a889..9993e73353 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1173,12 +1173,14 @@ static char **new_completion(const char *text, int start, int end)
}
/* Vty node structures. */
+#ifdef HAVE_BGPD
static struct cmd_node bgp_node = {
.name = "bgp",
.node = BGP_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-router)# ",
};
+#endif /* HAVE_BGPD */
static struct cmd_node rip_node = {
.name = "rip",
@@ -1187,19 +1189,23 @@ static struct cmd_node rip_node = {
.prompt = "%s(config-router)# ",
};
+#ifdef HAVE_ISISD
static struct cmd_node isis_node = {
.name = "isis",
.node = ISIS_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-router)# ",
};
+#endif /* HAVE_ISISD */
+#ifdef HAVE_FABRICD
static struct cmd_node openfabric_node = {
.name = "openfabric",
.node = OPENFABRIC_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-router)# ",
};
+#endif /* HAVE_FABRICD */
static struct cmd_node interface_node = {
.name = "interface",
@@ -1236,12 +1242,14 @@ static struct cmd_node rmap_node = {
.prompt = "%s(config-route-map)# ",
};
+#ifdef HAVE_PBRD
static struct cmd_node pbr_map_node = {
.name = "pbr-map",
.node = PBRMAP_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-pbr-map)# ",
};
+#endif /* HAVE_PBRD */
static struct cmd_node zebra_node = {
.name = "zebra",
@@ -1250,6 +1258,7 @@ static struct cmd_node zebra_node = {
.prompt = "%s(config-router)# ",
};
+#ifdef HAVE_BGPD
static struct cmd_node bgp_vpnv4_node = {
.name = "bgp vpnv4",
.node = BGP_VPNV4_NODE,
@@ -1334,6 +1343,7 @@ static struct cmd_node bgp_ipv6l_node = {
.prompt = "%s(config-router-af)# ",
};
+#ifdef ENABLE_BGP_VNC
static struct cmd_node bgp_vnc_defaults_node = {
.name = "bgp vnc defaults",
.node = BGP_VNC_DEFAULTS_NODE,
@@ -1361,6 +1371,7 @@ static struct cmd_node bgp_vnc_l2_group_node = {
.parent_node = BGP_NODE,
.prompt = "%s(config-router-vnc-l2-group)# ",
};
+#endif /* ENABLE_BGP_VNC */
static struct cmd_node bmp_node = {
.name = "bmp",
@@ -1368,27 +1379,34 @@ static struct cmd_node bmp_node = {
.parent_node = BGP_NODE,
.prompt = "%s(config-bgp-bmp)# "
};
+#endif /* HAVE_BGPD */
+#ifdef HAVE_OSPFD
static struct cmd_node ospf_node = {
.name = "ospf",
.node = OSPF_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-router)# ",
};
+#endif /* HAVE_OSPFD */
+#ifdef HAVE_EIGRPD
static struct cmd_node eigrp_node = {
.name = "eigrp",
.node = EIGRP_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-router)# ",
};
+#endif /* HAVE_EIGRPD */
+#ifdef HAVE_BABELD
static struct cmd_node babel_node = {
.name = "babel",
.node = BABEL_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-router)# ",
};
+#endif /* HAVE_BABELD */
static struct cmd_node ripng_node = {
.name = "ripng",
@@ -1397,13 +1415,16 @@ static struct cmd_node ripng_node = {
.prompt = "%s(config-router)# ",
};
+#ifdef HAVE_OSPF6D
static struct cmd_node ospf6_node = {
.name = "ospf6",
.node = OSPF6_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-ospf6)# ",
};
+#endif /* HAVE_OSPF6D */
+#ifdef HAVE_LDPD
static struct cmd_node ldp_node = {
.name = "ldp",
.node = LDP_NODE,
@@ -1452,6 +1473,7 @@ static struct cmd_node ldp_pseudowire_node = {
.parent_node = LDP_L2VPN_NODE,
.prompt = "%s(config-l2vpn-pw)# ",
};
+#endif /* HAVE_LDPD */
static struct cmd_node keychain_node = {
.name = "keychain",
@@ -1474,12 +1496,14 @@ struct cmd_node link_params_node = {
.prompt = "%s(config-link-params)# ",
};
+#ifdef HAVE_BGPD
static struct cmd_node rpki_node = {
.name = "rpki",
.node = RPKI_NODE,
.parent_node = CONFIG_NODE,
.prompt = "%s(config-rpki)# ",
};
+#endif /* HAVE_BGPD */
#if HAVE_BFDD > 0
static struct cmd_node bfd_node = {
@@ -1528,6 +1552,7 @@ DEFUNSH(VTYSH_REALLYALL, vtysh_end_all, vtysh_end_all_cmd, "end",
return vtysh_end();
}
+#ifdef HAVE_BGPD
DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd,
"router bgp [(1-4294967295) [<view|vrf> WORD]]",
ROUTER_STR BGP_STR AS_STR
@@ -1748,6 +1773,7 @@ DEFUNSH(VTYSH_BGPD, vnc_l2_group, vnc_l2_group_cmd, "vnc l2-group NAME",
return CMD_SUCCESS;
}
#endif
+#endif /* HAVE_BGPD */
DEFUNSH(VTYSH_KEYS, key_chain, key_chain_cmd, "key chain WORD",
"Authentication key management\n"
@@ -1766,20 +1792,25 @@ DEFUNSH(VTYSH_KEYS, key, key_cmd, "key (0-2147483647)",
return CMD_SUCCESS;
}
+#ifdef HAVE_RIPD
DEFUNSH(VTYSH_RIPD, router_rip, router_rip_cmd, "router rip [vrf NAME]",
ROUTER_STR "RIP\n" VRF_CMD_HELP_STR)
{
vty->node = RIP_NODE;
return CMD_SUCCESS;
}
+#endif /* HAVE_RIPD */
+#ifdef HAVE_RIPNGD
DEFUNSH(VTYSH_RIPNGD, router_ripng, router_ripng_cmd, "router ripng [vrf NAME]",
ROUTER_STR "RIPng\n" VRF_CMD_HELP_STR)
{
vty->node = RIPNG_NODE;
return CMD_SUCCESS;
}
+#endif /* HAVE_RIPNGD */
+#ifdef HAVE_OSPFD
DEFUNSH(VTYSH_OSPFD, router_ospf, router_ospf_cmd,
"router ospf [(1-65535)] [vrf NAME]",
"Enable a routing process\n"
@@ -1790,7 +1821,9 @@ DEFUNSH(VTYSH_OSPFD, router_ospf, router_ospf_cmd,
vty->node = OSPF_NODE;
return CMD_SUCCESS;
}
+#endif /* HAVE_OSPFD */
+#ifdef HAVE_EIGRPD
DEFUNSH(VTYSH_EIGRPD, router_eigrp, router_eigrp_cmd, "router eigrp (1-65535) [vrf NAME]",
"Enable a routing process\n"
"Start EIGRP configuration\n"
@@ -1800,7 +1833,9 @@ DEFUNSH(VTYSH_EIGRPD, router_eigrp, router_eigrp_cmd, "router eigrp (1-65535) [v
vty->node = EIGRP_NODE;
return CMD_SUCCESS;
}
+#endif /* HAVE_EIGRPD */
+#ifdef HAVE_BABELD
DEFUNSH(VTYSH_BABELD, router_babel, router_babel_cmd, "router babel",
"Enable a routing process\n"
"Make Babel instance command\n")
@@ -1808,13 +1843,16 @@ DEFUNSH(VTYSH_BABELD, router_babel, router_babel_cmd, "router babel",
vty->node = BABEL_NODE;
return CMD_SUCCESS;
}
+#endif /* HAVE_BABELD */
+#ifdef HAVE_OSPF6D
DEFUNSH(VTYSH_OSPF6D, router_ospf6, router_ospf6_cmd, "router ospf6",
ROUTER_STR OSPF6_STR)
{
vty->node = OSPF6_NODE;
return CMD_SUCCESS;
}
+#endif
#if defined(HAVE_LDPD)
DEFUNSH(VTYSH_LDPD, ldp_mpls_ldp, ldp_mpls_ldp_cmd, "mpls ldp",
@@ -1892,6 +1930,7 @@ DEFUNSH(VTYSH_LDPD, ldp_member_pseudowire_ifname,
}
#endif
+#ifdef HAVE_ISISD
DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd,
"router isis WORD [vrf NAME]",
ROUTER_STR
@@ -1901,7 +1940,9 @@ DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd,
vty->node = ISIS_NODE;
return CMD_SUCCESS;
}
+#endif /* HAVE_ISISD */
+#ifdef HAVE_FABRICD
DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfabric WORD",
ROUTER_STR
"OpenFabric routing protocol\n"
@@ -1910,6 +1951,7 @@ DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfab
vty->node = OPENFABRIC_NODE;
return CMD_SUCCESS;
}
+#endif /* HAVE_FABRICD */
DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd,
"route-map WORD <deny|permit> (1-65535)",
@@ -1923,6 +1965,7 @@ DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd,
return CMD_SUCCESS;
}
+#ifdef HAVE_PBRD
DEFUNSH(VTYSH_PBRD, vtysh_pbr_map, vtysh_pbr_map_cmd,
"pbr-map PBRMAP seq (1-700)",
"Create pbr-map or enter pbr-map command mode\n"
@@ -1934,6 +1977,14 @@ DEFUNSH(VTYSH_PBRD, vtysh_pbr_map, vtysh_pbr_map_cmd,
return CMD_SUCCESS;
}
+DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
+ NO_STR
+ "Delete pbr-map\n"
+ "The name of the PBR MAP\n"
+ "Sequence to delete from existing pbr-map entry\n"
+ "Sequence number\n")
+#endif /* HAVE_PBRD */
+
#if HAVE_BFDD > 0
DEFUNSH(VTYSH_BFDD, bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
{
@@ -1969,13 +2020,6 @@ DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd,
}
#endif /* HAVE_BFDD */
-DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
- NO_STR
- "Delete pbr-map\n"
- "The name of the PBR MAP\n"
- "Sequence to delete from existing pbr-map entry\n"
- "Sequence number\n")
-
DEFUNSH(VTYSH_ALL, vtysh_line_vty, vtysh_line_vty_cmd, "line vty",
"Configure a terminal line\n"
"Virtual terminal\n")
@@ -2039,6 +2083,7 @@ DEFUNSH(VTYSH_ALL, vtysh_quit_all, vtysh_quit_all_cmd, "quit",
return vtysh_exit_all(self, vty, argc, argv);
}
+#ifdef HAVE_BGPD
DEFUNSH(VTYSH_BGPD, exit_address_family, exit_address_family_cmd,
"exit-address-family", "Exit from Address Family configuration mode\n")
{
@@ -2097,14 +2142,6 @@ DEFUNSH(VTYSH_BGPD, bmp_quit, bmp_quit_cmd, "quit",
return bmp_exit(self, vty, argc, argv);
}
-DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf",
- "Exit from VRF configuration mode\n")
-{
- if (vty->node == VRF_NODE)
- vty->node = CONFIG_NODE;
- return CMD_SUCCESS;
-}
-
DEFUNSH(VTYSH_BGPD, exit_vrf_policy, exit_vrf_policy_cmd, "exit-vrf-policy",
"Exit from VRF policy configuration mode\n")
{
@@ -2112,7 +2149,17 @@ DEFUNSH(VTYSH_BGPD, exit_vrf_policy, exit_vrf_policy_cmd, "exit-vrf-policy",
vty->node = BGP_NODE;
return CMD_SUCCESS;
}
+#endif /* HAVE_BGPD */
+DEFUNSH(VTYSH_VRF, exit_vrf_config, exit_vrf_config_cmd, "exit-vrf",
+ "Exit from VRF configuration mode\n")
+{
+ if (vty->node == VRF_NODE)
+ vty->node = CONFIG_NODE;
+ return CMD_SUCCESS;
+}
+
+#ifdef HAVE_RIPD
DEFUNSH(VTYSH_RIPD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2124,7 +2171,9 @@ DEFUNSH(VTYSH_RIPD, vtysh_quit_ripd, vtysh_quit_ripd_cmd, "quit",
{
return vtysh_exit_ripd(self, vty, argc, argv);
}
+#endif /* HAVE_RIPD */
+#ifdef HAVE_RIPNGD
DEFUNSH(VTYSH_RIPNGD, vtysh_exit_ripngd, vtysh_exit_ripngd_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2136,6 +2185,7 @@ DEFUNSH(VTYSH_RIPNGD, vtysh_quit_ripngd, vtysh_quit_ripngd_cmd, "quit",
{
return vtysh_exit_ripngd(self, vty, argc, argv);
}
+#endif /* HAVE_RIPNGD */
DEFUNSH(VTYSH_RMAP, vtysh_exit_rmap, vtysh_exit_rmap_cmd, "exit",
"Exit current mode and down to previous mode\n")
@@ -2149,6 +2199,7 @@ DEFUNSH(VTYSH_RMAP, vtysh_quit_rmap, vtysh_quit_rmap_cmd, "quit",
return vtysh_exit_rmap(self, vty, argc, argv);
}
+#ifdef HAVE_PBRD
DEFUNSH(VTYSH_PBRD, vtysh_exit_pbr_map, vtysh_exit_pbr_map_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2160,7 +2211,9 @@ DEFUNSH(VTYSH_PBRD, vtysh_quit_pbr_map, vtysh_quit_pbr_map_cmd, "quit",
{
return vtysh_exit_rmap(self, vty, argc, argv);
}
+#endif /* HAVE_PBRD */
+#ifdef HAVE_BGPD
DEFUNSH(VTYSH_BGPD, vtysh_exit_bgpd, vtysh_exit_bgpd_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2172,7 +2225,9 @@ DEFUNSH(VTYSH_BGPD, vtysh_quit_bgpd, vtysh_quit_bgpd_cmd, "quit",
{
return vtysh_exit_bgpd(self, vty, argc, argv);
}
+#endif /* HAVE_BGPD */
+#ifdef HAVE_OSPFD
DEFUNSH(VTYSH_OSPFD, vtysh_exit_ospfd, vtysh_exit_ospfd_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2184,7 +2239,9 @@ DEFUNSH(VTYSH_OSPFD, vtysh_quit_ospfd, vtysh_quit_ospfd_cmd, "quit",
{
return vtysh_exit_ospfd(self, vty, argc, argv);
}
+#endif /* HAVE_OSPFD */
+#ifdef HAVE_EIGRPD
DEFUNSH(VTYSH_EIGRPD, vtysh_exit_eigrpd, vtysh_exit_eigrpd_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2196,8 +2253,10 @@ DEFUNSH(VTYSH_EIGRPD, vtysh_quit_eigrpd, vtysh_quit_eigrpd_cmd, "quit",
{
return vtysh_exit(vty);
}
+#endif /* HAVE_EIGRPD */
-DEFUNSH(VTYSH_EIGRPD, vtysh_exit_babeld, vtysh_exit_babeld_cmd, "exit",
+#ifdef HAVE_BABELD
+DEFUNSH(VTYSH_BABELD, vtysh_exit_babeld, vtysh_exit_babeld_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
return vtysh_exit(vty);
@@ -2208,7 +2267,9 @@ DEFUNSH(VTYSH_BABELD, vtysh_quit_babeld, vtysh_quit_babeld_cmd, "quit",
{
return vtysh_exit(vty);
}
+#endif /* HAVE_BABELD */
+#ifdef HAVE_OSPF6D
DEFUNSH(VTYSH_OSPF6D, vtysh_exit_ospf6d, vtysh_exit_ospf6d_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2220,6 +2281,7 @@ DEFUNSH(VTYSH_OSPF6D, vtysh_quit_ospf6d, vtysh_quit_ospf6d_cmd, "quit",
{
return vtysh_exit_ospf6d(self, vty, argc, argv);
}
+#endif /* HAVE_OSPF6D */
#if defined(HAVE_LDPD)
DEFUNSH(VTYSH_LDPD, vtysh_exit_ldpd, vtysh_exit_ldpd_cmd, "exit",
@@ -2232,6 +2294,7 @@ ALIAS(vtysh_exit_ldpd, vtysh_quit_ldpd_cmd, "quit",
"Exit current mode and down to previous mode\n")
#endif
+#ifdef HAVE_ISISD
DEFUNSH(VTYSH_ISISD, vtysh_exit_isisd, vtysh_exit_isisd_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2243,6 +2306,7 @@ DEFUNSH(VTYSH_ISISD, vtysh_quit_isisd, vtysh_quit_isisd_cmd, "quit",
{
return vtysh_exit_isisd(self, vty, argc, argv);
}
+#endif /* HAVE_ISISD */
#if HAVE_BFDD > 0
DEFUNSH(VTYSH_BFDD, vtysh_exit_bfdd, vtysh_exit_bfdd_cmd, "exit",
@@ -2255,6 +2319,7 @@ ALIAS(vtysh_exit_bfdd, vtysh_quit_bfdd_cmd, "quit",
"Exit current mode and down to previous mode\n")
#endif
+#ifdef HAVE_FABRICD
DEFUNSH(VTYSH_FABRICD, vtysh_exit_fabricd, vtysh_exit_fabricd_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2266,6 +2331,19 @@ DEFUNSH(VTYSH_FABRICD, vtysh_quit_fabricd, vtysh_quit_fabricd_cmd, "quit",
{
return vtysh_exit_fabricd(self, vty, argc, argv);
}
+#endif /* HAVE_FABRICD */
+
+DEFUNSH(VTYSH_KEYS, vtysh_exit_keys, vtysh_exit_keys_cmd, "exit",
+ "Exit current mode and down to previous mode\n")
+{
+ return vtysh_exit(vty);
+}
+
+DEFUNSH(VTYSH_KEYS, vtysh_quit_keys, vtysh_quit_keys_cmd, "quit",
+ "Exit current mode and down to previous mode\n")
+{
+ return vtysh_exit_keys(self, vty, argc, argv);
+}
DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit",
"Exit current mode and down to previous mode\n")
@@ -3771,331 +3849,394 @@ void vtysh_init_vty(void)
cmd_init(0);
cmd_variable_handler_register(vtysh_var_handler);
- /* Install nodes. */
+ /* bgpd */
+#ifdef HAVE_BGPD
install_node(&bgp_node);
- install_node(&rip_node);
- install_node(&interface_node);
- install_node(&pw_node);
- install_node(&link_params_node);
- install_node(&vrf_node);
- install_node(&nh_group_node);
- install_node(&rmap_node);
- install_node(&pbr_map_node);
- install_node(&zebra_node);
+ install_element(CONFIG_NODE, &router_bgp_cmd);
+ install_element(BGP_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_NODE, &vtysh_end_all_cmd);
+
install_node(&bgp_vpnv4_node);
+ install_element(BGP_NODE, &address_family_ipv4_vpn_cmd);
+#ifdef KEEP_OLD_VPN_COMMANDS
+ install_element(BGP_NODE, &address_family_vpnv4_cmd);
+#endif /* KEEP_OLD_VPN_COMMANDS */
+ install_element(BGP_VPNV4_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_VPNV4_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_VPNV4_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_VPNV4_NODE, &exit_address_family_cmd);
+
install_node(&bgp_vpnv6_node);
+ install_element(BGP_NODE, &address_family_ipv6_vpn_cmd);
+#ifdef KEEP_OLD_VPN_COMMANDS
+ install_element(BGP_NODE, &address_family_vpnv6_cmd);
+#endif /* KEEP_OLD_VPN_COMMANDS */
+ install_element(BGP_VPNV6_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_VPNV6_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_VPNV6_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_VPNV6_NODE, &exit_address_family_cmd);
+
install_node(&bgp_flowspecv4_node);
+ install_element(BGP_NODE, &address_family_flowspecv4_cmd);
+ install_element(BGP_FLOWSPECV4_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_FLOWSPECV4_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_FLOWSPECV4_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd);
+
install_node(&bgp_flowspecv6_node);
+ install_element(BGP_NODE, &address_family_flowspecv6_cmd);
+ install_element(BGP_FLOWSPECV6_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_FLOWSPECV6_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_FLOWSPECV6_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd);
+
install_node(&bgp_ipv4_node);
+ install_element(BGP_NODE, &address_family_ipv4_cmd);
+ install_element(BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_IPV4_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_IPV4_NODE, &exit_address_family_cmd);
+
install_node(&bgp_ipv4m_node);
+ install_element(BGP_NODE, &address_family_ipv4_multicast_cmd);
+ install_element(BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_IPV4M_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_IPV4M_NODE, &exit_address_family_cmd);
+
install_node(&bgp_ipv4l_node);
+ install_element(BGP_NODE, &address_family_ipv4_labeled_unicast_cmd);
+ install_element(BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_IPV4L_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_IPV4L_NODE, &exit_address_family_cmd);
+
install_node(&bgp_ipv6_node);
+ install_element(BGP_NODE, &address_family_ipv6_cmd);
+ install_element(BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_IPV6_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_IPV6_NODE, &exit_address_family_cmd);
+
install_node(&bgp_ipv6m_node);
+ install_element(BGP_NODE, &address_family_ipv6_multicast_cmd);
+ install_element(BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_IPV6M_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_IPV6M_NODE, &exit_address_family_cmd);
+
install_node(&bgp_ipv6l_node);
+ install_element(BGP_NODE, &address_family_ipv6_labeled_unicast_cmd);
+ install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_IPV6L_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_IPV6L_NODE, &exit_address_family_cmd);
+
+#if defined(ENABLE_BGP_VNC)
install_node(&bgp_vrf_policy_node);
- install_node(&bgp_evpn_node);
- install_node(&bgp_evpn_vni_node);
+ install_element(BGP_NODE, &vnc_vrf_policy_cmd);
+ install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
+
install_node(&bgp_vnc_defaults_node);
+ install_element(BGP_NODE, &vnc_defaults_cmd);
+ install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
+
install_node(&bgp_vnc_nve_group_node);
+ install_element(BGP_NODE, &vnc_nve_group_cmd);
+ install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd);
+
install_node(&bgp_vnc_l2_group_node);
- install_node(&ospf_node);
- install_node(&eigrp_node);
- install_node(&babel_node);
- install_node(&ripng_node);
- install_node(&ospf6_node);
- install_node(&ldp_node);
- install_node(&ldp_ipv4_node);
- install_node(&ldp_ipv6_node);
- install_node(&ldp_ipv4_iface_node);
- install_node(&ldp_ipv6_iface_node);
- install_node(&ldp_l2vpn_node);
- install_node(&ldp_pseudowire_node);
- install_node(&keychain_node);
- install_node(&keychain_key_node);
- install_node(&isis_node);
- install_node(&openfabric_node);
- install_node(&vty_node);
- install_node(&rpki_node);
- install_node(&bmp_node);
-#if HAVE_BFDD > 0
- install_node(&bfd_node);
- install_node(&bfd_peer_node);
- install_node(&bfd_profile_node);
-#endif /* HAVE_BFDD */
+ install_element(BGP_NODE, &vnc_l2_group_cmd);
+ install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd);
+#endif
- struct cmd_node *node;
- for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
- node = vector_slot(cmdvec, i);
- if (!node || node->node == VIEW_NODE)
- continue;
- vtysh_install_default(node->node);
- }
+ install_node(&bgp_evpn_node);
+ install_element(BGP_NODE, &address_family_evpn_cmd);
+#if defined(HAVE_CUMULUS)
+ install_element(BGP_NODE, &address_family_evpn2_cmd);
+#endif
+ install_element(BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_EVPN_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_EVPN_NODE, &exit_address_family_cmd);
- install_element(VIEW_NODE, &vtysh_enable_cmd);
- install_element(ENABLE_NODE, &vtysh_config_terminal_cmd);
- install_element(ENABLE_NODE, &vtysh_disable_cmd);
+ install_node(&bgp_evpn_vni_node);
+ install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
+ install_element(BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd);
+ install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd);
+ install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd);
+ install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd);
- /* "exit" command. */
- install_element(VIEW_NODE, &vtysh_exit_all_cmd);
- install_element(CONFIG_NODE, &vtysh_exit_all_cmd);
- install_element(VIEW_NODE, &vtysh_quit_all_cmd);
- install_element(CONFIG_NODE, &vtysh_quit_all_cmd);
+ install_node(&rpki_node);
+ install_element(CONFIG_NODE, &rpki_cmd);
+ install_element(RPKI_NODE, &rpki_exit_cmd);
+ install_element(RPKI_NODE, &rpki_quit_cmd);
+ install_element(RPKI_NODE, &vtysh_end_all_cmd);
+
+ install_node(&bmp_node);
+ install_element(BGP_NODE, &bmp_targets_cmd);
+ install_element(BMP_NODE, &bmp_exit_cmd);
+ install_element(BMP_NODE, &bmp_quit_cmd);
+ install_element(BMP_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_BGPD */
+
+ /* ripd */
+ install_node(&rip_node);
+#ifdef HAVE_RIPD
+ install_element(CONFIG_NODE, &router_rip_cmd);
install_element(RIP_NODE, &vtysh_exit_ripd_cmd);
install_element(RIP_NODE, &vtysh_quit_ripd_cmd);
+ install_element(RIP_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_RIPD */
+
+ /* ripngd */
+ install_node(&ripng_node);
+#ifdef HAVE_RIPNGD
+ install_element(CONFIG_NODE, &router_ripng_cmd);
install_element(RIPNG_NODE, &vtysh_exit_ripngd_cmd);
install_element(RIPNG_NODE, &vtysh_quit_ripngd_cmd);
+ install_element(RIPNG_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_RIPNGD */
+
+ /* ospfd */
+#ifdef HAVE_OSPFD
+ install_node(&ospf_node);
+ install_element(CONFIG_NODE, &router_ospf_cmd);
install_element(OSPF_NODE, &vtysh_exit_ospfd_cmd);
install_element(OSPF_NODE, &vtysh_quit_ospfd_cmd);
- install_element(EIGRP_NODE, &vtysh_exit_eigrpd_cmd);
- install_element(EIGRP_NODE, &vtysh_quit_eigrpd_cmd);
- install_element(BABEL_NODE, &vtysh_exit_babeld_cmd);
- install_element(BABEL_NODE, &vtysh_quit_babeld_cmd);
+ install_element(OSPF_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_OSPFD */
+
+ /* ospf6d */
+#ifdef HAVE_OSPF6D
+ install_node(&ospf6_node);
+ install_element(CONFIG_NODE, &router_ospf6_cmd);
install_element(OSPF6_NODE, &vtysh_exit_ospf6d_cmd);
install_element(OSPF6_NODE, &vtysh_quit_ospf6d_cmd);
+ install_element(OSPF6_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_OSPF6D */
+
+ /* ldpd */
#if defined(HAVE_LDPD)
+ install_node(&ldp_node);
+ install_element(CONFIG_NODE, &ldp_mpls_ldp_cmd);
install_element(LDP_NODE, &vtysh_exit_ldpd_cmd);
install_element(LDP_NODE, &vtysh_quit_ldpd_cmd);
+ install_element(LDP_NODE, &vtysh_end_all_cmd);
+
+ install_node(&ldp_ipv4_node);
+ install_element(LDP_NODE, &ldp_address_family_ipv4_cmd);
install_element(LDP_IPV4_NODE, &vtysh_exit_ldpd_cmd);
install_element(LDP_IPV4_NODE, &vtysh_quit_ldpd_cmd);
install_element(LDP_IPV4_NODE, &ldp_exit_address_family_cmd);
+ install_element(LDP_IPV4_NODE, &vtysh_end_all_cmd);
+
+ install_node(&ldp_ipv6_node);
+ install_element(LDP_NODE, &ldp_address_family_ipv6_cmd);
install_element(LDP_IPV6_NODE, &vtysh_exit_ldpd_cmd);
install_element(LDP_IPV6_NODE, &vtysh_quit_ldpd_cmd);
install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd);
+ install_element(LDP_IPV6_NODE, &vtysh_end_all_cmd);
+
+ install_node(&ldp_ipv4_iface_node);
+ install_element(LDP_IPV4_NODE, &ldp_interface_ifname_cmd);
install_element(LDP_IPV4_IFACE_NODE, &vtysh_exit_ldpd_cmd);
install_element(LDP_IPV4_IFACE_NODE, &vtysh_quit_ldpd_cmd);
+ install_element(LDP_IPV4_IFACE_NODE, &vtysh_end_all_cmd);
+
+ install_node(&ldp_ipv6_iface_node);
+ install_element(LDP_IPV6_NODE, &ldp_interface_ifname_cmd);
install_element(LDP_IPV6_IFACE_NODE, &vtysh_exit_ldpd_cmd);
install_element(LDP_IPV6_IFACE_NODE, &vtysh_quit_ldpd_cmd);
+ install_element(LDP_IPV6_IFACE_NODE, &vtysh_end_all_cmd);
+
+ install_node(&ldp_l2vpn_node);
+ install_element(CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd);
install_element(LDP_L2VPN_NODE, &vtysh_exit_ldpd_cmd);
install_element(LDP_L2VPN_NODE, &vtysh_quit_ldpd_cmd);
+ install_element(LDP_L2VPN_NODE, &vtysh_end_all_cmd);
+
+ install_node(&ldp_pseudowire_node);
+ install_element(LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd);
install_element(LDP_PSEUDOWIRE_NODE, &vtysh_exit_ldpd_cmd);
install_element(LDP_PSEUDOWIRE_NODE, &vtysh_quit_ldpd_cmd);
+ install_element(LDP_PSEUDOWIRE_NODE, &vtysh_end_all_cmd);
#endif
- install_element(BGP_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_VPNV4_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_VPNV4_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_VPNV6_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_VPNV6_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_FLOWSPECV4_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_FLOWSPECV4_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_FLOWSPECV6_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_FLOWSPECV6_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd);
-#if defined(ENABLE_BGP_VNC)
- install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_quit_bgpd_cmd);
- install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_exit_bgpd_cmd);
- install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_quit_bgpd_cmd);
-#endif
+
+ /* eigrpd */
+#ifdef HAVE_EIGRPD
+ install_node(&eigrp_node);
+ install_element(CONFIG_NODE, &router_eigrp_cmd);
+ install_element(EIGRP_NODE, &vtysh_exit_eigrpd_cmd);
+ install_element(EIGRP_NODE, &vtysh_quit_eigrpd_cmd);
+ install_element(EIGRP_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_EIGRPD */
+
+ /* babeld */
+#ifdef HAVE_BABELD
+ install_node(&babel_node);
+ install_element(CONFIG_NODE, &router_babel_cmd);
+ install_element(BABEL_NODE, &vtysh_exit_babeld_cmd);
+ install_element(BABEL_NODE, &vtysh_quit_babeld_cmd);
+ install_element(BABEL_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_BABELD */
+
+ /* isisd */
+#ifdef HAVE_ISISD
+ install_node(&isis_node);
+ install_element(CONFIG_NODE, &router_isis_cmd);
install_element(ISIS_NODE, &vtysh_exit_isisd_cmd);
install_element(ISIS_NODE, &vtysh_quit_isisd_cmd);
+ install_element(ISIS_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_ISISD */
+
+ /* fabricd */
+#ifdef HAVE_FABRICD
+ install_node(&openfabric_node);
+ install_element(CONFIG_NODE, &router_openfabric_cmd);
install_element(OPENFABRIC_NODE, &vtysh_exit_fabricd_cmd);
install_element(OPENFABRIC_NODE, &vtysh_quit_fabricd_cmd);
- install_element(KEYCHAIN_NODE, &vtysh_exit_ripd_cmd);
- install_element(KEYCHAIN_NODE, &vtysh_quit_ripd_cmd);
- install_element(KEYCHAIN_KEY_NODE, &vtysh_exit_ripd_cmd);
- install_element(KEYCHAIN_KEY_NODE, &vtysh_quit_ripd_cmd);
- install_element(RMAP_NODE, &vtysh_exit_rmap_cmd);
- install_element(RMAP_NODE, &vtysh_quit_rmap_cmd);
+ install_element(OPENFABRIC_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_FABRICD */
+
+ /* pbrd */
+#ifdef HAVE_PBRD
+ install_node(&pbr_map_node);
+ install_element(CONFIG_NODE, &vtysh_pbr_map_cmd);
+ install_element(CONFIG_NODE, &vtysh_no_pbr_map_cmd);
install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd);
install_element(PBRMAP_NODE, &vtysh_quit_pbr_map_cmd);
+ install_element(PBRMAP_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_PBRD */
+
+ /* bfdd */
#if HAVE_BFDD > 0
- /* Enter node. */
+ install_node(&bfd_node);
install_element(CONFIG_NODE, &bfd_enter_cmd);
- install_element(BFD_NODE, &bfd_peer_enter_cmd);
- install_element(BFD_NODE, &bfd_profile_enter_cmd);
-
- /* Exit/quit node. */
install_element(BFD_NODE, &vtysh_exit_bfdd_cmd);
install_element(BFD_NODE, &vtysh_quit_bfdd_cmd);
+ install_element(BFD_NODE, &vtysh_end_all_cmd);
+
+ install_node(&bfd_peer_node);
+ install_element(BFD_NODE, &bfd_peer_enter_cmd);
install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd);
install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd);
+ install_element(BFD_PEER_NODE, &vtysh_end_all_cmd);
+
+ install_node(&bfd_profile_node);
+ install_element(BFD_NODE, &bfd_profile_enter_cmd);
install_element(BFD_PROFILE_NODE, &vtysh_exit_bfdd_cmd);
install_element(BFD_PROFILE_NODE, &vtysh_quit_bfdd_cmd);
-
- /* End/exit all. */
- install_element(BFD_NODE, &vtysh_end_all_cmd);
- install_element(BFD_PEER_NODE, &vtysh_end_all_cmd);
install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd);
#endif /* HAVE_BFDD */
- install_element(VTY_NODE, &vtysh_exit_line_vty_cmd);
- install_element(VTY_NODE, &vtysh_quit_line_vty_cmd);
- /* "end" command. */
- install_element(CONFIG_NODE, &vtysh_end_all_cmd);
- install_element(ENABLE_NODE, &vtysh_end_all_cmd);
- install_element(RIP_NODE, &vtysh_end_all_cmd);
- install_element(RIPNG_NODE, &vtysh_end_all_cmd);
- install_element(OSPF_NODE, &vtysh_end_all_cmd);
- install_element(EIGRP_NODE, &vtysh_end_all_cmd);
- install_element(BABEL_NODE, &vtysh_end_all_cmd);
- install_element(OSPF6_NODE, &vtysh_end_all_cmd);
- install_element(LDP_NODE, &vtysh_end_all_cmd);
- install_element(LDP_IPV4_NODE, &vtysh_end_all_cmd);
- install_element(LDP_IPV6_NODE, &vtysh_end_all_cmd);
- install_element(LDP_IPV4_IFACE_NODE, &vtysh_end_all_cmd);
- install_element(LDP_IPV6_IFACE_NODE, &vtysh_end_all_cmd);
- install_element(LDP_L2VPN_NODE, &vtysh_end_all_cmd);
- install_element(LDP_PSEUDOWIRE_NODE, &vtysh_end_all_cmd);
- install_element(BGP_NODE, &vtysh_end_all_cmd);
- install_element(BGP_IPV4_NODE, &vtysh_end_all_cmd);
- install_element(BGP_IPV4M_NODE, &vtysh_end_all_cmd);
- install_element(BGP_IPV4L_NODE, &vtysh_end_all_cmd);
- install_element(BGP_VPNV4_NODE, &vtysh_end_all_cmd);
- install_element(BGP_VPNV6_NODE, &vtysh_end_all_cmd);
- install_element(BGP_FLOWSPECV4_NODE, &vtysh_end_all_cmd);
- install_element(BGP_FLOWSPECV6_NODE, &vtysh_end_all_cmd);
- install_element(BGP_IPV6_NODE, &vtysh_end_all_cmd);
- install_element(BGP_IPV6M_NODE, &vtysh_end_all_cmd);
- install_element(BGP_IPV6L_NODE, &vtysh_end_all_cmd);
- install_element(BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd);
- install_element(BGP_EVPN_NODE, &vtysh_end_all_cmd);
- install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd);
- install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd);
- install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd);
- install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_end_all_cmd);
- install_element(ISIS_NODE, &vtysh_end_all_cmd);
- install_element(OPENFABRIC_NODE, &vtysh_end_all_cmd);
+ /* keychain */
+ install_node(&keychain_node);
+ install_element(CONFIG_NODE, &key_chain_cmd);
+ install_element(KEYCHAIN_NODE, &key_chain_cmd);
+ install_element(KEYCHAIN_NODE, &vtysh_exit_keys_cmd);
+ install_element(KEYCHAIN_NODE, &vtysh_quit_keys_cmd);
install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd);
+
+ install_node(&keychain_key_node);
+ install_element(KEYCHAIN_NODE, &key_cmd);
+ install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd);
+ install_element(KEYCHAIN_KEY_NODE, &vtysh_exit_keys_cmd);
+ install_element(KEYCHAIN_KEY_NODE, &vtysh_quit_keys_cmd);
install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd);
- install_element(RMAP_NODE, &vtysh_end_all_cmd);
- install_element(PBRMAP_NODE, &vtysh_end_all_cmd);
- install_element(VTY_NODE, &vtysh_end_all_cmd);
+ /* nexthop-group */
+ install_node(&nh_group_node);
+ install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd);
+ install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd);
+ install_element(NH_GROUP_NODE, &vtysh_end_all_cmd);
+ install_element(NH_GROUP_NODE, &vtysh_exit_nexthop_group_cmd);
+ install_element(NH_GROUP_NODE, &vtysh_quit_nexthop_group_cmd);
+
+ /* zebra and all */
+ install_node(&zebra_node);
+
+ install_node(&interface_node);
+ install_element(CONFIG_NODE, &vtysh_interface_cmd);
install_element(INTERFACE_NODE, &vtysh_end_all_cmd);
install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd);
+ install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd);
+
+ install_node(&link_params_node);
+ install_element(INTERFACE_NODE, &vtysh_link_params_cmd);
install_element(LINK_PARAMS_NODE, &exit_link_params_cmd);
install_element(LINK_PARAMS_NODE, &vtysh_end_all_cmd);
install_element(LINK_PARAMS_NODE, &vtysh_exit_interface_cmd);
- install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd);
+ install_node(&pw_node);
+ install_element(CONFIG_NODE, &vtysh_pseudowire_cmd);
install_element(PW_NODE, &vtysh_end_all_cmd);
install_element(PW_NODE, &vtysh_exit_interface_cmd);
install_element(PW_NODE, &vtysh_quit_interface_cmd);
- install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd);
- install_element(NH_GROUP_NODE, &vtysh_end_all_cmd);
- install_element(NH_GROUP_NODE, &vtysh_exit_nexthop_group_cmd);
- install_element(NH_GROUP_NODE, &vtysh_quit_nexthop_group_cmd);
-
+ install_node(&vrf_node);
+ install_element(CONFIG_NODE, &vtysh_vrf_cmd);
+ install_element(VRF_NODE, &vtysh_vrf_netns_cmd);
+ install_element(VRF_NODE, &vtysh_no_vrf_netns_cmd);
+ install_element(VRF_NODE, &exit_vrf_config_cmd);
install_element(VRF_NODE, &vtysh_end_all_cmd);
install_element(VRF_NODE, &vtysh_exit_vrf_cmd);
install_element(VRF_NODE, &vtysh_quit_vrf_cmd);
+
+ install_node(&rmap_node);
+ install_element(CONFIG_NODE, &vtysh_route_map_cmd);
+ install_element(RMAP_NODE, &vtysh_exit_rmap_cmd);
+ install_element(RMAP_NODE, &vtysh_quit_rmap_cmd);
+ install_element(RMAP_NODE, &vtysh_end_all_cmd);
- install_element(CONFIG_NODE, &router_eigrp_cmd);
- install_element(CONFIG_NODE, &router_babel_cmd);
- install_element(CONFIG_NODE, &router_rip_cmd);
- install_element(CONFIG_NODE, &router_ripng_cmd);
- install_element(CONFIG_NODE, &router_ospf_cmd);
- install_element(CONFIG_NODE, &router_ospf6_cmd);
-#if defined(HAVE_LDPD)
- install_element(CONFIG_NODE, &ldp_mpls_ldp_cmd);
- install_element(LDP_NODE, &ldp_address_family_ipv4_cmd);
- install_element(LDP_NODE, &ldp_address_family_ipv6_cmd);
- install_element(LDP_IPV4_NODE, &ldp_interface_ifname_cmd);
- install_element(LDP_IPV6_NODE, &ldp_interface_ifname_cmd);
- install_element(CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd);
- install_element(LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd);
-#endif
- install_element(CONFIG_NODE, &router_isis_cmd);
- install_element(CONFIG_NODE, &router_openfabric_cmd);
- install_element(CONFIG_NODE, &router_bgp_cmd);
-#ifdef KEEP_OLD_VPN_COMMANDS
- install_element(BGP_NODE, &address_family_vpnv4_cmd);
- install_element(BGP_NODE, &address_family_vpnv6_cmd);
-#endif /* KEEP_OLD_VPN_COMMANDS */
-#if defined(ENABLE_BGP_VNC)
- install_element(BGP_NODE, &vnc_vrf_policy_cmd);
- install_element(BGP_NODE, &vnc_defaults_cmd);
- install_element(BGP_NODE, &vnc_nve_group_cmd);
- install_element(BGP_NODE, &vnc_l2_group_cmd);
-#endif
- install_element(BGP_NODE, &address_family_ipv4_cmd);
- install_element(BGP_NODE, &address_family_ipv4_multicast_cmd);
- install_element(BGP_NODE, &address_family_ipv4_vpn_cmd);
- install_element(BGP_NODE, &address_family_ipv4_labeled_unicast_cmd);
- install_element(BGP_NODE, &address_family_ipv6_cmd);
- install_element(BGP_NODE, &address_family_ipv6_multicast_cmd);
- install_element(BGP_NODE, &address_family_ipv6_vpn_cmd);
- install_element(BGP_NODE, &address_family_ipv6_labeled_unicast_cmd);
- install_element(BGP_NODE, &address_family_evpn_cmd);
- install_element(BGP_NODE, &address_family_flowspecv4_cmd);
- install_element(BGP_NODE, &address_family_flowspecv6_cmd);
-#if defined(HAVE_CUMULUS)
- install_element(BGP_NODE, &address_family_evpn2_cmd);
-#endif
- install_element(BGP_VPNV4_NODE, &exit_address_family_cmd);
- install_element(BGP_VPNV6_NODE, &exit_address_family_cmd);
- install_element(BGP_IPV4_NODE, &exit_address_family_cmd);
- install_element(BGP_IPV4M_NODE, &exit_address_family_cmd);
- install_element(BGP_IPV4L_NODE, &exit_address_family_cmd);
- install_element(BGP_IPV6_NODE, &exit_address_family_cmd);
- install_element(BGP_IPV6M_NODE, &exit_address_family_cmd);
- install_element(BGP_EVPN_NODE, &exit_address_family_cmd);
- install_element(BGP_IPV6L_NODE, &exit_address_family_cmd);
- install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd);
- install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd);
+ install_node(&vty_node);
+ install_element(CONFIG_NODE, &vtysh_line_vty_cmd);
+ install_element(VTY_NODE, &vtysh_exit_line_vty_cmd);
+ install_element(VTY_NODE, &vtysh_quit_line_vty_cmd);
+ install_element(VTY_NODE, &vtysh_end_all_cmd);
- install_element(BGP_NODE, &bmp_targets_cmd);
- install_element(BMP_NODE, &bmp_exit_cmd);
- install_element(BMP_NODE, &bmp_quit_cmd);
- install_element(BMP_NODE, &vtysh_end_all_cmd);
- install_element(CONFIG_NODE, &rpki_cmd);
- install_element(RPKI_NODE, &rpki_exit_cmd);
- install_element(RPKI_NODE, &rpki_quit_cmd);
- install_element(RPKI_NODE, &vtysh_end_all_cmd);
+ struct cmd_node *node;
+ for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
+ node = vector_slot(cmdvec, i);
+ if (!node || node->node == VIEW_NODE)
+ continue;
+ vtysh_install_default(node->node);
+ }
- /* EVPN commands */
- install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd);
- install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd);
+ /* vtysh */
- install_element(BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd);
- install_element(BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd);
- install_element(BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd);
- install_element(BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd);
+ install_element(VIEW_NODE, &vtysh_enable_cmd);
+ install_element(ENABLE_NODE, &vtysh_config_terminal_cmd);
+ install_element(ENABLE_NODE, &vtysh_disable_cmd);
+
+ /* "exit" command. */
+ install_element(VIEW_NODE, &vtysh_exit_all_cmd);
+ install_element(CONFIG_NODE, &vtysh_exit_all_cmd);
+ install_element(VIEW_NODE, &vtysh_quit_all_cmd);
+ install_element(CONFIG_NODE, &vtysh_quit_all_cmd);
+
+ /* "end" command. */
+ install_element(CONFIG_NODE, &vtysh_end_all_cmd);
+ install_element(ENABLE_NODE, &vtysh_end_all_cmd);
- install_element(CONFIG_NODE, &key_chain_cmd);
- install_element(CONFIG_NODE, &vtysh_route_map_cmd);
- install_element(CONFIG_NODE, &vtysh_pbr_map_cmd);
- install_element(CONFIG_NODE, &vtysh_no_pbr_map_cmd);
- install_element(CONFIG_NODE, &vtysh_line_vty_cmd);
- install_element(KEYCHAIN_NODE, &key_cmd);
- install_element(KEYCHAIN_NODE, &key_chain_cmd);
- install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd);
- install_element(CONFIG_NODE, &vtysh_interface_cmd);
- install_element(CONFIG_NODE, &vtysh_pseudowire_cmd);
- install_element(INTERFACE_NODE, &vtysh_link_params_cmd);
install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd);
- install_element(CONFIG_NODE, &vtysh_vrf_cmd);
- install_element(VRF_NODE, &vtysh_vrf_netns_cmd);
- install_element(VRF_NODE, &vtysh_no_vrf_netns_cmd);
- install_element(VRF_NODE, &exit_vrf_config_cmd);
-
- install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd);
-
/* "write terminal" command. */
install_element(ENABLE_NODE, &vtysh_write_terminal_cmd);
diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang
index 4b7785e690..5b434162d0 100644
--- a/yang/frr-bfdd.yang
+++ b/yang/frr-bfdd.yang
@@ -12,6 +12,9 @@ module frr-bfdd {
import frr-interface {
prefix frr-interface;
}
+ import frr-vrf {
+ prefix frr-vrf;
+ }
import frr-route-types {
prefix frr-route-types;
}
@@ -396,14 +399,12 @@ module frr-bfdd {
}
leaf interface {
- type string {
- length "0..16";
- }
+ type frr-interface:interface-ref;
description "Interface to use to contact peer";
}
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
description "Virtual Routing Domain name";
}
@@ -441,14 +442,12 @@ module frr-bfdd {
}
leaf interface {
- type string {
- length "0..16";
- }
+ type frr-interface:interface-ref;
description "Interface to use to contact peer";
}
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
description "Virtual Routing Domain name";
}
diff --git a/yang/frr-bgp-common-structure.yang b/yang/frr-bgp-common-structure.yang
index 8162527e90..6543b1d1c3 100644
--- a/yang/frr-bgp-common-structure.yang
+++ b/yang/frr-bgp-common-structure.yang
@@ -9,6 +9,10 @@ submodule frr-bgp-common-structure {
prefix inet;
}
+ import frr-route-map {
+ prefix frr-route-map;
+ }
+
import frr-interface {
prefix frr-interface;
}
@@ -371,7 +375,7 @@ submodule frr-bgp-common-structure {
}
leaf rmap-policy-export {
- type frr-bt:rmap-ref;
+ type frr-route-map:route-map-ref;
description
"Route-map to specify criteria to originate default.";
}
diff --git a/yang/frr-bgp-common.yang b/yang/frr-bgp-common.yang
index 188cf856db..96ec9dc969 100644
--- a/yang/frr-bgp-common.yang
+++ b/yang/frr-bgp-common.yang
@@ -17,6 +17,10 @@ submodule frr-bgp-common {
prefix frr-bt;
}
+ import frr-route-map {
+ prefix frr-route-map;
+ }
+
import frr-route-types {
prefix frr-rt-type;
}
@@ -73,25 +77,25 @@ submodule frr-bgp-common {
grouping rmap-policy-import {
leaf rmap-import {
- type frr-bt:rmap-ref;
+ type frr-route-map:route-map-ref;
}
}
grouping rmap-policy-export {
leaf rmap-export {
- type frr-bt:rmap-ref;
+ type frr-route-map:route-map-ref;
}
}
grouping unsupress-map-policy-import {
leaf unsupress-map-import {
- type frr-bt:rmap-ref;
+ type frr-route-map:route-map-ref;
}
}
grouping unsupress-map-policy-export {
leaf unsupress-map-export {
- type frr-bt:rmap-ref;
+ type frr-route-map:route-map-ref;
}
}
@@ -728,7 +732,7 @@ submodule frr-bgp-common {
}
leaf rmap-policy-import {
- type frr-bt:rmap-ref;
+ type frr-route-map:route-map-ref;
description
"Route-map to be applied for redistributed routes into the bgp.";
}
@@ -743,7 +747,7 @@ submodule frr-bgp-common {
}
leaf rmap-policy-export {
- type frr-bt:rmap-ref;
+ type frr-route-map:route-map-ref;
description
"Route-map to modify the attributes for Routes going out
via BGP updates.";
@@ -771,7 +775,7 @@ submodule frr-bgp-common {
}
leaf rmap-policy-export {
- type frr-bt:rmap-ref;
+ type frr-route-map:route-map-ref;
description
"Apply route map to aggregate network.";
}
@@ -1097,7 +1101,7 @@ submodule frr-bgp-common {
}
leaf rmap-policy-export {
- type frr-bt:rmap-ref;
+ type frr-route-map:route-map-ref;
description
"Route-map to modify the attributes for Routes going out
via BGP updates.";
diff --git a/yang/frr-bgp-types.yang b/yang/frr-bgp-types.yang
index 0afdea1ba6..55834df2ee 100644
--- a/yang/frr-bgp-types.yang
+++ b/yang/frr-bgp-types.yang
@@ -41,10 +41,6 @@ module frr-bgp-types {
"Initial revision.";
}
- typedef rmap-ref {
- type string;
- }
-
typedef plist-ref {
type string;
}
diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang
index 3d1bf3baa5..2127ac4988 100644
--- a/yang/frr-eigrpd.yang
+++ b/yang/frr-eigrpd.yang
@@ -12,6 +12,12 @@ module frr-eigrpd {
import frr-interface {
prefix frr-interface;
}
+ import frr-vrf {
+ prefix frr-vrf;
+ }
+ import frr-route-map {
+ prefix frr-route-map;
+ }
import frr-route-types {
prefix frr-route-types;
}
@@ -109,9 +115,7 @@ module frr-eigrpd {
leaf vrf {
description "Virtual Routing Domain name";
- type string {
- length "0..16";
- }
+ type frr-vrf:vrf-ref;
}
/*
@@ -235,9 +239,7 @@ module frr-eigrpd {
"Applies the conditions of the specified route-map to
routes that are redistributed into the EIGRP routing
instance";
- type string {
- length "1..max";
- }
+ type frr-route-map:route-map-ref;
}
container metrics {
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index cc959bd9fe..79941a50e7 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -15,6 +15,14 @@ module frr-isisd {
prefix frr-interface;
}
+ import frr-vrf {
+ prefix frr-vrf;
+ }
+
+ import frr-route-map {
+ prefix frr-route-map;
+ }
+
import frr-route-types {
prefix frr-route-types;
}
@@ -240,9 +248,7 @@ module frr-isisd {
description
"Common optional attributes of any redistribute entry.";
leaf route-map {
- type string {
- length "1..max";
- }
+ type frr-route-map:route-map-ref;
description
"Applies the conditions of the specified route-map to routes that
are redistributed into this routing instance.";
@@ -341,7 +347,7 @@ module frr-isisd {
}
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
default "default";
description
"VRF NAME.";
@@ -830,7 +836,7 @@ module frr-isisd {
}
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
description
"VRF NAME.";
}
diff --git a/yang/frr-nexthop.yang b/yang/frr-nexthop.yang
index 0cb0f93ee4..52155dcd16 100644
--- a/yang/frr-nexthop.yang
+++ b/yang/frr-nexthop.yang
@@ -156,7 +156,7 @@ module frr-nexthop {
}
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
description
"The nexthop vrf name, if different from the route.";
}
@@ -167,7 +167,7 @@ module frr-nexthop {
}
leaf interface {
- type string;
+ type frr-interface:interface-ref;
description
"The nexthop egress interface.";
}
@@ -275,7 +275,7 @@ module frr-nexthop {
description
"List of nexthop groups, each contains group of nexthops";
leaf name {
- type string;
+ type nexthop-group-ref;
description
"The nexthop-group name.";
}
diff --git a/yang/frr-ospfd.yang b/yang/frr-ospfd.yang
index 466dd42ce4..42a7e8784c 100644
--- a/yang/frr-ospfd.yang
+++ b/yang/frr-ospfd.yang
@@ -15,6 +15,10 @@ module frr-ospfd {
prefix frr-interface;
}
+ import frr-route-map {
+ prefix frr-route-map;
+ }
+
import frr-route-types {
prefix frr-route-types;
}
@@ -41,10 +45,6 @@ module frr-ospfd {
}
/* Policy types to be removed later, once policy Yang finalized */
- typedef rmap-ref {
- type string;
- }
-
typedef plist-ref {
type string;
}
@@ -425,7 +425,7 @@ module frr-ospfd {
}
leaf route-map {
- type rmap-ref;
+ type frr-route-map:route-map-ref;
description
"Route map reference.";
}
diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang
index f5775ab968..929c916069 100644
--- a/yang/frr-ripd.yang
+++ b/yang/frr-ripd.yang
@@ -12,6 +12,12 @@ module frr-ripd {
import frr-interface {
prefix frr-interface;
}
+ import frr-vrf {
+ prefix frr-vrf;
+ }
+ import frr-route-map {
+ prefix frr-route-map;
+ }
import frr-route-types {
prefix frr-route-types;
}
@@ -72,7 +78,7 @@ module frr-ripd {
"RIP routing instance.";
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
description
"VRF name.";
}
@@ -227,9 +233,7 @@ module frr-ripd {
must '. != "rip"';
}
leaf route-map {
- type string {
- length "1..max";
- }
+ type frr-route-map:route-map-ref;
description
"Applies the conditions of the specified route-map to
routes that are redistributed into the RIP routing
@@ -396,7 +400,7 @@ module frr-ripd {
"Next hop IPv4 address.";
}
leaf interface {
- type string;
+ type frr-interface:interface-ref;
description
"The interface that the route uses.";
}
@@ -587,7 +591,7 @@ module frr-ripd {
input {
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
description
"VRF name identifying a specific RIP instance.
This leaf is optional for the rpc.
@@ -608,7 +612,7 @@ module frr-ripd {
receives a PDU with the wrong authentication type
field.";
leaf interface-name {
- type string;
+ type frr-interface:interface-ref;
description
"Describes the name of the RIP interface.";
}
@@ -624,7 +628,7 @@ module frr-ripd {
receives a PDU with the wrong authentication
information.";
leaf interface-name {
- type string;
+ type frr-interface:interface-ref;
description
"Describes the name of the RIP interface.";
}
diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang
index 52e208b2c9..07d38bd416 100644
--- a/yang/frr-ripngd.yang
+++ b/yang/frr-ripngd.yang
@@ -12,6 +12,12 @@ module frr-ripngd {
import frr-interface {
prefix frr-interface;
}
+ import frr-vrf {
+ prefix frr-vrf;
+ }
+ import frr-route-map {
+ prefix frr-route-map;
+ }
import frr-route-types {
prefix frr-route-types;
}
@@ -71,7 +77,7 @@ module frr-ripngd {
"RIPng routing instance.";
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
description
"VRF name.";
}
@@ -170,9 +176,7 @@ module frr-ripngd {
must '. != "ripng"';
}
leaf route-map {
- type string {
- length "1..max";
- }
+ type frr-route-map:route-map-ref;
description
"Applies the conditions of the specified route-map to
routes that are redistributed into the RIPng routing
@@ -298,7 +302,7 @@ module frr-ripngd {
"Next hop IPv6 address.";
}
leaf interface {
- type string;
+ type frr-interface:interface-ref;
description
"The interface that the route uses.";
}
@@ -359,7 +363,7 @@ module frr-ripngd {
input {
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
description
"VRF name identifying a specific RIPng instance.
This leaf is optional for the rpc.
diff --git a/yang/frr-routing.yang b/yang/frr-routing.yang
index 52607f9ad0..f8441669af 100644
--- a/yang/frr-routing.yang
+++ b/yang/frr-routing.yang
@@ -249,7 +249,7 @@ module frr-routing {
instance.";
}
leaf vrf {
- type string;
+ type frr-vrf:vrf-ref;
description
"vrf for control-plane protocol";
}
diff --git a/yang/frr-test-module.yang b/yang/frr-test-module.yang
index 61915b1349..2f89ebca88 100644
--- a/yang/frr-test-module.yang
+++ b/yang/frr-test-module.yang
@@ -57,7 +57,7 @@ module frr-test-module {
}
container interfaces {
leaf-list interface {
- type string;
+ type frr-interface:interface-ref;
}
}
container routes {
@@ -69,7 +69,7 @@ module frr-test-module {
type inet:ipv4-address;
}
leaf interface {
- type string;
+ type frr-interface:interface-ref;
}
leaf metric {
type uint8;
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
index 2efc45c146..782e0a4b74 100644
--- a/yang/frr-zebra.yang
+++ b/yang/frr-zebra.yang
@@ -2137,7 +2137,7 @@ module frr-zebra {
"The admin distance to use for imported routes.";
}
leaf route-map {
- type string;
+ type frr-route-map:route-map-ref;
description
"A route-map to filter imported routes.";
}
diff --git a/zebra/rib.h b/zebra/rib.h
index be680a112f..9ddc35b091 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -333,6 +333,10 @@ extern void route_entry_copy_nexthops(struct route_entry *re,
int route_entry_update_nhe(struct route_entry *re,
struct nhg_hash_entry *new_nhghe);
+/* NHG replace has happend, we have to update route_entry pointers to new one */
+void rib_handle_nhg_replace(struct nhg_hash_entry *old,
+ struct nhg_hash_entry *new);
+
#define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re)
extern void _route_entry_dump(const char *func, union prefixconstptr pp,
union prefixconstptr src_pp,
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 146650f602..1ce3c435fe 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -126,6 +126,31 @@ static bool kernel_nexthops_supported(void)
}
/*
+ * Some people may only want to use NHGs created by protos and not
+ * implicitly created by Zebra. This check accounts for that.
+ */
+static bool proto_nexthops_only(void)
+{
+ return zebra_nhg_proto_nexthops_only();
+}
+
+/* Is this a proto created NHG? */
+static bool is_proto_nhg(uint32_t id, int type)
+{
+ /* If type is available, use it as the source of truth */
+ if (type) {
+ if (type != ZEBRA_ROUTE_NHG)
+ return true;
+ return false;
+ }
+
+ if (id >= ZEBRA_NHG_PROTO_LOWER)
+ return true;
+
+ return false;
+}
+
+/*
* The ipv4_ll data structure is used for all 5549
* additions to the kernel. Let's figure out the
* correct value one time instead for every
@@ -1748,7 +1773,10 @@ ssize_t netlink_route_multipath_msg_encode(int cmd,
nl_attr_nest_end(&req->n, nest);
}
- if ((!fpm && kernel_nexthops_supported()) || (fpm && force_nhg)) {
+ if ((!fpm && kernel_nexthops_supported()
+ && (!proto_nexthops_only()
+ || is_proto_nhg(dplane_ctx_get_nhe_id(ctx), 0)))
+ || (fpm && force_nhg)) {
/* Kernel supports nexthop objects */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("%s: %pFX nhg_id is %u", __func__, p,
@@ -2072,6 +2100,35 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
mpls_lse_t out_lse[MPLS_MAX_LABELS];
char label_buf[256];
int num_labels = 0;
+ uint32_t id = dplane_ctx_get_nhe_id(ctx);
+ int type = dplane_ctx_get_nhe_type(ctx);
+
+ if (!id) {
+ flog_err(
+ EC_ZEBRA_NHG_FIB_UPDATE,
+ "Failed trying to update a nexthop group in the kernel that does not have an ID");
+ return -1;
+ }
+
+ /*
+ * Nothing to do if the kernel doesn't support nexthop objects or
+ * we dont want to install this type of NHG
+ */
+ if (!kernel_nexthops_supported()) {
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: nhg_id %u (%s): kernel nexthops not supported, ignoring",
+ __func__, id, zebra_route_string(type));
+ return 0;
+ }
+
+ if (proto_nexthops_only() && !is_proto_nhg(id, type)) {
+ if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: nhg_id %u (%s): proto-based nexthops only, ignoring",
+ __func__, id, zebra_route_string(type));
+ return 0;
+ }
label_buf[0] = '\0';
@@ -2092,15 +2149,6 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
req->nhm.nh_family = AF_UNSPEC;
/* TODO: Scope? */
- uint32_t id = dplane_ctx_get_nhe_id(ctx);
-
- if (!id) {
- flog_err(
- EC_ZEBRA_NHG_FIB_UPDATE,
- "Failed trying to update a nexthop group in the kernel that does not have an ID");
- return -1;
- }
-
if (!nl_attr_put32(&req->n, buflen, NHA_ID, id))
return 0;
@@ -2221,8 +2269,7 @@ nexthop_done:
nh->vrf_id, label_buf);
}
- req->nhm.nh_protocol =
- zebra2proto(dplane_ctx_get_nhe_type(ctx));
+req->nhm.nh_protocol = zebra2proto(type);
} else if (cmd != RTM_DELNEXTHOP) {
flog_err(
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index e436e5a288..c33bca3d86 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -712,6 +712,34 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client,
return zserv_send_message(client, s);
}
+static int nhg_notify(uint16_t type, uint16_t instance, uint32_t id,
+ enum zapi_nhg_notify_owner note)
+{
+ struct zserv *client;
+ struct stream *s;
+
+ client = zserv_find_client(type, instance);
+ if (!client) {
+ if (IS_ZEBRA_DEBUG_PACKET) {
+ zlog_debug("Not Notifying Owner: %u(%u) about %u(%d)",
+ type, instance, id, note);
+ }
+ return 0;
+ }
+
+ s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_NHG_NOTIFY_OWNER, VRF_DEFAULT);
+
+ stream_put(s, &note, sizeof(note));
+ stream_putl(s, id);
+
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return zserv_send_message(client, s);
+}
+
/*
* Common utility send route notification, called from a path using a
* route_entry and from a path using a dataplane context.
@@ -1411,27 +1439,32 @@ stream_failure:
return;
}
-
-void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
+bool zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
const unsigned int nexthop_num)
{
if (nexthop_num > zrouter.multipath_num) {
char buff[PREFIX2STR_BUFFER];
- prefix2str(p, buff, sizeof(buff));
+ if (p)
+ prefix2str(p, buff, sizeof(buff));
+
flog_warn(
EC_ZEBRA_MORE_NH_THAN_MULTIPATH,
"%s: Prefix %s has %d nexthops, but we can only use the first %d",
- caller, buff, nexthop_num, zrouter.multipath_num);
+ caller, (p ? buff : "(NULL)"), nexthop_num,
+ zrouter.multipath_num);
+ return true;
}
+
+ return false;
}
/*
* Create a new nexthop based on a zapi nexthop.
*/
-static struct nexthop *nexthop_from_zapi(struct route_entry *re,
- const struct zapi_nexthop *api_nh,
- const struct zapi_route *api)
+static struct nexthop *nexthop_from_zapi(const struct zapi_nexthop *api_nh,
+ uint32_t flags, struct prefix *p,
+ uint16_t backup_nexthop_num)
{
struct nexthop *nexthop = NULL;
struct ipaddr vtep_ip;
@@ -1469,14 +1502,13 @@ static struct nexthop *nexthop_from_zapi(struct route_entry *re,
/* Special handling for IPv4 routes sourced from EVPN:
* the nexthop and associated MAC need to be installed.
*/
- if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+ if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) {
memset(&vtep_ip, 0, sizeof(struct ipaddr));
vtep_ip.ipa_type = IPADDR_V4;
memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4),
sizeof(struct in_addr));
zebra_vxlan_evpn_vrf_route_add(
- api_nh->vrf_id, &api_nh->rmac,
- &vtep_ip, &api->prefix);
+ api_nh->vrf_id, &api_nh->rmac, &vtep_ip, p);
}
break;
case NEXTHOP_TYPE_IPV6:
@@ -1503,14 +1535,13 @@ static struct nexthop *nexthop_from_zapi(struct route_entry *re,
/* Special handling for IPv6 routes sourced from EVPN:
* the nexthop and associated MAC need to be installed.
*/
- if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
+ if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) {
memset(&vtep_ip, 0, sizeof(struct ipaddr));
vtep_ip.ipa_type = IPADDR_V6;
memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
sizeof(struct in6_addr));
zebra_vxlan_evpn_vrf_route_add(
- api_nh->vrf_id, &api_nh->rmac,
- &vtep_ip, &api->prefix);
+ api_nh->vrf_id, &api_nh->rmac, &vtep_ip, p);
}
break;
case NEXTHOP_TYPE_BLACKHOLE:
@@ -1558,7 +1589,7 @@ static struct nexthop *nexthop_from_zapi(struct route_entry *re,
for (i = 0; i < api_nh->backup_num; i++) {
/* Validate backup index */
- if (api_nh->backup_idx[i] < api->backup_nexthop_num) {
+ if (api_nh->backup_idx[i] < backup_nexthop_num) {
nexthop->backup_idx[i] = api_nh->backup_idx[i];
} else {
if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
@@ -1576,99 +1607,69 @@ done:
return nexthop;
}
-static void zread_route_add(ZAPI_HANDLER_ARGS)
+static bool zapi_read_nexthops(struct zserv *client, struct prefix *p,
+ struct zapi_nexthop *nhops, uint32_t flags,
+ uint32_t message, uint16_t nexthop_num,
+ uint16_t backup_nh_num,
+ struct nexthop_group **png,
+ struct nhg_backup_info **pbnhg)
{
- struct stream *s;
- struct zapi_route api;
- struct zapi_nexthop *api_nh;
- afi_t afi;
- struct prefix_ipv6 *src_p = NULL;
- struct route_entry *re;
- struct nexthop *nexthop = NULL, *last_nh;
struct nexthop_group *ng = NULL;
struct nhg_backup_info *bnhg = NULL;
- int i, ret;
- vrf_id_t vrf_id;
- struct nhg_hash_entry nhe;
- enum lsp_types_t label_type;
- char nhbuf[NEXTHOP_STRLEN];
- char labelbuf[MPLS_LABEL_STRLEN];
-
- s = msg;
- if (zapi_route_decode(s, &api) < 0) {
- if (IS_ZEBRA_DEBUG_RECV)
- zlog_debug("%s: Unable to decode zapi_route sent",
- __func__);
- return;
- }
-
- vrf_id = zvrf_id(zvrf);
-
- if (IS_ZEBRA_DEBUG_RECV) {
- char buf_prefix[PREFIX_STRLEN];
+ uint16_t i;
+ struct nexthop *last_nh = NULL;
- prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
- zlog_debug("%s: p=(%u:%u)%s, msg flags=0x%x, flags=0x%x",
- __func__, vrf_id, api.tableid, buf_prefix, (int)api.message, api.flags);
- }
-
- /* Allocate new route. */
- re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
- re->type = api.type;
- re->instance = api.instance;
- re->flags = api.flags;
- re->uptime = monotime(NULL);
- re->vrf_id = vrf_id;
-
- if (api.tableid)
- re->table = api.tableid;
- else
- re->table = zvrf->table_id;
+ assert(!(png && pbnhg));
- if (!CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)
- || api.nexthop_num == 0) {
- flog_warn(EC_ZEBRA_RX_ROUTE_NO_NEXTHOPS,
- "%s: received a route without nexthops for prefix %pFX from client %s",
- __func__, &api.prefix,
- zebra_route_string(client->proto));
+ if (png)
+ ng = nexthop_group_new();
- XFREE(MTYPE_RE, re);
- return;
- }
+ if (pbnhg && backup_nh_num > 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: adding %d backup nexthops", __func__,
+ backup_nh_num);
- /* Report misuse of the backup flag */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS) &&
- api.backup_nexthop_num == 0) {
- if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("%s: client %s: BACKUP flag set but no backup nexthops, prefix %pFX",
- __func__,
- zebra_route_string(client->proto), &api.prefix);
+ bnhg = zebra_nhg_backup_alloc();
}
- /* Use temporary list of nexthops */
- ng = nexthop_group_new();
-
/*
* TBD should _all_ of the nexthop add operations use
* api_nh->vrf_id instead of re->vrf_id ? I only changed
* for cases NEXTHOP_TYPE_IPV4 and NEXTHOP_TYPE_IPV6.
*/
- for (i = 0; i < api.nexthop_num; i++) {
- api_nh = &api.nexthops[i];
+ for (i = 0; i < nexthop_num; i++) {
+ struct nexthop *nexthop;
+ enum lsp_types_t label_type;
+ char nhbuf[NEXTHOP_STRLEN];
+ char labelbuf[MPLS_LABEL_STRLEN];
+ struct zapi_nexthop *api_nh = &nhops[i];
/* Convert zapi nexthop */
- nexthop = nexthop_from_zapi(re, api_nh, &api);
+ nexthop = nexthop_from_zapi(api_nh, flags, p, backup_nh_num);
if (!nexthop) {
flog_warn(
EC_ZEBRA_NEXTHOP_CREATION_FAILED,
- "%s: Nexthops Specified: %d but we failed to properly create one",
- __func__, api.nexthop_num);
- nexthop_group_delete(&ng);
- XFREE(MTYPE_RE, re);
- return;
+ "%s: Nexthops Specified: %u(%u) but we failed to properly create one",
+ __func__, nexthop_num, i);
+ if (ng)
+ nexthop_group_delete(&ng);
+ if (bnhg)
+ zebra_nhg_backup_free(&bnhg);
+ return false;
}
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRTE)) {
+ if (bnhg
+ && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ if (IS_ZEBRA_DEBUG_RECV) {
+ nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
+ zlog_debug("%s: backup nh %s with BACKUP flag!",
+ __func__, nhbuf);
+ }
+ UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
+ nexthop->backup_num = 0;
+ }
+
+ if (CHECK_FLAG(message, ZAPI_MESSAGE_SRTE)) {
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE);
nexthop->srte_color = api_nh->srte_color;
}
@@ -1703,100 +1704,266 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
__func__, nhbuf, api_nh->vrf_id, labelbuf);
}
- /* Add new nexthop to temporary list. This list is
- * canonicalized - sorted - so that it can be hashed later
- * in route processing. We expect that the sender has sent
- * the list sorted, and the zapi client api attempts to enforce
- * that, so this should be inexpensive - but it is necessary
- * to support shared nexthop-groups.
- */
- nexthop_group_add_sorted(ng, nexthop);
+ if (ng) {
+ /* Add new nexthop to temporary list. This list is
+ * canonicalized - sorted - so that it can be hashed
+ * later in route processing. We expect that the sender
+ * has sent the list sorted, and the zapi client api
+ * attempts to enforce that, so this should be
+ * inexpensive - but it is necessary to support shared
+ * nexthop-groups.
+ */
+ nexthop_group_add_sorted(ng, nexthop);
+ }
+ if (bnhg) {
+ /* Note that the order of the backup nexthops is
+ * significant, so we don't sort this list as we do the
+ * primary nexthops, we just append.
+ */
+ if (last_nh)
+ NEXTHOP_APPEND(last_nh, nexthop);
+ else
+ bnhg->nhe->nhg.nexthop = nexthop;
+
+ last_nh = nexthop;
+ }
}
- /* Allocate temporary list of backup nexthops, if necessary */
- if (api.backup_nexthop_num > 0) {
- if (IS_ZEBRA_DEBUG_RECV)
- zlog_debug("%s: adding %d backup nexthops",
- __func__, api.backup_nexthop_num);
- bnhg = zebra_nhg_backup_alloc();
- nexthop = NULL;
- last_nh = NULL;
+ /* succesfully read, set caller pointers now */
+ if (png)
+ *png = ng;
+
+ if (pbnhg)
+ *pbnhg = bnhg;
+
+ return true;
+}
+
+int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
+{
+ uint16_t i;
+ struct zapi_nexthop *znh;
+
+ STREAM_GETW(s, api_nhg->proto);
+ STREAM_GETL(s, api_nhg->id);
+
+ if (cmd == ZEBRA_NHG_DEL)
+ goto done;
+
+ /* Nexthops */
+ STREAM_GETW(s, api_nhg->nexthop_num);
+
+ if (zserv_nexthop_num_warn(__func__, NULL, api_nhg->nexthop_num))
+ return -1;
+
+ if (api_nhg->nexthop_num <= 0) {
+ flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: No nexthops sent", __func__);
+ return -1;
}
- /* Copy backup nexthops also, if present */
- for (i = 0; i < api.backup_nexthop_num; i++) {
- api_nh = &api.backup_nexthops[i];
+ for (i = 0; i < api_nhg->nexthop_num; i++) {
+ znh = &((api_nhg->nexthops)[i]);
- /* Convert zapi backup nexthop */
- nexthop = nexthop_from_zapi(re, api_nh, &api);
- if (!nexthop) {
- flog_warn(
- EC_ZEBRA_NEXTHOP_CREATION_FAILED,
- "%s: Backup Nexthops Specified: %d but we failed to properly create one",
- __func__, api.backup_nexthop_num);
- nexthop_group_delete(&ng);
- zebra_nhg_backup_free(&bnhg);
- XFREE(MTYPE_RE, re);
- return;
+ if (zapi_nexthop_decode(s, znh, 0, 0) != 0) {
+ flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Nexthop creation failed", __func__);
+ return -1;
}
+ }
- /* Backup nexthops can't have backups; that's not valid. */
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
- if (IS_ZEBRA_DEBUG_RECV) {
- nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
- zlog_debug("%s: backup nh %s with BACKUP flag!",
- __func__, nhbuf);
- }
- UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
- nexthop->backup_num = 0;
- }
+ /* Backup Nexthops */
+ STREAM_GETW(s, api_nhg->backup_nexthop_num);
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRTE)) {
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE);
- nexthop->srte_color = api_nh->srte_color;
- }
+ if (zserv_nexthop_num_warn(__func__, NULL, api_nhg->backup_nexthop_num))
+ return -1;
- /* MPLS labels for BGP-LU or Segment Routing */
- if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
- && api_nh->type != NEXTHOP_TYPE_IFINDEX
- && api_nh->type != NEXTHOP_TYPE_BLACKHOLE
- && api_nh->label_num > 0) {
+ for (i = 0; i < api_nhg->backup_nexthop_num; i++) {
+ znh = &((api_nhg->backup_nexthops)[i]);
- label_type = lsp_type_from_re_type(client->proto);
- nexthop_add_labels(nexthop, label_type,
- api_nh->label_num,
- &api_nh->labels[0]);
+ if (zapi_nexthop_decode(s, znh, 0, 0) != 0) {
+ flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Backup Nexthop creation failed",
+ __func__);
+ return -1;
}
+ }
- if (IS_ZEBRA_DEBUG_RECV) {
- labelbuf[0] = '\0';
- nhbuf[0] = '\0';
+done:
+ return 0;
- nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
+stream_failure:
+ flog_warn(
+ EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Nexthop Group decode failed with some sort of stream read failure",
+ __func__);
+ return -1;
+}
- if (nexthop->nh_label &&
- nexthop->nh_label->num_labels > 0) {
- mpls_label2str(nexthop->nh_label->num_labels,
- nexthop->nh_label->label,
- labelbuf, sizeof(labelbuf),
- false);
- }
+static void zread_nhg_del(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_nhg api_nhg = {};
+ struct nhg_hash_entry *nhe;
- zlog_debug("%s: backup nh=%s, vrf_id=%d %s",
- __func__, nhbuf, api_nh->vrf_id, labelbuf);
- }
+ s = msg;
+ if (zapi_nhg_decode(s, hdr->command, &api_nhg) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_nhg sent",
+ __func__);
+ return;
+ }
- /* Note that the order of the backup nexthops is significant,
- * so we don't sort this list as we do the primary nexthops,
- * we just append.
- */
- if (last_nh)
- NEXTHOP_APPEND(last_nh, nexthop);
- else
- bnhg->nhe->nhg.nexthop = nexthop;
+ /*
+ * Delete the received nhg id
+ */
+
+ nhe = zebra_nhg_proto_del(api_nhg.id, api_nhg.proto);
+
+ if (nhe) {
+ zebra_nhg_decrement_ref(nhe);
+ nhg_notify(api_nhg.proto, client->instance, api_nhg.id,
+ ZAPI_NHG_REMOVED);
+ } else
+ nhg_notify(api_nhg.proto, client->instance, api_nhg.id,
+ ZAPI_NHG_REMOVE_FAIL);
+}
+
+static void zread_nhg_add(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_nhg api_nhg = {};
+ struct nexthop_group *nhg = NULL;
+ struct nhg_backup_info *bnhg = NULL;
+ struct nhg_hash_entry *nhe;
- last_nh = nexthop;
+ s = msg;
+ if (zapi_nhg_decode(s, hdr->command, &api_nhg) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_nhg sent",
+ __func__);
+ return;
+ }
+
+ if ((!zapi_read_nexthops(client, NULL, api_nhg.nexthops, 0, 0,
+ api_nhg.nexthop_num,
+ api_nhg.backup_nexthop_num, &nhg, NULL))
+ || (!zapi_read_nexthops(client, NULL, api_nhg.backup_nexthops, 0, 0,
+ api_nhg.backup_nexthop_num,
+ api_nhg.backup_nexthop_num, NULL, &bnhg))) {
+
+ flog_warn(EC_ZEBRA_NEXTHOP_CREATION_FAILED,
+ "%s: Nexthop Group Creation failed", __func__);
+ return;
+ }
+
+ /*
+ * Create the nhg
+ */
+ nhe = zebra_nhg_proto_add(api_nhg.id, api_nhg.proto, nhg, 0);
+
+ nexthop_group_delete(&nhg);
+ zebra_nhg_backup_free(&bnhg);
+
+ /*
+ * TODO:
+ * Assume fully resolved for now and install.
+ *
+ * Resolution is going to need some more work.
+ */
+ if (nhe)
+ nhg_notify(api_nhg.proto, client->instance, api_nhg.id,
+ ZAPI_NHG_INSTALLED);
+ else
+ nhg_notify(api_nhg.proto, client->instance, api_nhg.id,
+ ZAPI_NHG_FAIL_INSTALL);
+}
+
+static void zread_route_add(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ struct zapi_route api;
+ afi_t afi;
+ struct prefix_ipv6 *src_p = NULL;
+ struct route_entry *re;
+ struct nexthop_group *ng = NULL;
+ struct nhg_backup_info *bnhg = NULL;
+ int ret;
+ vrf_id_t vrf_id;
+ struct nhg_hash_entry nhe;
+
+ s = msg;
+ if (zapi_route_decode(s, &api) < 0) {
+ if (IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("%s: Unable to decode zapi_route sent",
+ __func__);
+ return;
+ }
+
+ vrf_id = zvrf_id(zvrf);
+
+ if (IS_ZEBRA_DEBUG_RECV) {
+ char buf_prefix[PREFIX_STRLEN];
+
+ prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
+ zlog_debug("%s: p=(%u:%u)%s, msg flags=0x%x, flags=0x%x",
+ __func__, vrf_id, api.tableid, buf_prefix,
+ (int)api.message, api.flags);
+ }
+
+ /* Allocate new route. */
+ re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
+ re->type = api.type;
+ re->instance = api.instance;
+ re->flags = api.flags;
+ re->uptime = monotime(NULL);
+ re->vrf_id = vrf_id;
+
+ if (api.tableid)
+ re->table = api.tableid;
+ else
+ re->table = zvrf->table_id;
+
+ if (!CHECK_FLAG(api.message, ZAPI_MESSAGE_NHG)
+ && (!CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)
+ || api.nexthop_num == 0)) {
+ flog_warn(
+ EC_ZEBRA_RX_ROUTE_NO_NEXTHOPS,
+ "%s: received a route without nexthops for prefix %pFX from client %s",
+ __func__, &api.prefix,
+ zebra_route_string(client->proto));
+
+ XFREE(MTYPE_RE, re);
+ return;
+ }
+
+ /* Report misuse of the backup flag */
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)
+ && api.backup_nexthop_num == 0) {
+ if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug(
+ "%s: client %s: BACKUP flag set but no backup nexthops, prefix %pFX",
+ __func__, zebra_route_string(client->proto),
+ &api.prefix);
+ }
+
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NHG))
+ re->nhe_id = api.nhgid;
+
+ if (!re->nhe_id
+ && (!zapi_read_nexthops(client, &api.prefix, api.nexthops,
+ api.flags, api.message, api.nexthop_num,
+ api.backup_nexthop_num, &ng, NULL)
+ || !zapi_read_nexthops(client, &api.prefix, api.backup_nexthops,
+ api.flags, api.message,
+ api.backup_nexthop_num,
+ api.backup_nexthop_num, NULL, &bnhg))) {
+
+ nexthop_group_delete(&ng);
+ zebra_nhg_backup_free(&bnhg);
+ XFREE(MTYPE_RE, re);
+ return;
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
@@ -1831,13 +1998,21 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
return;
}
- /* Include backup info with the route. We use a temporary nhe here;
+ /*
+ * If we have an ID, this proto owns the NHG it sent along with the
+ * route, so we just send the ID into rib code with it.
+ *
+ * Havent figured out how to handle backup NHs with this yet, so lets
+ * keep that separate.
+ * Include backup info with the route. We use a temporary nhe here;
* if this is a new/unknown nhe, a new copy will be allocated
* and stored.
*/
- zebra_nhe_init(&nhe, afi, ng->nexthop);
- nhe.nhg.nexthop = ng->nexthop;
- nhe.backup_info = bnhg;
+ if (!re->nhe_id) {
+ zebra_nhe_init(&nhe, afi, ng->nexthop);
+ nhe.nhg.nexthop = ng->nexthop;
+ nhe.backup_info = bnhg;
+ }
ret = rib_add_multipath_nhe(afi, api.safi, &api.prefix, src_p,
re, &nhe);
@@ -3118,7 +3293,10 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_MLAG_CLIENT_UNREGISTER] = zebra_mlag_client_unregister,
[ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg,
[ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities,
- [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover};
+ [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover,
+ [ZEBRA_NHG_ADD] = zread_nhg_add,
+ [ZEBRA_NHG_DEL] = zread_nhg_del,
+};
/*
* Process a batch of zapi messages.
diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h
index e7c755c2bf..9f23a313bf 100644
--- a/zebra/zapi_msg.h
+++ b/zebra/zapi_msg.h
@@ -90,7 +90,7 @@ zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset,
enum zapi_ipset_entry_notify_owner note);
extern void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable,
enum zapi_iptable_notify_owner note);
-extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
+extern bool zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
const unsigned int nexthop_num);
extern void zsend_capabilities_all_clients(void);
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index abd0adb64e..76d7d00e4a 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -73,6 +73,7 @@ const uint32_t DPLANE_DEFAULT_NEW_WORK = 100;
*/
struct dplane_nexthop_info {
uint32_t id;
+ uint32_t old_id;
afi_t afi;
vrf_id_t vrf_id;
int type;
@@ -1242,6 +1243,12 @@ uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx)
return ctx->u.rinfo.nhe.id;
}
+uint32_t dplane_ctx_get_old_nhe_id(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+ return ctx->u.rinfo.nhe.old_id;
+}
+
afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@@ -1912,6 +1919,7 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
struct nhg_hash_entry *nhe = zebra_nhg_resolve(re->nhe);
ctx->u.rinfo.nhe.id = nhe->id;
+ ctx->u.rinfo.nhe.old_id = 0;
/*
* Check if the nhe is installed/queued before doing anything
* with this route.
@@ -2328,6 +2336,7 @@ dplane_route_update_internal(struct route_node *rn,
ctx->u.rinfo.zd_old_instance = old_re->instance;
ctx->u.rinfo.zd_old_distance = old_re->distance;
ctx->u.rinfo.zd_old_metric = old_re->metric;
+ ctx->u.rinfo.nhe.old_id = old_re->nhe->id;
#ifndef HAVE_NETLINK
/* For bsd, capture previous re's nexthops too, sigh.
@@ -2349,6 +2358,40 @@ dplane_route_update_internal(struct route_node *rn,
#endif /* !HAVE_NETLINK */
}
+ /*
+ * If the old and new context type, and nexthop group id
+ * are the same there is no need to send down a route replace
+ * as that we know we have sent a nexthop group replace
+ * or an upper level protocol has sent us the exact
+ * same route again.
+ */
+ if ((dplane_ctx_get_type(ctx) == dplane_ctx_get_old_type(ctx))
+ && (dplane_ctx_get_nhe_id(ctx)
+ == dplane_ctx_get_old_nhe_id(ctx))
+ && (dplane_ctx_get_nhe_id(ctx) >= ZEBRA_NHG_PROTO_LOWER)) {
+ struct nexthop *nexthop;
+
+ if (IS_ZEBRA_DEBUG_DPLANE)
+ zlog_debug(
+ "%s: Ignoring Route exactly the same",
+ __func__);
+
+ for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
+ nexthop)) {
+ if (CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_RECURSIVE))
+ continue;
+
+ if (CHECK_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_ACTIVE))
+ SET_FLAG(nexthop->flags,
+ NEXTHOP_FLAG_FIB);
+ }
+
+ dplane_ctx_free(&ctx);
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+ }
+
/* Enqueue context for processing */
ret = dplane_update_enqueue(ctx);
}
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 1d852b1bac..fd70211f7c 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -316,6 +316,7 @@ dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx);
/* Accessors for nexthop information */
uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_get_old_nhe_id(const struct zebra_dplane_ctx *ctx);
afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx);
vrf_id_t dplane_ctx_get_nhe_vrf_id(const struct zebra_dplane_ctx *ctx);
int dplane_ctx_get_nhe_type(const struct zebra_dplane_ctx *ctx);
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index aabbd875ec..de79c59caa 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -53,14 +53,15 @@ uint32_t id_counter;
/* */
static bool g_nexthops_enabled = true;
+static bool proto_nexthops_only;
-static struct nhg_hash_entry *depends_find(const struct nexthop *nh,
- afi_t afi);
+static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
+ int type);
static void depends_add(struct nhg_connected_tree_head *head,
struct nhg_hash_entry *depend);
static struct nhg_hash_entry *
depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
- afi_t afi);
+ afi_t afi, int type);
static struct nhg_hash_entry *
depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
static void depends_decrement_free(struct nhg_connected_tree_head *head);
@@ -68,6 +69,35 @@ static void depends_decrement_free(struct nhg_connected_tree_head *head);
static struct nhg_backup_info *
nhg_backup_copy(const struct nhg_backup_info *orig);
+/* Helper function for getting the next allocatable ID */
+static uint32_t nhg_get_next_id(void)
+{
+ while (1) {
+ id_counter++;
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: ID %u checking", __func__, id_counter);
+
+ if (id_counter == ZEBRA_NHG_PROTO_LOWER) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: ID counter wrapped", __func__);
+
+ id_counter = 0;
+ continue;
+ }
+
+ if (zebra_nhg_lookup_id(id_counter)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: ID already exists", __func__);
+
+ continue;
+ }
+
+ break;
+ }
+
+ return id_counter;
+}
static void nhg_connected_free(struct nhg_connected *dep)
{
@@ -431,7 +461,6 @@ static void *zebra_nhg_hash_alloc(void *arg)
nhe->nhg.nexthop->vrf_id, nhe->id);
}
- zebra_nhg_insert_id(nhe);
return nhe;
}
@@ -439,17 +468,17 @@ static void *zebra_nhg_hash_alloc(void *arg)
uint32_t zebra_nhg_hash_key(const void *arg)
{
const struct nhg_hash_entry *nhe = arg;
- uint32_t val, key = 0x5a351234;
+ uint32_t key = 0x5a351234;
+ uint32_t primary = 0;
+ uint32_t backup = 0;
- val = nexthop_group_hash(&(nhe->nhg));
- if (nhe->backup_info) {
- val = jhash_2words(val,
- nexthop_group_hash(
- &(nhe->backup_info->nhe->nhg)),
- key);
- }
+ primary = nexthop_group_hash(&(nhe->nhg));
+ if (nhe->backup_info)
+ backup = nexthop_group_hash(&(nhe->backup_info->nhe->nhg));
+
+ key = jhash_3words(primary, backup, nhe->type, key);
- key = jhash_3words(nhe->vrf_id, nhe->afi, val, key);
+ key = jhash_2words(nhe->vrf_id, nhe->afi, key);
return key;
}
@@ -512,6 +541,9 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
return true;
+ if (nhe1->type != nhe2->type)
+ return false;
+
if (nhe1->vrf_id != nhe2->vrf_id)
return false;
@@ -611,7 +643,7 @@ static int zebra_nhg_process_grp(struct nexthop_group *nhg,
}
static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
- struct nexthop *nh, afi_t afi)
+ struct nexthop *nh, afi_t afi, int type)
{
struct nhg_hash_entry *depend = NULL;
struct nexthop_group resolved_ng = {};
@@ -622,7 +654,7 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
zlog_debug("%s: head %p, nh %pNHv",
__func__, nhg_depends, nh);
- depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
+ depend = zebra_nhg_rib_find(0, &resolved_ng, afi, type);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: nh %pNHv => %p (%u)",
@@ -671,8 +703,26 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
* assign the next global id value if necessary.
*/
if (lookup->id == 0)
- lookup->id = ++id_counter;
- newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
+ lookup->id = nhg_get_next_id();
+
+ if (lookup->id < ZEBRA_NHG_PROTO_LOWER) {
+ /*
+ * This is a zebra hashed/owned NHG.
+ *
+ * It goes in HASH and ID table.
+ */
+ newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
+ zebra_nhg_insert_id(newnhe);
+ } else {
+ /*
+ * This is upperproto owned NHG and should not be hashed to.
+ *
+ * It goes in ID table.
+ */
+ newnhe =
+ hash_get(zrouter.nhgs_id, lookup, zebra_nhg_hash_alloc);
+ }
+
created = true;
/* Mail back the new object */
@@ -709,14 +759,16 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE))
SET_FLAG(newnhe->flags, NEXTHOP_GROUP_VALID);
- if (nh->next == NULL) {
+ if (nh->next == NULL && newnhe->id < ZEBRA_NHG_PROTO_LOWER) {
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
/* Single recursive nexthop */
handle_recursive_depend(&newnhe->nhg_depends,
- nh->resolved, afi);
+ nh->resolved, afi,
+ newnhe->type);
recursive = true;
}
} else {
+ /* Proto-owned are groups by default */
/* List of nexthops */
for (nh = newnhe->nhg.nexthop; nh; nh = nh->next) {
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
@@ -726,7 +778,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
NEXTHOP_FLAG_RECURSIVE) ?
"(R)" : "");
- depends_find_add(&newnhe->nhg_depends, nh, afi);
+ depends_find_add(&newnhe->nhg_depends, nh, afi,
+ newnhe->type);
}
}
@@ -753,8 +806,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
__func__, nh);
/* Single recursive nexthop */
- handle_recursive_depend(&backup_nhe->nhg_depends,
- nh->resolved, afi);
+ handle_recursive_depend(&backup_nhe->nhg_depends, nh->resolved,
+ afi, backup_nhe->type);
recursive = true;
} else {
/* One or more backup NHs */
@@ -766,8 +819,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
NEXTHOP_FLAG_RECURSIVE) ?
"(R)" : "");
- depends_find_add(&backup_nhe->nhg_depends,
- nh, afi);
+ depends_find_add(&backup_nhe->nhg_depends, nh, afi,
+ backup_nhe->type);
}
}
@@ -960,30 +1013,6 @@ static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
return ctx;
}
-static bool zebra_nhg_contains_unhashable(struct nhg_hash_entry *nhe)
-{
- struct nhg_connected *rb_node_dep = NULL;
-
- frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
- if (CHECK_FLAG(rb_node_dep->nhe->flags,
- NEXTHOP_GROUP_UNHASHABLE))
- return true;
- }
-
- return false;
-}
-
-static void zebra_nhg_set_unhashable(struct nhg_hash_entry *nhe)
-{
- SET_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE);
- SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
-
- flog(LOG_INFO,
- EC_ZEBRA_DUPLICATE_NHG_MESSAGE,
- "Nexthop Group with ID (%d) is a duplicate, therefore unhashable, ignoring",
- nhe->id);
-}
-
static void zebra_nhg_set_valid(struct nhg_hash_entry *nhe)
{
struct nhg_connected *rb_node_dep;
@@ -1025,23 +1054,27 @@ done:
zebra_nhg_set_invalid(nhe);
}
-
-static void zebra_nhg_release(struct nhg_hash_entry *nhe)
+static void zebra_nhg_release_all_deps(struct nhg_hash_entry *nhe)
{
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nhe %p (%u)", __func__, nhe, nhe->id);
-
/* Remove it from any lists it may be on */
zebra_nhg_depends_release(nhe);
zebra_nhg_dependents_release(nhe);
if (nhe->ifp)
if_nhg_dependents_del(nhe->ifp, nhe);
+}
+
+static void zebra_nhg_release(struct nhg_hash_entry *nhe)
+{
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u)", __func__, nhe, nhe->id);
+
+ zebra_nhg_release_all_deps(nhe);
/*
- * If its unhashable, we didn't store it here and have to be
+ * If its not zebra owned, we didn't store it here and have to be
* sure we don't clear one thats actually being used.
*/
- if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
+ if (nhe->id < ZEBRA_NHG_PROTO_LOWER)
hash_release(zrouter.nhgs, nhe);
hash_release(zrouter.nhgs_id, nhe);
@@ -1117,8 +1150,8 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
return -ENOENT;
}
- if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type,
- afi))
+ if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, afi,
+ type))
depends_decrement_free(&nhg_depends);
/* These got copied over in zebra_nhg_alloc() */
@@ -1127,54 +1160,7 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
nhe = zebra_nhg_find_nexthop(id, nhg_ctx_get_nh(ctx), afi,
type);
- if (nhe) {
- if (id != nhe->id) {
- struct nhg_hash_entry *kernel_nhe = NULL;
-
- /* Duplicate but with different ID from
- * the kernel
- */
-
- /* The kernel allows duplicate nexthops
- * as long as they have different IDs.
- * We are ignoring those to prevent
- * syncing problems with the kernel
- * changes.
- *
- * We maintain them *ONLY* in the ID hash table to
- * track them and set the flag to indicated
- * their attributes are unhashable.
- */
-
- kernel_nhe = zebra_nhe_copy(nhe, id);
-
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: copying kernel nhe (%u), dup of %u",
- __func__, id, nhe->id);
-
- zebra_nhg_insert_id(kernel_nhe);
- zebra_nhg_set_unhashable(kernel_nhe);
- } else if (zebra_nhg_contains_unhashable(nhe)) {
- /* The group we got contains an unhashable/duplicated
- * depend, so lets mark this group as unhashable as well
- * and release it from the non-ID hash.
- */
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nhe %p (%u) unhashable",
- __func__, nhe, nhe->id);
-
- hash_release(zrouter.nhgs, nhe);
- zebra_nhg_set_unhashable(nhe);
- } else {
- /* It actually created a new nhe */
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- zlog_debug("%s: nhe %p (%u) is new",
- __func__, nhe, nhe->id);
-
- SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
- SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
- }
- } else {
+ if (!nhe) {
flog_err(
EC_ZEBRA_TABLE_LOOKUP_FAILED,
"Zebra failed to find or create a nexthop hash entry for ID (%u)",
@@ -1182,6 +1168,12 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
return -1;
}
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: nhe %p (%u) is new", __func__, nhe, nhe->id);
+
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_VALID);
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
+
return 0;
}
@@ -1283,7 +1275,7 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
zlog_debug("%s: nh %pNHv, id %u, count %d",
__func__, nh, id, (int)count);
- if (id > id_counter)
+ if (id > id_counter && id < ZEBRA_NHG_PROTO_LOWER)
/* Increase our counter so we don't try to create
* an ID that already exists
*/
@@ -1326,14 +1318,14 @@ int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
/* Some dependency helper functions */
static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
- afi_t afi)
+ afi_t afi, int type)
{
struct nhg_hash_entry *nhe;
struct nexthop *lookup = NULL;
lookup = nexthop_dup(nh, NULL);
- nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
+ nhe = zebra_nhg_find_nexthop(0, lookup, afi, type);
nexthops_free(lookup);
@@ -1341,7 +1333,7 @@ static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
}
static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
- afi_t afi)
+ afi_t afi, int type)
{
struct nhg_hash_entry *nhe;
struct nexthop lookup = {};
@@ -1351,7 +1343,7 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
*/
nexthop_copy_no_recurse(&lookup, nh, NULL);
- nhe = zebra_nhg_find_nexthop(0, &lookup, afi, 0);
+ nhe = zebra_nhg_find_nexthop(0, &lookup, afi, type);
/* The copy may have allocated labels; free them if necessary. */
nexthop_del_labels(&lookup);
@@ -1363,7 +1355,8 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
return nhe;
}
-static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
+static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
+ int type)
{
struct nhg_hash_entry *nhe = NULL;
@@ -1374,9 +1367,9 @@ static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
* in the non-recursive case (by not alloc/freeing)
*/
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
- nhe = depends_find_recursive(nh, afi);
+ nhe = depends_find_recursive(nh, afi, type);
else
- nhe = depends_find_singleton(nh, afi);
+ nhe = depends_find_singleton(nh, afi, type);
if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
@@ -1409,11 +1402,11 @@ static void depends_add(struct nhg_connected_tree_head *head,
static struct nhg_hash_entry *
depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
- afi_t afi)
+ afi_t afi, int type)
{
struct nhg_hash_entry *depend = NULL;
- depend = depends_find(nh, afi);
+ depend = depends_find(nh, afi, type);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: nh %pNHv => %p",
@@ -1445,8 +1438,9 @@ static void depends_decrement_free(struct nhg_connected_tree_head *head)
}
/* Find an nhe based on a list of nexthops */
-struct nhg_hash_entry *
-zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
+struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id,
+ struct nexthop_group *nhg,
+ afi_t rt_afi, int type)
{
struct nhg_hash_entry *nhe = NULL;
vrf_id_t vrf_id;
@@ -1458,7 +1452,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
assert(nhg->nexthop);
vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
- zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
+ zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, type);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: => nhe %p (%u)",
@@ -1829,13 +1823,13 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
if (!ifp) {
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("nexthop %pNHv marked onlink but nhif %u doesn't exist",
nexthop, nexthop->ifindex);
return 0;
}
if (!if_is_operative(ifp)) {
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("nexthop %pNHv marked onlink but nhif %s is not operational",
nexthop, ifp->name);
return 0;
@@ -1991,6 +1985,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|| nexthop->type == NEXTHOP_TYPE_IPV6)
nexthop->ifindex = newhop->ifindex;
else if (nexthop->ifindex != newhop->ifindex) {
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug(
+ "%s: %pNHv given ifindex does not match nexthops ifindex found found: %pNHv",
+ __func__, nexthop,
+ newhop);
/*
* NEXTHOP_TYPE_*_IFINDEX but ifindex
* doesn't match what we found.
@@ -2012,7 +2011,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
/* Only useful if installed */
if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) {
- if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug("%s: match %p (%u) not installed",
__func__, match,
match->nhe->id);
@@ -2326,6 +2325,22 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
return counter;
}
+
+static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg)
+{
+ struct nexthop *nh;
+ uint32_t curr_active = 0;
+
+ /* Assume all active for now */
+
+ for (nh = nhg->nexthop; nh; nh = nh->next) {
+ SET_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE);
+ curr_active++;
+ }
+
+ return curr_active;
+}
+
/*
* Iterate over all nexthops of the given RIB entry and refresh their
* ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
@@ -2338,6 +2353,9 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
struct nhg_hash_entry *curr_nhe;
uint32_t curr_active = 0, backup_active = 0;
+ if (re->nhe->id >= ZEBRA_NHG_PROTO_LOWER)
+ return proto_nhg_nexthop_active_update(&re->nhe->nhg);
+
afi_t rt_afi = family2afi(rn->p.family);
UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
@@ -2543,7 +2561,8 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
&& !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
&& !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
/* Change its type to us since we are installing it */
- nhe->type = ZEBRA_ROUTE_NHG;
+ if (!ZEBRA_NHG_CREATED(nhe))
+ nhe->type = ZEBRA_ROUTE_NHG;
int ret = dplane_nexthop_add(nhe);
@@ -2700,3 +2719,251 @@ bool zebra_nhg_kernel_nexthops_enabled(void)
{
return g_nexthops_enabled;
}
+
+/*
+ * Global control to only use kernel nexthops for protocol created NHGs.
+ * There are some use cases where you may not want zebra to implicitly
+ * create kernel nexthops for all routes and only create them for NHGs
+ * passed down by upper level protos.
+ *
+ * Default is off.
+ */
+void zebra_nhg_set_proto_nexthops_only(bool set)
+{
+ proto_nexthops_only = set;
+}
+
+bool zebra_nhg_proto_nexthops_only(void)
+{
+ return proto_nexthops_only;
+}
+
+/* Add NHE from upper level proto */
+struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
+ struct nexthop_group *nhg, afi_t afi)
+{
+ struct nhg_hash_entry lookup;
+ struct nhg_hash_entry *new, *old;
+ struct nhg_connected *rb_node_dep = NULL;
+ struct nexthop *newhop;
+ bool replace = false;
+
+ if (!nhg->nexthop) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug("%s: id %u, no nexthops passed to add",
+ __func__, id);
+ return NULL;
+ }
+
+
+ /* Set nexthop list as active, since they wont go through rib
+ * processing.
+ *
+ * Assuming valid/onlink for now.
+ *
+ * Once resolution is figured out, we won't need this!
+ */
+ for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
+ if (CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: id %u, backup nexthops not supported",
+ __func__, id);
+ return NULL;
+ }
+
+ if (newhop->type == NEXTHOP_TYPE_BLACKHOLE) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: id %u, blackhole nexthop not supported",
+ __func__, id);
+ return NULL;
+ }
+
+ if (newhop->type == NEXTHOP_TYPE_IFINDEX) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: id %u, nexthop without gateway not supported",
+ __func__, id);
+ return NULL;
+ }
+
+ if (!newhop->ifindex) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: id %u, nexthop without ifindex is not supported",
+ __func__, id);
+ return NULL;
+ }
+ SET_FLAG(newhop->flags, NEXTHOP_FLAG_ACTIVE);
+ }
+
+ zebra_nhe_init(&lookup, afi, nhg->nexthop);
+ lookup.nhg.nexthop = nhg->nexthop;
+ lookup.id = id;
+ lookup.type = type;
+
+ old = zebra_nhg_lookup_id(id);
+
+ if (old) {
+ /*
+ * This is a replace, just release NHE from ID for now, The
+ * depends/dependents may still be used in the replacement.
+ */
+ replace = true;
+ hash_release(zrouter.nhgs_id, old);
+ }
+
+ new = zebra_nhg_rib_find_nhe(&lookup, afi);
+
+ zebra_nhg_increment_ref(new);
+
+ zebra_nhg_set_valid_if_active(new);
+
+ zebra_nhg_install_kernel(new);
+
+ if (old) {
+ /*
+ * Check to handle recving DEL while routes still in use then
+ * a replace.
+ *
+ * In this case we would have decremented the refcnt already
+ * but set the FLAG here. Go ahead and increment once to fix
+ * the misordering we have been sent.
+ */
+ if (CHECK_FLAG(old->flags, NEXTHOP_GROUP_PROTO_RELEASED))
+ zebra_nhg_increment_ref(old);
+
+ rib_handle_nhg_replace(old, new);
+
+ /* if this != 1 at this point, we have a bug */
+ assert(old->refcnt == 1);
+
+ /* We have to decrement its singletons
+ * because some might not exist in NEW.
+ */
+ if (!zebra_nhg_depends_is_empty(old)) {
+ frr_each (nhg_connected_tree, &old->nhg_depends,
+ rb_node_dep)
+ zebra_nhg_decrement_ref(rb_node_dep->nhe);
+ }
+
+ /* Free all the things */
+ zebra_nhg_release_all_deps(old);
+
+ /* Dont call the dec API, we dont want to uninstall the ID */
+ old->refcnt = 0;
+ zebra_nhg_free(old);
+ old = NULL;
+ }
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: %s nhe %p (%u), vrf %d, type %s", __func__,
+ (replace ? "replaced" : "added"), new, new->id,
+ new->vrf_id, zebra_route_string(new->type));
+
+ return new;
+}
+
+/* Delete NHE from upper level proto, caller must decrement ref */
+struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id, int type)
+{
+ struct nhg_hash_entry *nhe;
+
+ nhe = zebra_nhg_lookup_id(id);
+
+ if (!nhe) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug("%s: id %u, lookup failed", __func__, id);
+
+ return NULL;
+ }
+
+ if (type != nhe->type) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: id %u, type %s mismatch, sent by %s, ignoring",
+ __func__, id, zebra_route_string(nhe->type),
+ zebra_route_string(type));
+ return NULL;
+ }
+
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_PROTO_RELEASED)) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug("%s: id %u, already released", __func__, id);
+
+ return NULL;
+ }
+
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_PROTO_RELEASED);
+
+ if (nhe->refcnt > 1) {
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug(
+ "%s: id %u, still being used by routes refcnt %u",
+ __func__, nhe->id, nhe->refcnt);
+ return nhe;
+ }
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: deleted nhe %p (%u), vrf %d, type %s", __func__,
+ nhe, nhe->id, nhe->vrf_id,
+ zebra_route_string(nhe->type));
+
+ return nhe;
+}
+
+struct nhg_score_proto_iter {
+ int type;
+ struct list *found;
+};
+
+static void zebra_nhg_score_proto_entry(struct hash_bucket *bucket, void *arg)
+{
+ struct nhg_hash_entry *nhe;
+ struct nhg_score_proto_iter *iter;
+
+ nhe = (struct nhg_hash_entry *)bucket->data;
+ iter = arg;
+
+ /* Needs to match type and outside zebra ID space */
+ if (nhe->type == iter->type && nhe->id >= ZEBRA_NHG_PROTO_LOWER) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug(
+ "%s: found nhe %p (%u), vrf %d, type %s after client disconnect",
+ __func__, nhe, nhe->id, nhe->vrf_id,
+ zebra_route_string(nhe->type));
+
+ /* Add to removal list */
+ listnode_add(iter->found, nhe);
+ }
+}
+
+/* Remove specific by proto NHGs */
+unsigned long zebra_nhg_score_proto(int type)
+{
+ struct nhg_hash_entry *nhe;
+ struct nhg_score_proto_iter iter = {};
+ struct listnode *ln;
+ unsigned long count;
+
+ iter.type = type;
+ iter.found = list_new();
+
+ /* Find matching entries to remove */
+ hash_iterate(zrouter.nhgs_id, zebra_nhg_score_proto_entry, &iter);
+
+ /* Now remove them */
+ for (ALL_LIST_ELEMENTS_RO(iter.found, ln, nhe)) {
+ /*
+ * This should be the last ref if we remove client routes too,
+ * and thus should remove and free them.
+ */
+ zebra_nhg_decrement_ref(nhe);
+ }
+
+ count = iter.found->count;
+ list_delete(&iter.found);
+
+ return count;
+}
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index de5f097472..052fa65d06 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -102,20 +102,23 @@ struct nhg_hash_entry {
* Is this a nexthop that is recursively resolved?
*/
#define NEXTHOP_GROUP_RECURSIVE (1 << 3)
-/*
- * This is a nexthop group we got from the kernel, it is identical to
- * one we already have. (The kernel allows duplicate nexthops, we don't
- * since we hash on them). We are only tracking it in our ID table,
- * it is unusable by our created routes but may be used by routes we get
- * from the kernel. Therefore, it is unhashable.
- */
-#define NEXTHOP_GROUP_UNHASHABLE (1 << 4)
/*
* Backup nexthop support - identify groups that are backups for
* another group.
*/
-#define NEXTHOP_GROUP_BACKUP (1 << 5)
+#define NEXTHOP_GROUP_BACKUP (1 << 4)
+
+/*
+ * The NHG has been release by an upper level protocol via the
+ * `zebra_nhg_proto_del()` API.
+ *
+ * We use this flag to track this state in case the NHG is still being used
+ * by routes therefore holding their refcnts as well. Otherwise, the NHG will
+ * be removed and uninstalled.
+ *
+ */
+#define NEXTHOP_GROUP_PROTO_RELEASED (1 << 5)
/*
* Track FPM installation status..
@@ -124,7 +127,11 @@ struct nhg_hash_entry {
};
/* Was this one we created, either this session or previously? */
-#define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG)
+#define ZEBRA_NHG_CREATED(NHE) \
+ (((NHE->type) <= ZEBRA_ROUTE_MAX) && (NHE->type != ZEBRA_ROUTE_KERNEL))
+
+/* Is this an NHE owned by zebra and not an upper level protocol? */
+#define ZEBRA_OWNED(NHE) (NHE->type == ZEBRA_ROUTE_NHG)
/*
* Backup nexthops: this is a group object itself, so
@@ -186,6 +193,10 @@ struct nhg_ctx {
void zebra_nhg_enable_kernel_nexthops(bool set);
bool zebra_nhg_kernel_nexthops_enabled(void);
+/* Global control for zebra to only use proto-owned nexthops */
+void zebra_nhg_set_proto_nexthops_only(bool set);
+bool zebra_nhg_proto_nexthops_only(void);
+
/**
* NHE abstracted tree functions.
* Use these where possible instead of direct access.
@@ -249,13 +260,50 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
/* Find an nhe based on a nexthop_group */
-extern struct nhg_hash_entry *
-zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi);
+extern struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id,
+ struct nexthop_group *nhg,
+ afi_t rt_afi, int type);
/* Find an nhe based on a route's nhe, used during route creation */
struct nhg_hash_entry *
zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi);
+
+/**
+ * Functions for Add/Del/Replace via protocol NHG creation.
+ *
+ * The NHEs will not be hashed. They will only be present in the
+ * ID table and therefore not sharable.
+ *
+ * It is the owning protocols job to manage these.
+ */
+
+/*
+ * Add NHE. If already exists, Replace.
+ *
+ * Returns allocated NHE on success, otherwise NULL.
+ */
+struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
+ struct nexthop_group *nhg,
+ afi_t afi);
+
+/*
+ * Del NHE.
+ *
+ * Returns deleted NHE on success, otherwise NULL.
+ *
+ * Caller must decrement ref with zebra_nhg_decrement_ref() when done.
+ */
+struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id, int type);
+
+/*
+ * Remove specific by proto NHGs.
+ *
+ * Called after client disconnect.
+ *
+ */
+unsigned long zebra_nhg_score_proto(int type);
+
/* Reference counter functions */
extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe);
extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index ff30de18a3..aac0e628fe 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -235,7 +235,7 @@ int route_entry_update_nhe(struct route_entry *re,
goto done;
}
- if ((re->nhe_id != 0) && (re->nhe_id != new_nhghe->id)) {
+ if ((re->nhe_id != 0) && re->nhe && (re->nhe != new_nhghe)) {
old = re->nhe;
route_entry_attach_ref(re, new_nhghe);
@@ -250,6 +250,29 @@ done:
return ret;
}
+void rib_handle_nhg_replace(struct nhg_hash_entry *old,
+ struct nhg_hash_entry *new)
+{
+ struct zebra_router_table *zrt;
+ struct route_node *rn;
+ struct route_entry *re, *next;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED || IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: replacing routes nhe (%u) OLD %p NEW %p",
+ __func__, new->id, new, old);
+
+ /* We have to do them ALL */
+ RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
+ for (rn = route_top(zrt->table); rn;
+ rn = srcdest_route_next(rn)) {
+ RNODE_FOREACH_RE_SAFE (rn, re, next) {
+ if (re->nhe && re->nhe == old)
+ route_entry_update_nhe(re, new);
+ }
+ }
+ }
+}
+
struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
union g_addr *addr, struct route_node **rn_out)
{
@@ -2906,14 +2929,14 @@ int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
if (!table)
return -1;
- if (re_nhe->id > 0) {
- nhe = zebra_nhg_lookup_id(re_nhe->id);
+ if (re->nhe_id > 0) {
+ nhe = zebra_nhg_lookup_id(re->nhe_id);
if (!nhe) {
flog_err(
EC_ZEBRA_TABLE_LOOKUP_FAILED,
"Zebra failed to find the nexthop hash entry for id=%u in a route entry",
- re_nhe->id);
+ re->nhe_id);
return -1;
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 0088b49512..6785151705 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1300,13 +1300,10 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
struct nhg_connected *rb_node_dep = NULL;
struct nexthop_group *backup_nhg;
- vty_out(vty, "ID: %u\n", nhe->id);
+ vty_out(vty, "ID: %u (%s)\n", nhe->id, zebra_route_string(nhe->type));
vty_out(vty, " RefCnt: %d\n", nhe->refcnt);
vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id));
- if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_UNHASHABLE))
- vty_out(vty, " Duplicate - from kernel not hashable\n");
-
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
vty_out(vty, " Valid");
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED))
@@ -1569,6 +1566,17 @@ DEFPY_HIDDEN(nexthop_group_use_enable,
return CMD_SUCCESS;
}
+DEFPY_HIDDEN(proto_nexthop_group_only, proto_nexthop_group_only_cmd,
+ "[no] zebra nexthop proto only",
+ NO_STR ZEBRA_STR
+ "Nexthop configuration\n"
+ "Configure exclusive use of proto nexthops\n"
+ "Only use proto nexthops\n")
+{
+ zebra_nhg_set_proto_nexthops_only(!no);
+ return CMD_SUCCESS;
+}
+
DEFUN (no_ip_nht_default_route,
no_ip_nht_default_route_cmd,
"no ip nht resolve-via-default",
@@ -3451,6 +3459,9 @@ static int config_write_protocol(struct vty *vty)
if (!zebra_nhg_kernel_nexthops_enabled())
vty_out(vty, "no zebra nexthop kernel enable\n");
+ if (zebra_nhg_proto_nexthops_only())
+ vty_out(vty, "zebra nexthop proto only\n");
+
#ifdef HAVE_NETLINK
/* Include netlink info */
netlink_config_write_helper(vty);
@@ -3885,6 +3896,7 @@ void zebra_vty_init(void)
install_element(CONFIG_NODE, &zebra_packet_process_cmd);
install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
install_element(CONFIG_NODE, &nexthop_group_use_enable_cmd);
+ install_element(CONFIG_NODE, &proto_nexthop_group_only_cmd);
install_element(VIEW_NODE, &show_nexthop_group_cmd);
install_element(VIEW_NODE, &show_interface_nexthop_group_cmd);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 61498973e9..d8ed58edef 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -4594,6 +4594,11 @@ int zebra_vxlan_if_down(struct interface *ifp)
assert(zevpn->vxlan_if == ifp);
+ /* remove from l3-vni list */
+ zl3vni = zl3vni_from_vrf(zevpn->vrf_id);
+ if (zl3vni)
+ listnode_delete(zl3vni->l2vnis, zevpn);
+
/* Delete this VNI from BGP. */
zebra_evpn_send_del_to_client(zevpn);
@@ -4668,7 +4673,7 @@ int zebra_vxlan_if_up(struct interface *ifp)
zevpn->vrf_id = vlan_if->vrf_id;
zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
if (zl3vni)
- listnode_add_sort(zl3vni->l2vnis, zevpn);
+ listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
}
/* If part of a bridge, inform BGP about this VNI. */
@@ -5007,7 +5012,7 @@ int zebra_vxlan_if_add(struct interface *ifp)
zevpn->vrf_id = vlan_if->vrf_id;
zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
if (zl3vni)
- listnode_add_sort(zl3vni->l2vnis, zevpn);
+ listnode_add_sort_nodup(zl3vni->l2vnis, zevpn);
}
if (IS_ZEBRA_DEBUG_VXLAN) {
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 4c8656af0d..44f4641fcf 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -590,6 +590,7 @@ static void zserv_client_free(struct zserv *client)
/* Close file descriptor. */
if (client->sock) {
unsigned long nroutes;
+ unsigned long nnhgs;
close(client->sock);
@@ -600,6 +601,13 @@ static void zserv_client_free(struct zserv *client)
"client %d disconnected %lu %s routes removed from the rib",
client->sock, nroutes,
zebra_route_string(client->proto));
+
+ /* Not worrying about instance for now */
+ nnhgs = zebra_nhg_score_proto(client->proto);
+ zlog_notice(
+ "client %d disconnected %lu %s nhgs removed from the rib",
+ client->sock, nnhgs,
+ zebra_route_string(client->proto));
}
client->sock = -1;
}