// SPDX-License-Identifier: GPL-2.0-or-later /* * January 29 2024, Christian Hopps * * Copyright (c) 2024, LabN Consulting, L.L.C. * */ #include #include #include "darr.h" #include "libfrr.h" #include "mgmt_be_client.h" #include "northbound.h" /* ---------------- */ /* Local Prototypes */ /* ---------------- */ static void async_notification(struct nb_cb_notify_args *args); static void sigusr1(void); static void sigint(void); /* ----------- */ /* Global Data */ /* ----------- */ /* privileges */ static zebra_capabilities_t _caps_p[] = {}; struct zebra_privs_t __privs = { #if defined(FRR_USER) && defined(FRR_GROUP) .user = FRR_USER, .group = FRR_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = array_size(_caps_p), .cap_num_i = 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; struct mgmt_be_client *mgmt_be_client; static struct frr_daemon_info mgmtd_testc_di; struct frr_signal_t __signals[] = { { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; #define MGMTD_TESTC_VTY_PORT 2624 /* clang-format off */ static const struct frr_yang_module_info frr_ripd_info = { .name = "frr-ripd", .ignore_cfg_cbs = true, .nodes = { { .xpath = "/frr-ripd:authentication-failure", .cbs.notify = async_notification, }, { .xpath = NULL, } } }; static const struct frr_yang_module_info *const mgmt_yang_modules[] = { &frr_ripd_info, }; FRR_DAEMON_INFO(mgmtd_testc, MGMTD_TESTC, .proghelp = "FRR Management Daemon Test Client.", .signals = __signals, .n_signals = array_size(__signals), .privs = &__privs, .yang_modules = mgmt_yang_modules, .n_yang_modules = array_size(mgmt_yang_modules), /* avoid libfrr trying to read our config file for us */ .flags = FRR_MANUAL_VTY_START, ); /* clang-format on */ const char **__notif_xpaths; struct mgmt_be_client_cbs __client_cbs = {}; struct event *event_timeout; int o_notif_count = 1; int o_timeout; /* --------- */ /* Functions */ /* --------- */ static void sigusr1(void) { zlog_rotate(); } static void quit(int exit_code) { EVENT_OFF(event_timeout); frr_fini(); darr_free(__client_cbs.notif_xpaths); exit(exit_code); } static void sigint(void) { zlog_notice("Terminating on signal"); quit(0); } static void timeout(struct event *event) { zlog_notice("Timeout, exiting"); quit(1); } static void async_notification(struct nb_cb_notify_args *args) { zlog_notice("Received YANG notification"); printf("{\"frr-ripd:authentication-failure\": {\"interface-name\": \"%s\"}}\n", yang_dnode_get_string(args->dnode, "interface-name")); 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, ""); while (1) { int opt; opt = frr_getopt(argc, argv, NULL); if (opt == EOF) 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: frr_help_exit(1); } } 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) { for (i = 0; i < argc; i++) { zlog_notice("Listen on xpath: %s", argv[i]); darr_push(__notif_xpaths, argv[i]); } __client_cbs.notif_xpaths = __notif_xpaths; __client_cbs.nnotif_xpaths = darr_len(__notif_xpaths); } 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. */ return 0; }