diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/command.c | 7 | ||||
| -rw-r--r-- | lib/if.c | 50 | ||||
| -rw-r--r-- | lib/northbound_cli.c | 43 | ||||
| -rw-r--r-- | lib/northbound_cli.h | 94 | ||||
| -rw-r--r-- | lib/northbound_confd.c | 2 | ||||
| -rw-r--r-- | lib/prefix.c | 2 | ||||
| -rw-r--r-- | lib/stream.h | 7 | ||||
| -rw-r--r-- | lib/vty.h | 12 | ||||
| -rw-r--r-- | lib/yang.c | 33 | ||||
| -rw-r--r-- | lib/yang.h | 42 | ||||
| -rw-r--r-- | lib/yang_translator.c | 8 |
11 files changed, 213 insertions, 87 deletions
diff --git a/lib/command.c b/lib/command.c index bd000c3746..a01aabcc2a 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1051,8 +1051,13 @@ static int cmd_execute_command_real(vector vline, enum filter_type filter, int ret; if (matched_element->daemon) ret = CMD_SUCCESS_DAEMON; - else + else { + /* Clear enqueued configuration changes. */ + vty->num_cfg_changes = 0; + memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes)); + ret = matched_element->func(matched_element, vty, argc, argv); + } // delete list and cmd_token's in it list_delete(&argv_list); @@ -1086,12 +1086,6 @@ DEFPY_NOSH (interface, VRF_CMD_HELP_STR) { char xpath_list[XPATH_MAXLEN]; - struct cli_config_change changes[] = { - { - .xpath = ".", - .operation = NB_OP_CREATE, - }, - }; vrf_id_t vrf_id; struct interface *ifp; int ret; @@ -1136,7 +1130,8 @@ DEFPY_NOSH (interface, "/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname, vrfname); - ret = nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes)); + nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); + ret = nb_cli_apply_changes(vty, xpath_list); if (ret == CMD_SUCCESS) { VTY_PUSH_XPATH(INTERFACE_NODE, xpath_list); @@ -1162,22 +1157,14 @@ DEFPY (no_interface, "Interface's name\n" VRF_CMD_HELP_STR) { - char xpath_list[XPATH_MAXLEN]; - struct cli_config_change changes[] = { - { - .xpath = ".", - .operation = NB_OP_DELETE, - }, - }; - if (!vrfname) vrfname = VRF_DEFAULT_NAME; - snprintf(xpath_list, sizeof(xpath_list), - "/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname, - vrfname); + nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL); - return nb_cli_cfg_change(vty, xpath_list, changes, array_size(changes)); + return nb_cli_apply_changes( + vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']", + ifname, vrfname); } static void cli_show_interface(struct vty *vty, struct lyd_node *dnode, @@ -1203,18 +1190,12 @@ DEFPY (interface_desc, "Interface specific description\n" "Characters describing this interface\n") { - struct cli_config_change changes[] = { - { - .xpath = "./description", - .operation = NB_OP_MODIFY, - }, - }; char *desc; int ret; desc = argv_concat(argv, argc, 1); - changes[0].value = desc; - ret = nb_cli_cfg_change(vty, NULL, changes, array_size(changes)); + nb_cli_enqueue_change(vty, "./description", NB_OP_MODIFY, desc); + ret = nb_cli_apply_changes(vty, NULL); XFREE(MTYPE_TMP, desc); return ret; @@ -1226,14 +1207,9 @@ DEFPY (no_interface_desc, NO_STR "Interface specific description\n") { - struct cli_config_change changes[] = { - { - .xpath = "./description", - .operation = NB_OP_DELETE, - }, - }; + nb_cli_enqueue_change(vty, "./description", NB_OP_DELETE, NULL); - return nb_cli_cfg_change(vty, NULL, changes, array_size(changes)); + return nb_cli_apply_changes(vty, NULL); } static void cli_show_interface_desc(struct vty *vty, struct lyd_node *dnode, @@ -1338,7 +1314,7 @@ static int lib_interface_delete(enum nb_event event, { struct interface *ifp; - ifp = yang_dnode_get_entry(dnode); + ifp = yang_dnode_get_entry(dnode, true); switch (event) { case NB_EV_VALIDATE: @@ -1372,7 +1348,7 @@ static int lib_interface_description_modify(enum nb_event event, if (event != NB_EV_APPLY) return NB_OK; - ifp = yang_dnode_get_entry(dnode); + ifp = yang_dnode_get_entry(dnode, true); if (ifp->desc) XFREE(MTYPE_TMP, ifp->desc); description = yang_dnode_get_string(dnode, NULL); @@ -1389,7 +1365,7 @@ static int lib_interface_description_delete(enum nb_event event, if (event != NB_EV_APPLY) return NB_OK; - ifp = yang_dnode_get_entry(dnode); + ifp = yang_dnode_get_entry(dnode, true); if (ifp->desc) XFREE(MTYPE_TMP, ifp->desc); diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 1ffd65af42..a3006264f1 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -56,10 +56,30 @@ static void vty_show_libyang_errors(struct vty *vty, struct ly_ctx *ly_ctx) ly_err_clean(ly_ctx, NULL); } -int nb_cli_cfg_change(struct vty *vty, char *xpath_base, - struct cli_config_change changes[], size_t size) +void nb_cli_enqueue_change(struct vty *vty, const char *xpath, + enum nb_operation operation, const char *value) +{ + struct vty_cfg_change *change; + + if (vty->num_cfg_changes == VTY_MAXCFGCHANGES) { + /* Not expected to happen. */ + vty_out(vty, + "%% Exceeded the maximum number of changes (%u) for a single command\n\n", + VTY_MAXCFGCHANGES); + return; + } + + change = &vty->cfg_changes[vty->num_cfg_changes++]; + change->xpath = xpath; + change->operation = operation; + change->value = value; +} + +int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, ...) { struct nb_config *candidate_transitory; + char xpath_base[XPATH_MAXLEN]; + va_list ap; bool error = false; int ret; @@ -72,9 +92,14 @@ int nb_cli_cfg_change(struct vty *vty, char *xpath_base, */ candidate_transitory = nb_config_dup(vty->candidate_config); + /* Parse the base XPath format string. */ + va_start(ap, xpath_base_fmt); + vsnprintf(xpath_base, sizeof(xpath_base), xpath_base_fmt, ap); + va_end(ap); + /* Edit candidate configuration. */ - for (size_t i = 0; i < size; i++) { - struct cli_config_change *change = &changes[i]; + for (size_t i = 0; i < vty->num_cfg_changes; i++) { + struct vty_cfg_change *change = &vty->cfg_changes[i]; struct nb_node *nb_node; char xpath[XPATH_MAXLEN]; struct yang_data *data; @@ -82,19 +107,21 @@ int nb_cli_cfg_change(struct vty *vty, char *xpath_base, /* Handle relative XPaths. */ memset(xpath, 0, sizeof(xpath)); if (vty->xpath_index > 0 - && ((xpath_base && xpath_base[0] == '.') + && ((xpath_base_fmt && xpath_base[0] == '.') || change->xpath[0] == '.')) strlcpy(xpath, VTY_CURR_XPATH, sizeof(xpath)); - if (xpath_base) { + if (xpath_base_fmt) { if (xpath_base[0] == '.') - xpath_base++; - strlcat(xpath, xpath_base, sizeof(xpath)); + strlcat(xpath, xpath_base + 1, sizeof(xpath)); + else + strlcat(xpath, xpath_base, sizeof(xpath)); } if (change->xpath[0] == '.') strlcat(xpath, change->xpath + 1, sizeof(xpath)); else strlcpy(xpath, change->xpath, sizeof(xpath)); + /* Find the northbound node associated to the data path. */ nb_node = nb_node_find(xpath); if (!nb_node) { flog_warn(EC_LIB_YANG_UNKNOWN_DATA_PATH, diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index 7f4a64c014..febcbd86f1 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -22,27 +22,6 @@ #include "northbound.h" -struct cli_config_change { - /* - * XPath (absolute or relative) of the configuration option being - * edited. - */ - char xpath[XPATH_MAXLEN]; - - /* - * Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or - * NB_OP_DELETE). - */ - enum nb_operation operation; - - /* - * New value of the configuration option. Should be NULL for typeless - * YANG data (e.g. presence-containers). For convenience, NULL can also - * be used to restore a leaf to its default value. - */ - const char *value; -}; - /* Possible formats in which a configuration can be displayed. */ enum nb_cfg_format { NB_CFG_FMT_CMDS = 0, @@ -52,13 +31,80 @@ enum nb_cfg_format { extern struct nb_config *vty_shared_candidate_config; -/* Prototypes. */ -extern int nb_cli_cfg_change(struct vty *vty, char *xpath_list, - struct cli_config_change changes[], size_t size); +/* + * Enqueue change to be applied in the candidate configuration. + * + * vty + * The vty context. + * + * xpath + * XPath (absolute or relative) of the configuration option being edited. + * + * operation + * Operation to apply (either NB_OP_CREATE, NB_OP_MODIFY or NB_OP_DELETE). + * + * value + * New value of the configuration option. Should be NULL for typeless YANG + * data (e.g. presence-containers). For convenience, NULL can also be used + * to restore a leaf to its default value. + */ +extern void nb_cli_enqueue_change(struct vty *vty, const char *xpath, + enum nb_operation operation, + const char *value); + +/* + * Apply enqueued changes to the candidate configuration. + * + * vty + * The vty context. + * + * xpath_base_fmt + * Prepend the given XPath (absolute or relative) to all enqueued + * configuration changes. + * + * Returns: + * CMD_SUCCESS on success, CMD_WARNING_CONFIG_FAILED otherwise. + */ +extern int nb_cli_apply_changes(struct vty *vty, const char *xpath_base_fmt, + ...); + +/* + * Execute a YANG RPC or Action. + * + * xpath + * XPath of the YANG RPC or Action node. + * + * input + * List of 'yang_data' structures containing the RPC input parameters. It + * can be set to NULL when there are no input parameters. + * + * output + * List of 'yang_data' structures used to retrieve the RPC output parameters. + * It can be set to NULL when it's known that the given YANG RPC or Action + * doesn't have any output parameters. + * + * Returns: + * CMD_SUCCESS on success, CMD_WARNING otherwise. + */ extern int nb_cli_rpc(const char *xpath, struct list *input, struct list *output); + +/* + * Show CLI commands associated to the given YANG data node. + * + * vty + * The vty terminal to dump the configuration to. + * + * dnode + * libyang data node that should be shown in the form of CLI commands. + * + * show_defaults + * Specify whether to display default configuration values or not. + */ extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode, bool show_defaults); + +/* Prototypes of internal functions. */ extern void nb_cli_install_default(int node); extern void nb_cli_init(void); extern void nb_cli_terminate(void); diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index 9d01541205..3579d1da00 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -1036,9 +1036,11 @@ static int frr_confd_dp_read(struct thread *thread) ret = confd_fd_ready(dctx, fd); if (ret == CONFD_EOF) { flog_err_confd("confd_fd_ready"); + frr_confd_finish(); return -1; } else if (ret == CONFD_ERR && confd_errno != CONFD_ERR_EXTERNAL) { flog_err_confd("confd_fd_ready"); + frr_confd_finish(); return -1; } diff --git a/lib/prefix.c b/lib/prefix.c index 21c3af7d49..858f860ee8 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -853,7 +853,7 @@ int str2prefix_ipv4(const char *str, struct prefix_ipv4 *p) /* String doesn't contail slash. */ if (pnt == NULL) { /* Convert string to prefix. */ - ret = inet_aton(str, &p->prefix); + ret = inet_pton(AF_INET, str, &p->prefix); if (ret == 0) return 0; diff --git a/lib/stream.h b/lib/stream.h index ef9366e1ae..32b6fb5af1 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -133,13 +133,6 @@ struct stream_fifo { #define STREAM_CONCAT_REMAIN(S1, S2, size) ((size) - (S1)->endp - (S2)->endp) -/* deprecated macros - do not use in new code */ -#if CONFDATE > 20181128 -CPP_NOTICE("lib: time to remove deprecated stream.h macros") -#endif -#define STREAM_PNT(S) stream_pnt((S)) -#define STREAM_REMAIN(S) STREAM_WRITEABLE((S)) - /* this macro is deprecated, but not slated for removal anytime soon */ #define STREAM_DATA(S) ((S)->data) @@ -35,11 +35,19 @@ #define VTY_MAXHIST 20 #define VTY_MAXDEPTH 8 +#define VTY_MAXCFGCHANGES 8 + struct vty_error { char error_buf[VTY_BUFSIZ]; uint32_t line_num; }; +struct vty_cfg_change { + const char *xpath; + enum nb_operation operation; + const char *value; +}; + /* VTY struct. */ struct vty { /* File descripter of this vty. */ @@ -98,6 +106,10 @@ struct vty { /* History insert end point */ int hindex; + /* Changes enqueued to be applied in the candidate configuration. */ + size_t num_cfg_changes; + struct vty_cfg_change cfg_changes[VTY_MAXCFGCHANGES]; + /* XPath of the current node */ int xpath_index; char xpath[VTY_MAXDEPTH][XPATH_MAXLEN]; diff --git a/lib/yang.c b/lib/yang.c index e426b3af3e..462e693549 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -366,6 +366,29 @@ void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath, free(xpath_ptr); } +const char *yang_dnode_get_schema_name(const struct lyd_node *dnode, + const char *xpath_fmt, ...) +{ + if (xpath_fmt) { + va_list ap; + char xpath[XPATH_MAXLEN]; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + dnode = yang_dnode_get(dnode, xpath); + if (!dnode) { + flog_err(EC_LIB_YANG_DNODE_NOT_FOUND, + "%s: couldn't find %s", __func__, xpath); + zlog_backtrace(LOG_ERR); + abort(); + } + } + + return dnode->schema->name; +} + struct lyd_node *yang_dnode_get(const struct lyd_node *dnode, const char *xpath_fmt, ...) { @@ -492,7 +515,8 @@ void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry) lyd_set_private(dnode, entry); } -void *yang_dnode_get_entry(const struct lyd_node *dnode) +void *yang_dnode_get_entry(const struct lyd_node *dnode, + bool abort_if_not_found) { const struct lyd_node *orig_dnode = dnode; char xpath[XPATH_MAXLEN]; @@ -511,6 +535,9 @@ void *yang_dnode_get_entry(const struct lyd_node *dnode) dnode = dnode->parent; } + if (!abort_if_not_found) + return NULL; + yang_dnode_get_path(orig_dnode, xpath, sizeof(xpath)); flog_err(EC_LIB_YANG_DNODE_NOT_FOUND, "%s: failed to find entry [xpath %s]", __func__, xpath); @@ -627,13 +654,13 @@ void yang_init(void) ly_log_options(LY_LOLOG | LY_LOSTORE); /* Initialize libyang container for native models. */ - ly_native_ctx = ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD); + ly_native_ctx = + ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD); if (!ly_native_ctx) { flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); exit(1); } ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL); - ly_ctx_set_searchdir(ly_native_ctx, YANG_MODELS_PATH); ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb); /* Detect if the required libyang plugin(s) were loaded successfully. */ diff --git a/lib/yang.h b/lib/yang.h index 2c18017af2..3259189e98 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -311,6 +311,22 @@ extern void yang_dnode_get_path(const struct lyd_node *dnode, char *xpath, size_t xpath_len); /* + * Return the schema name of the given libyang data node. + * + * dnode + * libyang data node. + * + * xpath_fmt + * Optional XPath expression (absolute or relative) to specify a different + * data node to operate on in the same data tree. + * + * Returns: + * Schema name of the libyang data node. + */ +extern const char *yang_dnode_get_schema_name(const struct lyd_node *dnode, + const char *xpath_fmt, ...); + +/* * Find a libyang data node by its YANG data path. * * dnode @@ -395,15 +411,37 @@ extern void yang_dnode_change_leaf(struct lyd_node *dnode, const char *value); extern void yang_dnode_set_entry(const struct lyd_node *dnode, void *entry); /* - * Find the closest data node that contains an user pointer and return it. + * Find the user pointer associated to the given libyang data node. + * + * The data node is traversed by following the parent pointers until an user + * pointer is found or until the root node is reached. * * dnode * libyang data node to operate on. * + * abort_if_not_found + * When set to true, abort the program if no user pointer is found. + * + * As a rule of thumb, this parameter should be set to true in the following + * scenarios: + * - Calling this function from any northbound configuration callback during + * the NB_EV_APPLY phase. + * - Calling this function from a 'delete' northbound configuration callback + * during any phase. + * + * In both the above cases, the libyang data node should contain an user + * pointer except when there's a bug in the code, in which case it's better + * to abort the program right away and eliminate the need for unnecessary + * NULL checks. + * + * In all other cases, this parameter should be set to false and the caller + * should check if the function returned NULL or not. + * * Returns: * User pointer if found, NULL otherwise. */ -extern void *yang_dnode_get_entry(const struct lyd_node *dnode); +extern void *yang_dnode_get_entry(const struct lyd_node *dnode, + bool abort_if_not_found); /* * Create a new libyang data node. diff --git a/lib/yang_translator.c b/lib/yang_translator.c index 836b64a34b..c3092e56e5 100644 --- a/lib/yang_translator.c +++ b/lib/yang_translator.c @@ -162,12 +162,12 @@ struct yang_translator *yang_translator_load(const char *path) RB_INSERT(yang_translators, &yang_translators, translator); /* Initialize the translator libyang context. */ - translator->ly_ctx = ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD); + translator->ly_ctx = + ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD); if (!translator->ly_ctx) { flog_warn(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); goto error; } - ly_ctx_set_searchdir(translator->ly_ctx, YANG_MODELS_PATH); /* Load modules and deviations. */ set = lyd_find_path(dnode, "./module"); @@ -525,12 +525,12 @@ static void str_replace(char *o_string, const char *s_string, void yang_translator_init(void) { - ly_translator_ctx = ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIR_CWD); + ly_translator_ctx = + ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD); if (!ly_translator_ctx) { flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); exit(1); } - ly_ctx_set_searchdir(ly_translator_ctx, YANG_MODELS_PATH); if (!ly_ctx_load_module(ly_translator_ctx, "frr-module-translator", NULL)) { |
