Skip to content

Commit

Permalink
Merge pull request #14764 from mjstapp/nb_gen_tool
Browse files Browse the repository at this point in the history
tools, vtysh: add the cli write callback, unhide an NB show command
  • Loading branch information
idryzhov authored Jan 30, 2024
2 parents 61aa468 + 55f6d01 commit 2a572ba
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 20 deletions.
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

0 comments on commit 2a572ba

Please sign in to comment.