summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn.c4
-rw-r--r--bgpd/bgp_evpn_mh.c42
-rw-r--r--bgpd/bgp_evpn_mh.h1
-rwxr-xr-xconfigure.ac14
-rw-r--r--doc/developer/building-frr-for-ubuntu2004.rst2
-rw-r--r--doc/developer/topotests.rst79
-rw-r--r--doc/user/bgp.rst6
-rw-r--r--doc/user/ospfd.rst21
-rw-r--r--isisd/isis_nb_config.c2
-rw-r--r--ospf6d/ospf6_flood.c13
-rw-r--r--ospf6d/ospf6_lsa.c16
-rw-r--r--ospfd/ospf_abr.c3
-rw-r--r--ospfd/ospf_lsa.c29
-rw-r--r--ospfd/ospf_lsa.h11
-rw-r--r--ospfd/ospf_vty.c58
-rw-r--r--ospfd/ospfd.c28
-rw-r--r--ospfd/ospfd.h6
-rw-r--r--pathd/path_nb_config.c8
-rw-r--r--pimd/pim_cmd.c6
-rw-r--r--pimd/pim_nb_config.c25
-rwxr-xr-xtests/topotests/conftest.py189
-rw-r--r--tests/topotests/lib/topotest.py137
-rwxr-xr-xtests/topotests/ospf_suppress_fa/__init__.py0
-rw-r--r--tests/topotests/ospf_suppress_fa/r1/ospfd.conf9
-rw-r--r--tests/topotests/ospf_suppress_fa/r1/zebra.conf4
-rw-r--r--tests/topotests/ospf_suppress_fa/r2/ospfd.conf16
-rw-r--r--tests/topotests/ospf_suppress_fa/r2/zebra.conf7
-rw-r--r--tests/topotests/ospf_suppress_fa/r3/ospfd.conf11
-rw-r--r--tests/topotests/ospf_suppress_fa/r3/zebra.conf8
-rw-r--r--tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot66
-rw-r--r--tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpgbin0 -> 33501 bytes
-rw-r--r--tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py181
-rw-r--r--tools/frrcommon.sh.in13
-rw-r--r--vtysh/vtysh.c2
-rw-r--r--yang/frr-pim.yang3
-rw-r--r--yang/frr-zebra.yang2
-rw-r--r--zebra/zebra_nb.c14
-rw-r--r--zebra/zebra_nb.h19
-rw-r--r--zebra/zebra_nb_config.c69
-rw-r--r--zebra/zebra_nb_state.c23
-rw-r--r--zebra/zebra_vty.c69
41 files changed, 1010 insertions, 206 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index ec71264081..cebc1c4d22 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -2235,6 +2235,8 @@ int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
int ret;
struct prefix_evpn p;
+ update_type1_routes_for_evi(bgp, vpn);
+
/* Update and advertise the type-3 route (only one) followed by the
* locally learnt type-2 routes (MACIP) - for this VNI.
*
@@ -3136,7 +3138,7 @@ static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
return ret;
ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE,
- 1);
+ 0);
if (ret)
return ret;
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index 123c46f12f..826de21b9d 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -970,6 +970,48 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp,
return 0;
}
+/*
+ * This function is called when the export RT for a VNI changes.
+ * Update all type-1 local routes for this VNI from VNI/ES tables and the global
+ * table and advertise these routes to peers.
+ */
+
+void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn)
+{
+ struct prefix_evpn p;
+ struct bgp_evpn_es *es;
+ struct bgp_evpn_es_evi *es_evi;
+ struct bgp_evpn_es_evi *es_evi_next;
+
+ RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head,
+ &vpn->es_evi_rb_tree, es_evi_next) {
+ es = es_evi->es;
+
+ /* Update EAD-ES */
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
+ build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
+ &es->esi, es->originator_ip);
+ if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
+ flog_err(EC_BGP_EVPN_ROUTE_CREATE,
+ "%u: EAD-ES route update failure for ESI %s VNI %u",
+ bgp->vrf_id, es->esi_str,
+ es_evi->vpn->vni);
+ }
+
+ /* Update EAD-EVI */
+ if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
+ build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
+ &es->esi, es->originator_ip);
+ if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn,
+ &p))
+ flog_err(EC_BGP_EVPN_ROUTE_DELETE,
+ "%u: EAD-EVI route update failure for ESI %s VNI %u",
+ bgp->vrf_id, es->esi_str,
+ es_evi->vpn->vni);
+ }
+ }
+}
+
/* Delete local Type-1 route */
static int bgp_evpn_type1_es_route_delete(struct bgp *bgp,
struct bgp_evpn_es *es, struct prefix_evpn *p)
diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h
index 1053e3f022..8c66e391b6 100644
--- a/bgpd/bgp_evpn_mh.h
+++ b/bgpd/bgp_evpn_mh.h
@@ -335,6 +335,7 @@ extern int bgp_evpn_es_route_install_uninstall(struct bgp *bgp,
struct bgp_evpn_es *es, afi_t afi, safi_t safi,
struct prefix_evpn *evp, struct bgp_path_info *pi,
int install);
+extern void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn);
int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
struct attr *attr, uint8_t *pfx, int psize,
uint32_t addpath_id);
diff --git a/configure.ac b/configure.ac
index 44d68f4845..f9516e559f 100755
--- a/configure.ac
+++ b/configure.ac
@@ -288,11 +288,17 @@ if test "$enable_clang_coverage" = "yes"; then
fi
if test "$enable_scripting" = "yes"; then
- AX_PROG_LUA([5.3])
- AX_LUA_HEADERS
+ AX_PROG_LUA([5.3], [5.4], [], [
+ AC_MSG_ERROR([Lua 5.3 is required to build with Lua support. No other version is supported.])
+ ])
+ AX_LUA_HEADERS([], [
+ AC_MSG_ERROR([Lua 5.3 headers are required to build with Lua support. No other version is supported.])
+ ])
AX_LUA_LIBS([
- AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting])
- LIBS="$LIBS $LUA_LIB"
+ AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting])
+ LIBS="$LIBS $LUA_LIB"
+ ], [
+ AC_MSG_ERROR([Lua 5.3 libraries are required to build with Lua support. No other version is supported.])
])
fi
diff --git a/doc/developer/building-frr-for-ubuntu2004.rst b/doc/developer/building-frr-for-ubuntu2004.rst
index ffc05a6841..58d72e2891 100644
--- a/doc/developer/building-frr-for-ubuntu2004.rst
+++ b/doc/developer/building-frr-for-ubuntu2004.rst
@@ -27,7 +27,7 @@ ubuntu apt repositories; in order to install it:
.. code-block:: shell
- curl https://bootstrap.pypa.io/2.7/get-pip.py --output get-pip.py
+ curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
sudo python2 ./get-pip.py
# And verify the installation
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index 4f58ee335b..2a6d2dda34 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -233,6 +233,85 @@ for ``master`` branch:
and create ``frr`` user and ``frrvty`` group as shown above.
+Debugging Topotest Failures
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For the below debugging options which launch programs, if the topotest is run
+within screen_ or tmux_, ``gdb``, the shell or ``vtysh`` will be launched using
+that windowing program, otherwise mininet's ``xterm`` functionality will be used
+to launch the given program.
+
+If you wish to force the use of ``xterm`` rather than ``tmux`` or ``screen``, or
+wish to use ``gnome-terminal`` instead of ``xterm``, set the environment
+variable ``FRR_TOPO_TERMINAL`` to either ``xterm`` or ``gnome-terminal``.
+
+.. _screen: https://www.gnu.org/software/screen/
+.. _tmux: https://github.com/tmux/tmux/wiki
+
+Spawning ``vtysh`` or Shells on Routers
+"""""""""""""""""""""""""""""""""""""""
+
+Topotest can automatically launch a shell or ``vtysh`` for any or all routers in
+a test. This is enabled by specifying 1 of 2 CLI arguments ``--shell`` or
+``--vtysh``. Both of these options can be set to a single router value, multiple
+comma-seperated values, or ``all``.
+
+When either of these options are specified topotest will pause after each test
+to allow for inspection of the router state.
+
+Here's an example of launching ``vtysh`` on routers ``rt1`` and ``rt2``.
+
+.. code:: shell
+
+ pytest --vtysh=rt1,rt2 all-protocol-startup
+
+Spawning Mininet CLI, ``vtysh`` or Shells on Routers on Test Failure
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+Similar to the previous section one can have ``vtysh`` or a shell launched on
+routers, but in this case only when a test fails. To launch the given process on
+each router after a test failure specify one of ``--shell-on-error`` or
+``--vtysh-on-error``.
+
+
+Here's an example of having ``vtysh`` launched on test failure.
+
+.. code:: shell
+
+ pytest --vtysh-on-error all-protocol-startup
+
+
+Additionally, one can have the mininet CLI invoked on test failures by
+specifying the ``--mininet-on-error`` CLI option as shown in the example below.
+
+.. code:: shell
+
+ pytest --mininet-on-error all-protocol-startup
+
+Debugging with GDB
+""""""""""""""""""
+
+Topotest can automatically launch any daemon with ``gdb``, possibly setting
+breakpoints for any test run. This is enabled by specifying 1 or 2 CLI arguments
+``--gdb-routers`` and ``--gdb-daemons``. Additionally ``--gdb-breakpoints`` can
+be used to automatically set breakpoints in the launched ``gdb`` processes.
+
+Each of these options can be set to a single value, multiple comma-seperated
+values, or ``all``. If ``--gdb-routers`` is empty but ``--gdb_daemons`` is set
+then the given daemons will be launched in ``gdb`` on all routers in the test.
+Likewise if ``--gdb_routers`` is set, but ``--gdb_daemons`` is empty then all
+daemons on the given routers will be launched in ``gdb``.
+
+Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router
+``r1`` with a breakpoint set on ``nb_config_diff``
+
+.. code:: shell
+
+ pytest --gdb-routers=r1 \
+ --gdb-daemons=bgpd,zebra \
+ --gdb-breakpoints=nb_config_diff \
+ all-protocol-startup
+
.. _topotests_docker:
Running Tests with Docker
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 4433dc9e21..61ed4d3e09 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1420,6 +1420,12 @@ Configuring Peers
This command is deprecated and may be removed in a future release. Its use
should be avoided.
+.. clicmd:: neighbor PEER interface remote-as <internal|external|ASN>
+
+ Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The
+ session will be established via IPv6 link locals. Use ``internal`` for iBGP
+ and ``external`` for eBGP sessions, or specify an ASN if you wish.
+
.. clicmd:: neighbor PEER next-hop-self [all]
This command specifies an announced route's nexthop as being equivalent to
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 64ce85503e..af9a7844a2 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -390,6 +390,27 @@ Areas
Prevents an *ospfd* ABR from injecting inter-area
summaries into the specified stub area.
+.. clicmd:: area A.B.C.D nssa
+
+.. clicmd:: area (0-4294967295) nssa
+
+ Configure the area to be a NSSA (Not-So-Stubby Area). This is an area that
+ allows OSPF to import external routes into a stub area via a new LSA type
+ (type 7). An NSSA autonomous system boundary router (ASBR) will generate this
+ type of LSA. The area border router (ABR) translates the LSA type 7 into LSA
+ type 5, which is propagated into the OSPF domain. NSSA areas are defined in
+ RFC 3101.
+
+.. clicmd:: area A.B.C.D nssa suppress-fa
+
+.. clicmd:: area (0-4294967295) nssa suppress-fa
+
+ Configure the router to set the forwarding address to 0.0.0.0 in all LSA type 5
+ translated from LSA type 7. The router needs to be elected the translator of the
+ area for this command to take effect. This feature causes routers that are
+ configured not to advertise forwarding addresses into the backbone to direct
+ forwarded traffic to the NSSA ABR translator.
+
.. clicmd:: area A.B.C.D default-cost (0-16777215)
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index d47d966f71..c8ad816b58 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -133,7 +133,7 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)
switch (args->event) {
case NB_EV_VALIDATE:
- area = nb_running_get_entry(args->dnode, NULL, true);
+ area = nb_running_get_entry(args->dnode, NULL, false);
if (area == NULL)
return NB_ERR_VALIDATION;
addr.addr_len = dotformat2buff(buff, net_title);
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 2d896546fa..5f4815fec1 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -463,6 +463,19 @@ static void ospf6_flood_process(struct ospf6_neighbor *from,
struct ospf6_area *oa;
for (ALL_LIST_ELEMENTS(process->area_list, node, nnode, oa)) {
+
+ /* If unknown LSA and U-bit clear, treat as link local
+ * flooding scope
+ */
+ if (!OSPF6_LSA_IS_KNOWN(lsa->header->type)
+ && !(ntohs(lsa->header->type) & OSPF6_LSTYPE_UBIT_MASK)
+ && (oa != OSPF6_INTERFACE(lsa->lsdb->data)->area)) {
+
+ if (IS_OSPF6_DEBUG_FLOODING)
+ zlog_debug("Unknown LSA, do not flood");
+ continue;
+ }
+
if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_AREA
&& oa != OSPF6_AREA(lsa->lsdb->data))
continue;
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index f2a933d878..b4f0c30f12 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -853,11 +853,12 @@ int ospf6_lsa_refresh(struct thread *thread)
void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6)
{
- struct listnode *node;
+ struct listnode *node, *nnode;
struct ospf6_area *oa;
struct ospf6_lsa *lsa;
const struct route_node *end = NULL;
uint32_t type, adv_router;
+ struct ospf6_interface *oi;
ospf6->inst_shutdown = 1;
@@ -872,6 +873,19 @@ void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6)
lsa = ospf6_lsdb_next(end, lsa);
}
+
+ for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
+ end = ospf6_lsdb_head(oi->lsdb_self, 0, 0,
+ ospf6->router_id, &lsa);
+ while (lsa) {
+ /* RFC 2328 (14.1): Set MAXAGE */
+ lsa->header->age = htons(OSPF_LSA_MAXAGE);
+ /* Flood MAXAGE LSA*/
+ ospf6_flood(NULL, lsa);
+
+ lsa = ospf6_lsdb_next(end, lsa);
+ }
+ }
}
type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c
index f3c4798906..b5c97eda3c 100644
--- a/ospfd/ospf_abr.c
+++ b/ospfd/ospf_abr.c
@@ -675,7 +675,8 @@ static int ospf_abr_translate_nssa(struct ospf_area *area, struct ospf_lsa *lsa)
* originate translated LSA
*/
- if (ospf_translated_nssa_originate(area->ospf, lsa) == NULL) {
+ if (ospf_translated_nssa_originate(area->ospf, lsa, old)
+ == NULL) {
if (IS_DEBUG_OSPF_NSSA)
zlog_debug(
"ospf_abr_translate_nssa(): Could not translate Type-7 for %pI4 to Type-5",
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 6bde5467b2..cb1c565d37 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -1765,7 +1765,14 @@ static struct ospf_lsa *ospf_lsa_translated_nssa_new(struct ospf *ospf,
/* copy over Type-7 data to new */
extnew->e[0].tos = ext->e[0].tos;
extnew->e[0].route_tag = ext->e[0].route_tag;
- extnew->e[0].fwd_addr.s_addr = ext->e[0].fwd_addr.s_addr;
+ if (type7->area->suppress_fa) {
+ extnew->e[0].fwd_addr.s_addr = 0;
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_debug(
+ "ospf_lsa_translated_nssa_new(): Suppress forwarding address for %pI4",
+ &ei.p.prefix);
+ } else
+ extnew->e[0].fwd_addr.s_addr = ext->e[0].fwd_addr.s_addr;
new->data->ls_seqnum = type7->data->ls_seqnum;
/* add translated flag, checksum and lock new lsa */
@@ -1777,7 +1784,8 @@ static struct ospf_lsa *ospf_lsa_translated_nssa_new(struct ospf *ospf,
/* Originate Translated Type-5 for supplied Type-7 NSSA LSA */
struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf,
- struct ospf_lsa *type7)
+ struct ospf_lsa *type7,
+ struct ospf_lsa *type5)
{
struct ospf_lsa *new;
struct as_external_lsa *extnew;
@@ -1796,6 +1804,10 @@ struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf,
extnew = (struct as_external_lsa *)new->data;
+ /* Update LSA sequence number from translated Type-5 LSA */
+ if (type5)
+ new->data->ls_seqnum = lsa_seqnum_increment(type5);
+
if ((new = ospf_lsa_install(ospf, NULL, new)) == NULL) {
flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
"%s: Could not install LSA id %pI4", __func__,
@@ -1823,6 +1835,8 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
struct ospf_lsa *type5)
{
struct ospf_lsa *new = NULL;
+ struct as_external_lsa *extold = NULL;
+ uint32_t ls_seqnum = 0;
/* Sanity checks. */
assert(type7 || type5);
@@ -1887,6 +1901,12 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
return NULL;
}
+ extold = (struct as_external_lsa *)type5->data;
+ if (type7->area->suppress_fa == 1) {
+ if (extold->e[0].fwd_addr.s_addr == 0)
+ ls_seqnum = ntohl(type5->data->ls_seqnum);
+ }
+
/* Delete LSA from neighbor retransmit-list. */
ospf_ls_retransmit_delete_nbr_as(ospf, type5);
@@ -1899,6 +1919,11 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
return NULL;
}
+ if (type7->area->suppress_fa == 1) {
+ if (extold->e[0].fwd_addr.s_addr == 0)
+ new->data->ls_seqnum = htonl(ls_seqnum + 1);
+ }
+
if (!(new = ospf_lsa_install(ospf, NULL, new))) {
flog_warn(
EC_OSPF_LSA_INSTALL_FAILURE,
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index f2a0d36e7e..3c1f94e628 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -341,11 +341,12 @@ extern char link_info_set(struct stream **s, struct in_addr id,
extern struct in_addr ospf_get_nssa_ip(struct ospf_area *);
extern int ospf_translated_nssa_compare(struct ospf_lsa *, struct ospf_lsa *);
-extern struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *,
- struct ospf_lsa *,
- struct ospf_lsa *);
-extern struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *,
- struct ospf_lsa *);
+extern struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf,
+ struct ospf_lsa *type7,
+ struct ospf_lsa *type5);
+extern struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf,
+ struct ospf_lsa *type7,
+ struct ospf_lsa *type5);
extern void ospf_flush_lsa_from_area(struct ospf *ospf, struct in_addr area_id,
int type);
#endif /* _ZEBRA_OSPF_LSA_H */
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index e6835ffc72..d634853b3e 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -1574,6 +1574,58 @@ DEFUN (ospf_area_nssa,
return ospf_area_nssa_cmd_handler(vty, argc, argv, 0, 0);
}
+DEFUN(ospf_area_nssa_suppress_fa, ospf_area_nssa_suppress_fa_cmd,
+ "area <A.B.C.D|(0-4294967295)> nssa suppress-fa",
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area as nssa\n"
+ "Suppress forwarding address\n")
+{
+ int idx_ipv4_number = 1;
+ struct in_addr area_id;
+ int format;
+
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+ VTY_GET_OSPF_AREA_ID_NO_BB("NSSA", area_id, format,
+ argv[idx_ipv4_number]->arg);
+
+ ospf_area_display_format_set(ospf, ospf_area_get(ospf, area_id),
+ format);
+ ospf_area_nssa_suppress_fa_set(ospf, area_id);
+
+ ospf_schedule_abr_task(ospf);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_ospf_area_nssa_suppress_fa, no_ospf_area_nssa_suppress_fa_cmd,
+ "no area <A.B.C.D|(0-4294967295)> nssa suppress-fa",
+ NO_STR
+ "OSPF area parameters\n"
+ "OSPF area ID in IP address format\n"
+ "OSPF area ID as a decimal value\n"
+ "Configure OSPF area as nssa\n"
+ "Suppress forwarding address\n")
+{
+ int idx_ipv4_number = 2;
+ struct in_addr area_id;
+ int format;
+
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+
+ VTY_GET_OSPF_AREA_ID_NO_BB("nssa", area_id, format,
+ argv[idx_ipv4_number]->arg);
+
+ ospf_area_display_format_set(ospf, ospf_area_get(ospf, area_id),
+ format);
+ ospf_area_nssa_suppress_fa_unset(ospf, area_id);
+
+ ospf_schedule_abr_task(ospf);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (ospf_area_nssa_no_summary,
ospf_area_nssa_no_summary_cmd,
"area <A.B.C.D|(0-4294967295)> nssa no-summary",
@@ -11823,6 +11875,10 @@ static int config_write_ospf_area(struct vty *vty, struct ospf *ospf)
vty_out(vty,
" area %s nssa no-summary\n",
buf);
+ if (area->suppress_fa)
+ vty_out(vty,
+ " area %s nssa suppress-fa\n",
+ buf);
}
if (area->default_cost != 1)
@@ -12684,6 +12740,8 @@ void ospf_vty_init(void)
install_element(OSPF_NODE, &ospf_area_nssa_translate_cmd);
install_element(OSPF_NODE, &ospf_area_nssa_no_summary_cmd);
install_element(OSPF_NODE, &no_ospf_area_nssa_no_summary_cmd);
+ install_element(OSPF_NODE, &ospf_area_nssa_suppress_fa_cmd);
+ install_element(OSPF_NODE, &no_ospf_area_nssa_suppress_fa_cmd);
install_element(OSPF_NODE, &no_ospf_area_nssa_cmd);
install_element(OSPF_NODE, &ospf_area_default_cost_cmd);
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 9856e60130..f126577aeb 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -1672,6 +1672,7 @@ int ospf_area_nssa_set(struct ospf *ospf, struct in_addr area_id)
/* set NSSA area defaults */
area->no_summary = 0;
+ area->suppress_fa = 0;
area->NSSATranslatorRole = OSPF_NSSA_ROLE_CANDIDATE;
area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED;
area->NSSATranslatorStabilityInterval =
@@ -1693,6 +1694,7 @@ int ospf_area_nssa_unset(struct ospf *ospf, struct in_addr area_id, int argc)
ospf->anyNSSA--;
/* set NSSA area defaults */
area->no_summary = 0;
+ area->suppress_fa = 0;
area->NSSATranslatorRole = OSPF_NSSA_ROLE_CANDIDATE;
area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED;
area->NSSATranslatorStabilityInterval =
@@ -1708,6 +1710,32 @@ int ospf_area_nssa_unset(struct ospf *ospf, struct in_addr area_id, int argc)
return 1;
}
+int ospf_area_nssa_suppress_fa_set(struct ospf *ospf, struct in_addr area_id)
+{
+ struct ospf_area *area;
+
+ area = ospf_area_lookup_by_area_id(ospf, area_id);
+ if (area == NULL)
+ return 0;
+
+ area->suppress_fa = 1;
+
+ return 1;
+}
+
+int ospf_area_nssa_suppress_fa_unset(struct ospf *ospf, struct in_addr area_id)
+{
+ struct ospf_area *area;
+
+ area = ospf_area_lookup_by_area_id(ospf, area_id);
+ if (area == NULL)
+ return 0;
+
+ area->suppress_fa = 0;
+
+ return 1;
+}
+
int ospf_area_nssa_translator_role_set(struct ospf *ospf,
struct in_addr area_id, int role)
{
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 5d64ee9ba2..a3f78b074e 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -476,7 +476,7 @@ struct ospf_area {
int shortcut_capability; /* Other ABRs agree on S-bit */
uint32_t default_cost; /* StubDefaultCost. */
int auth_type; /* Authentication type. */
-
+ int suppress_fa; /* Suppress forwarding address in NSSA ABR */
uint8_t NSSATranslatorRole; /* NSSA configured role */
#define OSPF_NSSA_ROLE_NEVER 0
@@ -668,6 +668,10 @@ extern int ospf_area_no_summary_set(struct ospf *, struct in_addr);
extern int ospf_area_no_summary_unset(struct ospf *, struct in_addr);
extern int ospf_area_nssa_set(struct ospf *, struct in_addr);
extern int ospf_area_nssa_unset(struct ospf *, struct in_addr, int);
+extern int ospf_area_nssa_suppress_fa_set(struct ospf *ospf,
+ struct in_addr area_id);
+extern int ospf_area_nssa_suppress_fa_unset(struct ospf *ospf,
+ struct in_addr area_id);
extern int ospf_area_nssa_translator_role_set(struct ospf *, struct in_addr,
int);
extern int ospf_area_export_list_set(struct ospf *, struct ospf_area *,
diff --git a/pathd/path_nb_config.c b/pathd/path_nb_config.c
index 669db169ae..af54f5bce2 100644
--- a/pathd/path_nb_config.c
+++ b/pathd/path_nb_config.c
@@ -302,7 +302,6 @@ int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args)
struct srte_policy *policy;
mpls_label_t binding_sid;
- policy = nb_running_get_entry(args->dnode, NULL, true);
binding_sid = yang_dnode_get_uint32(args->dnode, NULL);
switch (args->event) {
@@ -315,6 +314,7 @@ int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args)
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
+ policy = nb_running_get_entry(args->dnode, NULL, true);
srte_policy_update_binding_sid(policy, binding_sid);
SET_FLAG(policy->flags, F_POLICY_MODIFIED);
break;
@@ -668,12 +668,12 @@ int pathd_srte_policy_candidate_path_segment_list_name_modify(
struct srte_candidate *candidate;
const char *segment_list_name;
- candidate = nb_running_get_entry(args->dnode, NULL, true);
- segment_list_name = yang_dnode_get_string(args->dnode, NULL);
-
if (args->event != NB_EV_APPLY)
return NB_OK;
+ candidate = nb_running_get_entry(args->dnode, NULL, true);
+ segment_list_name = yang_dnode_get_string(args->dnode, NULL);
+
candidate->segment_list = srte_segment_list_find(segment_list_name);
candidate->lsp->segment_list = candidate->segment_list;
assert(candidate->segment_list);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index ae5b7940e9..4bbe7d35f0 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -1094,6 +1094,8 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
json_object_int_add(json_row, "helloPeriod",
pim_ifp->pim_hello_period);
+ json_object_int_add(json_row, "holdTime",
+ PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
json_object_string_add(json_row, "helloTimer",
hello_timer);
json_object_string_add(json_row, "helloStatStart",
@@ -1243,6 +1245,8 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
vty_out(vty, "------\n");
vty_out(vty, "Period : %d\n",
pim_ifp->pim_hello_period);
+ vty_out(vty, "HoldTime : %d\n",
+ PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
vty_out(vty, "Timer : %s\n", hello_timer);
vty_out(vty, "StatStart : %s\n", stat_uptime);
vty_out(vty, "Receive : %d\n",
@@ -8987,7 +8991,7 @@ DEFUN (interface_ip_pim_hello,
DEFUN (interface_no_ip_pim_hello,
interface_no_ip_pim_hello_cmd,
- "no ip pim hello [(1-180) (1-180)]",
+ "no ip pim hello [(1-180) [(1-180)]]",
NO_STR
IP_STR
PIM_STR
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index a7d7551cbd..475e393cf0 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -1830,6 +1830,7 @@ int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args)
pim_ifp = ifp->info;
pim_ifp->pim_hello_period =
yang_dnode_get_uint8(args->dnode, NULL);
+ pim_ifp->pim_default_holdtime = -1;
break;
}
@@ -2394,13 +2395,6 @@ int lib_interface_pim_address_family_mroute_oif_modify(
struct ipaddr group_addr;
const struct lyd_node *if_dnode;
- iif = nb_running_get_entry(args->dnode, NULL, true);
- pim_iifp = iif->info;
- pim = pim_iifp->pim;
-
- oifname = yang_dnode_get_string(args->dnode, NULL);
- oif = if_lookup_by_name(oifname, pim->vrf_id);
-
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
@@ -2411,6 +2405,17 @@ int lib_interface_pim_address_family_mroute_oif_modify(
}
#ifdef PIM_ENFORCE_LOOPFREE_MFC
+ iif = nb_running_get_entry(args->dnode, NULL, false);
+ if (!iif) {
+ return NB_OK;
+ }
+
+ pim_iifp = iif->info;
+ pim = pim_iifp->pim;
+
+ oifname = yang_dnode_get_string(args->dnode, NULL);
+ oif = if_lookup_by_name(oifname, pim->vrf_id);
+
if (oif && (iif->ifindex == oif->ifindex)) {
strlcpy(args->errmsg,
"% IIF same as OIF and loopfree enforcement is enabled; rejecting",
@@ -2423,6 +2428,12 @@ int lib_interface_pim_address_family_mroute_oif_modify(
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
+ iif = nb_running_get_entry(args->dnode, NULL, true);
+ pim_iifp = iif->info;
+ pim = pim_iifp->pim;
+
+ oifname = yang_dnode_get_string(args->dnode, NULL);
+ oif = if_lookup_by_name(oifname, pim->vrf_id);
if (!oif) {
snprintf(args->errmsg, args->errmsg_len,
"No such interface name %s",
diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py
index 04e9961f10..7ad5d8c9ab 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -2,13 +2,14 @@
Topotest conftest.py file.
"""
+import os
+import pdb
+import pytest
+
from lib.topogen import get_topogen, diagnose_env
from lib.topotest import json_cmp_result
+from lib.topotest import g_extra_config as topotest_extra_config
from lib.topolog import logger
-import pytest
-
-topology_only = False
-
def pytest_addoption(parser):
"""
@@ -16,20 +17,72 @@ def pytest_addoption(parser):
only run the setup_module() to setup the topology without running any tests.
"""
parser.addoption(
+ "--gdb-breakpoints",
+ metavar="SYMBOL[,SYMBOL...]",
+ help="Comma-separated list of functions to set gdb breakpoints on",
+ )
+
+ parser.addoption(
+ "--gdb-daemons",
+ metavar="DAEMON[,DAEMON...]",
+ help="Comma-separated list of daemons to spawn gdb on, or 'all'",
+ )
+
+ parser.addoption(
+ "--gdb-routers",
+ metavar="ROUTER[,ROUTER...]",
+ help="Comma-separated list of routers to spawn gdb on, or 'all'",
+ )
+
+ parser.addoption(
+ "--mininet-on-error",
+ action="store_true",
+ help="Mininet cli on test failure",
+ )
+
+ parser.addoption(
+ "--pause-after",
+ action="store_true",
+ help="Pause after each test",
+ )
+
+ parser.addoption(
+ "--shell",
+ metavar="ROUTER[,ROUTER...]",
+ help="Comma-separated list of routers to spawn shell on, or 'all'",
+ )
+
+ parser.addoption(
+ "--shell-on-error",
+ action="store_true",
+ help="Spawn shell on all routers on test failure",
+ )
+
+ parser.addoption(
"--topology-only",
action="store_true",
help="Only set up this topology, don't run tests",
)
+ parser.addoption(
+ "--vtysh",
+ metavar="ROUTER[,ROUTER...]",
+ help="Comma-separated list of routers to spawn vtysh on, or 'all'",
+ )
+
+ parser.addoption(
+ "--vtysh-on-error",
+ action="store_true",
+ help="Spawn vtysh on all routers on test failure",
+ )
+
def pytest_runtest_call():
"""
This function must be run after setup_module(), it does standarized post
setup routines. It is only being used for the 'topology-only' option.
"""
- global topology_only
-
- if topology_only:
+ if topotest_extra_config["topology_only"]:
tgen = get_topogen()
if tgen is not None:
# Allow user to play with the setup.
@@ -42,6 +95,8 @@ def pytest_assertrepr_compare(op, left, right):
"""
Show proper assertion error message for json_cmp results.
"""
+ del op
+
json_result = left
if not isinstance(json_result, json_cmp_result):
json_result = right
@@ -52,43 +107,105 @@ def pytest_assertrepr_compare(op, left, right):
def pytest_configure(config):
- "Assert that the environment is correctly configured."
-
- global topology_only
+ """
+ Assert that the environment is correctly configured, and get extra config.
+ """
if not diagnose_env():
- pytest.exit("enviroment has errors, please read the logs")
+ pytest.exit("environment has errors, please read the logs")
+
+ gdb_routers = config.getoption("--gdb-routers")
+ gdb_routers = gdb_routers.split(",") if gdb_routers else []
+ topotest_extra_config["gdb_routers"] = gdb_routers
+
+ gdb_daemons = config.getoption("--gdb-daemons")
+ gdb_daemons = gdb_daemons.split(",") if gdb_daemons else []
+ topotest_extra_config["gdb_daemons"] = gdb_daemons
+
+ gdb_breakpoints = config.getoption("--gdb-breakpoints")
+ gdb_breakpoints = gdb_breakpoints.split(",") if gdb_breakpoints else []
+ topotest_extra_config["gdb_breakpoints"] = gdb_breakpoints
+
+ mincli_on_error = config.getoption("--mininet-on-error")
+ topotest_extra_config["mininet_on_error"] = mincli_on_error
- if config.getoption("--topology-only"):
- topology_only = True
+ shell = config.getoption("--shell")
+ topotest_extra_config["shell"] = shell.split(",") if shell else []
+
+ pause_after = config.getoption("--pause-after")
+
+ shell_on_error = config.getoption("--shell-on-error")
+ topotest_extra_config["shell_on_error"] = shell_on_error
+
+ vtysh = config.getoption("--vtysh")
+ topotest_extra_config["vtysh"] = vtysh.split(",") if vtysh else []
+
+ vtysh_on_error = config.getoption("--vtysh-on-error")
+ topotest_extra_config["vtysh_on_error"] = vtysh_on_error
+
+ topotest_extra_config["pause_after"] = (
+ pause_after or shell or vtysh
+ )
+
+ topotest_extra_config["topology_only"] = config.getoption("--topology-only")
def pytest_runtest_makereport(item, call):
"Log all assert messages to default logger with error level"
- # Nothing happened
- if call.excinfo is None:
- return
- parent = item.parent
- modname = parent.module.__name__
+ # Nothing happened
+ if call.when == "call":
+ pause = topotest_extra_config["pause_after"]
+ else:
+ pause = False
- # Treat skips as non errors
- if call.excinfo.typename != "AssertionError":
- logger.info(
- 'assert skipped at "{}/{}": {}'.format(
- modname, item.name, call.excinfo.value
+ if call.excinfo is None:
+ error = False
+ else:
+ parent = item.parent
+ modname = parent.module.__name__
+
+ # Treat skips as non errors, don't pause after
+ if call.excinfo.typename != "AssertionError":
+ pause = False
+ error = False
+ logger.info(
+ 'assert skipped at "{}/{}": {}'.format(
+ modname, item.name, call.excinfo.value
+ )
+ )
+ else:
+ error = True
+ # Handle assert failures
+ parent._previousfailed = item # pylint: disable=W0212
+ logger.error(
+ 'assert failed at "{}/{}": {}'.format(modname, item.name, call.excinfo.value)
)
- )
- return
-
- # Handle assert failures
- parent._previousfailed = item
- logger.error(
- 'assert failed at "{}/{}": {}'.format(modname, item.name, call.excinfo.value)
- )
- # (topogen) Set topology error to avoid advancing in the test.
- tgen = get_topogen()
- if tgen is not None:
- # This will cause topogen to report error on `routers_have_failure`.
- tgen.set_error("{}/{}".format(modname, item.name))
+ # (topogen) Set topology error to avoid advancing in the test.
+ tgen = get_topogen()
+ if tgen is not None:
+ # This will cause topogen to report error on `routers_have_failure`.
+ tgen.set_error("{}/{}".format(modname, item.name))
+
+
+ if error and topotest_extra_config["shell_on_error"]:
+ for router in tgen.routers():
+ pause = True
+ tgen.net[router].runInWindow(os.getenv("SHELL", "bash"))
+
+ if error and topotest_extra_config["vtysh_on_error"]:
+ for router in tgen.routers():
+ pause = True
+ tgen.net[router].runInWindow("vtysh")
+
+ if error and topotest_extra_config["mininet_on_error"]:
+ tgen.mininet_cli()
+
+ if pause:
+ try:
+ user = raw_input('Testing paused, "pdb" to debug, "Enter" to continue: ')
+ except NameError:
+ user = input('Testing paused, "pdb" to debug, "Enter" to continue: ')
+ if user.strip() == "pdb":
+ pdb.set_trace()
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 70b2cfd648..104b215078 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -50,7 +50,9 @@ from mininet.node import Node, OVSSwitch, Host
from mininet.log import setLogLevel, info
from mininet.cli import CLI
from mininet.link import Intf
+from mininet.term import makeTerm
+g_extra_config = {}
def gdb_core(obj, daemon, corefiles):
gdbcmds = """
@@ -1341,6 +1343,37 @@ class Router(Node):
logger.info("No daemon {} known".format(daemon))
# print "Daemons after:", self.daemons
+ # Run a command in a new window (gnome-terminal, screen, tmux, xterm)
+ def runInWindow(self, cmd, title=None):
+ topo_terminal = os.getenv("FRR_TOPO_TERMINAL")
+ if topo_terminal or (
+ "TMUX" not in os.environ and "STY" not in os.environ
+ ):
+ term = topo_terminal if topo_terminal else "xterm"
+ makeTerm(
+ self,
+ title=title if title else cmd,
+ term=term,
+ cmd=cmd)
+ else:
+ nscmd = "sudo nsenter -m -n -t {} {}".format(self.pid, cmd)
+ if "TMUX" in os.environ:
+ self.cmd("tmux select-layout main-horizontal")
+ wcmd = "tmux split-window -h"
+ cmd = "{} {}".format(wcmd, nscmd)
+ elif "STY" in os.environ:
+ if os.path.exists(
+ "/run/screen/S-{}/{}".format(
+ os.environ['USER'], os.environ['STY']
+ )
+ ):
+ wcmd = "screen"
+ else:
+ wcmd = "sudo -u {} screen".format(os.environ["SUDO_USER"])
+ cmd = "{} {}".format(wcmd, nscmd)
+ self.cmd(cmd)
+
+
def startRouter(self, tgen=None):
# Disable integrated-vtysh-config
self.cmd(
@@ -1393,6 +1426,14 @@ class Router(Node):
return "LDP/MPLS Tests need mpls kernel modules"
self.cmd("echo 100000 > /proc/sys/net/mpls/platform_labels")
+ shell_routers = g_extra_config["shell"]
+ if "all" in shell_routers or self.name in shell_routers:
+ self.runInWindow(os.getenv("SHELL", "bash"))
+
+ vtysh_routers = g_extra_config["vtysh"]
+ if "all" in vtysh_routers or self.name in vtysh_routers:
+ self.runInWindow("vtysh")
+
if self.daemons["eigrpd"] == 1:
eigrpd_path = os.path.join(self.daemondir, "eigrpd")
if not os.path.isfile(eigrpd_path):
@@ -1419,6 +1460,10 @@ class Router(Node):
def startRouterDaemons(self, daemons=None):
"Starts all FRR daemons for this router."
+ gdb_breakpoints = g_extra_config["gdb_breakpoints"]
+ gdb_daemons = g_extra_config["gdb_daemons"]
+ gdb_routers = g_extra_config["gdb_routers"]
+
bundle_data = ""
if os.path.exists("/etc/frr/support_bundle_commands.conf"):
@@ -1448,7 +1493,7 @@ class Router(Node):
# If `daemons` was specified then some upper API called us with
# specific daemons, otherwise just use our own configuration.
daemons_list = []
- if daemons != None:
+ if daemons is not None:
daemons_list = daemons
else:
# Append all daemons configured.
@@ -1456,47 +1501,67 @@ class Router(Node):
if self.daemons[daemon] == 1:
daemons_list.append(daemon)
- # Start Zebra first
- if "zebra" in daemons_list:
- zebra_path = os.path.join(self.daemondir, "zebra")
- zebra_option = self.daemons_options["zebra"]
- self.cmd(
- "ASAN_OPTIONS=log_path=zebra.asan {0} {1} --log file:zebra.log --log-level debug -s 90000000 -d > zebra.out 2> zebra.err".format(
- zebra_path, zebra_option
+ def start_daemon(daemon, extra_opts=None):
+ daemon_opts = self.daemons_options.get(daemon, "")
+ rediropt = " > {0}.out 2> {0}.err".format(daemon)
+ if daemon == "snmpd":
+ binary = "/usr/sbin/snmpd"
+ cmdenv = ""
+ cmdopt = "{} -C -c /etc/frr/snmpd.conf -p ".format(
+ daemon_opts
+ ) + "/var/run/{}/snmpd.pid -x /etc/frr/agentx".format(self.routertype)
+ else:
+ binary = os.path.join(self.daemondir, daemon)
+ cmdenv = "ASAN_OPTIONS=log_path={0}.asan".format(daemon)
+ cmdopt = "{} --log file:{}.log --log-level debug".format(
+ daemon_opts, daemon
)
- )
- logger.debug("{}: {} zebra started".format(self, self.routertype))
+ if extra_opts:
+ cmdopt += " " + extra_opts
+
+ if (
+ (gdb_routers or gdb_daemons)
+ and (not gdb_routers
+ or self.name in gdb_routers
+ or "all" in gdb_routers)
+ and (not gdb_daemons
+ or daemon in gdb_daemons
+ or "all" in gdb_daemons)
+ ):
+ if daemon == "snmpd":
+ cmdopt += " -f "
+
+ cmdopt += rediropt
+ gdbcmd = "sudo -E gdb " + binary
+ if gdb_breakpoints:
+ gdbcmd += " -ex 'set breakpoint pending on'"
+ for bp in gdb_breakpoints:
+ gdbcmd += " -ex 'b {}'".format(bp)
+ gdbcmd += " -ex 'run {}'".format(cmdopt)
+
+ self.runInWindow(gdbcmd, daemon)
+ else:
+ if daemon != "snmpd":
+ cmdopt += " -d "
+ cmdopt += rediropt
+ self.cmd(" ".join([cmdenv, binary, cmdopt]))
+ logger.info("{}: {} {} started".format(self, self.routertype, daemon))
- # Remove `zebra` so we don't attempt to start it again.
+
+ # Start Zebra first
+ if "zebra" in daemons_list:
+ start_daemon("zebra", "-s 90000000")
while "zebra" in daemons_list:
daemons_list.remove("zebra")
# Start staticd next if required
if "staticd" in daemons_list:
- staticd_path = os.path.join(self.daemondir, "staticd")
- staticd_option = self.daemons_options["staticd"]
- self.cmd(
- "ASAN_OPTIONS=log_path=staticd.asan {0} {1} --log file:staticd.log --log-level debug -d > staticd.out 2> staticd.err".format(
- staticd_path, staticd_option
- )
- )
- logger.debug("{}: {} staticd started".format(self, self.routertype))
-
- # Remove `staticd` so we don't attempt to start it again.
+ start_daemon("staticd")
while "staticd" in daemons_list:
daemons_list.remove("staticd")
if "snmpd" in daemons_list:
- snmpd_path = "/usr/sbin/snmpd"
- snmpd_option = self.daemons_options["snmpd"]
- self.cmd(
- "{0} {1} -C -c /etc/frr/snmpd.conf -p /var/run/{2}/snmpd.pid -x /etc/frr/agentx > snmpd.out 2> snmpd.err".format(
- snmpd_path, snmpd_option, self.routertype
- )
- )
- logger.info("{}: {} snmpd started".format(self, self.routertype))
-
- # Remove `snmpd` so we don't attempt to start it again.
+ start_daemon("snmpd")
while "snmpd" in daemons_list:
daemons_list.remove("snmpd")
@@ -1508,17 +1573,9 @@ class Router(Node):
# Now start all the other daemons
for daemon in daemons_list:
- # Skip disabled daemons and zebra
if self.daemons[daemon] == 0:
continue
-
- daemon_path = os.path.join(self.daemondir, daemon)
- self.cmd(
- "ASAN_OPTIONS=log_path={2}.asan {0} {1} --log file:{2}.log --log-level debug -d > {2}.out 2> {2}.err".format(
- daemon_path, self.daemons_options.get(daemon, ""), daemon
- )
- )
- logger.debug("{}: {} {} started".format(self, self.routertype, daemon))
+ start_daemon(daemon)
# Check if daemons are running.
rundaemons = self.cmd("ls -1 /var/run/%s/*.pid" % self.routertype)
diff --git a/tests/topotests/ospf_suppress_fa/__init__.py b/tests/topotests/ospf_suppress_fa/__init__.py
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/__init__.py
diff --git a/tests/topotests/ospf_suppress_fa/r1/ospfd.conf b/tests/topotests/ospf_suppress_fa/r1/ospfd.conf
new file mode 100644
index 0000000000..c02be35b14
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r1/ospfd.conf
@@ -0,0 +1,9 @@
+!
+interface r1-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 10.0.12.0/24 area 0
+!
diff --git a/tests/topotests/ospf_suppress_fa/r1/zebra.conf b/tests/topotests/ospf_suppress_fa/r1/zebra.conf
new file mode 100644
index 0000000000..c1e31fb474
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r1/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r1-eth0
+ ip address 10.0.12.1/24
+!
diff --git a/tests/topotests/ospf_suppress_fa/r2/ospfd.conf b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf
new file mode 100644
index 0000000000..ebc7d252fd
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf
@@ -0,0 +1,16 @@
+!
+interface r2-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+interface r2-eth1
+ ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 10.0.12.0/24 area 0
+ network 10.0.23.0/24 area 1
+ area 1 nssa
+!
diff --git a/tests/topotests/ospf_suppress_fa/r2/zebra.conf b/tests/topotests/ospf_suppress_fa/r2/zebra.conf
new file mode 100644
index 0000000000..9f1a26349e
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r2/zebra.conf
@@ -0,0 +1,7 @@
+!
+interface r2-eth0
+ ip address 10.0.12.2/24
+!
+interface r2-eth1
+ ip address 10.0.23.2/24
+!
diff --git a/tests/topotests/ospf_suppress_fa/r3/ospfd.conf b/tests/topotests/ospf_suppress_fa/r3/ospfd.conf
new file mode 100644
index 0000000000..08be11a7b7
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r3/ospfd.conf
@@ -0,0 +1,11 @@
+!
+interface r3-eth0
+ ip ospf network point-to-point
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ redistribute static
+ network 10.0.23.0/24 area 1
+ area 1 nssa
+!
diff --git a/tests/topotests/ospf_suppress_fa/r3/zebra.conf b/tests/topotests/ospf_suppress_fa/r3/zebra.conf
new file mode 100644
index 0000000000..f76cbf74d2
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/r3/zebra.conf
@@ -0,0 +1,8 @@
+!
+ip route 3.3.1.1/32 Null0
+ip route 3.3.2.2/32 Null0
+ip route 3.3.3.3/32 Null0
+!
+interface r3-eth0
+ ip address 10.0.23.3/24
+!
diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot
new file mode 100644
index 0000000000..1036658f1a
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot
@@ -0,0 +1,66 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph ospf_topo1 {
+ label="ospf suppress-fa";
+
+ # Routers
+ r1 [
+ label="r1\nrtr-id 10.0.12.1",
+ shape=doubleoctagon,
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ label="r2 (ABR)\nrtr-id 10.0.23.2",
+ shape=doubleoctagon,
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ label="r3 (ASBR)\nrtr-id 10.0.23.3",
+ shape=doubleoctagon,
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ s1 [
+ label="s1\n10.0.12.0/24",
+ shape=oval,
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ label="s2\n10.0.23.0/24",
+ shape=oval,
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ subgraph cluster0 {
+ label="area 0"
+ r1 -- s1 [label="eth1\n.1"];
+ r2 -- s1 [label="eth1\n.2"];
+ }
+
+ subgraph cluster1 {
+ label="area 1\nNSSA"
+ r2 -- s2 [label="eth2\n.2"];
+ r3 -- s2 [label="eth1\n.3"];
+ }
+
+ { rank=same; r1; r2; r3; }
+}
diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg
new file mode 100644
index 0000000000..2907d799f5
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg
Binary files differ
diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py
new file mode 100644
index 0000000000..74d609c57e
--- /dev/null
+++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py
@@ -0,0 +1,181 @@
+#!/usr/bin/env python
+
+#
+# test_ospf_suppres_fa.py
+# Carles Kishimoto
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_ospf_suppres_fa.py: Test OSPF suppress-fa feature
+- Topology: r1 --- R2 (ABR) --- R3 (redistribute static)
+
+test_ospf_set_suppress_fa()
+ 1) R1: Get a dict[LSA_ID] = fwd_addr for all type 5 LSA
+ 2) R2: Configure: area 1 nssa suppress-fa
+ 3) R1: Get a dict[LSA_ID] and compare fwd_address with 0.0.0.0
+
+test_ospf_unset_suppress_fa()
+ 4) R2: Configure: no area 1 nssa suppress-fa
+ 5) R1: Get a dict[LSA_ID] = fwd_addr and compare it with the dict obtained in 1)
+"""
+
+import os
+import sys
+import re
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class NetworkTopo(Topo):
+ "OSPF topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+
+ tgen = get_topogen(self)
+
+ # Create routers
+ for router in range(1, 4):
+ tgen.add_router("r{}".format(router))
+
+ # R1-R2 backbone area
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ # R2-R3 NSSA area
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+
+ tgen = Topogen(NetworkTopo, mod.__name__)
+ tgen.start_topology()
+
+ # This is a sample of configuration loading.
+ router_list = tgen.routers()
+
+ # For all registred routers, load the zebra and ospf configuration file
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+def test_converge_protocols():
+ "Wait for protocol convergence"
+
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ topotest.sleep(10, "Waiting for OSPF convergence")
+
+def ospf_configure_suppress_fa(router_name, area):
+ "Configure OSPF suppress-fa in router_name"
+
+ tgen = get_topogen()
+ router = tgen.gears[router_name]
+ router.vtysh_cmd("conf t\nrouter ospf\narea {} nssa suppress-fa\nexit\n".format(area))
+
+def ospf_unconfigure_suppress_fa(router_name, area):
+ "Remove OSPF suppress-fa in router_name"
+
+ tgen = get_topogen()
+ router = tgen.gears[router_name]
+ router.vtysh_cmd("conf t\nrouter ospf\nno area {} nssa suppress-fa\nexit\n".format(area))
+
+def ospf_get_lsa_type5(router_name):
+ "Return a dict with link state id as key and forwarding addresses as value"
+
+ result = dict()
+ tgen = get_topogen()
+ router = tgen.gears[router_name]
+ cmd = "show ip ospf database external\n"
+ output = topotest.normalize_text(router.vtysh_cmd(cmd))
+ for line in output.splitlines():
+ re0 = re.match(r"\s+Link State ID: (\S+) \(External Network Number\)", line)
+ if re0:
+ lsa = re0.group(1)
+ re1 = re.match(r"\s+Forward Address: (\S+)", line)
+ if re1:
+ result[lsa] = re1.group(1)
+ return result
+
+@pytest.fixture(scope='module', name='original')
+def test_ospf_set_suppress_fa():
+ "Test OSPF area [x] nssa suppress-fa"
+
+ # Get current forwarding address for each LSA type-5 in r1
+ initial = ospf_get_lsa_type5("r1")
+
+ # Configure suppres-fa in r2 area 1
+ ospf_configure_suppress_fa("r2", "1")
+ topotest.sleep(10, "Waiting for OSPF convergence")
+
+ # Check forwarding address on r1 for all statics is 0.0.0.0
+ assertmsg = "Forwarding address is not 0.0.0.0 after enabling OSPF suppress-fa"
+ suppress = ospf_get_lsa_type5("r1")
+ for prefix in suppress:
+ assert suppress[prefix] == "0.0.0.0", assertmsg
+
+ # Return the original forwarding addresses so we can compare them
+ # in the test_ospf_unset_supress_fa
+ return initial
+
+def test_ospf_unset_supress_fa(original):
+ "Test OSPF no area [x] nssa suppress-fa"
+
+ # Remove suppress-fa in r2 area 1
+ ospf_unconfigure_suppress_fa("r2", "1")
+ topotest.sleep(10, "Waiting for OSPF convergence")
+
+ # Check forwarding address is the original value on r1 for all statics
+ assertmsg = "Forwarding address is not correct after removing OSPF suppress-fa"
+ restore = ospf_get_lsa_type5("r1")
+ for prefix in restore:
+ assert restore[prefix] == original[prefix], assertmsg
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index 3dbc6a1b43..2d925dbac3 100644
--- a/tools/frrcommon.sh.in
+++ b/tools/frrcommon.sh.in
@@ -149,6 +149,10 @@ daemon_prep() {
daemon_start() {
local dmninst daemon inst args instopt wrap bin
+
+ all=false
+ [ "$1" = "--all" ] && { all=true; shift; }
+
daemon_inst "$1"
ulimit -n $MAX_FDS > /dev/null 2> /dev/null
@@ -165,7 +169,11 @@ daemon_start() {
if eval "$all_wrap $wrap $bin $nsopt -d $frr_global_options $instopt $args"; then
log_success_msg "Started $dmninst"
- vtysh_b "$daemon"
+ if $all; then
+ debug "Skipping startup of vtysh until all have started"
+ else
+ vtysh_b "$daemon"
+ fi
else
log_failure_msg "Failed to start $dmninst!"
fi
@@ -237,8 +245,9 @@ print_status() {
all_start() {
daemon_list daemons
for dmninst in $daemons; do
- daemon_start "$dmninst"
+ daemon_start --all "$dmninst"
done
+ vtysh_b
}
all_stop() {
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 06d224ec24..62d9c255ad 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -2851,7 +2851,7 @@ DEFUN (vtysh_show_error_code,
}
/* Northbound. */
-DEFUN (show_config_running,
+DEFUN_HIDDEN (show_config_running,
show_config_running_cmd,
"show configuration running\
[<json|xml> [translate WORD]]\
diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang
index f959ff8be5..2070649ec2 100644
--- a/yang/frr-pim.yang
+++ b/yang/frr-pim.yang
@@ -294,6 +294,9 @@ module frr-pim {
type uint8 {
range "1..180";
}
+ must ". > ./../hello-interval" {
+ error-message "HoldTime must be greater than Hello";
+ }
description
"Hello holdtime";
}
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
index 782e0a4b74..be2f7b5a68 100644
--- a/yang/frr-zebra.yang
+++ b/yang/frr-zebra.yang
@@ -597,6 +597,7 @@ module frr-zebra {
grouping ribs {
container ribs {
+ config false;
description
"RIBs supported by FRR.";
list rib {
@@ -617,7 +618,6 @@ module frr-zebra {
list route {
key "prefix";
- config false;
leaf prefix {
type inet:ip-prefix;
description
diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c
index 1fc1faff67..bdeb84486d 100644
--- a/zebra/zebra_nb.c
+++ b/zebra/zebra_nb.c
@@ -401,14 +401,24 @@ const struct frr_yang_module_info frr_zebra_info = {
{
.xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib",
.cbs = {
- .create = lib_vrf_zebra_ribs_rib_create,
- .destroy = lib_vrf_zebra_ribs_rib_destroy,
.get_next = lib_vrf_zebra_ribs_rib_get_next,
.get_keys = lib_vrf_zebra_ribs_rib_get_keys,
.lookup_entry = lib_vrf_zebra_ribs_rib_lookup_entry,
}
},
{
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/afi-safi-name",
+ .cbs = {
+ .get_elem = lib_vrf_zebra_ribs_rib_afi_safi_name_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/table-id",
+ .cbs = {
+ .get_elem = lib_vrf_zebra_ribs_rib_table_id_get_elem,
+ }
+ },
+ {
.xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route",
.cbs = {
.get_next = lib_vrf_zebra_ribs_rib_route_get_next,
diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h
index e68b819767..79632dc83e 100644
--- a/zebra/zebra_nb.h
+++ b/zebra/zebra_nb.h
@@ -149,12 +149,14 @@ struct yang_data *lib_interface_zebra_state_remote_vtep_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *lib_interface_zebra_state_mcast_group_get_elem(
struct nb_cb_get_elem_args *args);
-int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args);
-int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args);
const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args);
int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args);
const void *
lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args);
+struct yang_data *
+lib_vrf_zebra_ribs_rib_afi_safi_name_get_elem(struct nb_cb_get_elem_args *args);
+struct yang_data *
+lib_vrf_zebra_ribs_rib_table_id_get_elem(struct nb_cb_get_elem_args *args);
const void *
lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args);
int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args);
@@ -201,19 +203,6 @@ lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_next(
struct nb_cb_get_next_args *args);
int lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_keys(
struct nb_cb_get_keys_args *args);
-int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args);
-int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args);
-const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args);
-const void *
-lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args);
-const void *
-lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args);
-const void *
-lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args);
-struct yang_data *
-lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args);
const void *lib_vrf_zebra_ribs_rib_route_route_entry_get_next(
struct nb_cb_get_next_args *args);
int lib_vrf_zebra_ribs_rib_route_route_entry_get_keys(
diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c
index ea2e20ed3b..ba9f96b7de 100644
--- a/zebra/zebra_nb_config.c
+++ b/zebra/zebra_nb_config.c
@@ -841,7 +841,6 @@ int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args)
struct interface *ifp;
struct prefix prefix;
- ifp = nb_running_get_entry(args->dnode, NULL, true);
// addr_family = yang_dnode_get_enum(dnode, "./address-family");
yang_dnode_get_prefix(&prefix, args->dnode, "./ip-prefix");
apply_mask(&prefix);
@@ -864,6 +863,7 @@ int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args)
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
if (prefix.family == AF_INET)
if_ip_address_install(ifp, &prefix, NULL, NULL);
else if (prefix.family == AF_INET6)
@@ -881,12 +881,15 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args)
struct prefix prefix;
struct connected *ifc;
- ifp = nb_running_get_entry(args->dnode, NULL, true);
yang_dnode_get_prefix(&prefix, args->dnode, "./ip-prefix");
apply_mask(&prefix);
switch (args->event) {
case NB_EV_VALIDATE:
+ ifp = nb_running_get_entry(args->dnode, NULL, false);
+ if (!ifp)
+ return NB_OK;
+
if (prefix.family == AF_INET) {
/* Check current interface address. */
ifc = connected_check_ptp(ifp, &prefix, NULL);
@@ -927,6 +930,7 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args)
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
if_ip_address_uinstall(ifp, &prefix);
break;
}
@@ -1068,6 +1072,9 @@ int lib_interface_zebra_link_detect_destroy(struct nb_cb_destroy_args *args)
*/
int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args)
{
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
struct interface *ifp;
ifp = nb_running_get_entry(args->dnode, NULL, true);
@@ -1079,6 +1086,9 @@ int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args)
int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args)
{
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
struct interface *ifp;
ifp = nb_running_get_entry(args->dnode, NULL, true);
@@ -1130,61 +1140,6 @@ int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args)
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib
- */
-int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args)
-{
- struct vrf *vrf;
- afi_t afi;
- safi_t safi;
- struct zebra_vrf *zvrf;
- struct zebra_router_table *zrt;
- uint32_t table_id;
- const char *afi_safi_name;
-
- vrf = nb_running_get_entry(args->dnode, NULL, false);
- zvrf = vrf_info_lookup(vrf->vrf_id);
- table_id = yang_dnode_get_uint32(args->dnode, "./table-id");
- if (!table_id)
- table_id = zvrf->table_id;
-
- afi_safi_name = yang_dnode_get_string(args->dnode, "./afi-safi-name");
- yang_afi_safi_identity2value(afi_safi_name, &afi, &safi);
-
- zrt = zebra_router_find_zrt(zvrf, table_id, afi, safi);
-
- switch (args->event) {
- case NB_EV_VALIDATE:
- if (!zrt) {
- snprintf(args->errmsg, args->errmsg_len,
- "vrf %s table is not found.", vrf->name);
- return NB_ERR_VALIDATION;
- }
- break;
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
-
- nb_running_set_entry(args->dnode, zrt);
-
- break;
- }
-
- return NB_OK;
-}
-
-int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args)
-{
- if (args->event != NB_EV_APPLY)
- return NB_OK;
-
- nb_running_unset_entry(args->dnode);
-
- return NB_OK;
-}
-
-/*
* XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id
*/
int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args)
diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c
index 21c89f64ed..a9cb096aee 100644
--- a/zebra/zebra_nb_state.c
+++ b/zebra/zebra_nb_state.c
@@ -214,6 +214,29 @@ lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args)
}
/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/afi-safi-name
+ */
+struct yang_data *
+lib_vrf_zebra_ribs_rib_afi_safi_name_get_elem(struct nb_cb_get_elem_args *args)
+{
+ const struct zebra_router_table *zrt = args->list_entry;
+
+ return yang_data_new_string(args->xpath,
+ yang_afi_safi_value2identity(zrt->afi, zrt->safi));
+}
+
+/*
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/table-id
+ */
+struct yang_data *
+lib_vrf_zebra_ribs_rib_table_id_get_elem(struct nb_cb_get_elem_args *args)
+{
+ const struct zebra_router_table *zrt = args->list_entry;
+
+ return yang_data_new_uint32(args->xpath, zrt->tableid);
+}
+
+/*
* XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route
*/
const void *
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index d5c9f7183d..283a3e52d6 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -2564,10 +2564,8 @@ DEFUN (default_vrf_vni_mapping,
"VNI-ID\n"
"Prefix routes only \n")
{
- int ret = 0;
- char err[ERR_STR_SZ];
+ char xpath[XPATH_MAXLEN];
struct zebra_vrf *zvrf = NULL;
- vni_t vni = strtoul(argv[1]->arg, NULL, 10);
int filter = 0;
zvrf = vrf_info_lookup(VRF_DEFAULT);
@@ -2577,25 +2575,35 @@ DEFUN (default_vrf_vni_mapping,
if (argc == 3)
filter = 1;
- ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ,
- filter, 1);
- if (ret != 0) {
- vty_out(vty, "%s\n", err);
- return CMD_WARNING;
+ snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath, sizeof(xpath),
+ FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[1]->arg);
+
+ if (filter) {
+ snprintf(xpath, sizeof(xpath),
+ FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true");
}
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, NULL);
}
DEFUN (no_default_vrf_vni_mapping,
no_default_vrf_vni_mapping_cmd,
- "no vni " CMD_VNI_RANGE,
+ "no vni " CMD_VNI_RANGE "[prefix-routes-only]",
NO_STR
"VNI corresponding to DEFAULT VRF\n"
- "VNI-ID")
+ "VNI-ID\n"
+ "Prefix routes only \n")
{
- int ret = 0;
- char err[ERR_STR_SZ];
+ char xpath[XPATH_MAXLEN];
+ int filter = 0;
vni_t vni = strtoul(argv[2]->arg, NULL, 10);
struct zebra_vrf *zvrf = NULL;
@@ -2603,13 +2611,32 @@ DEFUN (no_default_vrf_vni_mapping,
if (!zvrf)
return CMD_WARNING;
- ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0);
- if (ret != 0) {
- vty_out(vty, "%s\n", err);
+ if (argc == 4)
+ filter = 1;
+
+ if (zvrf->l3vni != vni) {
+ vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni,
+ zvrf->vrf->name);
return CMD_WARNING;
}
- return CMD_SUCCESS;
+ snprintf(xpath, sizeof(xpath),
+ FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, argv[2]->arg);
+
+ if (filter) {
+ snprintf(xpath, sizeof(xpath),
+ FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, "true");
+ }
+
+ snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra",
+ VRF_DEFAULT_NAME);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
}
DEFUN (vrf_vni_mapping,
@@ -2637,9 +2664,7 @@ DEFUN (vrf_vni_mapping,
nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only",
NB_OP_MODIFY, "true");
- nb_cli_apply_changes(vty, NULL);
-
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, NULL);
}
DEFUN (no_vrf_vni_mapping,
@@ -2676,9 +2701,7 @@ DEFUN (no_vrf_vni_mapping,
nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_DESTROY, NULL);
- nb_cli_apply_changes(vty, NULL);
-
- return CMD_SUCCESS;
+ return nb_cli_apply_changes(vty, NULL);
}
/* show vrf */