diff --git a/src/interfaces/CMakeLists.txt b/src/interfaces/CMakeLists.txt index 2710ed23..8ac11d4c 100644 --- a/src/interfaces/CMakeLists.txt +++ b/src/interfaces/CMakeLists.txt @@ -18,6 +18,10 @@ set( src/plugin/startup/load.c src/plugin/startup/store.c + # running + src/plugin/running/load.c + src/plugin/running/store.c + # subscription src/plugin/subscription/change.c src/plugin/subscription/operational.c diff --git a/src/interfaces/src/plugin.c b/src/interfaces/src/plugin.c index 3e776bf4..2e608709 100644 --- a/src/interfaces/src/plugin.c +++ b/src/interfaces/src/plugin.c @@ -4,12 +4,16 @@ #include "netlink/socket.h" #include "plugin/common.h" #include "plugin/context.h" - -// startup #include "plugin/data/interfaces/interface_state.h" + +// startup DS #include "plugin/startup/load.h" #include "plugin/startup/store.h" +// running DS +#include "plugin/running/load.h" +#include "plugin/running/store.h" + // subscription #include "plugin/subscription/change.h" #include "plugin/subscription/operational.h" @@ -284,21 +288,21 @@ int sr_plugin_init_cb(sr_session_ctx_t* running_session, void** private_data) ctx->startup_ctx.startup_session = startup_session; - SRPC_SAFE_CALL_ERR(error, srpc_check_empty_datastore(startup_session, INTERFACES_INTERFACES_INTERFACE_YANG_PATH, &empty_startup), error_out); + SRPC_SAFE_CALL_ERR(error, srpc_check_empty_datastore(running_session, INTERFACES_INTERFACES_INTERFACE_YANG_PATH, &empty_startup), error_out); if (empty_startup) { - SRPLG_LOG_INF(PLUGIN_NAME, "Startup datastore is empty"); + SRPLG_LOG_INF(PLUGIN_NAME, "Running datastore is empty"); SRPLG_LOG_INF(PLUGIN_NAME, "Loading initial system data"); - // load initial data on the system - SRPC_SAFE_CALL_ERR(error, interfaces_startup_load(ctx, running_session), error_out); + // load initial running DS data on the system + SRPC_SAFE_CALL_ERR(error, interfaces_running_load(ctx, running_session), error_out); } else { // make sure the data from startup DS is stored in the interfaces - SRPLG_LOG_INF(PLUGIN_NAME, "Startup datastore contains data"); - SRPLG_LOG_INF(PLUGIN_NAME, "Storing startup datastore data in the system"); + SRPLG_LOG_INF(PLUGIN_NAME, "Running datastore contains data"); + SRPLG_LOG_INF(PLUGIN_NAME, "Checking running datastore against system data"); - // check and store startup data on the system - SRPC_SAFE_CALL_ERR(error, interfaces_startup_store(ctx, startup_session), error_out); + // check and store running DS data on the system + SRPC_SAFE_CALL_ERR(error, interfaces_running_store(ctx, running_session), error_out); } // subscribe every module change diff --git a/src/interfaces/src/plugin/data/interfaces/interface.c b/src/interfaces/src/plugin/data/interfaces/interface.c index 125376f1..efb46763 100644 --- a/src/interfaces/src/plugin/data/interfaces/interface.c +++ b/src/interfaces/src/plugin/data/interfaces/interface.c @@ -611,7 +611,7 @@ int interfaces_interface_type_nl2ly(const char* nl_type, const char** ly_type) if (nl_type == NULL) { // fix for now - investigate more - lo interface has type == NULL - *ly_type = "iana-if-type:softwareLoopback"; + *ly_type = "iana-if-type:other"; return 0; } @@ -623,6 +623,8 @@ int interfaces_interface_type_nl2ly(const char* nl_type, const char** ly_type) *ly_type = "iana-if-type:l2vlan"; } else if (strcmp(nl_type, "dummy") == 0) { *ly_type = "iana-if-type:other"; + } else if (strcmp(nl_type, "bridge") == 0) { + *ly_type = "iana-if-type:bridge"; } else { error = -2; } diff --git a/src/interfaces/src/plugin/running/load.c b/src/interfaces/src/plugin/running/load.c new file mode 100644 index 00000000..986b1966 --- /dev/null +++ b/src/interfaces/src/plugin/running/load.c @@ -0,0 +1,104 @@ +#include "load.h" +#include "libyang/printer_data.h" +#include "plugin/common.h" +#include "plugin/data/interfaces/interface.h" +#include "plugin/ly_tree.h" + +#include "plugin/api/interfaces/load.h" +#include "plugin/types.h" +#include "src/uthash.h" +#include "src/utlist.h" +#include "srpc/common.h" + +#include +#include +#include + +static int interfaces_running_load_interface(void* priv, sr_session_ctx_t* session, const struct ly_ctx* ly_ctx, struct lyd_node* parent_node); + +int interfaces_running_load(interfaces_ctx_t* ctx, sr_session_ctx_t* session) +{ + int error = 0; + + const struct ly_ctx* ly_ctx = NULL; + struct lyd_node* root_node = NULL; + sr_conn_ctx_t* conn_ctx = NULL; + + srpc_startup_load_t load_values[] = { + { + "/ietf-interfaces:interfaces/interface", + interfaces_running_load_interface, + }, + }; + + SRPC_SAFE_CALL_PTR(conn_ctx, sr_session_get_connection(session), error_out); + SRPC_SAFE_CALL_PTR(ly_ctx, sr_acquire_context(conn_ctx), error_out); + + SRPC_SAFE_CALL_ERR(error, interfaces_ly_tree_create_interfaces(ly_ctx, &root_node), error_out); + + for (size_t i = 0; i < ARRAY_SIZE(load_values); i++) { + const srpc_startup_load_t* load = &load_values[i]; + + error = load->cb((void*)ctx, session, ly_ctx, root_node); + if (error) { + SRPLG_LOG_ERR(PLUGIN_NAME, "Node creation callback failed for value %s", load->name); + goto error_out; + } + } + +/* enable or disable storing into startup, use for testing */ +#define INTERFACES_PLUGIN_LOAD_STARTUP +/* disable for now */ +// #undef INTERFACES_PLUGIN_LOAD_STARTUP +#ifdef INTERFACES_PLUGIN_LOAD_STARTUP + error = sr_edit_batch(session, root_node, "merge"); + if (error != SR_ERR_OK) { + SRPLG_LOG_ERR(PLUGIN_NAME, "sr_edit_batch() error (%d): %s", error, sr_strerror(error)); + goto error_out; + } + + error = sr_apply_changes(session, 0); + if (error != 0) { + SRPLG_LOG_ERR(PLUGIN_NAME, "sr_apply_changes() error (%d): %s", error, sr_strerror(error)); + goto error_out; + } +#endif + + goto out; + +error_out: + error = -1; + +out: + if (root_node) { + lyd_free_tree(root_node); + } + sr_release_context(conn_ctx); + + return error; +} + +static int interfaces_running_load_interface(void* priv, sr_session_ctx_t* session, const struct ly_ctx* ly_ctx, struct lyd_node* parent_node) +{ + int error = 0; + interfaces_ctx_t* ctx = (interfaces_ctx_t*)priv; + interfaces_interface_hash_element_t* interface_hash = NULL; + + // load interfaces data + SRPC_SAFE_CALL_ERR(error, interfaces_load_interface(ctx, &interface_hash), error_out); + + // convert to libyang + SRPC_SAFE_CALL_ERR(error, interfaces_interface_hash_to_ly(ly_ctx, interface_hash, &parent_node), error_out); + + // print created tree + // lyd_print_file(stdout, parent_node, LYD_XML, 0); + + goto out; + +error_out: + error = -1; +out: + interfaces_interface_hash_free(&interface_hash); + + return error; +} diff --git a/src/interfaces/src/plugin/running/load.h b/src/interfaces/src/plugin/running/load.h new file mode 100644 index 00000000..b17d10aa --- /dev/null +++ b/src/interfaces/src/plugin/running/load.h @@ -0,0 +1,8 @@ +#ifndef INTERFACES_PLUGIN_RUNNING_LOAD_H +#define INTERFACES_PLUGIN_RUNNING_LOAD_H + +#include "plugin/context.h" + +int interfaces_running_load(interfaces_ctx_t* ctx, sr_session_ctx_t* session); + +#endif // INTERFACES_PLUGIN_RUNNING_LOAD_H \ No newline at end of file diff --git a/src/interfaces/src/plugin/running/store.c b/src/interfaces/src/plugin/running/store.c new file mode 100644 index 00000000..45e69cd0 --- /dev/null +++ b/src/interfaces/src/plugin/running/store.c @@ -0,0 +1,103 @@ +#include "store.h" +#include "plugin/common.h" + +#include "plugin/api/interfaces/check.h" +#include "plugin/api/interfaces/store.h" +#include "plugin/data/interfaces/interface.h" +#include "srpc/ly_tree.h" + +#include +#include +#include + +static int interfaces_running_store_interface(void* priv, const struct lyd_node* parent_container); + +int interfaces_running_store(interfaces_ctx_t* ctx, sr_session_ctx_t* session) +{ + int error = 0; + sr_data_t* subtree = NULL; + + SRPC_SAFE_CALL_ERR(error, sr_get_subtree(session, INTERFACES_INTERFACES_CONTAINER_YANG_PATH, 0, &subtree), error_out); + + srpc_startup_store_t store_values[] = { + { + "/ietf-interfaces:interfaces/interface[name='%s']", + interfaces_running_store_interface, + }, + }; + + for (size_t i = 0; i < ARRAY_SIZE(store_values); i++) { + const srpc_startup_store_t* store = &store_values[i]; + + error = store->cb(ctx, subtree->tree); + if (error != 0) { + SRPLG_LOG_ERR(PLUGIN_NAME, "Startup store callback failed for value %s", store->name); + goto error_out; + } + } + + goto out; + +error_out: + error = -1; + +out: + if (subtree) { + sr_release_data(subtree); + } + + return error; +} + +static int interfaces_running_store_interface(void* priv, const struct lyd_node* parent_container) +{ + int error = 0; + interfaces_ctx_t* ctx = (interfaces_ctx_t*)priv; + srpc_check_status_t check_status = srpc_check_status_none; + interfaces_interface_hash_element_t* if_hash = NULL; + struct lyd_node* interface_node = NULL; + + interface_node = srpc_ly_tree_get_child_list(parent_container, "interface"); + if (interface_node == NULL) { + SRPLG_LOG_ERR(PLUGIN_NAME, "srpc_ly_tree_get_child_leaf returned NULL for 'interfaces'"); + goto error_out; + } + + // map libyang data to the interface hash + SRPC_SAFE_CALL_ERR(error, interfaces_interface_hash_from_ly(&if_hash, interface_node), error_out); + + // check startup data + SRPLG_LOG_INF(PLUGIN_NAME, "Checking interface list data"); + check_status = interfaces_check_interface(ctx, if_hash); + + switch (check_status) { + case srpc_check_status_none: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error loading current interface list"); + goto error_out; + case srpc_check_status_error: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error loading current interface list"); + goto error_out; + case srpc_check_status_non_existant: + SRPLG_LOG_INF(PLUGIN_NAME, "Storing interface list"); + SRPC_SAFE_CALL_ERR(error, interfaces_store_interface(ctx, if_hash), error_out); + break; + case srpc_check_status_equal: + SRPLG_LOG_ERR(PLUGIN_NAME, "Startup interface list is already applied on the system"); + break; + case srpc_check_status_partial: + SRPLG_LOG_ERR(PLUGIN_NAME, "Error loading current interface list"); + goto error_out; + } + + goto out; + +error_out: + error = -1; + +out: + if (if_hash) { + interfaces_interface_hash_free(&if_hash); + } + + return error; +} diff --git a/src/interfaces/src/plugin/running/store.h b/src/interfaces/src/plugin/running/store.h new file mode 100644 index 00000000..a2a9cece --- /dev/null +++ b/src/interfaces/src/plugin/running/store.h @@ -0,0 +1,8 @@ +#ifndef INTERFACES_PLUGIN_RUNNING_STORE_H +#define INTERFACES_PLUGIN_RUNNING_STORE_H + +#include "plugin/context.h" + +int interfaces_running_store(interfaces_ctx_t* ctx, sr_session_ctx_t* session); + +#endif // INTERFACES_PLUGIN_RUNNING_STORE_H \ No newline at end of file