summaryrefslogtreecommitdiffstats
path: root/lib/northbound.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/northbound.h')
-rw-r--r--lib/northbound.h1495
1 files changed, 1495 insertions, 0 deletions
diff --git a/lib/northbound.h b/lib/northbound.h
new file mode 100644
index 0000000..1723a87
--- /dev/null
+++ b/lib/northbound.h
@@ -0,0 +1,1495 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ */
+
+#ifndef _FRR_NORTHBOUND_H_
+#define _FRR_NORTHBOUND_H_
+
+#include "frrevent.h"
+#include "hook.h"
+#include "linklist.h"
+#include "openbsd-tree.h"
+#include "yang.h"
+#include "yang_translator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declaration(s). */
+struct vty;
+struct debug;
+
+struct nb_yang_xpath_tag {
+ uint32_t ns;
+ uint32_t id;
+};
+
+struct nb_yang_value {
+ struct lyd_value value;
+ LY_DATA_TYPE value_type;
+ uint8_t value_flags;
+};
+
+struct nb_yang_xpath_elem {
+ struct nb_yang_xpath_tag tag;
+ struct nb_yang_value val;
+};
+
+#define NB_MAX_NUM_KEYS UINT8_MAX
+#define NB_MAX_NUM_XPATH_TAGS UINT8_MAX
+
+struct nb_yang_xpath {
+ uint8_t length;
+ struct {
+ uint8_t num_keys;
+ struct nb_yang_xpath_elem keys[NB_MAX_NUM_KEYS];
+ } tags[NB_MAX_NUM_XPATH_TAGS];
+};
+
+#define NB_YANG_XPATH_KEY(__xpath, __indx1, __indx2) \
+ ((__xpath->num_tags > __indx1) && \
+ (__xpath->tags[__indx1].num_keys > __indx2) \
+ ? &__xpath->tags[__indx1].keys[__indx2] \
+ : NULL)
+
+/* Northbound events. */
+enum nb_event {
+ /*
+ * The configuration callback is supposed to verify that the changes are
+ * valid and can be applied.
+ */
+ NB_EV_VALIDATE,
+
+ /*
+ * The configuration callback is supposed to prepare all resources
+ * required to apply the changes.
+ */
+ NB_EV_PREPARE,
+
+ /*
+ * Transaction has failed, the configuration callback needs to release
+ * all resources previously allocated.
+ */
+ NB_EV_ABORT,
+
+ /*
+ * The configuration changes need to be applied. The changes can't be
+ * rejected at this point (errors are logged and ignored).
+ */
+ NB_EV_APPLY,
+};
+
+/*
+ * Northbound operations.
+ *
+ * Refer to the documentation comments of nb_callbacks for more details.
+ */
+enum nb_operation {
+ NB_OP_CREATE,
+ NB_OP_MODIFY,
+ NB_OP_DESTROY,
+ NB_OP_MOVE,
+ NB_OP_PRE_VALIDATE,
+ NB_OP_APPLY_FINISH,
+ NB_OP_GET_ELEM,
+ NB_OP_GET_NEXT,
+ NB_OP_GET_KEYS,
+ NB_OP_LOOKUP_ENTRY,
+ NB_OP_RPC,
+};
+
+struct nb_cfg_change {
+ char xpath[XPATH_MAXLEN];
+ enum nb_operation operation;
+ const char *value;
+};
+
+union nb_resource {
+ int fd;
+ void *ptr;
+};
+
+/*
+ * Northbound callbacks parameters.
+ */
+
+struct nb_cb_create_args {
+ /* Context of the configuration transaction. */
+ struct nb_context *context;
+
+ /*
+ * The transaction phase. Refer to the documentation comments of
+ * nb_event for more details.
+ */
+ enum nb_event event;
+
+ /* libyang data node that is being created. */
+ const struct lyd_node *dnode;
+
+ /*
+ * Pointer to store resource(s) allocated during the NB_EV_PREPARE
+ * phase. The same pointer can be used during the NB_EV_ABORT and
+ * NB_EV_APPLY phases to either release or make use of the allocated
+ * resource(s). It's set to NULL when the event is NB_EV_VALIDATE.
+ */
+ union nb_resource *resource;
+
+ /* Buffer to store human-readable error message in case of error. */
+ char *errmsg;
+
+ /* Size of errmsg. */
+ size_t errmsg_len;
+};
+
+struct nb_cb_modify_args {
+ /* Context of the configuration transaction. */
+ struct nb_context *context;
+
+ /*
+ * The transaction phase. Refer to the documentation comments of
+ * nb_event for more details.
+ */
+ enum nb_event event;
+
+ /* libyang data node that is being modified. */
+ const struct lyd_node *dnode;
+
+ /*
+ * Pointer to store resource(s) allocated during the NB_EV_PREPARE
+ * phase. The same pointer can be used during the NB_EV_ABORT and
+ * NB_EV_APPLY phases to either release or make use of the allocated
+ * resource(s). It's set to NULL when the event is NB_EV_VALIDATE.
+ */
+ union nb_resource *resource;
+
+ /* Buffer to store human-readable error message in case of error. */
+ char *errmsg;
+
+ /* Size of errmsg. */
+ size_t errmsg_len;
+};
+
+struct nb_cb_destroy_args {
+ /* Context of the configuration transaction. */
+ struct nb_context *context;
+
+ /*
+ * The transaction phase. Refer to the documentation comments of
+ * nb_event for more details.
+ */
+ enum nb_event event;
+
+ /* libyang data node that is being deleted. */
+ const struct lyd_node *dnode;
+
+ /* Buffer to store human-readable error message in case of error. */
+ char *errmsg;
+
+ /* Size of errmsg. */
+ size_t errmsg_len;
+};
+
+struct nb_cb_move_args {
+ /* Context of the configuration transaction. */
+ struct nb_context *context;
+
+ /*
+ * The transaction phase. Refer to the documentation comments of
+ * nb_event for more details.
+ */
+ enum nb_event event;
+
+ /* libyang data node that is being moved. */
+ const struct lyd_node *dnode;
+
+ /* Buffer to store human-readable error message in case of error. */
+ char *errmsg;
+
+ /* Size of errmsg. */
+ size_t errmsg_len;
+};
+
+struct nb_cb_pre_validate_args {
+ /* Context of the configuration transaction. */
+ struct nb_context *context;
+
+ /* libyang data node associated with the 'pre_validate' callback. */
+ const struct lyd_node *dnode;
+
+ /* Buffer to store human-readable error message in case of error. */
+ char *errmsg;
+
+ /* Size of errmsg. */
+ size_t errmsg_len;
+};
+
+struct nb_cb_apply_finish_args {
+ /* Context of the configuration transaction. */
+ struct nb_context *context;
+
+ /* libyang data node associated with the 'apply_finish' callback. */
+ const struct lyd_node *dnode;
+
+ /* Buffer to store human-readable error message in case of error. */
+ char *errmsg;
+
+ /* Size of errmsg. */
+ size_t errmsg_len;
+};
+
+struct nb_cb_get_elem_args {
+ /* YANG data path of the data we want to get. */
+ const char *xpath;
+
+ /* Pointer to list entry (might be NULL). */
+ const void *list_entry;
+};
+
+struct nb_cb_get_next_args {
+ /* Pointer to parent list entry. */
+ const void *parent_list_entry;
+
+ /* Pointer to (leaf-)list entry. */
+ const void *list_entry;
+};
+
+struct nb_cb_get_keys_args {
+ /* Pointer to list entry. */
+ const void *list_entry;
+
+ /*
+ * Structure to be filled based on the attributes of the provided list
+ * entry.
+ */
+ struct yang_list_keys *keys;
+};
+
+struct nb_cb_lookup_entry_args {
+ /* Pointer to parent list entry. */
+ const void *parent_list_entry;
+
+ /* Structure containing the keys of the list entry. */
+ const struct yang_list_keys *keys;
+};
+
+struct nb_cb_rpc_args {
+ /* XPath of the YANG RPC or action. */
+ const char *xpath;
+
+ /* Read-only list of input parameters. */
+ const struct list *input;
+
+ /* List of output parameters to be populated by the callback. */
+ struct list *output;
+
+ /* Buffer to store human-readable error message in case of error. */
+ char *errmsg;
+
+ /* Size of errmsg. */
+ size_t errmsg_len;
+};
+
+/*
+ * Set of configuration callbacks that can be associated to a northbound node.
+ */
+struct nb_callbacks {
+ /*
+ * Configuration callback.
+ *
+ * A presence container, list entry, leaf-list entry or leaf of type
+ * empty has been created.
+ *
+ * For presence-containers and list entries, the callback is supposed to
+ * initialize the default values of its children (if any) from the YANG
+ * models.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_create_args for
+ * details.
+ *
+ * Returns:
+ * - NB_OK on success.
+ * - NB_ERR_VALIDATION when a validation error occurred.
+ * - NB_ERR_RESOURCE when the callback failed to allocate a resource.
+ * - NB_ERR_INCONSISTENCY when an inconsistency was detected.
+ * - NB_ERR for other errors.
+ */
+ int (*create)(struct nb_cb_create_args *args);
+
+ /*
+ * Configuration callback.
+ *
+ * The value of a leaf has been modified.
+ *
+ * List keys don't need to implement this callback. When a list key is
+ * modified, the northbound treats this as if the list was deleted and a
+ * new one created with the updated key value.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_modify_args for
+ * details.
+ *
+ * Returns:
+ * - NB_OK on success.
+ * - NB_ERR_VALIDATION when a validation error occurred.
+ * - NB_ERR_RESOURCE when the callback failed to allocate a resource.
+ * - NB_ERR_INCONSISTENCY when an inconsistency was detected.
+ * - NB_ERR for other errors.
+ */
+ int (*modify)(struct nb_cb_modify_args *args);
+
+ /*
+ * Configuration callback.
+ *
+ * A presence container, list entry, leaf-list entry or optional leaf
+ * has been deleted.
+ *
+ * The callback is supposed to delete the entire configuration object,
+ * including its children when they exist.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_destroy_args for
+ * details.
+ *
+ * Returns:
+ * - NB_OK on success.
+ * - NB_ERR_VALIDATION when a validation error occurred.
+ * - NB_ERR_INCONSISTENCY when an inconsistency was detected.
+ * - NB_ERR for other errors.
+ */
+ int (*destroy)(struct nb_cb_destroy_args *args);
+
+ /*
+ * Configuration callback.
+ *
+ * A list entry or leaf-list entry has been moved. Only applicable when
+ * the "ordered-by user" statement is present.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_move_args for
+ * details.
+ *
+ * Returns:
+ * - NB_OK on success.
+ * - NB_ERR_VALIDATION when a validation error occurred.
+ * - NB_ERR_INCONSISTENCY when an inconsistency was detected.
+ * - NB_ERR for other errors.
+ */
+ int (*move)(struct nb_cb_move_args *args);
+
+ /*
+ * Optional configuration callback.
+ *
+ * This callback can be used to validate subsections of the
+ * configuration being committed before validating the configuration
+ * changes themselves. It's useful to perform more complex validations
+ * that depend on the relationship between multiple nodes.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_pre_validate_args for
+ * details.
+ *
+ * Returns:
+ * - NB_OK on success.
+ * - NB_ERR_VALIDATION when a validation error occurred.
+ */
+ int (*pre_validate)(struct nb_cb_pre_validate_args *args);
+
+ /*
+ * Optional configuration callback.
+ *
+ * The 'apply_finish' callbacks are called after all other callbacks
+ * during the apply phase (NB_EV_APPLY). These callbacks are called only
+ * under one of the following two cases:
+ * - The data node has been created or modified (but not deleted);
+ * - Any change was made within the descendants of the data node (e.g. a
+ * child leaf was modified, created or deleted).
+ *
+ * In the second case above, the 'apply_finish' callback is called only
+ * once even if multiple changes occurred within the descendants of the
+ * data node.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_apply_finish_args for
+ * details.
+ */
+ void (*apply_finish)(struct nb_cb_apply_finish_args *args);
+
+ /*
+ * Operational data callback.
+ *
+ * The callback function should return the value of a specific leaf,
+ * leaf-list entry or inform if a typeless value (presence containers or
+ * leafs of type empty) exists or not.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_get_elem_args for
+ * details.
+ *
+ * Returns:
+ * Pointer to newly created yang_data structure, or NULL to indicate
+ * the absence of data.
+ */
+ struct yang_data *(*get_elem)(struct nb_cb_get_elem_args *args);
+
+ /*
+ * Operational data callback for YANG lists and leaf-lists.
+ *
+ * The callback function should return the next entry in the list or
+ * leaf-list. The 'list_entry' parameter will be NULL on the first
+ * invocation.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_get_next_args for
+ * details.
+ *
+ * Returns:
+ * Pointer to the next entry in the (leaf-)list, or NULL to signal
+ * that the end of the (leaf-)list was reached.
+ */
+ const void *(*get_next)(struct nb_cb_get_next_args *args);
+
+ /*
+ * Operational data callback for YANG lists.
+ *
+ * The callback function should fill the 'keys' parameter based on the
+ * given list_entry. Keyless lists don't need to implement this
+ * callback.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_get_keys_args for
+ * details.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR otherwise.
+ */
+ int (*get_keys)(struct nb_cb_get_keys_args *args);
+
+ /*
+ * Operational data callback for YANG lists.
+ *
+ * The callback function should return a list entry based on the list
+ * keys given as a parameter. Keyless lists don't need to implement this
+ * callback.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_lookup_entry_args for
+ * details.
+ *
+ * Returns:
+ * Pointer to the list entry if found, or NULL if not found.
+ */
+ const void *(*lookup_entry)(struct nb_cb_lookup_entry_args *args);
+
+ /*
+ * RPC and action callback.
+ *
+ * Both 'input' and 'output' are lists of 'yang_data' structures. The
+ * callback should fetch all the input parameters from the 'input' list,
+ * and add output parameters to the 'output' list if necessary.
+ *
+ * args
+ * Refer to the documentation comments of nb_cb_rpc_args for details.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR otherwise.
+ */
+ int (*rpc)(struct nb_cb_rpc_args *args);
+
+ /*
+ * Optional callback to compare the data nodes when printing
+ * the CLI commands associated with them.
+ *
+ * dnode1
+ * The first data node to compare.
+ *
+ * dnode2
+ * The second data node to compare.
+ *
+ * Returns:
+ * <0 when the CLI command for the dnode1 should be printed first
+ * >0 when the CLI command for the dnode2 should be printed first
+ * 0 when there is no difference
+ */
+ int (*cli_cmp)(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2);
+
+ /*
+ * Optional callback to show the CLI command 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 a CLI
+ * command.
+ *
+ * show_defaults
+ * Specify whether to display default configuration values or not.
+ * This parameter can be ignored most of the time since the
+ * northbound doesn't call this callback for default leaves or
+ * non-presence containers that contain only default child nodes.
+ * The exception are commands associated to multiple configuration
+ * nodes, in which case it might be desirable to hide one or more
+ * parts of the command when this parameter is set to false.
+ */
+ void (*cli_show)(struct vty *vty, const struct lyd_node *dnode,
+ bool show_defaults);
+
+ /*
+ * Optional callback to show the CLI node end for lists or containers.
+ *
+ * vty
+ * The vty terminal to dump the configuration to.
+ *
+ * dnode
+ * libyang data node that should be shown in the form of a CLI
+ * command.
+ */
+ void (*cli_show_end)(struct vty *vty, const struct lyd_node *dnode);
+};
+
+struct nb_dependency_callbacks {
+ void (*get_dependant_xpath)(const struct lyd_node *dnode, char *xpath);
+ void (*get_dependency_xpath)(const struct lyd_node *dnode, char *xpath);
+};
+
+/*
+ * Northbound-specific data that is allocated for each schema node of the native
+ * YANG modules.
+ */
+struct nb_node {
+ /* Back pointer to the libyang schema node. */
+ const struct lysc_node *snode;
+
+ /* Data path of this YANG node. */
+ char xpath[XPATH_MAXLEN];
+
+ /* Priority - lower priorities are processed first. */
+ uint32_t priority;
+
+ struct nb_dependency_callbacks dep_cbs;
+
+ /* Callbacks implemented for this node. */
+ struct nb_callbacks cbs;
+
+ /*
+ * Pointer to the parent node (disconsidering non-presence containers).
+ */
+ struct nb_node *parent;
+
+ /* Pointer to the nearest parent list, if any. */
+ struct nb_node *parent_list;
+
+ /* Flags. */
+ uint8_t flags;
+
+#ifdef HAVE_CONFD
+ /* ConfD hash value corresponding to this YANG path. */
+ int confd_hash;
+#endif
+};
+/* The YANG container or list contains only config data. */
+#define F_NB_NODE_CONFIG_ONLY 0x01
+/* The YANG list doesn't contain key leafs. */
+#define F_NB_NODE_KEYLESS_LIST 0x02
+/* Ignore callbacks for this node */
+#define F_NB_NODE_IGNORE_CBS 0x04
+
+/*
+ * HACK: old gcc versions (< 5.x) have a bug that prevents C99 flexible arrays
+ * from working properly on shared libraries. For those compilers, use a fixed
+ * size array to work around the problem.
+ */
+#define YANG_MODULE_MAX_NODES 2000
+
+struct frr_yang_module_info {
+ /* YANG module name. */
+ const char *name;
+
+ /*
+ * Ignore callbacks for this module. Set this to true to
+ * load module without any callbacks.
+ */
+ bool ignore_cbs;
+
+ /* Northbound callbacks. */
+ const struct {
+ /* Data path of this YANG node. */
+ const char *xpath;
+
+ /* Callbacks implemented for this node. */
+ struct nb_callbacks cbs;
+
+ /* Priority - lower priorities are processed first. */
+ uint32_t priority;
+#if defined(__GNUC__) && ((__GNUC__ - 0) < 5) && !defined(__clang__)
+ } nodes[YANG_MODULE_MAX_NODES + 1];
+#else
+ } nodes[];
+#endif
+};
+
+/* Northbound error codes. */
+enum nb_error {
+ NB_OK = 0,
+ NB_ERR,
+ NB_ERR_NO_CHANGES,
+ NB_ERR_NOT_FOUND,
+ NB_ERR_LOCKED,
+ NB_ERR_VALIDATION,
+ NB_ERR_RESOURCE,
+ NB_ERR_INCONSISTENCY,
+};
+
+/* Default priority. */
+#define NB_DFLT_PRIORITY (UINT32_MAX / 2)
+
+/* Default maximum of configuration rollbacks to store. */
+#define NB_DLFT_MAX_CONFIG_ROLLBACKS 20
+
+/* Northbound clients. */
+enum nb_client {
+ NB_CLIENT_NONE = 0,
+ NB_CLIENT_CLI,
+ NB_CLIENT_CONFD,
+ NB_CLIENT_SYSREPO,
+ NB_CLIENT_GRPC,
+ NB_CLIENT_PCEP,
+ NB_CLIENT_MGMTD_SERVER,
+ NB_CLIENT_MGMTD_BE,
+};
+
+/* Northbound context. */
+struct nb_context {
+ /* Northbound client. */
+ enum nb_client client;
+
+ /* Northbound user (can be NULL). */
+ const void *user;
+};
+
+/* Northbound configuration callback. */
+struct nb_config_cb {
+ RB_ENTRY(nb_config_cb) entry;
+ enum nb_operation operation;
+ uint32_t seq;
+ const struct nb_node *nb_node;
+ const struct lyd_node *dnode;
+};
+RB_HEAD(nb_config_cbs, nb_config_cb);
+RB_PROTOTYPE(nb_config_cbs, nb_config_cb, entry, nb_config_cb_compare);
+
+/* Northbound configuration change. */
+struct nb_config_change {
+ struct nb_config_cb cb;
+ union nb_resource resource;
+ bool prepare_ok;
+};
+
+/* Northbound configuration transaction. */
+struct nb_transaction {
+ struct nb_context context;
+ char comment[80];
+ struct nb_config *config;
+ struct nb_config_cbs changes;
+};
+
+/* Northbound configuration. */
+struct nb_config {
+ struct lyd_node *dnode;
+ uint32_t version;
+ struct nb_config_cbs cfg_chgs;
+};
+
+/* Callback function used by nb_oper_data_iterate(). */
+typedef int (*nb_oper_data_cb)(const struct lysc_node *snode,
+ struct yang_translator *translator,
+ struct yang_data *data, void *arg);
+
+/* Iterate over direct child nodes only. */
+#define NB_OPER_DATA_ITER_NORECURSE 0x0001
+
+/* Hooks. */
+DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments),
+ (xpath, arguments));
+DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty));
+DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set));
+
+/* Northbound debugging records */
+extern struct debug nb_dbg_cbs_config;
+extern struct debug nb_dbg_cbs_state;
+extern struct debug nb_dbg_cbs_rpc;
+extern struct debug nb_dbg_notif;
+extern struct debug nb_dbg_events;
+extern struct debug nb_dbg_libyang;
+
+/* Global running configuration. */
+extern struct nb_config *running_config;
+
+/* Wrappers for the northbound callbacks. */
+extern struct yang_data *nb_callback_get_elem(const struct nb_node *nb_node,
+ const char *xpath,
+ const void *list_entry);
+extern const void *nb_callback_get_next(const struct nb_node *nb_node,
+ const void *parent_list_entry,
+ const void *list_entry);
+extern int nb_callback_get_keys(const struct nb_node *nb_node,
+ const void *list_entry,
+ struct yang_list_keys *keys);
+extern const void *nb_callback_lookup_entry(const struct nb_node *nb_node,
+ const void *parent_list_entry,
+ const struct yang_list_keys *keys);
+extern int nb_callback_rpc(const struct nb_node *nb_node, const char *xpath,
+ const struct list *input, struct list *output,
+ char *errmsg, size_t errmsg_len);
+
+/*
+ * Create a northbound node for all YANG schema nodes.
+ */
+void nb_nodes_create(void);
+
+/*
+ * Delete all northbound nodes from all YANG schema nodes.
+ */
+void nb_nodes_delete(void);
+
+/*
+ * Find the northbound node corresponding to a YANG data path.
+ *
+ * xpath
+ * XPath to search for (with or without predicates).
+ *
+ * Returns:
+ * Pointer to northbound node if found, NULL otherwise.
+ */
+extern struct nb_node *nb_node_find(const char *xpath);
+
+extern void nb_node_set_dependency_cbs(const char *dependency_xpath,
+ const char *dependant_xpath,
+ struct nb_dependency_callbacks *cbs);
+
+bool nb_node_has_dependency(struct nb_node *node);
+
+/*
+ * Create a new northbound configuration.
+ *
+ * dnode
+ * Pointer to a libyang data node containing the configuration data. If NULL
+ * is given, an empty configuration will be created.
+ *
+ * Returns:
+ * Pointer to newly created northbound configuration.
+ */
+extern struct nb_config *nb_config_new(struct lyd_node *dnode);
+
+/*
+ * Delete a northbound configuration.
+ *
+ * config
+ * Pointer to the config that is going to be deleted.
+ */
+extern void nb_config_free(struct nb_config *config);
+
+/*
+ * Duplicate a northbound configuration.
+ *
+ * config
+ * Northbound configuration to duplicate.
+ *
+ * Returns:
+ * Pointer to duplicated configuration.
+ */
+extern struct nb_config *nb_config_dup(const struct nb_config *config);
+
+/*
+ * Merge one configuration into another.
+ *
+ * config_dst
+ * Configuration to merge to.
+ *
+ * config_src
+ * Configuration to merge config_dst with.
+ *
+ * preserve_source
+ * Specify whether config_src should be deleted or not after the merge
+ * operation.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR otherwise.
+ */
+extern int nb_config_merge(struct nb_config *config_dst,
+ struct nb_config *config_src, bool preserve_source);
+
+/*
+ * Replace one configuration by another.
+ *
+ * config_dst
+ * Configuration to be replaced.
+ *
+ * config_src
+ * Configuration to replace config_dst.
+ *
+ * preserve_source
+ * Specify whether config_src should be deleted or not after the replace
+ * operation.
+ */
+extern void nb_config_replace(struct nb_config *config_dst,
+ struct nb_config *config_src,
+ bool preserve_source);
+
+/*
+ * Edit a candidate configuration.
+ *
+ * candidate
+ * Candidate configuration to edit.
+ *
+ * nb_node
+ * Northbound node associated to the configuration being edited.
+ *
+ * operation
+ * Operation to apply.
+ *
+ * xpath
+ * XPath of the configuration node being edited.
+ *
+ * previous
+ * Previous value of the configuration node. Should be used only when the
+ * operation is NB_OP_MOVE, otherwise this parameter is ignored.
+ *
+ * data
+ * New value of the configuration node.
+ *
+ * Returns:
+ * - NB_OK on success.
+ * - NB_ERR_NOT_FOUND when the element to be deleted was not found.
+ * - NB_ERR for other errors.
+ */
+extern int nb_candidate_edit(struct nb_config *candidate,
+ const struct nb_node *nb_node,
+ enum nb_operation operation, const char *xpath,
+ const struct yang_data *previous,
+ const struct yang_data *data);
+
+/*
+ * Create diff for configuration.
+ *
+ * dnode
+ * Pointer to a libyang data node containing the configuration data. If NULL
+ * is given, an empty configuration will be created.
+ *
+ * seq
+ * Returns sequence number assigned to the specific change.
+ *
+ * changes
+ * Northbound config callback head.
+ */
+extern void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
+ struct nb_config_cbs *changes);
+
+/*
+ * Check if a candidate configuration is outdated and needs to be updated.
+ *
+ * candidate
+ * Candidate configuration to check.
+ *
+ * Returns:
+ * true if the candidate is outdated, false otherwise.
+ */
+extern bool nb_candidate_needs_update(const struct nb_config *candidate);
+
+/*
+ * Edit candidate configuration changes.
+ *
+ * candidate_config
+ * Candidate configuration to edit.
+ *
+ * cfg_changes
+ * Northbound config changes.
+ *
+ * num_cfg_changes
+ * Number of config changes.
+ *
+ * xpath_base
+ * Base xpath for config.
+ *
+ * curr_xpath
+ * Current xpath for config.
+ *
+ * xpath_index
+ * Index of xpath being processed.
+ *
+ * err_buf
+ * Buffer to store human-readable error message in case of error.
+ *
+ * err_bufsize
+ * Size of err_buf.
+ *
+ * error
+ * TRUE on error, FALSE on success
+ */
+extern void nb_candidate_edit_config_changes(
+ struct nb_config *candidate_config, struct nb_cfg_change cfg_changes[],
+ size_t num_cfg_changes, const char *xpath_base, const char *curr_xpath,
+ int xpath_index, char *err_buf, int err_bufsize, bool *error);
+
+/*
+ * Delete candidate configuration changes.
+ *
+ * changes
+ * Northbound config changes.
+ */
+extern void nb_config_diff_del_changes(struct nb_config_cbs *changes);
+
+/*
+ * Create candidate diff and validate on yang tree
+ *
+ * context
+ * Context of the northbound transaction.
+ *
+ * candidate
+ * Candidate DB configuration.
+ *
+ * changes
+ * Northbound config changes.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR_VALIDATION otherwise
+ */
+extern int nb_candidate_diff_and_validate_yang(struct nb_context *context,
+ struct nb_config *candidate,
+ struct nb_config_cbs *changes,
+ char *errmsg, size_t errmsg_len);
+
+/*
+ * Calculate the delta between two different configurations.
+ *
+ * reference
+ * Running DB config changes to be compared against.
+ *
+ * incremental
+ * Candidate DB config changes that will be compared against reference.
+ *
+ * changes
+ * Will hold the final diff generated.
+ *
+ */
+extern void nb_config_diff(const struct nb_config *reference,
+ const struct nb_config *incremental,
+ struct nb_config_cbs *changes);
+
+/*
+ * Perform YANG syntactic and semantic validation.
+ *
+ * WARNING: lyd_validate() can change the configuration as part of the
+ * validation process.
+ *
+ * candidate
+ * Candidate DB configuration.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR_VALIDATION otherwise
+ */
+extern int nb_candidate_validate_yang(struct nb_config *candidate,
+ bool no_state, char *errmsg,
+ size_t errmsg_len);
+
+/*
+ * Perform code-level validation using the northbound callbacks.
+ *
+ * context
+ * Context of the northbound transaction.
+ *
+ * candidate
+ * Candidate DB configuration.
+ *
+ * changes
+ * Northbound config changes.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR_VALIDATION otherwise
+ */
+extern int nb_candidate_validate_code(struct nb_context *context,
+ struct nb_config *candidate,
+ struct nb_config_cbs *changes,
+ char *errmsg, size_t errmsg_len);
+
+/*
+ * Update a candidate configuration by rebasing the changes on top of the latest
+ * running configuration. Resolve conflicts automatically by giving preference
+ * to the changes done in the candidate configuration.
+ *
+ * candidate
+ * Candidate configuration to update.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR otherwise.
+ */
+extern int nb_candidate_update(struct nb_config *candidate);
+
+/*
+ * Validate a candidate configuration. Perform both YANG syntactic/semantic
+ * validation and code-level validation using the northbound callbacks.
+ *
+ * WARNING: the candidate can be modified as part of the validation process
+ * (e.g. add default nodes).
+ *
+ * context
+ * Context of the northbound transaction.
+ *
+ * candidate
+ * Candidate configuration to validate.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR_VALIDATION otherwise.
+ */
+extern int nb_candidate_validate(struct nb_context *context,
+ struct nb_config *candidate, char *errmsg,
+ size_t errmsg_len);
+
+/*
+ * Create a new configuration transaction but do not commit it yet. Only
+ * validate the candidate and prepare all resources required to apply the
+ * configuration changes.
+ *
+ * context
+ * Context of the northbound transaction.
+ *
+ * candidate
+ * Candidate configuration to commit.
+ *
+ * comment
+ * Optional comment describing the commit.
+ *
+ * transaction
+ * Output parameter providing the created transaction when one is created
+ * successfully. In this case, it must be either aborted using
+ * nb_candidate_commit_abort() or committed using
+ * nb_candidate_commit_apply().
+ *
+ * skip_validate
+ * TRUE to skip commit validation, FALSE otherwise.
+ *
+ * ignore_zero_change
+ * TRUE to ignore if zero changes, FALSE otherwise.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
+ *
+ * Returns:
+ * - NB_OK on success.
+ * - NB_ERR_NO_CHANGES when the candidate is identical to the running
+ * configuration.
+ * - NB_ERR_LOCKED when there's already another transaction in progress.
+ * - NB_ERR_VALIDATION when the candidate fails the validation checks.
+ * - NB_ERR_RESOURCE when the system fails to allocate resources to apply
+ * the candidate configuration.
+ * - NB_ERR for other errors.
+ */
+extern int nb_candidate_commit_prepare(struct nb_context context,
+ struct nb_config *candidate,
+ const char *comment,
+ struct nb_transaction **transaction,
+ bool skip_validate,
+ bool ignore_zero_change, char *errmsg,
+ size_t errmsg_len);
+
+/*
+ * Abort a previously created configuration transaction, releasing all resources
+ * allocated during the preparation phase.
+ *
+ * transaction
+ * Candidate configuration to abort. It's consumed by this function.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
+ */
+extern void nb_candidate_commit_abort(struct nb_transaction *transaction,
+ char *errmsg, size_t errmsg_len);
+
+/*
+ * Commit a previously created configuration transaction.
+ *
+ * transaction
+ * Configuration transaction to commit. It's consumed by this function.
+ *
+ * save_transaction
+ * Specify whether the transaction should be recorded in the transactions log
+ * or not.
+ *
+ * transaction_id
+ * Optional output parameter providing the ID of the committed transaction.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
+ */
+extern void nb_candidate_commit_apply(struct nb_transaction *transaction,
+ bool save_transaction,
+ uint32_t *transaction_id, char *errmsg,
+ size_t errmsg_len);
+
+/*
+ * Create a new transaction to commit a candidate configuration. This is a
+ * convenience function that performs the two-phase commit protocol
+ * transparently to the user. The cost is reduced flexibility, since
+ * network-wide and multi-daemon transactions require the network manager to
+ * take into account the results of the preparation phase of multiple managed
+ * entities.
+ *
+ * context
+ * Context of the northbound transaction.
+ *
+ * candidate
+ * Candidate configuration to commit. It's preserved regardless if the commit
+ * operation fails or not.
+ *
+ * save_transaction
+ * Specify whether the transaction should be recorded in the transactions log
+ * or not.
+ *
+ * comment
+ * Optional comment describing the commit.
+ *
+ * transaction_id
+ * Optional output parameter providing the ID of the committed transaction.
+ *
+ * errmsg
+ * Buffer to store human-readable error message in case of error.
+ *
+ * errmsg_len
+ * Size of errmsg.
+ *
+ * Returns:
+ * - NB_OK on success.
+ * - NB_ERR_NO_CHANGES when the candidate is identical to the running
+ * configuration.
+ * - NB_ERR_LOCKED when there's already another transaction in progress.
+ * - NB_ERR_VALIDATION when the candidate fails the validation checks.
+ * - NB_ERR_RESOURCE when the system fails to allocate resources to apply
+ * the candidate configuration.
+ * - NB_ERR for other errors.
+ */
+extern int nb_candidate_commit(struct nb_context context,
+ struct nb_config *candidate,
+ bool save_transaction, const char *comment,
+ uint32_t *transaction_id, char *errmsg,
+ size_t errmsg_len);
+
+/*
+ * Lock the running configuration.
+ *
+ * client
+ * Northbound client.
+ *
+ * user
+ * Northbound user (can be NULL).
+ *
+ * Returns:
+ * 0 on success, -1 when the running configuration is already locked.
+ */
+extern int nb_running_lock(enum nb_client client, const void *user);
+
+/*
+ * Unlock the running configuration.
+ *
+ * client
+ * Northbound client.
+ *
+ * user
+ * Northbound user (can be NULL).
+ *
+ * Returns:
+ * 0 on success, -1 when the running configuration is already unlocked or
+ * locked by another client/user.
+ */
+extern int nb_running_unlock(enum nb_client client, const void *user);
+
+/*
+ * Check if the running configuration is locked or not for the given
+ * client/user.
+ *
+ * client
+ * Northbound client.
+ *
+ * user
+ * Northbound user (can be NULL).
+ *
+ * Returns:
+ * 0 if the running configuration is unlocked or if the client/user owns the
+ * lock, -1 otherwise.
+ */
+extern int nb_running_lock_check(enum nb_client client, const void *user);
+
+/*
+ * Iterate over operational data.
+ *
+ * xpath
+ * Data path of the YANG data we want to iterate over.
+ *
+ * translator
+ * YANG module translator (might be NULL).
+ *
+ * flags
+ * NB_OPER_DATA_ITER_ flags to control how the iteration is performed.
+ *
+ * cb
+ * Function to call with each data node.
+ *
+ * arg
+ * Arbitrary argument passed as the fourth parameter in each call to 'cb'.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR otherwise.
+ */
+extern int nb_oper_data_iterate(const char *xpath,
+ struct yang_translator *translator,
+ uint32_t flags, nb_oper_data_cb cb, void *arg);
+
+/*
+ * Validate if the northbound operation is valid for the given node.
+ *
+ * operation
+ * Operation we want to check.
+ *
+ * snode
+ * libyang schema node we want to check.
+ *
+ * Returns:
+ * true if the operation is valid, false otherwise.
+ */
+extern bool nb_operation_is_valid(enum nb_operation operation,
+ const struct lysc_node *snode);
+
+/*
+ * Send a YANG notification. This is a no-op unless the 'nb_notification_send'
+ * hook was registered by a northbound plugin.
+ *
+ * xpath
+ * XPath of the YANG notification.
+ *
+ * arguments
+ * Linked list containing the arguments that should be sent. This list is
+ * deleted after being used.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR otherwise.
+ */
+extern int nb_notification_send(const char *xpath, struct list *arguments);
+
+/*
+ * Associate a user pointer to a configuration node.
+ *
+ * This should be called by northbound 'create' callbacks in the NB_EV_APPLY
+ * phase only.
+ *
+ * dnode
+ * libyang data node - only its XPath is used.
+ *
+ * entry
+ * Arbitrary user-specified pointer.
+ */
+extern void nb_running_set_entry(const struct lyd_node *dnode, void *entry);
+
+/*
+ * Move an entire tree of user pointer nodes.
+ *
+ * Suppose we have xpath A/B/C/D, with user pointers associated to C and D. We
+ * need to move B to be under Z, so the new xpath is Z/B/C/D. Because user
+ * pointers are indexed with their absolute path, We need to move all user
+ * pointers at and below B to their new absolute paths; this function does
+ * that.
+ *
+ * xpath_from
+ * base xpath of tree to move (A/B)
+ *
+ * xpath_to
+ * base xpath of new location of tree (Z/B)
+ */
+extern void nb_running_move_tree(const char *xpath_from, const char *xpath_to);
+
+/*
+ * Unset the user pointer associated to a configuration node.
+ *
+ * This should be called by northbound 'destroy' callbacks in the NB_EV_APPLY
+ * phase only.
+ *
+ * dnode
+ * libyang data node - only its XPath is used.
+ *
+ * Returns:
+ * The user pointer that was unset.
+ */
+extern void *nb_running_unset_entry(const struct lyd_node *dnode);
+
+/*
+ * Find the user pointer (if any) associated to a configuration node.
+ *
+ * The XPath associated to the configuration node can be provided directly or
+ * indirectly through a libyang data node.
+ *
+ * If an user point is not found, this function follows the parent nodes in the
+ * running configuration until an user pointer is found or until the root node
+ * is reached.
+ *
+ * dnode
+ * libyang data node - only its XPath is used (can be NULL if 'xpath' is
+ * provided).
+ *
+ * xpath
+ * XPath of the configuration node (can be NULL if 'dnode' is provided).
+ *
+ * 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 given configuration 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 *nb_running_get_entry(const struct lyd_node *dnode,
+ const char *xpath, bool abort_if_not_found);
+
+/*
+ * Same as 'nb_running_get_entry', but doesn't search within parent nodes
+ * recursively if an user point is not found.
+ */
+extern void *nb_running_get_entry_non_rec(const struct lyd_node *dnode,
+ const char *xpath,
+ bool abort_if_not_found);
+
+/*
+ * Return a human-readable string representing a northbound event.
+ *
+ * event
+ * Northbound event.
+ *
+ * Returns:
+ * String representation of the given northbound event.
+ */
+extern const char *nb_event_name(enum nb_event event);
+
+/*
+ * Return a human-readable string representing a northbound operation.
+ *
+ * operation
+ * Northbound operation.
+ *
+ * Returns:
+ * String representation of the given northbound operation.
+ */
+extern const char *nb_operation_name(enum nb_operation operation);
+
+/*
+ * Return a human-readable string representing a northbound error.
+ *
+ * error
+ * Northbound error.
+ *
+ * Returns:
+ * String representation of the given northbound error.
+ */
+extern const char *nb_err_name(enum nb_error error);
+
+/*
+ * Return a human-readable string representing a northbound client.
+ *
+ * client
+ * Northbound client.
+ *
+ * Returns:
+ * String representation of the given northbound client.
+ */
+extern const char *nb_client_name(enum nb_client client);
+
+/*
+ * Validate all northbound callbacks.
+ *
+ * Some errors, like missing callbacks or invalid priorities, are fatal and
+ * can't be recovered from. Other errors, like unneeded callbacks, are logged
+ * but otherwise ignored.
+ *
+ * Whenever a YANG module is loaded after startup, *all* northbound callbacks
+ * need to be validated and not only the callbacks from the newly loaded module.
+ * This is because augmentations can change the properties of the augmented
+ * module, making mandatory the implementation of additional callbacks.
+ */
+void nb_validate_callbacks(void);
+
+/*
+ * Initialize the northbound layer. Should be called only once during the
+ * daemon initialization process.
+ *
+ * modules
+ * Array of YANG modules to parse and initialize.
+ *
+ * nmodules
+ * Size of the modules array.
+ *
+ * db_enabled
+ * Set this to record the transactions in the transaction log.
+ */
+extern void nb_init(struct event_loop *tm,
+ const struct frr_yang_module_info *const modules[],
+ size_t nmodules, bool db_enabled);
+
+/*
+ * Finish the northbound layer gracefully. Should be called only when the daemon
+ * is exiting.
+ */
+extern void nb_terminate(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_NORTHBOUND_H_ */