summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/command.c7
-rw-r--r--lib/if.c50
-rw-r--r--lib/northbound_cli.c43
-rw-r--r--lib/northbound_cli.h94
-rw-r--r--lib/northbound_confd.c2
-rw-r--r--lib/prefix.c2
-rw-r--r--lib/stream.h7
-rw-r--r--lib/vty.h12
-rw-r--r--lib/yang.c33
-rw-r--r--lib/yang.h42
-rw-r--r--lib/yang_translator.c8
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);
diff --git a/lib/if.c b/lib/if.c
index e02c89b9ac..0fd65da03a 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -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)
diff --git a/lib/vty.h b/lib/vty.h
index 4c434fb2f2..5cc077523f 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -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)) {