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",
},
};
+/*
+ * 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;
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:
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;
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:
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;
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:
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) {
char module_name_underscores[64];
struct stat st;
int opt;
+ bool config_pass;
while ((opt = getopt(argc, argv, "hp:s")) != -1) {
switch (opt) {
/* 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");
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");