summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/mgmt_be_client.c2
-rw-r--r--lib/mgmt_fe_client.c5
-rw-r--r--lib/mgmt_fe_client.h2
-rw-r--r--lib/vty.c12
-rw-r--r--mgmtd/mgmt_be_adapter.c2
-rw-r--r--mgmtd/mgmt_ds.c2
-rw-r--r--mgmtd/mgmt_fe_adapter.c2
-rw-r--r--mgmtd/mgmt_txn.c22
-rw-r--r--mgmtd/mgmt_txn.h4
-rw-r--r--staticd/static_main.c4
-rw-r--r--tests/topotests/mgmt_config/r1/early-end-zebra.conf6
-rw-r--r--tests/topotests/mgmt_config/r1/early-end.conf8
-rw-r--r--tests/topotests/mgmt_config/r1/early-end2-zebra.conf7
-rw-r--r--tests/topotests/mgmt_config/r1/early-end2.conf9
-rw-r--r--tests/topotests/mgmt_config/r1/early-exit-zebra.conf6
-rw-r--r--tests/topotests/mgmt_config/r1/early-exit.conf8
-rw-r--r--tests/topotests/mgmt_config/r1/early-exit2-zebra.conf7
-rw-r--r--tests/topotests/mgmt_config/r1/early-exit2.conf9
-rw-r--r--tests/topotests/mgmt_config/r1/mgmtd.conf11
-rw-r--r--tests/topotests/mgmt_config/r1/normal-exit.conf8
-rw-r--r--tests/topotests/mgmt_config/r1/one-exit-zebra.conf3
-rw-r--r--tests/topotests/mgmt_config/r1/one-exit.conf3
-rw-r--r--tests/topotests/mgmt_config/r1/one-exit2-zebra.conf4
-rw-r--r--tests/topotests/mgmt_config/r1/one-exit2.conf4
-rw-r--r--tests/topotests/mgmt_config/r1/zebra.conf7
-rw-r--r--tests/topotests/mgmt_config/test_config.py385
-rw-r--r--tests/topotests/mgmt_startup/test_cfgfile_var.py (renamed from tests/topotests/mgmt_startup/test_config.py)0
-rw-r--r--vtysh/vtysh.c7
28 files changed, 512 insertions, 37 deletions
diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c
index 5c875204f7..24084f6fe8 100644
--- a/lib/mgmt_be_client.c
+++ b/lib/mgmt_be_client.c
@@ -21,7 +21,7 @@
#include "lib/mgmt_be_client_clippy.c"
#define MGMTD_BE_CLIENT_DBG(fmt, ...) \
- DEBUGD(&mgmt_dbg_be_client, "BE-CLIENT: %s:" fmt, __func__, \
+ DEBUGD(&mgmt_dbg_be_client, "BE-CLIENT: %s: " fmt, __func__, \
##__VA_ARGS__)
#define MGMTD_BE_CLIENT_ERR(fmt, ...) \
zlog_err("BE-CLIENT: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c
index 35a6d7d909..7af421405b 100644
--- a/lib/mgmt_fe_client.c
+++ b/lib/mgmt_fe_client.c
@@ -124,18 +124,15 @@ static int mgmt_fe_send_session_req(struct mgmt_fe_client *client,
{
Mgmtd__FeMessage fe_msg;
Mgmtd__FeSessionReq sess_req;
- bool scok;
mgmtd__fe_session_req__init(&sess_req);
sess_req.create = create;
if (create) {
sess_req.id_case = MGMTD__FE_SESSION_REQ__ID_CLIENT_CONN_ID;
sess_req.client_conn_id = session->client_id;
- scok = true;
} else {
sess_req.id_case = MGMTD__FE_SESSION_REQ__ID_SESSION_ID;
sess_req.session_id = session->session_id;
- scok = false;
}
mgmtd__fe_message__init(&fe_msg);
@@ -146,7 +143,7 @@ static int mgmt_fe_send_session_req(struct mgmt_fe_client *client,
"Sending SESSION_REQ %s message for client-id %" PRIu64,
create ? "create" : "destroy", session->client_id);
- return mgmt_fe_client_send_msg(client, &fe_msg, scok);
+ return mgmt_fe_client_send_msg(client, &fe_msg, true);
}
int mgmt_fe_send_lockds_req(struct mgmt_fe_client *client, uint64_t session_id,
diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h
index edf861746c..845d0bd94a 100644
--- a/lib/mgmt_fe_client.h
+++ b/lib/mgmt_fe_client.h
@@ -120,7 +120,7 @@ struct mgmt_fe_client_cbs {
extern struct debug mgmt_dbg_fe_client;
#define MGMTD_FE_CLIENT_DBG(fmt, ...) \
- DEBUGD(&mgmt_dbg_fe_client, "FE-CLIENT: %s:" fmt, __func__, \
+ DEBUGD(&mgmt_dbg_fe_client, "FE-CLIENT: %s: " fmt, __func__, \
##__VA_ARGS__)
#define MGMTD_FE_CLIENT_ERR(fmt, ...) \
zlog_err("FE-CLIENT: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
diff --git a/lib/vty.c b/lib/vty.c
index fedbdbb813..cbf42de473 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2423,6 +2423,14 @@ void vty_close(struct vty *vty)
vty->status = VTY_CLOSE;
+ /*
+ * If we reach here with pending config to commit we will be losing it
+ * so warn the user.
+ */
+ if (vty->mgmt_num_pending_setcfg)
+ MGMTD_FE_CLIENT_ERR(
+ "vty closed, uncommitted config will be lost.");
+
if (mgmt_fe_client && vty->mgmt_session_id) {
MGMTD_FE_CLIENT_DBG("closing vty session");
mgmt_fe_destroy_client_session(mgmt_fe_client,
@@ -3445,7 +3453,9 @@ static void vty_mgmt_session_notify(struct mgmt_fe_client *client,
vty->mgmt_session_id = session_id;
} else {
vty->mgmt_session_id = 0;
- vty_close(vty);
+ /* We may come here by way of vty_close() and short-circuits */
+ if (vty->status != VTY_CLOSE)
+ vty_close(vty);
}
}
diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c
index e4a62951d2..49a307e9c2 100644
--- a/mgmtd/mgmt_be_adapter.c
+++ b/mgmtd/mgmt_be_adapter.c
@@ -20,7 +20,7 @@
#include "mgmtd/mgmt_be_adapter.h"
#define MGMTD_BE_ADAPTER_DBG(fmt, ...) \
- DEBUGD(&mgmt_debug_be, "BE-ADAPTER: %s:" fmt, __func__, ##__VA_ARGS__)
+ DEBUGD(&mgmt_debug_be, "BE-ADAPTER: %s: " fmt, __func__, ##__VA_ARGS__)
#define MGMTD_BE_ADAPTER_ERR(fmt, ...) \
zlog_err("BE-ADAPTER: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
diff --git a/mgmtd/mgmt_ds.c b/mgmtd/mgmt_ds.c
index 3fd47862b2..2926c9dd4f 100644
--- a/mgmtd/mgmt_ds.c
+++ b/mgmtd/mgmt_ds.c
@@ -16,7 +16,7 @@
#include "libyang/libyang.h"
#define MGMTD_DS_DBG(fmt, ...) \
- DEBUGD(&mgmt_debug_ds, "%s:" fmt, __func__, ##__VA_ARGS__)
+ DEBUGD(&mgmt_debug_ds, "DS: %s: " fmt, __func__, ##__VA_ARGS__)
#define MGMTD_DS_ERR(fmt, ...) \
zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c
index 7509d24a6a..eb23fc3d60 100644
--- a/mgmtd/mgmt_fe_adapter.c
+++ b/mgmtd/mgmt_fe_adapter.c
@@ -21,7 +21,7 @@
#include "mgmtd/mgmt_fe_adapter.h"
#define MGMTD_FE_ADAPTER_DBG(fmt, ...) \
- DEBUGD(&mgmt_debug_fe, "FE-ADAPTER: %s:" fmt, __func__, ##__VA_ARGS__)
+ DEBUGD(&mgmt_debug_fe, "FE-ADAPTER: %s: " fmt, __func__, ##__VA_ARGS__)
#define MGMTD_FE_ADAPTER_ERR(fmt, ...) \
zlog_err("FE-ADAPTER: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c
index 588693b7e3..18aeab711f 100644
--- a/mgmtd/mgmt_txn.c
+++ b/mgmtd/mgmt_txn.c
@@ -15,7 +15,7 @@
#include "mgmtd/mgmt_txn.h"
#define MGMTD_TXN_DBG(fmt, ...) \
- DEBUGD(&mgmt_debug_txn, "%s:" fmt, __func__, ##__VA_ARGS__)
+ DEBUGD(&mgmt_debug_txn, "TXN: %s: " fmt, __func__, ##__VA_ARGS__)
#define MGMTD_TXN_ERR(fmt, ...) \
zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
@@ -2618,26 +2618,6 @@ int mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success,
return 0;
}
-int mgmt_txn_send_commit_config_reply(uint64_t txn_id,
- enum mgmt_result result,
- const char *error_if_any)
-{
- struct mgmt_txn_ctx *txn;
-
- txn = mgmt_txn_id2ctx(txn_id);
- if (!txn)
- return -1;
-
- if (!txn->commit_cfg_req) {
- MGMTD_TXN_ERR("NO commit in-progress txn-id: %" PRIu64
- " session-id: %" PRIu64,
- txn->txn_id, txn->session_id);
- return -1;
- }
-
- return mgmt_txn_send_commit_cfg_reply(txn, result, error_if_any);
-}
-
int mgmt_txn_send_get_config_req(uint64_t txn_id, uint64_t req_id,
Mgmtd__DatastoreId ds_id,
struct mgmt_ds_ctx *ds_ctx,
diff --git a/mgmtd/mgmt_txn.h b/mgmtd/mgmt_txn.h
index 0718397138..1a9f6d8502 100644
--- a/mgmtd/mgmt_txn.h
+++ b/mgmtd/mgmt_txn.h
@@ -176,10 +176,6 @@ extern int mgmt_txn_send_commit_config_req(uint64_t txn_id, uint64_t req_id,
bool validate_only, bool abort,
bool implicit);
-extern int mgmt_txn_send_commit_config_reply(uint64_t txn_id,
- enum mgmt_result result,
- const char *error_if_any);
-
/*
* Send get-config request to be processed later in transaction.
*
diff --git a/staticd/static_main.c b/staticd/static_main.c
index f6b7847602..9101a95b17 100644
--- a/staticd/static_main.c
+++ b/staticd/static_main.c
@@ -56,11 +56,11 @@ struct event_loop *master;
struct mgmt_be_client *mgmt_be_client;
static struct frr_daemon_info staticd_di;
+
/* SIGHUP handler. */
static void sighup(void)
{
- zlog_info("SIGHUP received");
- vty_read_config(NULL, staticd_di.config_file, config_default);
+ zlog_info("SIGHUP received and ignored");
}
/* SIGINT / SIGTERM handler. */
diff --git a/tests/topotests/mgmt_config/r1/early-end-zebra.conf b/tests/topotests/mgmt_config/r1/early-end-zebra.conf
new file mode 100644
index 0000000000..44a2f96825
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/early-end-zebra.conf
@@ -0,0 +1,6 @@
+allow-external-route-update
+end
+ip multicast rpf-lookup-mode urib-only
+end
+ip table range 2 3
+end \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/early-end.conf b/tests/topotests/mgmt_config/r1/early-end.conf
new file mode 100644
index 0000000000..3aacad6471
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/early-end.conf
@@ -0,0 +1,8 @@
+ip route 15.1.0.0/24 101.0.0.2
+end
+ip route 15.2.0.0/24 101.0.0.2
+end
+ip route 15.3.0.0/24 101.0.0.2
+end
+ip route 15.4.0.0/24 101.0.0.2
+end \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/early-end2-zebra.conf b/tests/topotests/mgmt_config/r1/early-end2-zebra.conf
new file mode 100644
index 0000000000..37619d52ac
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/early-end2-zebra.conf
@@ -0,0 +1,7 @@
+conf t
+allow-external-route-update
+end
+ip multicast rpf-lookup-mode urib-only
+end
+ip table range 2 3
+end \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/early-end2.conf b/tests/topotests/mgmt_config/r1/early-end2.conf
new file mode 100644
index 0000000000..229ccc7410
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/early-end2.conf
@@ -0,0 +1,9 @@
+conf t
+ip route 16.1.0.0/24 101.0.0.2
+end
+ip route 16.2.0.0/24 101.0.0.2
+end
+ip route 16.3.0.0/24 101.0.0.2
+end
+ip route 16.4.0.0/24 101.0.0.2
+end \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/early-exit-zebra.conf b/tests/topotests/mgmt_config/r1/early-exit-zebra.conf
new file mode 100644
index 0000000000..44f202dbcb
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/early-exit-zebra.conf
@@ -0,0 +1,6 @@
+allow-external-route-update
+exit
+ip multicast rpf-lookup-mode urib-only
+exit
+ip table range 2 3
+exit \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/early-exit.conf b/tests/topotests/mgmt_config/r1/early-exit.conf
new file mode 100644
index 0000000000..c6a52df5d3
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/early-exit.conf
@@ -0,0 +1,8 @@
+ip route 13.1.0.0/24 101.0.0.2
+exit
+ip route 13.2.0.0/24 101.0.0.2
+exit
+ip route 13.3.0.0/24 101.0.0.2
+exit
+ip route 13.4.0.0/24 101.0.0.2
+exit \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/early-exit2-zebra.conf b/tests/topotests/mgmt_config/r1/early-exit2-zebra.conf
new file mode 100644
index 0000000000..c7109bfd39
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/early-exit2-zebra.conf
@@ -0,0 +1,7 @@
+conf t
+allow-external-route-update
+exit
+ip multicast rpf-lookup-mode urib-only
+exit
+ip table range 2 3
+exit \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/early-exit2.conf b/tests/topotests/mgmt_config/r1/early-exit2.conf
new file mode 100644
index 0000000000..79510c0aec
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/early-exit2.conf
@@ -0,0 +1,9 @@
+conf t
+ip route 14.1.0.0/24 101.0.0.2
+exit
+ip route 14.2.0.0/24 101.0.0.2
+exit
+ip route 14.3.0.0/24 101.0.0.2
+exit
+ip route 14.4.0.0/24 101.0.0.2
+exit \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/mgmtd.conf b/tests/topotests/mgmt_config/r1/mgmtd.conf
new file mode 100644
index 0000000000..318de765c8
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/mgmtd.conf
@@ -0,0 +1,11 @@
+debug northbound notifications
+debug northbound libyang
+debug northbound events
+debug northbound callbacks
+debug mgmt backend datastore frontend transaction
+debug mgmt client backend
+debug mgmt client frontend
+
+ip route 12.0.0.0/24 101.0.0.2
+
+ipv6 route 2012::/48 2101::2 \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/normal-exit.conf b/tests/topotests/mgmt_config/r1/normal-exit.conf
new file mode 100644
index 0000000000..c6a52df5d3
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/normal-exit.conf
@@ -0,0 +1,8 @@
+ip route 13.1.0.0/24 101.0.0.2
+exit
+ip route 13.2.0.0/24 101.0.0.2
+exit
+ip route 13.3.0.0/24 101.0.0.2
+exit
+ip route 13.4.0.0/24 101.0.0.2
+exit \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/one-exit-zebra.conf b/tests/topotests/mgmt_config/r1/one-exit-zebra.conf
new file mode 100644
index 0000000000..0c38459702
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/one-exit-zebra.conf
@@ -0,0 +1,3 @@
+allow-external-route-update
+exit
+ip multicast rpf-lookup-mode urib-only
diff --git a/tests/topotests/mgmt_config/r1/one-exit.conf b/tests/topotests/mgmt_config/r1/one-exit.conf
new file mode 100644
index 0000000000..47147d44eb
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/one-exit.conf
@@ -0,0 +1,3 @@
+ip route 20.1.0.0/24 101.0.0.2
+exit
+ip route 20.2.0.0/24 101.0.0.2
diff --git a/tests/topotests/mgmt_config/r1/one-exit2-zebra.conf b/tests/topotests/mgmt_config/r1/one-exit2-zebra.conf
new file mode 100644
index 0000000000..34acb76d92
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/one-exit2-zebra.conf
@@ -0,0 +1,4 @@
+conf t
+allow-external-route-update
+exit
+ip multicast rpf-lookup-mode urib-only \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/r1/one-exit2.conf b/tests/topotests/mgmt_config/r1/one-exit2.conf
new file mode 100644
index 0000000000..262339a854
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/one-exit2.conf
@@ -0,0 +1,4 @@
+conf t
+ip route 21.1.0.0/24 101.0.0.2
+exit
+ip route 21.2.0.0/24 101.0.0.2
diff --git a/tests/topotests/mgmt_config/r1/zebra.conf b/tests/topotests/mgmt_config/r1/zebra.conf
new file mode 100644
index 0000000000..f3264efb00
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/zebra.conf
@@ -0,0 +1,7 @@
+log timestamp precision 6
+log file frr-r1.log debug
+
+interface r1-eth0
+ ip address 101.0.0.1/24
+ ipv6 address 2101::1/64
+exit \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/test_config.py b/tests/topotests/mgmt_config/test_config.py
new file mode 100644
index 0000000000..b07ed8f7fd
--- /dev/null
+++ b/tests/topotests/mgmt_config/test_config.py
@@ -0,0 +1,385 @@
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+# SPDX-License-Identifier: ISC
+#
+# June 10 2023, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2023, LabN Consulting, L.L.C.
+#
+"""
+Test mgmtd parsing of configs.
+
+So:
+
+MGMTD matches zebra:
+
+one exit file: ONE: vty -f file
+one exit redir: ONE: vty < file
+early exit file: ONE: vty -f file
+early exit redir: ONE: vty < file
+early end file: ALL: vty -f file
+early end redir: ONE: vty < file
+
+Raw tests:
+
+FAILED mgmt_config/test_config.py::test_mgmtd_one_exit_file - AssertionError: vtysh < didn't work after exit
+FAILED mgmt_config/test_config.py::test_mgmtd_one_exit_redir - AssertionError: vtysh < didn't work after exit
+FAILED mgmt_config/test_config.py::test_mgmtd_early_exit_file - AssertionError: vtysh -f didn't work after 1 exit
+FAILED mgmt_config/test_config.py::test_mgmtd_early_exit_redir - AssertionError: vtysh < didn't work after 1 exits
+FAILED mgmt_config/test_config.py::test_mgmtd_early_end_redir - AssertionError: vtysh < didn't work after 1 end
+
+FAILED mgmt_config/test_config.py::test_zebra_one_exit_file - AssertionError: zebra second conf missing
+FAILED mgmt_config/test_config.py::test_zebra_one_exit_redir - AssertionError: zebra second conf missing
+FAILED mgmt_config/test_config.py::test_zebra_early_exit_file - AssertionError: zebra second conf missing
+FAILED mgmt_config/test_config.py::test_zebra_early_exit_redir - AssertionError: zebra second conf missing
+FAILED mgmt_config/test_config.py::test_zebra_early_end_redir - AssertionError: zebra second conf missing
+
+Before fixed:
+
+one exit file: NONE: vty -f file
+early exit file: NONE: vty -f file
+
+FAILED mgmt_config/test_config.py::test_mgmtd_one_exit_file - AssertionError: vtysh -f didn't work before exit
+FAILED mgmt_config/test_config.py::test_mgmtd_one_exit_redir - AssertionError: vtysh < didn't work after exit
+FAILED mgmt_config/test_config.py::test_mgmtd_early_exit_file - AssertionError: vtysh -f didn't work before exit
+FAILED mgmt_config/test_config.py::test_mgmtd_early_exit_redir - AssertionError: vtysh < didn't work after 1 exits
+FAILED mgmt_config/test_config.py::test_mgmtd_early_end_redir - AssertionError: vtysh < didn't work after 1 end
+
+FAILED mgmt_config/test_config.py::test_zebra_one_exit_file - AssertionError: zebra second conf missing
+FAILED mgmt_config/test_config.py::test_zebra_one_exit_redir - AssertionError: zebra second conf missing
+FAILED mgmt_config/test_config.py::test_zebra_early_exit_file - AssertionError: zebra second conf missing
+FAILED mgmt_config/test_config.py::test_zebra_early_exit_redir - AssertionError: zebra second conf missing
+FAILED mgmt_config/test_config.py::test_zebra_early_end_redir - AssertionError: zebra second conf missing
+
+"""
+import ipaddress
+import logging
+import os
+import re
+from pathlib import Path
+
+import pytest
+from lib.common_config import retry, step
+from lib.topogen import Topogen, TopoRouter
+
+# pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd]
+pytestmark = [pytest.mark.staticd]
+
+
+@retry(retry_timeout=1, initial_wait=0.1)
+def check_kernel(r1, prefix, expected=True):
+ net = ipaddress.ip_network(prefix)
+ if net.version == 6:
+ kernel = r1.cmd_nostatus("ip -6 route show", warn=not expected)
+ else:
+ kernel = r1.cmd_nostatus("ip -4 route show", warn=not expected)
+
+ logging.debug("checking kernel routing table:\n%0.1920s", kernel)
+ route = f"{str(net)}(?: nhid [0-9]+)?.*proto (static|196)"
+ m = re.search(route, kernel)
+ if expected and not m:
+ return f"Failed to find \n'{route}'\n in \n'{kernel:.1920}'"
+ elif not expected and m:
+ return f"Failed found \n'{route}'\n in \n'{kernel:.1920}'"
+ return None
+
+
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
+ topodef = {"s1": ("r1",)}
+
+ tgen = Topogen(topodef, request.module.__name__)
+ tgen.start_topology()
+
+ # configure mgmtd using current mgmtd config file
+ tgen.gears["r1"].load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
+ tgen.gears["r1"].load_config(TopoRouter.RD_MGMTD)
+
+ tgen.start_router()
+ yield tgen
+ tgen.stop_topology()
+
+
+def save_log_snippet(logfile, content, savepath=None):
+ os.sync()
+ os.sync()
+ os.sync()
+
+ with open(logfile, encoding="utf-8") as f:
+ buf = f.read()
+ assert content == buf[: len(content)]
+ newcontent = buf[len(content) :]
+
+ if savepath:
+ with open(savepath, "w", encoding="utf-8") as f:
+ f.write(newcontent)
+
+ return buf
+
+
+def mapname(lname):
+ return lname.replace(".conf", "") + "-log.txt"
+
+
+logbuf = ""
+
+
+@pytest.fixture(scope="module")
+def r1(tgen):
+ return tgen.gears["r1"].net
+
+
+@pytest.fixture(scope="module")
+def confdir():
+ return Path(os.environ["PYTEST_TOPOTEST_SCRIPTDIR"]) / "r1"
+
+
+@pytest.fixture(scope="module")
+def tempdir(r1):
+ return Path(r1.rundir)
+
+
+@pytest.fixture(scope="module")
+def logpath(tempdir):
+ return tempdir / "mgmtd.log"
+
+
+@pytest.fixture(autouse=True, scope="function")
+def cleanup_config(r1, tempdir, logpath):
+ global logbuf
+
+ logbuf = save_log_snippet(logpath, logbuf, "/dev/null")
+
+ yield
+
+ r1.cmd_nostatus("vtysh -c 'conf t' -c 'no allow-external-route-update'")
+ r1.cmd_nostatus("vtysh -c 'conf t' -c 'no ip multicast rpf-lookup-mode urib-only'")
+ r1.cmd_nostatus("vtysh -c 'conf t' -c 'no ip table range 2 3'")
+
+ logbuf = save_log_snippet(logpath, logbuf, "/dev/null")
+
+
+def test_staticd_startup(r1):
+ r1.cmd_nostatus(
+ "vtysh -c 'debug mgmt client frontend' "
+ "-c 'debug mgmt client backend' "
+ "-c 'debug mgmt backend frontend datastore transaction'"
+ )
+ step("Verifying routes are present on r1")
+ result = check_kernel(r1, "12.0.0.0/24", retry_timeout=3.0)
+ assert result is None
+
+
+def test_mgmtd_one_exit_file(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "one-exit.conf"
+ step(f"load {conf} file with vtysh -f ")
+ output = r1.cmd_nostatus(f"vtysh -f {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ result1 = check_kernel(r1, "20.1.0.0/24")
+ result2 = check_kernel(r1, "20.2.0.0/24")
+
+ assert result1 is None, "vtysh -f didn't work before exit"
+ assert result2 is not None, "vtysh < worked after exit, unexpected"
+
+
+def test_mgmtd_one_exit_redir(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "one-exit2.conf"
+ step(f"Redirect {conf} file into vtysh")
+ output = r1.cmd_nostatus(f"vtysh < {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ result1 = check_kernel(r1, "21.1.0.0/24")
+ result2 = check_kernel(r1, "21.2.0.0/24")
+
+ assert result1 is None, "vtysh < didn't work before exit"
+ assert result2 is not None, "vtysh < worked after exit, unexpected"
+
+
+def test_mgmtd_early_exit_file(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "early-exit.conf"
+ step(f"load {conf} file with vtysh -f ")
+ output = r1.cmd_nostatus(f"vtysh -f {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ result1 = check_kernel(r1, "13.1.0.0/24")
+ result2 = check_kernel(r1, "13.2.0.0/24")
+ result3 = check_kernel(r1, "13.3.0.0/24")
+
+ assert result1 is None, "vtysh -f didn't work before exit"
+ assert result2 is not None, "vtysh -f worked after 1 exit, unexpected"
+ assert result3 is not None, "vtysh -f worked after 2 exit, unexpected"
+
+
+def test_mgmtd_early_exit_redir(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "early-exit2.conf"
+ step(f"Redirect {conf} file into vtysh")
+ output = r1.cmd_nostatus(f"vtysh < {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ result1 = check_kernel(r1, "14.1.0.0/24")
+ result2 = check_kernel(r1, "14.2.0.0/24")
+ result3 = check_kernel(r1, "14.3.0.0/24")
+
+ assert result1 is None, "vtysh < didn't work before exit"
+ assert result2 is not None, "vtysh < worked after 1 exits, unexpected"
+ assert result3 is not None, "vtysh < worked after 2 exits, unexpected"
+
+
+def test_mgmtd_early_end_file(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "early-end.conf"
+ step(f"load {conf} file with vtysh -f ")
+ output = r1.cmd_nostatus(f"vtysh -f {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ result1 = check_kernel(r1, "15.1.0.0/24")
+ result2 = check_kernel(r1, "15.2.0.0/24")
+ result3 = check_kernel(r1, "15.3.0.0/24")
+
+ assert result1 is None, "vtysh -f didn't work before end"
+ assert result2 is None, "vtysh -f didn't work after 1 end"
+ assert result3 is None, "vtysh -f didn't work after 2 ends"
+
+
+def test_mgmtd_early_end_redir(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "early-end2.conf"
+ step(f"Redirect {conf} file into vtysh")
+ output = r1.cmd_nostatus(f"vtysh < {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ result1 = check_kernel(r1, "16.1.0.0/24")
+ result2 = check_kernel(r1, "16.2.0.0/24")
+ result3 = check_kernel(r1, "16.3.0.0/24")
+
+ assert result1 is None, "vtysh < didn't work before end"
+ assert result2 is not None, "vtysh < worked after 1 end, unexpected"
+ assert result3 is not None, "vtysh < worked after 2 end, unexpected"
+
+
+#
+# Zebra
+#
+
+
+def test_zebra_one_exit_file(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "one-exit-zebra.conf"
+ step(f"load {conf} file with vtysh -f ")
+ output = r1.cmd_nostatus(f"vtysh -f {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ showrun = r1.cmd_nostatus("vtysh -c 'show running'")
+ assert "allow-external-route-update" in showrun, "zebra conf missing"
+ assert (
+ "ip multicast rpf-lookup-mode urib-only" not in showrun
+ ), "zebra second conf present, unexpected"
+
+
+def test_zebra_one_exit_redir(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "one-exit2-zebra.conf"
+ step(f"Redirect {conf} file into vtysh")
+ output = r1.cmd_nostatus(f"vtysh < {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ showrun = r1.cmd_nostatus("vtysh -c 'show running'")
+
+ assert "allow-external-route-update" in showrun, "zebra conf missing"
+ assert (
+ "ip multicast rpf-lookup-mode urib-only" not in showrun
+ ), "zebra second conf present, unexpected"
+
+
+def test_zebra_early_exit_file(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "early-exit-zebra.conf"
+ step(f"load {conf} file with vtysh -f ")
+ output = r1.cmd_nostatus(f"vtysh -f {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ showrun = r1.cmd_nostatus("vtysh -c 'show running'")
+
+ assert "allow-external-route-update" in showrun, "zebra conf missing"
+ assert (
+ "ip multicast rpf-lookup-mode urib-only" not in showrun
+ ), "zebra second conf present, unexpected"
+ assert "ip table range 2 3" not in showrun, "zebra third conf present, unexpected"
+
+
+def test_zebra_early_exit_redir(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "early-exit2-zebra.conf"
+ step(f"Redirect {conf} file into vtysh")
+ output = r1.cmd_nostatus(f"vtysh < {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ showrun = r1.cmd_nostatus("vtysh -c 'show running'")
+
+ assert "allow-external-route-update" in showrun, "zebra conf missing"
+ assert (
+ "ip multicast rpf-lookup-mode urib-only" not in showrun
+ ), "zebra second conf present, unexpected"
+ assert "ip table range 2 3" not in showrun, "zebra third conf present, unexpected"
+
+
+def test_zebra_early_end_file(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "early-end-zebra.conf"
+ step(f"load {conf} file with vtysh -f ")
+ output = r1.cmd_nostatus(f"vtysh -f {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ showrun = r1.cmd_nostatus("vtysh -c 'show running'")
+
+ assert "allow-external-route-update" in showrun, "zebra conf missing"
+ assert (
+ "ip multicast rpf-lookup-mode urib-only" in showrun
+ ), "zebra second conf missing"
+ assert "ip table range 2 3" in showrun, "zebra third missing"
+
+
+def test_zebra_early_end_redir(r1, confdir, tempdir, logpath):
+ global logbuf
+
+ conf = "early-end2-zebra.conf"
+ step(f"Redirect {conf} file into vtysh")
+ output = r1.cmd_nostatus(f"vtysh < {confdir / conf}")
+ logbuf = save_log_snippet(logpath, logbuf, tempdir / mapname(conf))
+ print(output)
+
+ showrun = r1.cmd_nostatus("vtysh -c 'show running'")
+
+ assert "allow-external-route-update" in showrun, "zebra conf missing"
+ assert (
+ "ip multicast rpf-lookup-mode urib-only" not in showrun
+ ), "zebra second conf present, unexpected"
+ assert "ip table range 2 3" not in showrun, "zebra third conf present, unexpected"
diff --git a/tests/topotests/mgmt_startup/test_config.py b/tests/topotests/mgmt_startup/test_cfgfile_var.py
index 6a54f71910..6a54f71910 100644
--- a/tests/topotests/mgmt_startup/test_config.py
+++ b/tests/topotests/mgmt_startup/test_cfgfile_var.py
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 04f7ff65e9..c94b47fef5 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -880,6 +880,13 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp)
if (strmatch(vty_buf_trimmed, "end"))
continue;
+ if (strmatch(vty_buf_trimmed, "exit") &&
+ vty->node == CONFIG_NODE) {
+ fprintf(stderr, "line %d: Warning[%d]...: %s\n", lineno,
+ vty->node, "early exit from config file");
+ break;
+ }
+
ret = command_config_read_one_line(vty, &cmd, lineno, 1);
switch (ret) {