#include <zebra.h>
#include <lib/version.h>
+#include "darr.h"
#include "libfrr.h"
#include "mgmt_be_client.h"
/* Local Prototypes */
/* ---------------- */
-static void ripd_notification(struct mgmt_be_client *client, uintptr_t usr_data,
- struct mgmt_be_client_notification_cb *this,
- const char *notif_data);
+static void async_notification(struct mgmt_be_client *client, uintptr_t usr_data,
+ struct mgmt_be_client_notification_cb *this,
+ const char *notif_data);
static void sigusr1(void);
static void sigint(void);
.cap_num_i = 0,
};
-struct option longopts[] = {{0}};
+#define OPTION_LISTEN 2000
+#define OPTION_NOTIF_COUNT 2001
+#define OPTION_TIMEOUT 2002
+const struct option longopts[] = {
+ { "listen", no_argument, NULL, OPTION_LISTEN },
+ { "notif-count", required_argument, NULL, OPTION_NOTIF_COUNT },
+ { "timeout", required_argument, NULL, OPTION_TIMEOUT },
+ { 0 }
+};
+
/* Master of threads. */
struct event_loop *master;
);
/* clang-format on */
-struct mgmt_be_client_notification_cb __notify_cbs[] = { {
- .xpath = "frr-ripd",
- .format = LYD_JSON,
- .callback = ripd_notification,
-} };
+struct mgmt_be_client_notification_cb *__notify_cbs;
-struct mgmt_be_client_cbs __client_cbs = {
- .notify_cbs = __notify_cbs,
- .nnotify_cbs = array_size(__notify_cbs),
-};
+struct mgmt_be_client_cbs __client_cbs = {};
+struct event *event_timeout;
+int o_notif_count = 1;
+int o_timeout;
/* --------- */
/* Functions */
zlog_rotate();
}
+static void quit(int exit_code)
+{
+ EVENT_OFF(event_timeout);
+ frr_fini();
+ darr_free(__client_cbs.notify_cbs);
+ exit(exit_code);
+}
+
static void sigint(void)
{
zlog_notice("Terminating on signal");
- frr_fini();
- exit(0);
+ quit(0);
}
-static void ripd_notification(struct mgmt_be_client *client, uintptr_t usr_data,
- struct mgmt_be_client_notification_cb *this,
- const char *notif_data)
+static void timeout(struct event *event)
{
- zlog_notice("Received RIPd notification");
+ zlog_notice("Timeout, exiting");
+ quit(1);
+}
+
+static void async_notification(struct mgmt_be_client *client, uintptr_t usr_data,
+ struct mgmt_be_client_notification_cb *this,
+ const char *notif_data)
+{
+ zlog_notice("Received YANG notification");
+
+ printf("%s\n", notif_data);
+
+ if (o_notif_count && !--o_notif_count)
+ quit(0);
}
int main(int argc, char **argv)
{
+ int f_listen = 0;
+ int i;
+
frr_preinit(&mgmtd_testc_di, argc, argv);
frr_opt_add("", longopts, "");
break;
switch (opt) {
+ case OPTION_LISTEN:
+ f_listen = 1;
+ break;
+ case OPTION_NOTIF_COUNT:
+ o_notif_count = atoi(optarg);
+ break;
+ case OPTION_TIMEOUT:
+ o_timeout = atoi(optarg);
+ break;
case 0:
break;
default:
master = frr_init();
+ /*
+ * Setup notification listen
+ */
+ argv += optind;
+ argc -= optind;
+ if (!argc && f_listen) {
+ fprintf(stderr,
+ "Must specify at least one notification xpath to listen to\n");
+ exit(1);
+ }
+ if (argc && f_listen) {
+ struct mgmt_be_client_notification_cb *cb;
+
+ for (i = 0; i < argc; i++) {
+ zlog_notice("Listen on xpath: %s", argv[i]);
+ cb = darr_append(__notify_cbs);
+ cb->xpath = argv[i];
+ cb->format = LYD_JSON;
+ cb->callback = async_notification;
+ }
+ __client_cbs.notify_cbs = __notify_cbs;
+ __client_cbs.nnotify_cbs = darr_len(__notify_cbs);
+ }
+
mgmt_be_client = mgmt_be_client_create("mgmtd-testc", &__client_cbs, 0,
master);
frr_config_fork();
+
+ if (o_timeout)
+ event_add_timer(master, timeout, NULL, o_timeout, &event_timeout);
+
frr_run(master);
/* Reached. */
tgen.stop_topology()
-def test_oper_simple(tgen):
+def test_frontend_notification(tgen):
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
if rc:
pytest.skip("No protoc or present cannot run test")
+ # The first notifications is a frr-ripd:authentication-type-failure
+ # So we filter to avoid that, all the rest are frr-ripd:authentication-failure
+ # making our test deterministic
+ output = r1.cmd_raises(
+ fe_client_path + " --listen frr-ripd:authentication-failure"
+ )
+ jsout = json.loads(output)
+
+ expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}}
+ result = json_cmp(jsout, expected)
+ assert result is None
+
output = r1.cmd_raises(fe_client_path + " --listen")
jsout = json.loads(output)
- expected = {"frr-ripd:authentication-type-failure": {"interface-name": "r1-eth0"}}
+ expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}}
+ result = json_cmp(jsout, expected)
+ assert result is None
+
+
+def test_backend_notification(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"].net
+
+ check_kernel_32(r1, "11.11.11.11", 1, "")
+
+ be_client_path = "/usr/lib/frr/mgmtd_testc"
+ rc, _, _ = r1.cmd_status(be_client_path + " --help")
+
+ if rc:
+ pytest.skip("No mgmtd_testc")
+
+ output = r1.cmd_raises(
+ be_client_path + " --timeout 20 --log file:mgmt_testc.log --listen frr-ripd"
+ )
+
+ jsout = json.loads(output)
+
+ expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}}
result = json_cmp(jsout, expected)
assert result is None