mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-24 19:59:34 +00:00
lib: northbound: add basic oper-state update functions
Signed-off-by: Christian Hopps <chopps@labn.net>
This commit is contained in:
parent
bbebaa5d6b
commit
8a52b69ca4
@ -1744,6 +1744,68 @@ extern void nb_oper_init(struct event_loop *loop);
|
||||
extern void nb_oper_terminate(void);
|
||||
extern bool nb_oper_is_yang_lib_query(const char *xpath);
|
||||
|
||||
|
||||
/**
|
||||
* nb_op_update() - Create new state data.
|
||||
* @tree: subtree @path is relative to or NULL in which case @path must be
|
||||
* absolute.
|
||||
* @path: The path of the state node to create.
|
||||
* @value: The canonical value of the state.
|
||||
*
|
||||
* Return: The new libyang node.
|
||||
*/
|
||||
extern struct lyd_node *nb_op_update(struct lyd_node *tree, const char *path, const char *value);
|
||||
|
||||
/**
|
||||
* nb_op_update_delete() - Delete state data.
|
||||
* @tree: subtree @path is relative to or NULL in which case @path must be
|
||||
* absolute.
|
||||
* @path: The path of the state node to delete, or NULL if @tree should just be
|
||||
* deleted.
|
||||
*/
|
||||
extern void nb_op_update_delete(struct lyd_node *tree, const char *path);
|
||||
|
||||
/**
|
||||
* nb_op_update_pathf() - Create new state data.
|
||||
* @tree: subtree @path_fmt is relative to or NULL in which case @path_fmt must
|
||||
* be absolute.
|
||||
* @path_fmt: The path format string of the state node to create.
|
||||
* @value: The canonical value of the state.
|
||||
* @...: The values to substitute into @path_fmt.
|
||||
*
|
||||
* Return: The new libyang node.
|
||||
*/
|
||||
extern struct lyd_node *nb_op_update_pathf(struct lyd_node *tree, const char *path_fmt,
|
||||
const char *value, ...) PRINTFRR(2, 4);
|
||||
extern struct lyd_node *nb_op_update_vpathf(struct lyd_node *tree, const char *path_fmt,
|
||||
const char *value, va_list ap);
|
||||
/**
|
||||
* nb_op_update_delete_pathf() - Delete state data.
|
||||
* @tree: subtree @path_fmt is relative to or NULL in which case @path_fmt must
|
||||
* be absolute.
|
||||
* @path: The path of the state node to delete.
|
||||
* @...: The values to substitute into @path_fmt.
|
||||
*/
|
||||
extern void nb_op_update_delete_pathf(struct lyd_node *tree, const char *path_fmt, ...)
|
||||
PRINTFRR(2, 3);
|
||||
extern void nb_op_update_delete_vpathf(struct lyd_node *tree, const char *path_fmt, va_list ap);
|
||||
|
||||
/**
|
||||
* nb_op_updatef() - Create new state data.
|
||||
* @tree: subtree @path is relative to or NULL in which case @path must be
|
||||
* absolute.
|
||||
* @path: The path of the state node to create.
|
||||
* @val_fmt: The value format string to set the canonical value of the state.
|
||||
* @...: The values to substitute into @val_fmt.
|
||||
*
|
||||
* Return: The new libyang node.
|
||||
*/
|
||||
extern struct lyd_node *nb_op_updatef(struct lyd_node *tree, const char *path, const char *val_fmt,
|
||||
...) PRINTFRR(3, 4);
|
||||
|
||||
extern struct lyd_node *nb_op_vupdatef(struct lyd_node *tree, const char *path, const char *val_fmt,
|
||||
va_list ap);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
156
lib/northbound_notif.c
Normal file
156
lib/northbound_notif.c
Normal file
@ -0,0 +1,156 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* December 1 2024, Christian Hopps <chopps@labn.net>
|
||||
*
|
||||
* Copyright (c) 2024, LabN Consulting, L.L.C.
|
||||
*
|
||||
*/
|
||||
#include <zebra.h>
|
||||
#include "debug.h"
|
||||
#include "typesafe.h"
|
||||
#include "northbound.h"
|
||||
|
||||
#define __dbg(fmt, ...) DEBUGD(&nb_dbg_notif, "NB_OP_CHANGE: %s: " fmt, __func__, ##__VA_ARGS__)
|
||||
#define __log_err(fmt, ...) zlog_err("NB_OP_CHANGE: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
|
||||
|
||||
static void nb_notif_add(const char *path)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void nb_notif_delete(const char *path)
|
||||
{
|
||||
}
|
||||
|
||||
struct lyd_node *nb_op_update(struct lyd_node *tree, const char *path, const char *value)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
const char *abs_path = NULL;
|
||||
|
||||
|
||||
__dbg("updating path: %s with value: %s", path, value);
|
||||
|
||||
dnode = yang_state_new(tree, path, value);
|
||||
|
||||
if (path[0] == '/')
|
||||
abs_path = path;
|
||||
else {
|
||||
abs_path = lyd_path(dnode, LYD_PATH_STD, NULL, 0);
|
||||
}
|
||||
|
||||
nb_notif_add(abs_path);
|
||||
|
||||
if (abs_path != path)
|
||||
free((char *)abs_path);
|
||||
|
||||
return dnode;
|
||||
}
|
||||
|
||||
void nb_op_update_delete(struct lyd_node *tree, const char *path)
|
||||
{
|
||||
char *abs_path = NULL;
|
||||
|
||||
__dbg("deleting path: %s", path);
|
||||
|
||||
if (path && path[0] == '/')
|
||||
abs_path = (char *)path;
|
||||
else {
|
||||
assert(tree);
|
||||
abs_path = lyd_path(tree, LYD_PATH_STD, NULL, 0);
|
||||
assert(abs_path);
|
||||
if (path) {
|
||||
char *tmp = darr_strdup(abs_path);
|
||||
free(abs_path);
|
||||
abs_path = tmp;
|
||||
if (*darr_last(abs_path) != '/')
|
||||
darr_in_strcat(abs_path, "/");
|
||||
assert(abs_path); /* silence bad CLANG NULL warning */
|
||||
darr_in_strcat(abs_path, path);
|
||||
}
|
||||
}
|
||||
|
||||
yang_state_delete(tree, path);
|
||||
|
||||
nb_notif_delete(abs_path);
|
||||
|
||||
if (abs_path != path) {
|
||||
if (path)
|
||||
darr_free(abs_path);
|
||||
else
|
||||
free(abs_path);
|
||||
}
|
||||
}
|
||||
|
||||
PRINTFRR(2, 0)
|
||||
struct lyd_node *nb_op_update_vpathf(struct lyd_node *tree, const char *path_fmt, const char *value,
|
||||
va_list ap)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
char *path;
|
||||
|
||||
path = darr_vsprintf(path_fmt, ap);
|
||||
dnode = nb_op_update(tree, path, value);
|
||||
darr_free(path);
|
||||
|
||||
return dnode;
|
||||
}
|
||||
|
||||
struct lyd_node *nb_op_update_pathf(struct lyd_node *tree, const char *path_fmt, const char *value,
|
||||
...)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, value);
|
||||
dnode = nb_op_update_vpathf(tree, path_fmt, value, ap);
|
||||
va_end(ap);
|
||||
|
||||
return dnode;
|
||||
}
|
||||
|
||||
PRINTFRR(2, 0)
|
||||
void nb_op_update_delete_vpathf(struct lyd_node *tree, const char *path_fmt, va_list ap)
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = darr_vsprintf(path_fmt, ap);
|
||||
nb_op_update_delete(tree, path);
|
||||
darr_free(path);
|
||||
}
|
||||
|
||||
void nb_op_update_delete_pathf(struct lyd_node *tree, const char *path_fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, path_fmt);
|
||||
nb_op_update_delete_vpathf(tree, path_fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
PRINTFRR(3, 0)
|
||||
struct lyd_node *nb_op_vupdatef(struct lyd_node *tree, const char *path, const char *val_fmt,
|
||||
va_list ap)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
char *value;
|
||||
|
||||
value = darr_vsprintf(val_fmt, ap);
|
||||
dnode = nb_op_update(tree, path, value);
|
||||
darr_free(value);
|
||||
|
||||
return dnode;
|
||||
}
|
||||
|
||||
|
||||
struct lyd_node *nb_op_updatef(struct lyd_node *tree, const char *path, const char *val_fmt, ...)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, val_fmt);
|
||||
dnode = nb_op_vupdatef(tree, path, val_fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return dnode;
|
||||
}
|
@ -35,6 +35,7 @@
|
||||
* We must also process containers with lookup-next descendants last.
|
||||
*/
|
||||
|
||||
DEFINE_MTYPE_STATIC(LIB, NB_STATE, "Northbound State");
|
||||
DEFINE_MTYPE_STATIC(LIB, NB_YIELD_STATE, "NB Yield State");
|
||||
DEFINE_MTYPE_STATIC(LIB, NB_NODE_INFOS, "NB Node Infos");
|
||||
|
||||
|
@ -84,6 +84,7 @@ lib_libfrr_la_SOURCES = \
|
||||
lib/northbound.c \
|
||||
lib/northbound_cli.c \
|
||||
lib/northbound_db.c \
|
||||
lib/northbound_notif.c \
|
||||
lib/northbound_oper.c \
|
||||
lib/ntop.c \
|
||||
lib/openbsd-tree.c \
|
||||
|
111
lib/yang.c
111
lib/yang.c
@ -14,6 +14,7 @@
|
||||
#include <libyang/version.h>
|
||||
#include "northbound.h"
|
||||
#include "frrstr.h"
|
||||
#include "darr.h"
|
||||
|
||||
#include "lib/config_paths.h"
|
||||
|
||||
@ -680,6 +681,116 @@ void yang_dnode_rpc_output_add(struct lyd_node *output, const char *xpath,
|
||||
assert(err == LY_SUCCESS);
|
||||
}
|
||||
|
||||
struct lyd_node *yang_state_new(struct lyd_node *tree, const char *path, const char *value)
|
||||
{
|
||||
struct lyd_node *dnode, *parent;
|
||||
LY_ERR err;
|
||||
|
||||
err = lyd_new_path2(tree, ly_native_ctx, path, value, 0, 0, LYD_NEW_PATH_UPDATE, &parent,
|
||||
&dnode);
|
||||
assert(err == LY_SUCCESS);
|
||||
|
||||
/*
|
||||
* If the node exists and isn't updated returned dnode will be NULL, so
|
||||
* we need to find it. But even if returned it can be the first newly
|
||||
* created node (could be container of path) not the actual path dnode.
|
||||
* So we always find.
|
||||
*/
|
||||
err = lyd_find_path(tree ?: parent, path, false, &dnode);
|
||||
assert(err == LY_SUCCESS);
|
||||
|
||||
return dnode;
|
||||
}
|
||||
|
||||
void yang_state_delete(struct lyd_node *tree, const char *path)
|
||||
{
|
||||
LY_ERR err;
|
||||
|
||||
if (!tree)
|
||||
return;
|
||||
|
||||
if (path) {
|
||||
err = lyd_find_path(tree, path, false, &tree);
|
||||
if (err != LY_SUCCESS) {
|
||||
zlog_info("State %s has already been deleted", path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
lyd_free_tree(tree);
|
||||
}
|
||||
|
||||
PRINTFRR(2, 0)
|
||||
struct lyd_node *yang_state_new_vpathf(struct lyd_node *tree, const char *path_fmt,
|
||||
const char *value, va_list ap)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
char *path;
|
||||
|
||||
path = darr_vsprintf(path_fmt, ap);
|
||||
dnode = yang_state_new(tree, path, value);
|
||||
darr_free(path);
|
||||
|
||||
return dnode;
|
||||
}
|
||||
|
||||
struct lyd_node *yang_state_new_pathf(struct lyd_node *tree, const char *path_fmt,
|
||||
const char *value, ...)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, value);
|
||||
dnode = yang_state_new_vpathf(tree, path_fmt, value, ap);
|
||||
va_end(ap);
|
||||
|
||||
return dnode;
|
||||
}
|
||||
|
||||
PRINTFRR(2, 0)
|
||||
void yang_state_delete_vpathf(struct lyd_node *tree, const char *path_fmt, va_list ap)
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = darr_vsprintf(path_fmt, ap);
|
||||
yang_state_delete(tree, path);
|
||||
darr_free(path);
|
||||
}
|
||||
|
||||
void yang_state_delete_pathf(struct lyd_node *tree, const char *path_fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, path_fmt);
|
||||
yang_state_delete_vpathf(tree, path_fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
PRINTFRR(3, 0)
|
||||
struct lyd_node *yang_state_vnewf(struct lyd_node *tree, const char *path, const char *val_fmt,
|
||||
va_list ap)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
char *value;
|
||||
|
||||
value = darr_vsprintf(val_fmt, ap);
|
||||
dnode = yang_state_new(tree, path, value);
|
||||
darr_free(value);
|
||||
|
||||
return dnode;
|
||||
}
|
||||
|
||||
struct lyd_node *yang_state_newf(struct lyd_node *tree, const char *path, const char *val_fmt, ...)
|
||||
{
|
||||
struct lyd_node *dnode;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, val_fmt);
|
||||
dnode = yang_state_vnewf(tree, path, val_fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return dnode;
|
||||
}
|
||||
|
||||
struct yang_data *yang_data_new(const char *xpath, const char *value)
|
||||
{
|
||||
struct yang_data *data;
|
||||
|
60
lib/yang.h
60
lib/yang.h
@ -535,6 +535,66 @@ extern struct lyd_node *yang_dnode_dup(const struct lyd_node *dnode);
|
||||
*/
|
||||
extern void yang_dnode_free(struct lyd_node *dnode);
|
||||
|
||||
/**
|
||||
* yang_state_new() - Create new state data.
|
||||
* @tree: subtree @path is relative to or NULL in which case @path must be
|
||||
* absolute.
|
||||
* @path: The path of the state node to create.
|
||||
* @value: The canonical value of the state.
|
||||
*
|
||||
* Return: The new libyang node.
|
||||
*/
|
||||
extern struct lyd_node *yang_state_new(struct lyd_node *tree, const char *path, const char *value);
|
||||
|
||||
/**
|
||||
* yang_state_delete() - Delete state data.
|
||||
* @tree: subtree @path is relative to or NULL in which case @path must be
|
||||
* absolute.
|
||||
* @path: The path of the state node to delete, or NULL if @tree should just be
|
||||
* deleted.
|
||||
*/
|
||||
extern void yang_state_delete(struct lyd_node *tree, const char *path);
|
||||
|
||||
/**
|
||||
* yang_state_new_pathf() - Create new state data.
|
||||
* @tree: subtree @path_fmt is relative to or NULL in which case @path_fmt must
|
||||
* be absolute.
|
||||
* @path_fmt: The path format string of the state node to create.
|
||||
* @value: The canonical value of the state.
|
||||
* @...: The values to substitute into @path_fmt.
|
||||
*
|
||||
* Return: The new libyang node.
|
||||
*/
|
||||
extern struct lyd_node *yang_state_new_pathf(struct lyd_node *tree, const char *path_fmt,
|
||||
const char *value, ...) PRINTFRR(2, 4);
|
||||
extern struct lyd_node *yang_state_new_vpathf(struct lyd_node *tree, const char *path_fmt,
|
||||
const char *value, va_list ap);
|
||||
/**
|
||||
* yang_state_delete_pathf() - Delete state data.
|
||||
* @tree: subtree @path_fmt is relative to or NULL in which case @path_fmt must
|
||||
* be absolute.
|
||||
* @path: The path of the state node to delete.
|
||||
* @...: The values to substitute into @path_fmt.
|
||||
*/
|
||||
extern void yang_state_delete_pathf(struct lyd_node *tree, const char *path_fmt, ...) PRINTFRR(2, 3);
|
||||
extern void yang_state_delete_vpathf(struct lyd_node *tree, const char *path_fmt, va_list ap);
|
||||
|
||||
/**
|
||||
* yang_state_newf() - Create new state data.
|
||||
* @tree: subtree @path is relative to or NULL in which case @path must be
|
||||
* absolute.
|
||||
* @path: The path of the state node to create.
|
||||
* @val_fmt: The value format string to set the canonical value of the state.
|
||||
* @...: The values to substitute into @val_fmt.
|
||||
*
|
||||
* Return: The new libyang node.
|
||||
*/
|
||||
extern struct lyd_node *yang_state_newf(struct lyd_node *tree, const char *path,
|
||||
const char *val_fmt, ...) PRINTFRR(3, 4);
|
||||
|
||||
extern struct lyd_node *yang_state_vnewf(struct lyd_node *tree, const char *path,
|
||||
const char *val_fmt, va_list ap);
|
||||
|
||||
/*
|
||||
* Add a libyang data node to an RPC/action output container.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user