diff --git a/lib/vty.c b/lib/vty.c index 1d04e75bf445..5fe980372a44 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -138,6 +138,9 @@ char const *const mgmt_daemons[] = { #ifdef HAVE_STATICD "staticd", #endif +#ifdef HAVE_OSPFD + "ospfd", +#endif }; uint mgmt_daemons_count = array_size(mgmt_daemons); diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c index 8f7049037967..933737ff08c7 100644 --- a/mgmtd/mgmt_be_adapter.c +++ b/mgmtd/mgmt_be_adapter.c @@ -37,6 +37,9 @@ const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1] = { [MGMTD_BE_CLIENT_ID_TESTC] = "mgmtd-testc", /* always first */ [MGMTD_BE_CLIENT_ID_ZEBRA] = "zebra", +#ifdef HAVE_OSPFD + [MGMTD_BE_CLIENT_ID_OSPFD] = "ospfd", +#endif #ifdef HAVE_RIPD [MGMTD_BE_CLIENT_ID_RIPD] = "ripd", #endif @@ -91,6 +94,14 @@ static const char *const mgmtd_testc_oper_xpaths[] = { }; #endif +#if HAVE_OSPFD +static const char *const ospfd_oper_xpaths[] = { + "/frr-interface:lib/interface/state/frr-ospfd-lite:ospf/state/*", + "/frr-ospfd-lite:ospf/instance/state/*", + NULL, +}; +#endif + #ifdef HAVE_RIPD static const char *const ripd_config_xpaths[] = { "/frr-filter:lib", @@ -174,6 +185,9 @@ static const char *const *be_client_oper_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { [MGMTD_BE_CLIENT_ID_STATICD] = staticd_oper_xpaths, #endif [MGMTD_BE_CLIENT_ID_ZEBRA] = zebra_oper_xpaths, +#if HAVE_OSPFD + [MGMTD_BE_CLIENT_ID_OSPFD] = ospfd_oper_xpaths, +#endif }; static const char *const *be_client_notif_xpaths[MGMTD_BE_CLIENT_ID_MAX] = { diff --git a/mgmtd/mgmt_be_adapter.h b/mgmtd/mgmt_be_adapter.h index c9f2ab1b7a88..ad5473475480 100644 --- a/mgmtd/mgmt_be_adapter.h +++ b/mgmtd/mgmt_be_adapter.h @@ -29,6 +29,9 @@ enum mgmt_be_client_id { MGMTD_BE_CLIENT_ID_TESTC, /* always first */ MGMTD_BE_CLIENT_ID_ZEBRA, +#ifdef HAVE_OSPFD + MGMTD_BE_CLIENT_ID_OSPFD, +#endif #ifdef HAVE_RIPD MGMTD_BE_CLIENT_ID_RIPD, #endif diff --git a/mgmtd/mgmt_main.c b/mgmtd/mgmt_main.c index e3fc6b7f29ac..a9c0826b021a 100644 --- a/mgmtd/mgmt_main.c +++ b/mgmtd/mgmt_main.c @@ -15,6 +15,7 @@ #include "frr_pthread.h" #include "mgmtd/mgmt.h" #include "mgmtd/mgmt_ds.h" +#include "ospfd/ospf_nb.h" #include "ripd/rip_nb.h" #include "ripngd/ripng_nb.h" #include "routing_nb.h" @@ -175,6 +176,7 @@ const struct frr_yang_module_info zebra_route_map_info = { * List of YANG modules to be loaded in the process context of * MGMTd. */ +/* clang-format off */ static const struct frr_yang_module_info *const mgmt_yang_modules[] = { &frr_filter_cli_info, &frr_interface_cli_info, @@ -205,9 +207,11 @@ static const struct frr_yang_module_info *const mgmt_yang_modules[] = { #ifdef HAVE_STATICD &frr_staticd_cli_info, #endif +#ifdef HAVE_OSPFD + &frr_ospfd_lite_cli_info +#endif }; -/* clang-format off */ FRR_DAEMON_INFO(mgmtd, MGMTD, .vty_port = MGMTD_VTY_PORT, .proghelp = "FRR Management Daemon.", diff --git a/mgmtd/subdir.am b/mgmtd/subdir.am index 14544c4f0507..aead15444ec8 100644 --- a/mgmtd/subdir.am +++ b/mgmtd/subdir.am @@ -78,6 +78,15 @@ nodist_mgmtd_mgmtd_SOURCES += yang/frr-bfdd.yang.c endif endif +if OSPFD +nodist_mgmtd_mgmtd_SOURCES += \ + yang/frr-ospfd-lite.yang.c \ + # end +mgmtd_libmgmt_be_nb_la_SOURCES += \ + ospfd/ospf_cli.c \ + # end +endif + if RIPD nodist_mgmtd_mgmtd_SOURCES += \ yang/frr-ripd.yang.c \ diff --git a/ospfd/ospf_cli.c b/ospfd/ospf_cli.c new file mode 100644 index 000000000000..159e375d6db4 --- /dev/null +++ b/ospfd/ospf_cli.c @@ -0,0 +1,62 @@ +/* + * March 15 2025, Christian Hopps + * + * Copyright (c) 2025, LabN Consulting, L.L.C. + * + */ +#include +#include "ospf_nb.h" +#include "ospfd/ospf_cli_clippy.c" + +/* + * XXX Add YANG based CLI config writing functions here. + */ + +#if 0 +static void lib_interface_ospf_interface_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + /* TODO: this cli callback is optional; the cli output may not need to be done at each node. */ +} + +static void ospf_instance_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + /* TODO: this cli callback is optional; the cli output may not need to be done at each node. */ +} + +static void ospf_instance_areas_area_cli_write(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) +{ + /* TODO: this cli callback is optional; the cli output may not need to be done at each node. */ +} +#endif + +/* clang-format off */ +const struct frr_yang_module_info frr_ospfd_lite_cli_info = { + .name = "frr-ospfd-lite", + .ignore_cfg_cbs = true, + .nodes = { +#if 0 + { + .xpath = "/frr-interface:lib/interface/frr-ospfd-lite:ospf-interface", + .cbs = { + .cli_show = lib_interface_ospf_interface_cli_write, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance", + .cbs = { + .cli_show = ospf_instance_cli_write, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area", + .cbs = { + .cli_show = ospf_instance_areas_area_cli_write, + } + }, +#endif + { + .xpath = NULL, + }, + } +}; +/* clang-format on */ diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index c1431731550e..6ff68139b66d 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -15,6 +15,7 @@ #include "stream.h" #include "log.h" #include "sockopt.h" +#include "mgmt_be_client.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -2112,4 +2113,7 @@ void ospf_debug_init(void) install_element(CONFIG_NODE, &no_debug_ospf_instance_event_cmd); install_element(CONFIG_NODE, &no_debug_ospf_instance_nssa_cmd); install_element(CONFIG_NODE, &no_debug_ospf_cmd); + + /* Init mgmtd backend client debug commands. */ + mgmt_be_client_lib_vty_init(); } diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 5c11027506dd..7b38a27bb7f7 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -29,6 +29,7 @@ #include "routemap.h" #include "keychain.h" #include "libagentx.h" +#include "mgmt_be_client.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -46,6 +47,7 @@ #include "ospfd/ospf_ldp_sync.h" #include "ospfd/ospf_routemap_nb.h" #include "ospfd/ospf_apiserver.h" +#include "ospfd/ospf_nb.h" #define OSPFD_STATE_NAME "%s/ospfd.json", frr_libstatedir #define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_libstatedir, i @@ -92,6 +94,8 @@ const struct option longopts[] = { /* Master of threads. */ struct event_loop *master; +struct mgmt_be_client *mgmt_be_client; + /* SIGHUP handler. */ static void sighup(void) { @@ -103,6 +107,7 @@ static void sigint(void) { zlog_notice("Terminating on signal"); bfd_protocol_integration_set_shutdown(true); + mgmt_be_client_destroy(mgmt_be_client); ospf_terminate(); exit(0); @@ -134,13 +139,10 @@ struct frr_signal_t ospf_signals[] = { }; static const struct frr_yang_module_info *const ospfd_yang_modules[] = { - &frr_filter_info, - &frr_interface_info, - &frr_route_map_info, - &frr_vrf_info, - &frr_ospf_route_map_info, - &ietf_key_chain_info, - &ietf_key_chain_deviation_info, + &frr_filter_info, &frr_interface_info, + &frr_route_map_info, &frr_vrf_info, + &frr_ospf_route_map_info, &frr_ospfd_lite_info, + &ietf_key_chain_info, &ietf_key_chain_deviation_info, }; /* actual paths filled in main() */ @@ -291,6 +293,8 @@ int main(int argc, char **argv) ospf_vty_show_init(); ospf_vty_clear_init(); + mgmt_be_client = mgmt_be_client_create("ospfd", NULL, 0, master); + /* OSPF BFD init */ ospf_bfd_init(master); diff --git a/ospfd/ospf_nb.c b/ospfd/ospf_nb.c new file mode 100644 index 000000000000..c13d669c6914 --- /dev/null +++ b/ospfd/ospf_nb.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * June 21 2023, Christian Hopps + * + * Copyright (C) 2023 LabN Consulting, L.L.C. + */ + +#include + +#include "ospfd/ospf_nb.h" + +/* clang-format off */ +const struct frr_yang_module_info frr_ospfd_lite_info = { + .name = "frr-ospfd-lite", + .nodes = { + { + .xpath = "/frr-interface:lib/interface/frr-ospfd-lite:ospf-interface", + .cbs = { + .create = lib_interface_ospf_interface_create, + .destroy = lib_interface_ospf_interface_destroy, + .get_next = lib_interface_ospf_interface_get_next, + .get_keys = lib_interface_ospf_interface_get_keys, + .lookup_entry = lib_interface_ospf_interface_lookup_entry, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/state", + .cbs = { + .get_elem = lib_interface_ospf_interface_state_state_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/hello-timer", + .cbs = { + .get_elem = lib_interface_ospf_interface_state_hello_timer_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/neighbors/neighbor", + .cbs = { + .get_next = lib_interface_ospf_interface_state_neighbors_neighbor_get_next, + .get_keys = lib_interface_ospf_interface_state_neighbors_neighbor_get_keys, + .lookup_entry = lib_interface_ospf_interface_state_neighbors_neighbor_lookup_entry, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/neighbors/neighbor/neighbor-router-id", + .cbs = { + .get_elem = lib_interface_ospf_interface_state_neighbors_neighbor_neighbor_router_id_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/neighbors/neighbor/address", + .cbs = { + .get_elem = lib_interface_ospf_interface_state_neighbors_neighbor_address_get_elem, + } + }, + { + .xpath = "/frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/neighbors/neighbor/state", + .cbs = { + .get_elem = lib_interface_ospf_interface_state_neighbors_neighbor_state_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance", + .cbs = { + .create = ospf_instance_create, + .destroy = ospf_instance_destroy, + .get_next = ospf_instance_get_next, + .get_keys = ospf_instance_get_keys, + .lookup_entry = ospf_instance_lookup_entry, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/state/router-flags/router-flag", + .cbs = { + .get_elem = ospf_instance_state_router_flags_router_flag_get_elem, + .get_next = ospf_instance_state_router_flags_router_flag_get_next, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/state/statistics/originate-new-lsa-count", + .cbs = { + .get_elem = ospf_instance_state_statistics_originate_new_lsa_count_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/state/statistics/rx-new-lsas-count", + .cbs = { + .get_elem = ospf_instance_state_statistics_rx_new_lsas_count_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/state/statistics/spf/timestamp", + .cbs = { + .get_elem = ospf_instance_state_statistics_spf_timestamp_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/state/statistics/spf/duration", + .cbs = { + .get_elem = ospf_instance_state_statistics_spf_duration_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area", + .cbs = { + .create = ospf_instance_areas_area_create, + .destroy = ospf_instance_areas_area_destroy, + .get_next = ospf_instance_areas_area_get_next, + .get_keys = ospf_instance_areas_area_get_keys, + .lookup_entry = ospf_instance_areas_area_lookup_entry, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area/state/statistics/spf-runs-count", + .cbs = { + .get_elem = ospf_instance_areas_area_state_statistics_spf_runs_count_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area/state/statistics/abr-count", + .cbs = { + .get_elem = ospf_instance_areas_area_state_statistics_abr_count_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area/state/statistics/asbr-count", + .cbs = { + .get_elem = ospf_instance_areas_area_state_statistics_asbr_count_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area/state/statistics/area-scope-lsa-count", + .cbs = { + .get_elem = ospf_instance_areas_area_state_statistics_area_scope_lsa_count_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area/state/statistics/spf-timestamp", + .cbs = { + .get_elem = ospf_instance_areas_area_state_statistics_spf_timestamp_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area/state/statistics/active-interfaces", + .cbs = { + .get_elem = ospf_instance_areas_area_state_statistics_active_interfaces_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area/state/statistics/full-nbrs", + .cbs = { + .get_elem = ospf_instance_areas_area_state_statistics_full_nbrs_get_elem, + } + }, + { + .xpath = "/frr-ospfd-lite:ospf/instance/areas/area/state/statistics/full-virtual", + .cbs = { + .get_elem = ospf_instance_areas_area_state_statistics_full_virtual_get_elem, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/ospfd/ospf_nb.h b/ospfd/ospf_nb.h new file mode 100644 index 000000000000..d24677e609c5 --- /dev/null +++ b/ospfd/ospf_nb.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * June 21 2023, Christian Hopps + * + * Copyright (c) 2023, LabN Consulting, L.L.C. + * + */ +#ifndef _FRR_OSPF_NB_H_ +#define _FRR_OSPF_NB_H_ + +#include "northbound.h" + +extern const struct frr_yang_module_info frr_ospfd_lite_info; +extern const struct frr_yang_module_info frr_ospfd_lite_cli_info; + +int lib_interface_ospf_interface_create(struct nb_cb_create_args *args); +int lib_interface_ospf_interface_destroy(struct nb_cb_destroy_args *args); +const void *lib_interface_ospf_interface_get_next(struct nb_cb_get_next_args *args); +int lib_interface_ospf_interface_get_keys(struct nb_cb_get_keys_args *args); +const void *lib_interface_ospf_interface_lookup_entry(struct nb_cb_lookup_entry_args *args); +struct yang_data *lib_interface_ospf_interface_state_state_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *lib_interface_ospf_interface_state_hello_timer_get_elem(struct nb_cb_get_elem_args *args); +const void *lib_interface_ospf_interface_state_neighbors_neighbor_get_next(struct nb_cb_get_next_args *args); +int lib_interface_ospf_interface_state_neighbors_neighbor_get_keys(struct nb_cb_get_keys_args *args); +const void *lib_interface_ospf_interface_state_neighbors_neighbor_lookup_entry(struct nb_cb_lookup_entry_args *args); + +struct yang_data *lib_interface_ospf_interface_state_neighbors_neighbor_get_elem(struct nb_cb_get_elem_args *args); + +struct yang_data *lib_interface_ospf_interface_state_neighbors_neighbor_neighbor_router_id_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *lib_interface_ospf_interface_state_neighbors_neighbor_address_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *lib_interface_ospf_interface_state_neighbors_neighbor_state_get_elem(struct nb_cb_get_elem_args *args); + +int ospf_instance_create(struct nb_cb_create_args *args); +int ospf_instance_destroy(struct nb_cb_destroy_args *args); +const void *ospf_instance_get_next(struct nb_cb_get_next_args *args); +int ospf_instance_get_keys(struct nb_cb_get_keys_args *args); +const void *ospf_instance_lookup_entry(struct nb_cb_lookup_entry_args *args); +struct yang_data *ospf_instance_state_router_flags_router_flag_get_elem(struct nb_cb_get_elem_args *args); +const void *ospf_instance_state_router_flags_router_flag_get_next(struct nb_cb_get_next_args *args); +struct yang_data *ospf_instance_state_statistics_originate_new_lsa_count_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_state_statistics_rx_new_lsas_count_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_state_statistics_spf_timestamp_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_state_statistics_spf_duration_get_elem(struct nb_cb_get_elem_args *args); +int ospf_instance_areas_area_create(struct nb_cb_create_args *args); +int ospf_instance_areas_area_destroy(struct nb_cb_destroy_args *args); +const void *ospf_instance_areas_area_get_next(struct nb_cb_get_next_args *args); +int ospf_instance_areas_area_get_keys(struct nb_cb_get_keys_args *args); +const void *ospf_instance_areas_area_lookup_entry(struct nb_cb_lookup_entry_args *args); +struct yang_data *ospf_instance_areas_area_state_statistics_spf_runs_count_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_areas_area_state_statistics_abr_count_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_areas_area_state_statistics_asbr_count_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_areas_area_state_statistics_area_scope_lsa_count_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_areas_area_state_statistics_spf_timestamp_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_areas_area_state_statistics_active_interfaces_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_areas_area_state_statistics_full_nbrs_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data *ospf_instance_areas_area_state_statistics_full_virtual_get_elem(struct nb_cb_get_elem_args *args); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ospfd/ospf_nb_config.c b/ospfd/ospf_nb_config.c new file mode 100644 index 000000000000..7318ea34cb4c --- /dev/null +++ b/ospfd/ospf_nb_config.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * June 21 2023, Christian Hopps + * + * Copyright (C) 2023 LabN Consulting, L.L.C. + * + */ + +#include + +#include "ospfd/ospf_nb.h" + +/* + * XPath: /frr-interface:lib/interface/frr-ospfd-lite:ospf-interface + */ +int lib_interface_ospf_interface_create(struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int lib_interface_ospf_interface_destroy(struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance + */ +int ospf_instance_create(struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int ospf_instance_destroy(struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/areas/area + */ +int ospf_instance_areas_area_create(struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int ospf_instance_areas_area_destroy(struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} diff --git a/ospfd/ospf_nb_state.c b/ospfd/ospf_nb_state.c new file mode 100644 index 000000000000..34ed70f2bdae --- /dev/null +++ b/ospfd/ospf_nb_state.c @@ -0,0 +1,455 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * June 21 2023, Christian Hopps + * + * Copyright (C) 2023 LabN Consulting, L.L.C. + */ + +#include +#include "debug.h" +#include "northbound.h" +#include "table.h" + +#include "ospfd/ospfd.h" +#include "ospfd/ospf_asbr.h" +#include "ospfd/ospf_lsa.h" +#include "ospfd/ospf_lsdb.h" +#include "ospfd/ospf_interface.h" +#include "ospfd/ospf_opaque.h" +#include "ospfd/ospf_neighbor.h" +#include "ospfd/ospf_nb.h" +#include "ospfd/ospf_vty.h" + + +#define RNPARENT(args) ((struct route_node *)((args)->parent_list_entry)) +#define RNENTRY(args) ((struct route_node *)((args)->list_entry)) +#define OIPARENT(args) ((struct ospf_interface *)RNPARENT(args)->info) +#define OIENTRY(args) ((struct ospf_interface *)RNENTRY(args)->info) +#define NBRENTRY(args) ((struct ospf_neighbor *)RNENTRY(args)->info) + + +/* + * XPath: /frr-interface:lib/interface/state/frr-ospfd-lite:ospf/state + */ +const void * +lib_interface_ospf_interface_get_next(struct nb_cb_get_next_args *args) +{ + struct interface *ifp = (struct interface *)args->parent_list_entry; + struct route_node *rn = (struct route_node *)args->list_entry; + + assert(ifp); + if (!rn) + rn = route_top(IF_OIFS(ifp)); + else + rn = route_next(rn); + for (; rn && !rn->info; rn = route_next(rn)) + ; + return rn; +} + +int lib_interface_ospf_interface_get_keys(struct nb_cb_get_keys_args *args) +{ + struct ospf_interface *oi = OIENTRY(args); + + args->keys->num = 1; + if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) + args->keys->key[0][0] = 0; + else + snprintfrr(args->keys->key[0], sizeof(args->keys->key[0]), + "%pI4", &oi->address->u.prefix4); + return NB_OK; +} + +const void * +lib_interface_ospf_interface_lookup_entry(struct nb_cb_lookup_entry_args *args) +{ + struct interface *ifp = (struct interface *)args->parent_list_entry; + const char *key = args->keys->key[0]; + struct ospf_interface *oi; + struct route_node *rn; + struct prefix_ipv4 p; + + assert(ifp); + + /* handle unnumbered case */ + if (!key[0]) { + for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { + oi = rn->info; + if (oi && CHECK_FLAG(oi->connected->flags, + ZEBRA_IFA_UNNUMBERED)) + return rn; + } + return NULL; + } + + if (!str2prefix_ipv4(key, &p)) { + DEBUGD(&nb_dbg_cbs_state, "invalid interface address key: %s", + key); + return NULL; + } + + rn = route_node_match(IF_OIFS(ifp), &p); + if (!rn || !rn->info) + return NULL; + return rn; +} + +/* + * XPath: /frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/state + */ +struct yang_data *lib_interface_ospf_interface_state_state_get_elem( + struct nb_cb_get_elem_args *args) +{ + return yang_data_new_enum(args->xpath, OIENTRY(args)->state); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/hello-timer + */ +struct yang_data *lib_interface_ospf_interface_state_hello_timer_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf_interface *oi = OIENTRY(args); + uint16_t secs; + + /* TODO: update the model to support fast-hello */ + secs = OSPF_IF_PARAM(oi, fast_hello) ? 1 : OSPF_IF_PARAM(oi, v_hello); + + return yang_data_new_uint16(args->xpath, secs); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/neighbors/neighbor + */ +const void *lib_interface_ospf_interface_state_neighbors_neighbor_get_next( + struct nb_cb_get_next_args *args) +{ + struct route_node *rn = RNENTRY(args); + + if (rn) + rn = route_next(rn); + else { + struct ospf_interface *oi = OIPARENT(args); + + assert(oi); + rn = route_top(oi->nbrs); + } + for (; rn && !rn->info; rn = route_next(rn)) + ; + return rn; +} + +int lib_interface_ospf_interface_state_neighbors_neighbor_get_keys( + struct nb_cb_get_keys_args *args) +{ + struct ospf_neighbor *nbr = NBRENTRY(args); + + args->keys->num = 1; + snprintfrr(args->keys->key[0], sizeof(args->keys->key[0]), "%pI4", + &nbr->router_id); + return NB_OK; +} + +const void *lib_interface_ospf_interface_state_neighbors_neighbor_lookup_entry( + struct nb_cb_lookup_entry_args *args) +{ + struct ospf_interface *oi = OIPARENT(args); + const char *key = args->keys->key[0]; + struct route_node *rn; + struct prefix_ipv4 p; + + if (!str2prefix_ipv4(key, &p) || p.prefixlen != IPV4_MAX_BITLEN) { + DEBUGD(&nb_dbg_cbs_state, "invalid neighbor router id key : %s", + key); + return NULL; + } + + rn = route_node_match(oi->nbrs, &p); + if (!rn || !rn->info) + return NULL; + return rn; +} + +struct yang_data * +lib_interface_ospf_interface_state_neighbors_neighbor_get_elem( + struct nb_cb_get_elem_args *args) +{ + return yang_data_new_ipv4(args->xpath, &NBRENTRY(args)->router_id); +} + + +/* + * XPath: + * /frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/neighbors/neighbor/neighbor-router-id + */ +struct yang_data * +lib_interface_ospf_interface_state_neighbors_neighbor_neighbor_router_id_get_elem( + struct nb_cb_get_elem_args *args) +{ + return yang_data_new_ipv4(args->xpath, &NBRENTRY(args)->router_id); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/neighbors/neighbor/address + */ +struct yang_data * +lib_interface_ospf_interface_state_neighbors_neighbor_address_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf_neighbor *nbr = NBRENTRY(args); + + if (CHECK_FLAG(nbr->oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) + return NULL; + return yang_data_new_ipv4(args->xpath, &nbr->address.u.prefix4); +} + +/* + * XPath: + * /frr-interface:lib/interface/frr-ospfd-lite:ospf-interface/state/neighbors/neighbor/state + */ +struct yang_data * +lib_interface_ospf_interface_state_neighbors_neighbor_state_get_elem( + struct nb_cb_get_elem_args *args) +{ + return yang_data_new_enum(args->xpath, NBRENTRY(args)->state); +} + +#define LNPARENT(args) ((const struct listnode *)((args)->parent_list_entry)) +#define LNENTRY(args) ((const struct listnode *)((args)->list_entry)) +#define OPARENT(args) ((struct ospf *)listgetdata(LNPARENT(args))) +#define OENTRY(args) ((struct ospf *)listgetdata(LNENTRY(args))) + +const void *ospf_instance_get_next(struct nb_cb_get_next_args *args) +{ + const struct listnode *node = LNENTRY(args); + + if (node == NULL) + return listhead(om->ospf); + else + return listnextnode(node); +} + +int ospf_instance_get_keys(struct nb_cb_get_keys_args *args) +{ + struct ospf *ospf = OENTRY(args); + + args->keys->num = 1; + if (!ospf->name) + args->keys->key[0][0] = 0; + else + strlcpy(args->keys->key[0], ospf->name, sizeof(args->keys->key[0])); + + return NB_OK; +} + +const void *ospf_instance_lookup_entry(struct nb_cb_lookup_entry_args *args) +{ + const char *vrf_name = args->keys->key[0]; + const struct listnode *node; + struct ospf *ospf; + + for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) + if ((ospf->name == NULL && vrf_name[0]) || + (ospf->name && vrf_name[0] && !strcmp(ospf->name, vrf_name))) + return node; + return NULL; +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/state/router-flags/router-flag + */ +struct yang_data *ospf_instance_state_router_flags_router_flag_get_elem( + struct nb_cb_get_elem_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +const void *ospf_instance_state_router_flags_router_flag_get_next( + struct nb_cb_get_next_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/state/statistics/originate-new-lsa-count + */ +struct yang_data * +ospf_instance_state_statistics_originate_new_lsa_count_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf *ospf = OENTRY(args); + + return yang_data_new_uint32(args->xpath, ospf->lsa_originate_count); +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/state/statistics/rx-new-lsas-count + */ +struct yang_data *ospf_instance_state_statistics_rx_new_lsas_count_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf *ospf = OENTRY(args); + + return yang_data_new_uint32(args->xpath, ospf->rx_lsa_count); +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/state/statistics/spf/timestamp + */ +struct yang_data *ospf_instance_state_statistics_spf_timestamp_get_elem( + struct nb_cb_get_elem_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/state/statistics/spf/duration + */ +struct yang_data *ospf_instance_state_statistics_spf_duration_get_elem( + struct nb_cb_get_elem_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +#define APARENT(args) ((struct ospf_area *)listgetdata(LNPARENT(args))) +#define AENTRY(args) ((struct ospf_area *)listgetdata(LNENTRY(args))) + +const void *ospf_instance_areas_area_get_next(struct nb_cb_get_next_args *args) +{ + struct ospf *ospf = OPARENT(args); + const struct listnode *node = LNENTRY(args); + + if (node == NULL) + return listhead(ospf->areas); + else + return listnextnode(node); +} + +int ospf_instance_areas_area_get_keys(struct nb_cb_get_keys_args *args) +{ + struct ospf_area *area = AENTRY(args); + + args->keys->num = 1; + snprintfrr(args->keys->key[0], sizeof(args->keys->key[0]), "%pI4", + &area->area_id); + + return NB_OK; +} + +const void * +ospf_instance_areas_area_lookup_entry(struct nb_cb_lookup_entry_args *args) +{ + struct ospf *ospf = OPARENT(args); + const char *key = args->keys->key[0]; + struct ospf_area *area; + struct listnode *node; + struct in_addr area_id; + int aid_fmt; + + if (str2area_id(key, &area_id, &aid_fmt)) + /* TODO: dbg log ? */ + return NULL; + + for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) + if (area->area_id.s_addr == area_id.s_addr) + return node; + return NULL; +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/areas/area/state/statistics/spf-runs-count + */ +struct yang_data *ospf_instance_areas_area_state_statistics_spf_runs_count_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf_area *area = AENTRY(args); + + return yang_data_new_uint32(args->xpath, area->spf_calculation); +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/areas/area/state/statistics/abr-count + */ +struct yang_data *ospf_instance_areas_area_state_statistics_abr_count_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf_area *area = AENTRY(args); + + return yang_data_new_uint32(args->xpath, area->abr_count); +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/areas/area/state/statistics/asbr-count + */ +struct yang_data *ospf_instance_areas_area_state_statistics_asbr_count_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf_area *area = AENTRY(args); + + return yang_data_new_uint32(args->xpath, area->asbr_count); +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/areas/area/state/statistics/area-scope-lsa-count + */ +struct yang_data *ospf_instance_areas_area_state_statistics_area_scope_lsa_count_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf_area *area = AENTRY(args); + + return yang_data_new_uint32(args->xpath, area->lsdb->total); +} + +/* + * XPath: + * /frr-ospfd-lite:ospf/instance/areas/area/state/statistics/spf-timestamp + */ +struct yang_data * +ospf_instance_areas_area_state_statistics_spf_timestamp_get_elem( + struct nb_cb_get_elem_args *args) +{ + /* TODO: implement me. */ + return NULL; +} + +/* + * XPath: + * /frr-ospfd-lite:ospf/instance/areas/area/state/statistics/active-interfaces + */ +struct yang_data *ospf_instance_areas_area_state_statistics_active_interfaces_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf_area *area = AENTRY(args); + + return yang_data_new_uint32(args->xpath, area->act_ints); +} + + +/* + * XPath: /frr-ospfd-lite:ospf/instance/areas/area/state/statistics/full-nbrs + */ +struct yang_data *ospf_instance_areas_area_state_statistics_full_nbrs_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf_area *area = AENTRY(args); + + return yang_data_new_uint32(args->xpath, area->full_nbrs); +} + +/* + * XPath: /frr-ospfd-lite:ospf/instance/areas/area/state/statistics/full-virtual + */ +struct yang_data *ospf_instance_areas_area_state_statistics_full_virtual_get_elem( + struct nb_cb_get_elem_args *args) +{ + struct ospf_area *area = AENTRY(args); + + return yang_data_new_uint32(args->xpath, area->full_vls); +} diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 4803aae68d84..14a53e476077 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -38,6 +38,9 @@ ospfd_libfrrospf_a_SOURCES = \ ospfd/ospf_lsa.c \ ospfd/ospf_lsdb.c \ ospfd/ospf_memory.c \ + ospfd/ospf_nb.c \ + ospfd/ospf_nb_config.c \ + ospfd/ospf_nb_state.c \ ospfd/ospf_neighbor.c \ ospfd/ospf_network.c \ ospfd/ospf_nsm.c \ @@ -80,6 +83,7 @@ clippy_scan += \ ospfd/ospf_ldp_sync.c \ ospfd/ospf_dump.c \ ospfd/ospf_gr.c \ + ospfd/ospf_cli.c \ # end noinst_HEADERS += \ @@ -94,6 +98,7 @@ noinst_HEADERS += \ ospfd/ospf_interface.h \ ospfd/ospf_ldp_sync.h \ ospfd/ospf_memory.h \ + ospfd/ospf_nb.h \ ospfd/ospf_neighbor.h \ ospfd/ospf_network.h \ ospfd/ospf_packet.h \ diff --git a/tests/topotests/ospf_simple/r1/frr.conf b/tests/topotests/ospf_simple/r1/frr.conf new file mode 100644 index 000000000000..0760126a904a --- /dev/null +++ b/tests/topotests/ospf_simple/r1/frr.conf @@ -0,0 +1,25 @@ +log timestamp precision 6 +log file frr.log + +debug northbound notifications +debug northbound libyang +debug northbound events +debug northbound callbacks + +debug mgmt backend datastore frontend transaction +debug mgmt client frontend + +debug mgmt client backend + +interface r1-eth0 + ip address 10.0.1.1/24 + ip ospf hello-interval 3 + ip ospf dead-interval 10 + ip ospf retransmit-interval 2 + +ip route 11.0.0.0/8 Null0 + +router ospf + ospf router-id 1.1.1.1 + network 10.0.0.0/16 area 0.0.0.0 + redistribute static \ No newline at end of file diff --git a/tests/topotests/ospf_simple/r2/frr.conf b/tests/topotests/ospf_simple/r2/frr.conf new file mode 100644 index 000000000000..37c93b3d2a7a --- /dev/null +++ b/tests/topotests/ospf_simple/r2/frr.conf @@ -0,0 +1,17 @@ +interface r2-eth0 + ip address 10.0.1.2/24 + ip ospf hello-interval 3 + ip ospf dead-interval 10 + ip ospf retransmit-interval 2 +interface r2-eth1 + ip address 10.0.2.2/24 + ip ospf hello-interval 3 + ip ospf dead-interval 10 + ip ospf retransmit-interval 2 + +ip route 22.0.0.0/8 Null0 + +router ospf + ospf router-id 2.2.2.2 + network 10.0.0.0/16 area 0.0.0.0 + redistribute static \ No newline at end of file diff --git a/tests/topotests/ospf_simple/r3/frr.conf b/tests/topotests/ospf_simple/r3/frr.conf new file mode 100644 index 000000000000..a6e3cbe50d5c --- /dev/null +++ b/tests/topotests/ospf_simple/r3/frr.conf @@ -0,0 +1,12 @@ +interface r3-eth0 + ip address 10.0.2.3/24 + ip ospf hello-interval 3 + ip ospf dead-interval 10 + ip ospf retransmit-interval 2 + +ip route 33.0.0.0/8 Null0 + +router ospf + ospf router-id 3.3.3.3 + network 10.0.0.0/16 area 0.0.0.0 + redistribute static \ No newline at end of file diff --git a/tests/topotests/ospf_simple/test_ospf_simple.py b/tests/topotests/ospf_simple/test_ospf_simple.py new file mode 100644 index 000000000000..f1846b38254a --- /dev/null +++ b/tests/topotests/ospf_simple/test_ospf_simple.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# SPDX-License-Identifier: ISC +# +#