summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2021-03-30 10:37:31 -0400
committerGitHub <noreply@github.com>2021-03-30 10:37:31 -0400
commitfb7c845e0d94dba9341dbefdddb3b592a4221e45 (patch)
tree2f63b1ab1d2ec003f01a70e18a3e9506a1ec1e67
parent1bed7a6fef0bb50c9f7e5b42ae59578336620102 (diff)
parent73695730f55a25cae086cec02c29482f8d296739 (diff)
Merge pull request #8311 from idryzhov/nb-sorting
Sort route-maps/access-lists/prefix-lists by sequence number in running-config
-rw-r--r--lib/filter.h2
-rw-r--r--lib/filter_cli.c16
-rw-r--r--lib/filter_nb.c2
-rw-r--r--lib/northbound.h17
-rw-r--r--lib/northbound_cli.c114
-rw-r--r--lib/routemap.h2
-rw-r--r--lib/routemap_cli.c8
-rw-r--r--lib/routemap_northbound.c1
8 files changed, 109 insertions, 53 deletions
diff --git a/lib/filter.h b/lib/filter.h
index b1bf1d67ba..28f5202022 100644
--- a/lib/filter.h
+++ b/lib/filter.h
@@ -240,10 +240,12 @@ 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,
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 24980f7858..96444ac970 100644
--- a/lib/filter_cli.c
+++ b/lib/filter_cli.c
@@ -1077,6 +1077,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)
{
@@ -1700,6 +1708,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 3b650742f3..3aa362ad63 100644
--- a/lib/filter_nb.c
+++ b/lib/filter_nb.c
@@ -1665,6 +1665,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,
}
},
@@ -1788,6 +1789,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,
}
},
diff --git a/lib/northbound.h b/lib/northbound.h
index 21aad64a09..417ecc81ea 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -474,6 +474,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 a2c8bc8633..f88c2161da 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,53 +550,80 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults)
ly_native_ctx);
}
-void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
- bool with_defaults)
+static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root,
+ bool with_defaults)
{
- struct lyd_node *next, *child, *parent;
-
- LY_TREE_DFS_BEGIN (root, next, child) {
- struct nb_node *nb_node;
+ 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;
- if (!nb_node || !nb_node->cbs.cli_show)
- goto next;
- /* Skip default values. */
- if (!with_defaults && yang_dnode_is_default_recursive(child))
- goto next;
-
- (*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...).
+ * We finished processing current list,
+ * it's time to print the config.
*/
- 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 (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;
}
/*
- * 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.
+ * If the config needs to be sorted,
+ * then add the dnode to the sorting
+ * list for later processing.
*/
-#ifndef __clang_analyzer__
- LY_TREE_DFS_END(root, next, child);
-#endif
+ 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;
+ }
+
+ 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,
+ bool with_defaults)
+{
+ struct nb_node *nb_node;
+
+ if (!with_defaults && yang_dnode_is_default_recursive(root))
+ return;
+
+ nb_node = root->schema->priv;
+
+ if (nb_node && nb_node->cbs.cli_show)
+ (*nb_node->cbs.cli_show)(vty, root, with_defaults);
+
+ if (!(root->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)))
+ show_dnode_children_cmds(vty, root, with_defaults);
+
+ 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,
bool with_defaults)
{
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,
}