Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tools, vtysh: add the cli write callback, unhide an NB show command #14764

Merged
merged 3 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/user/basic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,11 @@ Terminal Mode Commands
This command displays FRR's timer data for timers that will pop in
the future.

.. clicmd:: show configuration running [<json|xml> [translate WORD]] [with-defaults] DAEMON

This command displays the northbound/YANG configuration data for a
daemon in text/vty, json, or xml format.

.. clicmd:: show yang operational-data XPATH [{format <json|xml>|translate TRANSLATOR|with-config}] DAEMON

Display the YANG operational data starting from XPATH. The default
Expand Down
177 changes: 158 additions & 19 deletions tools/gen_northbound_callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,21 @@ static void __attribute__((noreturn)) usage(int status)
static struct nb_callback_info {
int operation;
bool optional;
bool need_config_write;
char return_type[32];
char return_value[32];
char arguments[128];
} nb_callbacks[] = {
{
.operation = NB_CB_CREATE,
.need_config_write = true,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_create_args *args",
},
{
.operation = NB_CB_MODIFY,
.need_config_write = true,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_modify_args *args",
Expand Down Expand Up @@ -97,6 +100,16 @@ static struct nb_callback_info {
},
};

/*
* Special-purpose info block for the cli-config-write callback. This
* is different enough from the config-oriented callbacks that it doesn't
* really fit in the array above.
*/
static struct nb_callback_info nb_config_write = {
.return_type = "void ",
.arguments = "struct vty *vty, const struct lyd_node *dnode, bool show_defaults",
};

static void replace_hyphens_by_underscores(char *str)
{
char *p;
Expand Down Expand Up @@ -135,14 +148,53 @@ static void generate_callback_name(const struct lysc_node *snode,
replace_hyphens_by_underscores(buffer);
}

static void generate_config_write_cb_name(const struct lysc_node *snode,
char *buffer, size_t size)
{
struct list *snodes;
struct listnode *ln;

buffer[0] = '\0';

snodes = list_new();
for (; snode; snode = snode->parent) {
/* Skip schema-only snodes. */
if (CHECK_FLAG(snode->nodetype, LYS_USES | LYS_CHOICE | LYS_CASE
| LYS_INPUT
| LYS_OUTPUT))
continue;

listnode_add_head(snodes, (void *)snode);
}

for (ALL_LIST_ELEMENTS_RO(snodes, ln, snode)) {
strlcat(buffer, snode->name, size);
strlcat(buffer, "_", size);
}

strlcat(buffer, "cli_write", size);

list_delete(&snodes);

replace_hyphens_by_underscores(buffer);
}

static void generate_prototype(const struct nb_callback_info *ncinfo,
const char *cb_name)
{
printf("%s%s(%s);\n", ncinfo->return_type, cb_name, ncinfo->arguments);
}

static void generate_config_write_prototype(const struct nb_callback_info *ncinfo,
const char *cb_name)
{
printf("%s%s(%s);\n", ncinfo->return_type, cb_name, ncinfo->arguments);
}

static int generate_prototypes(const struct lysc_node *snode, void *arg)
{
bool need_config_write = true;

switch (snode->nodetype) {
case LYS_CONTAINER:
case LYS_LEAF:
Expand All @@ -166,6 +218,15 @@ static int generate_prototypes(const struct lysc_node *snode, void *arg)
generate_callback_name(snode, cb->operation, cb_name,
sizeof(cb_name));
generate_prototype(cb, cb_name);

if (cb->need_config_write && need_config_write) {
generate_config_write_cb_name(snode, cb_name,
sizeof(cb_name));
generate_config_write_prototype(&nb_config_write,
cb_name);

need_config_write = false;
}
}

return YANG_ITER_CONTINUE;
Expand Down Expand Up @@ -201,9 +262,22 @@ static void generate_callback(const struct nb_callback_info *ncinfo,
printf("\treturn %s;\n}\n\n", ncinfo->return_value);
}

static void generate_config_write_callback(const struct nb_callback_info *ncinfo,
const char *cb_name)
{
printf("%s%s%s(%s)\n{\n", static_cbs ? "static " : "",
ncinfo->return_type, cb_name, ncinfo->arguments);

/* Add a comment, since these callbacks may not all be needed. */
printf("\t/* TODO: this cli callback is optional; the cli output may not need to be done at each node. */\n");

printf("}\n\n");
}

static int generate_callbacks(const struct lysc_node *snode, void *arg)
{
bool first = true;
bool need_config_write = true;

switch (snode->nodetype) {
case LYS_CONTAINER:
Expand Down Expand Up @@ -241,6 +315,15 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg)
generate_callback_name(snode, cb->operation, cb_name,
sizeof(cb_name));
generate_callback(cb, cb_name);

if (cb->need_config_write && need_config_write) {
generate_config_write_cb_name(snode, cb_name,
sizeof(cb_name));
generate_config_write_callback(&nb_config_write,
cb_name);

need_config_write = false;
}
}

return YANG_ITER_CONTINUE;
Expand All @@ -249,6 +332,10 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg)
static int generate_nb_nodes(const struct lysc_node *snode, void *arg)
{
bool first = true;
char cb_name[BUFSIZ];
char xpath[XPATH_MAXLEN];
bool config_pass = *(bool *)arg;
bool need_config_write = true;

switch (snode->nodetype) {
case LYS_CONTAINER:
Expand All @@ -262,32 +349,53 @@ static int generate_nb_nodes(const struct lysc_node *snode, void *arg)
return YANG_ITER_CONTINUE;
}

/* We generate two types of structs currently; behavior is a little
* different between the types.
*/
for (struct nb_callback_info *cb = &nb_callbacks[0];
cb->operation != -1; cb++) {
char cb_name[BUFSIZ];

if (cb->optional
|| !nb_cb_operation_is_valid(cb->operation, snode))
continue;

if (first) {
char xpath[XPATH_MAXLEN];
if (config_pass) {
if (first) {
yang_snode_get_path(snode, YANG_PATH_DATA, xpath,
sizeof(xpath));

yang_snode_get_path(snode, YANG_PATH_DATA, xpath,
sizeof(xpath));
printf("\t\t{\n"
"\t\t\t.xpath = \"%s\",\n",
xpath);
printf("\t\t\t.cbs = {\n");
first = false;
}

printf("\t\t{\n"
"\t\t\t.xpath = \"%s\",\n",
xpath);
printf("\t\t\t.cbs = {\n");
first = false;
}
generate_callback_name(snode, cb->operation, cb_name,
sizeof(cb_name));
printf("\t\t\t\t.%s = %s,\n",
nb_cb_operation_name(cb->operation),
cb_name);
} else if (cb->need_config_write && need_config_write) {
if (first) {
yang_snode_get_path(snode,
YANG_PATH_DATA,
xpath,
sizeof(xpath));

printf("\t\t{\n"
"\t\t\t.xpath = \"%s\",\n",
xpath);
printf("\t\t\t.cbs = {\n");
first = false;
}

generate_callback_name(snode, cb->operation, cb_name,
sizeof(cb_name));
printf("\t\t\t\t.%s = %s,\n",
nb_cb_operation_name(cb->operation),
cb_name);
generate_config_write_cb_name(snode, cb_name,
sizeof(cb_name));
printf("\t\t\t\t.cli_show = %s,\n", cb_name);

need_config_write = false;
}
}

if (!first) {
Expand All @@ -305,6 +413,7 @@ int main(int argc, char *argv[])
char module_name_underscores[64];
struct stat st;
int opt;
bool config_pass;

while ((opt = getopt(argc, argv, "hp:s")) != -1) {
switch (opt) {
Expand Down Expand Up @@ -357,6 +466,11 @@ int main(int argc, char *argv[])
/* Create a nb_node for all YANG schema nodes. */
nb_nodes_create();

/* Emit bare-bones license line (and fool the checkpatch regex
* that triggers a warning).
*/
printf("// SPDX-" "License-Identifier: GPL-2.0-or-later\n\n");

/* Generate callback prototypes. */
if (!static_cbs) {
printf("/* prototypes */\n");
Expand All @@ -371,13 +485,38 @@ int main(int argc, char *argv[])
sizeof(module_name_underscores));
replace_hyphens_by_underscores(module_name_underscores);

/* Generate frr_yang_module_info array. */
/*
* We're going to generate two structs here, two arrays of callbacks:
* first one with config-handling callbacks, then a second struct with
* config-output-oriented callbacks.
*/

/* Generate frr_yang_module_info array, with config-handling callbacks */
config_pass = true;
printf("/* clang-format off */\n"
"const struct frr_yang_module_info %s_info = {\n"
"const struct frr_yang_module_info %s_nb_info = {\n"
"\t.name = \"%s\",\n"
"\t.nodes = {\n",
module_name_underscores, module->name);
yang_snodes_iterate(module->info, generate_nb_nodes, 0, NULL);
yang_snodes_iterate(module->info, generate_nb_nodes, 0, &config_pass);

/* Emit terminator element */
printf("\t\t{\n"
"\t\t\t.xpath = NULL,\n"
"\t\t},\n");
printf("\t}\n"
"};\n");

/* Generate second array, with output-oriented callbacks. */
config_pass = false;
printf("\n/* clang-format off */\n"
"const struct frr_yang_module_info %s_cli_info = {\n"
"\t.name = \"%s\",\n"
"\t.nodes = {\n",
module_name_underscores, module->name);
yang_snodes_iterate(module->info, generate_nb_nodes, 0, &config_pass);

/* Emit terminator element */
printf("\t\t{\n"
"\t\t\t.xpath = NULL,\n"
"\t\t},\n");
Expand Down
2 changes: 1 addition & 1 deletion vtysh/vtysh.c
Original file line number Diff line number Diff line change
Expand Up @@ -3120,7 +3120,7 @@ DEFUN (vtysh_show_error_code,
}

/* Northbound. */
DEFUN_HIDDEN (show_config_running,
DEFUN (show_config_running,
show_config_running_cmd,
"show configuration running\
[<json|xml> [translate WORD]]\
Expand Down
Loading