summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn.c50
-rw-r--r--doc/developer/topotests.rst82
-rw-r--r--ldpd/ldpd.c3
-rw-r--r--lib/libfrr.c14
-rw-r--r--lib/module.c92
-rw-r--r--lib/module.h4
-rw-r--r--pimd/pim_cmd.c8
-rw-r--r--pimd/pim_nb_config.c7
-rw-r--r--tests/lib/test_grpc.cpp18
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py7
-rw-r--r--tests/topotests/lib/ltemplate.py6
-rw-r--r--tools/coccinelle/zlog_no_newline.cocci20
12 files changed, 247 insertions, 64 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 6248ad927b..3219ae13b5 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -4335,6 +4335,54 @@ static void update_autort_vni(struct hash_bucket *bucket, struct bgp *bgp)
}
/*
+ * Handle autort change for L3VNI.
+ */
+static void update_autort_l3vni(struct bgp *bgp)
+{
+ if ((CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
+ && (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)))
+ return;
+
+ if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
+ if (is_l3vni_live(bgp))
+ uninstall_routes_for_vrf(bgp);
+
+ /* Cleanup the RT to VRF mapping */
+ bgp_evpn_unmap_vrf_from_its_rts(bgp);
+
+ /* Remove auto generated RT */
+ evpn_auto_rt_import_delete_for_vrf(bgp);
+
+ list_delete_all_node(bgp->vrf_import_rtl);
+
+ /* Map auto derive or configured RTs */
+ evpn_auto_rt_import_add_for_vrf(bgp);
+ }
+
+ if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
+ list_delete_all_node(bgp->vrf_export_rtl);
+
+ evpn_auto_rt_export_delete_for_vrf(bgp);
+
+ evpn_auto_rt_export_add_for_vrf(bgp);
+
+ if (is_l3vni_live(bgp))
+ bgp_evpn_map_vrf_to_its_rts(bgp);
+ }
+
+ if (!is_l3vni_live(bgp))
+ return;
+
+ /* advertise type-5 routes if needed */
+ update_advertise_vrf_routes(bgp);
+
+ /* install all remote routes belonging to this l3vni
+ * into corresponding vrf
+ */
+ install_routes_for_vrf(bgp);
+}
+
+/*
* Public functions.
*/
@@ -4706,6 +4754,8 @@ void bgp_evpn_handle_autort_change(struct bgp *bgp)
(void (*)(struct hash_bucket *,
void*))update_autort_vni,
bgp);
+ if (bgp->l3vni)
+ update_autort_l3vni(bgp);
}
/*
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index c52d210ee5..b4f6ec521c 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -130,12 +130,42 @@ And create ``frr`` user and ``frrvty`` group as follows:
Executing Tests
---------------
+Configure your sudo environment
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Topotests must be run as root. Normally this will be accomplished through the
+use of the ``sudo`` command. In order for topotests to be able to open new
+windows (either XTerm or byobu/screen/tmux windows) certain environment
+variables must be passed through the sudo command. One way to do this is to
+specify the :option:`-E` flag to ``sudo``. This will carry over most if not all
+your environment variables include ``PATH``. For example:
+
+.. code:: shell
+
+ sudo -E python3 -m pytest -s -v
+
+If you do not wish to use :option:`-E` (e.g., to avoid ``sudo`` inheriting
+``PATH``) you can modify your `/etc/sudoers` config file to specifically pass
+the environment variables required by topotests. Add the following commands to
+your ``/etc/sudoers`` config file.
+
+.. code:: shell
+
+ Defaults env_keep="TMUX"
+ Defaults env_keep+="TMUX_PANE"
+ Defaults env_keep+="STY"
+ Defaults env_keep+="DISPLAY"
+
+If there was already an ``env_keep`` configuration there be sure to use the
+``+=`` rather than ``=`` on the first line above as well.
+
+
Execute all tests in distributed test mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code:: shell
- py.test -s -v -nauto --dist=loadfile
+ sudo -E pytest -s -v -nauto --dist=loadfile
The above command must be executed from inside the topotests directory.
@@ -167,7 +197,7 @@ the run.
Here we see that 4 tests have failed. We an dig deeper by displaying the
captured logs and errors. First let's redisplay the results enumerated by adding
-the ``-E`` flag
+the :option:`-E` flag
.. code:: shell
@@ -353,6 +383,12 @@ be run within ``tmux`` (or ``screen``)_, as ``gdb``, the shell or ``vtysh`` will
be launched using that windowing program, otherwise ``xterm`` will be attempted
to launch the given programs.
+NOTE: you must run the topotest (pytest) such that your DISPLAY, STY or TMUX
+environment variables are carried over. You can do this by passing the
+:option:`-E` flag to ``sudo`` or you can modify your ``/etc/sudoers`` config to
+automatically pass that environment variable through to the ``sudo``
+environment.
+
.. _screen: https://www.gnu.org/software/screen/
.. _tmux: https://github.com/tmux/tmux/wiki
@@ -364,7 +400,7 @@ One can have a debugging CLI invoked on test failures by specifying the
.. code:: shell
- pytest --cli-on-error all-protocol-startup
+ sudo -E pytest --cli-on-error all-protocol-startup
The debugging CLI can run shell or vtysh commands on any combination of routers
It can also open shells or vtysh in their own windows for any combination of
@@ -415,7 +451,7 @@ Here's an example of launching ``vtysh`` on routers ``rt1`` and ``rt2``.
.. code:: shell
- pytest --vtysh=rt1,rt2 all-protocol-startup
+ sudo -E pytest --vtysh=rt1,rt2 all-protocol-startup
Debugging with GDB
""""""""""""""""""
@@ -436,7 +472,7 @@ Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router
.. code:: shell
- pytest --gdb-routers=r1 \
+ sudo -E pytest --gdb-routers=r1 \
--gdb-daemons=bgpd,zebra \
--gdb-breakpoints=nb_config_diff \
all-protocol-startup
@@ -453,7 +489,7 @@ memleak detection is enabled.
.. code:: shell
- pytest --valgrind-memleaks all-protocol-startup
+ sudo -E pytest --valgrind-memleaks all-protocol-startup
.. _topotests_docker:
@@ -555,21 +591,21 @@ top level directory of topotest:
$ # Change to the top level directory of topotests.
$ cd path/to/topotests
$ # Tests must be run as root, since micronet requires it.
- $ sudo pytest
+ $ sudo -E pytest
In order to run a specific test, you can use the following command:
.. code:: shell
$ # running a specific topology
- $ sudo pytest ospf-topo1/
+ $ sudo -E pytest ospf-topo1/
$ # or inside the test folder
$ cd ospf-topo1
- $ sudo pytest # to run all tests inside the directory
- $ sudo pytest test_ospf_topo1.py # to run a specific test
+ $ sudo -E pytest # to run all tests inside the directory
+ $ sudo -E pytest test_ospf_topo1.py # to run a specific test
$ # or outside the test folder
$ cd ..
- $ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one
+ $ sudo -E pytest ospf-topo1/test_ospf_topo1.py # to run a specific one
The output of the tested daemons will be available at the temporary folder of
your machine:
@@ -588,7 +624,7 @@ You can also run memory leak tests to get reports:
.. code:: shell
$ # Set the environment variable to apply to a specific test...
- $ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py
+ $ sudo -E env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py
$ # ...or apply to all tests adding this line to the configuration file
$ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini
$ # You can also use your editor
@@ -626,12 +662,12 @@ Some things to keep in mind:
- Using sleep is almost never appropriate. As an example: if the test resets the
peers in BGP, the test should look for the peers re-converging instead of just
sleeping an arbitrary amount of time and continuing on. See
- `verify_bgp_convergence` as a good example of this. In particular look at it's
- use of the `@retry` decorator. If you are having troubles figuring out what to
- look for, please do not be afraid to ask.
+ ``verify_bgp_convergence`` as a good example of this. In particular look at
+ it's use of the ``@retry`` decorator. If you are having troubles figuring out
+ what to look for, please do not be afraid to ask.
- Don't duplicate effort. There exists many protocol utility functions that can
- be found in their eponymous module under `tests/topotests/lib/` (e.g.,
- `ospf.py`)
+ be found in their eponymous module under ``tests/topotests/lib/`` (e.g.,
+ ``ospf.py``)
@@ -827,11 +863,11 @@ that using the following example commands:
.. code:: shell
$ # Running your bootstraped topology
- $ sudo pytest -s --topology-only new-topo/test_new_topo.py
+ $ sudo -E pytest -s --topology-only new-topo/test_new_topo.py
$ # Running the test_template.py topology
- $ sudo pytest -s --topology-only example-test/test_template.py
+ $ sudo -E pytest -s --topology-only example-test/test_template.py
$ # Running the ospf_topo1.py topology
- $ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py
+ $ sudo -E pytest -s --topology-only ospf-topo1/test_ospf_topo1.py
Parameters explanation:
@@ -851,7 +887,7 @@ output:
.. code:: shell
- frr/tests/topotests# sudo pytest -s --topology-only ospf_topo1/test_ospf_topo1.py
+ frr/tests/topotests# sudo -E pytest -s --topology-only ospf_topo1/test_ospf_topo1.py
============================= test session starts ==============================
platform linux -- Python 3.9.2, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: /home/chopps/w/frr/tests/topotests, configfile: pytest.ini
@@ -1011,8 +1047,8 @@ Example:
# topology build code
...
-- pytest setup/teardown fixture to start the topology and supply `tgen` argument
- to tests.
+- pytest setup/teardown fixture to start the topology and supply ``tgen``
+ argument to tests.
.. code:: py
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 000d1a3301..e24eba7cd4 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -94,10 +94,9 @@ static void ldp_load_module(const char *name)
{
const char *dir;
dir = ldpd_di.module_path ? ldpd_di.module_path : frr_moduledir;
- char moderr[256];
struct frrmod_runtime *module;
- module = frrmod_load(name, dir, moderr, sizeof(moderr));
+ module = frrmod_load(name, dir, NULL,NULL);
if (!module) {
fprintf(stderr, "%s: failed to load %s", __func__, name);
log_warnx("%s: failed to load %s", __func__, name);
diff --git a/lib/libfrr.c b/lib/libfrr.c
index d03437328b..9b05bb4fbf 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -674,13 +674,19 @@ static void frr_mkdir(const char *path, bool strip)
strerror(errno));
}
+static void _err_print(const void *cookie, const char *errstr)
+{
+ const char *prefix = (const char *)cookie;
+
+ fprintf(stderr, "%s: %s\n", prefix, errstr);
+}
+
static struct thread_master *master;
struct thread_master *frr_init(void)
{
struct option_chain *oc;
struct frrmod_runtime *module;
struct zprivs_ids_t ids;
- char moderr[256];
char p_instance[16] = "", p_pathspace[256] = "";
const char *dir;
dir = di->module_path ? di->module_path : frr_moduledir;
@@ -734,11 +740,9 @@ struct thread_master *frr_init(void)
frrmod_init(di->module);
while (modules) {
modules = (oc = modules)->next;
- module = frrmod_load(oc->arg, dir, moderr, sizeof(moderr));
- if (!module) {
- fprintf(stderr, "%s\n", moderr);
+ module = frrmod_load(oc->arg, dir, _err_print, __func__);
+ if (!module)
exit(1);
- }
XFREE(MTYPE_TMP, oc);
}
diff --git a/lib/module.c b/lib/module.c
index 1d51a6396d..4037bfbeb0 100644
--- a/lib/module.c
+++ b/lib/module.c
@@ -26,9 +26,11 @@
#include "module.h"
#include "memory.h"
#include "lib/version.h"
+#include "printfrr.h"
DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name");
DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments");
+DEFINE_MTYPE_STATIC(LIB, MODULE_LOAD_ERR, "Module loading error");
static struct frrmod_info frrmod_default_info = {
.name = "libfrr",
@@ -67,14 +69,64 @@ void frrmod_init(struct frrmod_runtime *modinfo)
execname = modinfo->info->name;
}
-struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err,
- size_t err_len)
+/*
+ * If caller wants error strings, it should define non-NULL pFerrlog
+ * which will be called with 0-terminated error messages. These
+ * messages will NOT contain newlines, and the (*pFerrlog)() function
+ * could be called multiple times for a single call to frrmod_load().
+ *
+ * The (*pFerrlog)() function may copy these strings if needed, but
+ * should expect them to be freed by frrmod_load() before frrmod_load()
+ * returns.
+ *
+ * frrmod_load() is coded such that (*pFerrlog)() will be called only
+ * in the case where frrmod_load() returns an error.
+ */
+struct frrmod_runtime *frrmod_load(const char *spec, const char *dir,
+ void (*pFerrlog)(const void *, const char *),
+ const void *pErrlogCookie)
{
void *handle = NULL;
char name[PATH_MAX], fullpath[PATH_MAX * 2], *args;
struct frrmod_runtime *rtinfo, **rtinfop;
const struct frrmod_info *info;
+#define FRRMOD_LOAD_N_ERRSTR 10
+ char *aErr[FRRMOD_LOAD_N_ERRSTR];
+ unsigned int iErr = 0;
+
+ memset(aErr, 0, sizeof(aErr));
+
+#define ERR_RECORD(...) \
+ do { \
+ if (pFerrlog && (iErr < FRRMOD_LOAD_N_ERRSTR)) { \
+ aErr[iErr++] = asprintfrr(MTYPE_MODULE_LOAD_ERR, \
+ __VA_ARGS__); \
+ } \
+ } while (0)
+
+#define ERR_REPORT \
+ do { \
+ if (pFerrlog) { \
+ unsigned int i; \
+ \
+ for (i = 0; i < iErr; ++i) { \
+ (*pFerrlog)(pErrlogCookie, aErr[i]); \
+ } \
+ } \
+ } while (0)
+
+#define ERR_FREE \
+ do { \
+ unsigned int i; \
+ \
+ for (i = 0; i < iErr; ++i) { \
+ XFREE(MTYPE_MODULE_LOAD_ERR, aErr[i]); \
+ aErr[i] = 0; \
+ } \
+ iErr = 0; \
+ } while (0)
+
snprintf(name, sizeof(name), "%s", spec);
args = strchr(name, ':');
if (args)
@@ -85,32 +137,41 @@ struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err,
snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", dir,
execname, name);
handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
+ if (!handle)
+ ERR_RECORD("loader error: dlopen(%s): %s",
+ fullpath, dlerror());
}
if (!handle) {
snprintf(fullpath, sizeof(fullpath), "%s/%s.so", dir,
name);
handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
+ if (!handle)
+ ERR_RECORD("loader error: dlopen(%s): %s",
+ fullpath, dlerror());
}
}
if (!handle) {
snprintf(fullpath, sizeof(fullpath), "%s", name);
handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
+ if (!handle)
+ ERR_RECORD("loader error: dlopen(%s): %s", fullpath,
+ dlerror());
}
if (!handle) {
- if (err)
- snprintf(err, err_len,
- "loading module \"%s\" failed: %s", name,
- dlerror());
+ ERR_REPORT;
+ ERR_FREE;
return NULL;
}
+ /* previous dlopen() errors are no longer relevant */
+ ERR_FREE;
+
rtinfop = dlsym(handle, "frr_module");
if (!rtinfop) {
dlclose(handle);
- if (err)
- snprintf(err, err_len,
- "\"%s\" is not an FRR module: %s", name,
- dlerror());
+ ERR_RECORD("\"%s\" is not an FRR module: %s", name, dlerror());
+ ERR_REPORT;
+ ERR_FREE;
return NULL;
}
rtinfo = *rtinfop;
@@ -122,17 +183,13 @@ struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err,
if (rtinfo->finished_loading) {
dlclose(handle);
- if (err)
- snprintf(err, err_len, "module \"%s\" already loaded",
- name);
+ ERR_RECORD("module \"%s\" already loaded", name);
goto out_fail;
}
if (info->init && info->init()) {
dlclose(handle);
- if (err)
- snprintf(err, err_len,
- "module \"%s\" initialisation failed", name);
+ ERR_RECORD("module \"%s\" initialisation failed", name);
goto out_fail;
}
@@ -140,11 +197,14 @@ struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err,
*frrmod_last = rtinfo;
frrmod_last = &rtinfo->next;
+ ERR_FREE;
return rtinfo;
out_fail:
XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args);
XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name);
+ ERR_REPORT;
+ ERR_FREE;
return NULL;
}
diff --git a/lib/module.h b/lib/module.h
index 6275877cb3..ae1ca2f757 100644
--- a/lib/module.h
+++ b/lib/module.h
@@ -91,7 +91,9 @@ extern struct frrmod_runtime *frrmod_list;
extern void frrmod_init(struct frrmod_runtime *modinfo);
extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir,
- char *err, size_t err_len);
+ void (*pFerrlog)(const void *,
+ const char *),
+ const void *pErrlogCookie);
#if 0
/* not implemented yet */
extern void frrmod_unload(struct frrmod_runtime *module);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 5fb2ddf732..4cd94e0df9 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -3842,7 +3842,7 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty,
xpath_member_value)) {
member_dnode = yang_dnode_get(vty->candidate_config->dnode,
xpath_member_value);
- if (!yang_is_last_list_dnode(member_dnode))
+ if (!member_dnode || !yang_is_last_list_dnode(member_dnode))
return;
}
@@ -9761,7 +9761,7 @@ DEFPY(no_ip_msdp_mesh_group_member,
return CMD_WARNING_CONFIG_FAILED;
}
- nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
+ nb_cli_enqueue_change(vty, xpath_member_value, NB_OP_DESTROY, NULL);
/*
* If this is the last member, then we must remove the group altogether
@@ -9795,7 +9795,7 @@ DEFPY(ip_msdp_mesh_group_source,
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
- /* Create mesh group member. */
+ /* Create mesh group source. */
strlcat(xpath_value, "/source", sizeof(xpath_value));
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str);
@@ -9826,7 +9826,7 @@ DEFPY(no_ip_msdp_mesh_group_source,
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
- /* Create mesh group member. */
+ /* Create mesh group source. */
strlcat(xpath_value, "/source", sizeof(xpath_value));
nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index f4627cbcc2..b9da8ec068 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -1168,6 +1168,7 @@ int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args)
{
struct pim_msdp_mg_mbr *mbr;
struct pim_msdp_mg *mg;
+ const struct lyd_node *mg_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
@@ -1176,9 +1177,11 @@ int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args)
break;
case NB_EV_APPLY:
mbr = nb_running_get_entry(args->dnode, NULL, true);
- mg = nb_running_get_entry(args->dnode, "../", true);
-
+ mg_dnode =
+ yang_dnode_get_parent(args->dnode, "msdp-mesh-groups");
+ mg = nb_running_get_entry(mg_dnode, NULL, true);
pim_msdp_mg_mbr_del(mg, mbr);
+ nb_running_unset_entry(args->dnode);
break;
}
diff --git a/tests/lib/test_grpc.cpp b/tests/lib/test_grpc.cpp
index 491796802a..0aa1bbb7e1 100644
--- a/tests/lib/test_grpc.cpp
+++ b/tests/lib/test_grpc.cpp
@@ -81,11 +81,16 @@ static const struct frr_yang_module_info *const staticd_yang_modules[] = {
static int grpc_thread_stop(struct thread *thread);
+static void _err_print(const void *cookie, const char *errstr)
+{
+ std::cout << "Failed to load grpc module:" << errstr << std::endl;
+}
+
static void static_startup(void)
{
// struct frrmod_runtime module;
// static struct option_chain *oc;
- char moderr[256] = {};
+
cmd_init(1);
zlog_aux_init("NONE: ", LOG_DEBUG);
@@ -94,17 +99,14 @@ static void static_startup(void)
/* Load the server side module -- check libtool path first */
std::string modpath = std::string(binpath) + std::string("../../../lib/.libs");
- grpc_module = frrmod_load("grpc:50051", modpath.c_str(), moderr, sizeof(moderr));
+ grpc_module = frrmod_load("grpc:50051", modpath.c_str(), 0, 0);
if (!grpc_module) {
modpath = std::string(binpath) + std::string("../../lib");
- grpc_module = frrmod_load("grpc:50051", modpath.c_str(), moderr,
- sizeof(moderr));
+ grpc_module = frrmod_load("grpc:50051", modpath.c_str(),
+ _err_print, 0);
}
- if (!grpc_module) {
- std::cout << "Failed to load grpc module:" << moderr
- << std::endl;
+ if (!grpc_module)
exit(1);
- }
static_debug_init();
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
index 8fd344696e..fce8e708f2 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
@@ -206,7 +206,7 @@ def ltemplatePreRouterStartHook():
for cmd in cmds:
cc.doCmd(tgen, rtr, cmd.format(rtr))
cc.doCmd(tgen, rtr, "ip link set dev {0}-eth0 master {0}-cust2".format(rtr))
- if cc.getOutput() != 4:
+ if cc.getOutput() != 0:
InitSuccess = False
logger.info(
"Unexpected output seen ({} times, tests will be skipped".format(
@@ -214,6 +214,11 @@ def ltemplatePreRouterStartHook():
)
)
else:
+ rtrs = ["r1", "r3", "r4", "ce4"]
+ for rtr in rtrs:
+ logger.info("{} configured".format(rtr))
+ cc.doCmd(tgen, rtr, "ip -d link show type vrf")
+ cc.doCmd(tgen, rtr, "ip link show")
InitSuccess = True
logger.info("VRF config successful!")
return InitSuccess
diff --git a/tests/topotests/lib/ltemplate.py b/tests/topotests/lib/ltemplate.py
index 910573c14c..c98bfac9ee 100644
--- a/tests/topotests/lib/ltemplate.py
+++ b/tests/topotests/lib/ltemplate.py
@@ -217,6 +217,7 @@ class ltemplateRtrCmd:
self.resetCounts()
def doCmd(self, tgen, rtr, cmd, checkstr=None):
+ logger.info("doCmd: {} {}".format(rtr, cmd))
output = tgen.net[rtr].cmd(cmd).strip()
if len(output):
self.output += 1
@@ -227,9 +228,10 @@ class ltemplateRtrCmd:
else:
self.match += 1
return ret
- logger.info("command: {} {}".format(rtr, cmd))
logger.info("output: " + output)
- self.none += 1
+ else:
+ logger.info("No output")
+ self.none += 1
return None
def resetCounts(self):
diff --git a/tools/coccinelle/zlog_no_newline.cocci b/tools/coccinelle/zlog_no_newline.cocci
new file mode 100644
index 0000000000..20cf9d2c78
--- /dev/null
+++ b/tools/coccinelle/zlog_no_newline.cocci
@@ -0,0 +1,20 @@
+// zlog_* should not have \n or \r at the end usually.
+// spatch --sp-file tools/coccinelle/zlog_no_newline.cocci --macro-file tools/cocci.h ./ 2>/dev/null
+
+@r@
+expression fmt;
+identifier func =~ "zlog_";
+position p;
+@@
+(
+ func(fmt)@p
+|
+ func(fmt, ...)@p
+)
+
+@script:python@
+fmt << r.fmt;
+p << r.p;
+@@
+if "\\n" in str(fmt) or "\\r" in str(fmt):
+ print("Newline in logging function detected %s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt))