From 634aa8253ea224d094f4a0aab01126cbd79c811e Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Mon, 22 Mar 2021 19:29:50 +0300 Subject: [PATCH 1/5] lib: simplify nb_cli_show_dnode_cmds Signed-off-by: Igor Ryzhov --- lib/northbound_cli.c | 75 +++++++++++--------------------------------- 1 file changed, 19 insertions(+), 56 deletions(-) diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index a2c8bc8633..efb8877488 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -529,25 +529,6 @@ static int nb_cli_candidate_load_transaction(struct vty *vty, return CMD_SUCCESS; } -/* - * ly_iter_next_is_up: detects when iterating up on the yang model. - * - * This function detects whether next node in the iteration is upwards, - * then return the node otherwise return NULL. - */ -static struct lyd_node *ly_iter_next_up(const struct lyd_node *elem) -{ - /* Are we going downwards? Is this still not a leaf? */ - if (!(elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) - return NULL; - - /* Are there still leaves in this branch? */ - if (elem->next != NULL) - return NULL; - - return elem->parent; -} - /* Prepare the configuration for display. */ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults) { @@ -569,51 +550,33 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults) ly_native_ctx); } +static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root, + bool with_defaults) +{ + struct lyd_node *child; + + LY_TREE_FOR (root->child, child) + nb_cli_show_dnode_cmds(vty, child, with_defaults); +} + void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root, bool with_defaults) { - struct lyd_node *next, *child, *parent; + struct nb_node *nb_node; - LY_TREE_DFS_BEGIN (root, next, child) { - struct nb_node *nb_node; + if (!with_defaults && yang_dnode_is_default_recursive(root)) + return; - nb_node = child->schema->priv; - if (!nb_node || !nb_node->cbs.cli_show) - goto next; + nb_node = root->schema->priv; - /* Skip default values. */ - if (!with_defaults && yang_dnode_is_default_recursive(child)) - goto next; + if (nb_node && nb_node->cbs.cli_show) + (*nb_node->cbs.cli_show)(vty, root, with_defaults); - (*nb_node->cbs.cli_show)(vty, child, with_defaults); - next: - /* - * When transiting upwards in the yang model we should - * give the previous container/list node a chance to - * print its close vty output (e.g. "!" or "end-family" - * etc...). - */ - parent = ly_iter_next_up(child); - if (parent != NULL) { - nb_node = parent->schema->priv; - if (nb_node && nb_node->cbs.cli_show_end) - (*nb_node->cbs.cli_show_end)(vty, parent); - } + if (!(root->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) + show_dnode_children_cmds(vty, root, with_defaults); - /* - * There is a possible path in this macro that ends up - * dereferencing child->parent->parent. We just null checked - * child->parent by checking (ly_iter_next_up(child) != NULL) - * above. - * - * I am not sure whether it is possible for the other - * conditions within this macro guarding the problem - * dereference to be satisfied when child->parent == NULL. - */ -#ifndef __clang_analyzer__ - LY_TREE_DFS_END(root, next, child); -#endif - } + if (nb_node && nb_node->cbs.cli_show_end) + (*nb_node->cbs.cli_show_end)(vty, root); } static void nb_cli_show_config_cmds(struct vty *vty, struct nb_config *config, From c6f1f711bf885a6d110d22ebe8c647c5ff95c688 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Tue, 23 Mar 2021 16:16:01 +0300 Subject: [PATCH 2/5] lib: add ability to sort CLI commands printed by NB layer Signed-off-by: Igor Ryzhov --- lib/northbound.h | 17 ++++++++++++++++ lib/northbound_cli.c | 47 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/lib/northbound.h b/lib/northbound.h index 21aad64a09..417ecc81ea 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -473,6 +473,23 @@ struct nb_callbacks { */ int (*rpc)(struct nb_cb_rpc_args *args); + /* + * Optional callback to compare the data nodes when printing + * the CLI commands associated with them. + * + * dnode1 + * The first data node to compare. + * + * dnode2 + * The second data node to compare. + * + * Returns: + * <0 when the CLI command for the dnode1 should be printed first + * >0 when the CLI command for the dnode2 should be printed first + * 0 when there is no difference + */ + int (*cli_cmp)(struct lyd_node *dnode1, struct lyd_node *dnode2); + /* * Optional callback to show the CLI command associated to the given * YANG data node. diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index efb8877488..f88c2161da 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -553,10 +553,55 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults) static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root, bool with_defaults) { + struct nb_node *nb_node, *sort_node = NULL; + struct listnode *listnode; struct lyd_node *child; + struct list *sort_list; + void *data; + + LY_TREE_FOR (root->child, child) { + nb_node = child->schema->priv; + + /* + * We finished processing current list, + * it's time to print the config. + */ + if (sort_node && nb_node != sort_node) { + for (ALL_LIST_ELEMENTS_RO(sort_list, listnode, data)) + nb_cli_show_dnode_cmds(vty, data, + with_defaults); + + list_delete(&sort_list); + sort_node = NULL; + } + + /* + * If the config needs to be sorted, + * then add the dnode to the sorting + * list for later processing. + */ + if (nb_node && nb_node->cbs.cli_cmp) { + if (!sort_node) { + sort_node = nb_node; + sort_list = list_new(); + sort_list->cmp = (int (*)(void *, void *)) + nb_node->cbs.cli_cmp; + } + + listnode_add_sort(sort_list, child); + continue; + } - LY_TREE_FOR (root->child, child) nb_cli_show_dnode_cmds(vty, child, with_defaults); + } + + if (sort_node) { + for (ALL_LIST_ELEMENTS_RO(sort_list, listnode, data)) + nb_cli_show_dnode_cmds(vty, data, with_defaults); + + list_delete(&sort_list); + sort_node = NULL; + } } void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root, From de8936be5e298103160ce6862e5a94d108c80ec7 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Mon, 22 Mar 2021 23:24:23 +0300 Subject: [PATCH 3/5] lib: sort route-map commands by sequence number in running-config Signed-off-by: Igor Ryzhov --- lib/routemap.h | 2 ++ lib/routemap_cli.c | 8 ++++++++ lib/routemap_northbound.c | 1 + 3 files changed, 11 insertions(+) diff --git a/lib/routemap.h b/lib/routemap.h index bad3ca6d3d..f1791405db 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -694,6 +694,8 @@ void routemap_hook_context_free(struct routemap_hook_context *rhc); extern const struct frr_yang_module_info frr_route_map_info; /* routemap_cli.c */ +extern int route_map_instance_cmp(struct lyd_node *dnode1, + struct lyd_node *dnode2); extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); extern void route_map_instance_show_end(struct vty *vty, diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 339d025124..bf61e10fe4 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -113,6 +113,14 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } +int route_map_instance_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +{ + uint16_t seq1 = yang_dnode_get_uint16(dnode1, "./sequence"); + uint16_t seq2 = yang_dnode_get_uint16(dnode2, "./sequence"); + + return seq1 - seq2; +} + void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 597a6b1ecf..8546284c3e 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -1140,6 +1140,7 @@ const struct frr_yang_module_info frr_route_map_info = { .cbs = { .create = lib_route_map_entry_create, .destroy = lib_route_map_entry_destroy, + .cli_cmp = route_map_instance_cmp, .cli_show = route_map_instance_show, .cli_show_end = route_map_instance_show_end, } From ae253f502eff939c52a9b2a2993962754804bbdb Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Mon, 22 Mar 2021 23:25:05 +0300 Subject: [PATCH 4/5] lib: sort access-list commands by sequence-number in running-config Signed-off-by: Igor Ryzhov --- lib/filter.h | 1 + lib/filter_cli.c | 8 ++++++++ lib/filter_nb.c | 1 + 3 files changed, 10 insertions(+) diff --git a/lib/filter.h b/lib/filter.h index 091a5197f6..d5a7e7d5e2 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -234,6 +234,7 @@ bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda); struct lyd_node; struct vty; +extern int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); extern void access_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); extern void access_list_remark_show(struct vty *vty, struct lyd_node *dnode, diff --git a/lib/filter_cli.c b/lib/filter_cli.c index 5d66a9fc73..fd20ffc36e 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -1072,6 +1072,14 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) +int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +{ + uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence"); + uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence"); + + return seq1 - seq2; +} + void access_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { diff --git a/lib/filter_nb.c b/lib/filter_nb.c index c83738e729..717c56ee7c 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -1567,6 +1567,7 @@ const struct frr_yang_module_info frr_filter_info = { .cbs = { .create = lib_access_list_entry_create, .destroy = lib_access_list_entry_destroy, + .cli_cmp = access_list_cmp, .cli_show = access_list_show, } }, From 73695730f55a25cae086cec02c29482f8d296739 Mon Sep 17 00:00:00 2001 From: Igor Ryzhov Date: Mon, 22 Mar 2021 23:25:28 +0300 Subject: [PATCH 5/5] lib: sort prefix-list commands by sequence-number in running-config Signed-off-by: Igor Ryzhov --- lib/filter.h | 1 + lib/filter_cli.c | 8 ++++++++ lib/filter_nb.c | 1 + 3 files changed, 10 insertions(+) diff --git a/lib/filter.h b/lib/filter.h index d5a7e7d5e2..c7108b26ba 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -239,6 +239,7 @@ extern void access_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); extern void access_list_remark_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +extern int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); extern void prefix_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); extern void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode, diff --git a/lib/filter_cli.c b/lib/filter_cli.c index fd20ffc36e..893981ffab 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -1701,6 +1701,14 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) +int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +{ + uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence"); + uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence"); + + return seq1 - seq2; +} + void prefix_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { diff --git a/lib/filter_nb.c b/lib/filter_nb.c index 717c56ee7c..3c05f10750 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -1691,6 +1691,7 @@ const struct frr_yang_module_info frr_filter_info = { .cbs = { .create = lib_prefix_list_entry_create, .destroy = lib_prefix_list_entry_destroy, + .cli_cmp = prefix_list_cmp, .cli_show = prefix_list_show, } },