summaryrefslogtreecommitdiffstats
path: root/tools/gen_northbound_callbacks.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gen_northbound_callbacks.c')
-rw-r--r--tools/gen_northbound_callbacks.c217
1 files changed, 179 insertions, 38 deletions
diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c
index 5b778a1..a879811 100644
--- a/tools/gen_northbound_callbacks.c
+++ b/tools/gen_northbound_callbacks.c
@@ -7,6 +7,7 @@
#define REALLY_NEED_PLAIN_GETOPT 1
#include <zebra.h>
+#include <sys/stat.h>
#include <unistd.h>
@@ -25,67 +26,70 @@ 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_OP_CREATE,
+ .operation = NB_CB_CREATE,
+ .need_config_write = true,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_create_args *args",
},
{
- .operation = NB_OP_MODIFY,
+ .operation = NB_CB_MODIFY,
+ .need_config_write = true,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_modify_args *args",
},
{
- .operation = NB_OP_DESTROY,
+ .operation = NB_CB_DESTROY,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_destroy_args *args",
},
{
- .operation = NB_OP_MOVE,
+ .operation = NB_CB_MOVE,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_move_args *args",
},
{
- .operation = NB_OP_APPLY_FINISH,
+ .operation = NB_CB_APPLY_FINISH,
.optional = true,
.return_type = "void ",
.return_value = "",
.arguments = "struct nb_cb_apply_finish_args *args",
},
{
- .operation = NB_OP_GET_ELEM,
+ .operation = NB_CB_GET_ELEM,
.return_type = "struct yang_data *",
.return_value = "NULL",
.arguments = "struct nb_cb_get_elem_args *args",
},
{
- .operation = NB_OP_GET_NEXT,
+ .operation = NB_CB_GET_NEXT,
.return_type = "const void *",
.return_value = "NULL",
.arguments = "struct nb_cb_get_next_args *args",
},
{
- .operation = NB_OP_GET_KEYS,
+ .operation = NB_CB_GET_KEYS,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_get_keys_args *args",
},
{
- .operation = NB_OP_LOOKUP_ENTRY,
+ .operation = NB_CB_LOOKUP_ENTRY,
.return_type = "const void *",
.return_value = "NULL",
.arguments = "struct nb_cb_lookup_entry_args *args",
},
{
- .operation = NB_OP_RPC,
+ .operation = NB_CB_RPC,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_rpc_args *args",
@@ -96,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;
@@ -106,7 +120,7 @@ static void replace_hyphens_by_underscores(char *str)
}
static void generate_callback_name(const struct lysc_node *snode,
- enum nb_operation operation, char *buffer,
+ enum nb_cb_operation operation, char *buffer,
size_t size)
{
struct list *snodes;
@@ -128,7 +142,38 @@ static void generate_callback_name(const struct lysc_node *snode,
strlcat(buffer, snode->name, size);
strlcat(buffer, "_", size);
}
- strlcat(buffer, nb_operation_name(operation), size);
+ strlcat(buffer, nb_cb_operation_name(operation), size);
+ list_delete(&snodes);
+
+ 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);
@@ -140,8 +185,16 @@ static void generate_prototype(const struct nb_callback_info *ncinfo,
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:
@@ -159,12 +212,21 @@ static int generate_prototypes(const struct lysc_node *snode, void *arg)
char cb_name[BUFSIZ];
if (cb->optional
- || !nb_operation_is_valid(cb->operation, snode))
+ || !nb_cb_operation_is_valid(cb->operation, snode))
continue;
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;
@@ -177,10 +239,10 @@ static void generate_callback(const struct nb_callback_info *ncinfo,
ncinfo->return_type, cb_name, ncinfo->arguments);
switch (ncinfo->operation) {
- case NB_OP_CREATE:
- case NB_OP_MODIFY:
- case NB_OP_DESTROY:
- case NB_OP_MOVE:
+ case NB_CB_CREATE:
+ case NB_CB_MODIFY:
+ case NB_CB_DESTROY:
+ case NB_CB_MOVE:
printf("\tswitch (args->event) {\n"
"\tcase NB_EV_VALIDATE:\n"
"\tcase NB_EV_PREPARE:\n"
@@ -200,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:
@@ -221,7 +296,7 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg)
char cb_name[BUFSIZ];
if (cb->optional
- || !nb_operation_is_valid(cb->operation, snode))
+ || !nb_cb_operation_is_valid(cb->operation, snode))
continue;
if (first) {
@@ -240,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;
@@ -248,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:
@@ -261,31 +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_operation_is_valid(cb->operation, snode))
+ || !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_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) {
@@ -303,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) {
@@ -348,13 +459,18 @@ int main(int argc, char *argv[])
module = yang_module_find(argv[0]);
if (!module)
/* Non-native FRR module (e.g. modules from unit tests). */
- module = yang_module_load(argv[0]);
+ module = yang_module_load(argv[0], NULL);
yang_init_loading_complete();
/* 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");
@@ -369,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");