]> git.puffer.fish Git - mirror/frr.git/commitdiff
tools: add config-write callbacks to nb templates
authorMark Stapp <mjs@labn.net>
Thu, 9 Nov 2023 15:26:06 +0000 (10:26 -0500)
committerMark Stapp <mjs@labn.net>
Tue, 30 Jan 2024 13:09:25 +0000 (08:09 -0500)
Add the cli_show (config write) callback when emitting the
create or modify callback in the northbound template. Split
the config-handling and config-output callbacks into two
structs/arrays; this seems to be helpful when doing mgmtd
conversion.

Signed-off-by: Mark Stapp <mjs@labn.net>
tools/gen_northbound_callbacks.c

index 618855901017713a44b6dfa4529217ae156b46b6..a8798113635768af170c9e954b8bbdf627fc8faa 100644 (file)
@@ -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",
@@ -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;
@@ -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:
@@ -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;
@@ -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:
@@ -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;
@@ -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:
@@ -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) {
@@ -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) {
@@ -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");
@@ -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");