]> git.puffer.fish Git - matthieu/frr.git/commitdiff
staticd : Configuration northbound implementation
authorvdhingra <vdhingra@vmware.com>
Fri, 24 Apr 2020 12:38:43 +0000 (05:38 -0700)
committervdhingra <vdhingra@vmware.com>
Thu, 16 Jul 2020 15:33:00 +0000 (08:33 -0700)
1. Modifies the data structs to make the distance, tag and table-id
   property of a route, i.e created a hireachical data struct to save
   route and nexthop information.
2. Backend northbound implementation

Signed-off-by: VishalDhingra <vdhingra@vmware.com>
19 files changed:
lib/routing_nb.c
lib/srcdest_table.c
lib/srcdest_table.h
staticd/static_main.c
staticd/static_memory.c
staticd/static_memory.h
staticd/static_nb.c [new file with mode: 0644]
staticd/static_nb.h [new file with mode: 0644]
staticd/static_nb_config.c [new file with mode: 0644]
staticd/static_nht.c
staticd/static_routes.c
staticd/static_routes.h
staticd/static_vrf.c
staticd/static_vrf.h
staticd/static_vty.c
staticd/static_vty.h
staticd/static_zebra.c
staticd/static_zebra.h
staticd/subdir.am

index 7a6754baa7164de9cbc4515129d8966ff4753665..0160354a7e07e63913890cae7fa4e46e4f8300f3 100644 (file)
@@ -1,3 +1,21 @@
+/*
+ * Copyright (C) 2018        Vmware
+ *                           Vishal Dhingra
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
 #include "northbound.h"
 #include "libfrr.h"
 #include "routing_nb.h"
index 66b735919b892e1f0e147d7906ce0f964c299d8b..8ffa0e97094b7094aecb6b71f05c87eb965eec21 100644 (file)
@@ -317,3 +317,13 @@ static ssize_t printfrr_rn(char *buf, size_t bsz, const char *fmt,
        srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, buf, bsz);
        return 2;
 }
+
+struct route_table *srcdest_srcnode_table(struct route_node *rn)
+{
+       if (rnode_is_dstnode(rn)) {
+               struct srcdest_rnode *srn = srcdest_rnode_from_rnode(rn);
+
+               return srn->src_table;
+       }
+       return NULL;
+}
index 798226077758b5d438d6d8c615d92dbdd6a571a0..79afef9bb088fccd9b59bb164949f92c73958c06 100644 (file)
@@ -100,6 +100,8 @@ static inline void *srcdest_rnode_table_info(struct route_node *rn)
        return route_table_get_info(srcdest_rnode_table(rn));
 }
 
+extern struct route_table *srcdest_srcnode_table(struct route_node *rn);
+
 #ifdef __cplusplus
 }
 #endif
index 3c5922b85a4690954fc7405a284c8e59fd7ce253..0b5063a083d083ff3ce9523ffc1a3c06edd0690c 100644 (file)
 #include "vrf.h"
 #include "nexthop.h"
 #include "filter.h"
+#include "routing_nb.h"
 
 #include "static_vrf.h"
 #include "static_vty.h"
 #include "static_routes.h"
 #include "static_zebra.h"
 #include "static_debug.h"
+#include "static_nb.h"
 
 char backup_config_file[256];
 
@@ -63,10 +65,12 @@ struct option longopts[] = { { 0 } };
 /* Master of threads. */
 struct thread_master *master;
 
+static struct frr_daemon_info staticd_di;
 /* SIGHUP handler. */
 static void sighup(void)
 {
        zlog_info("SIGHUP received");
+       vty_read_config(NULL, staticd_di.config_file, config_default);
 }
 
 /* SIGINT / SIGTERM handler. */
@@ -108,7 +112,10 @@ struct quagga_signal_t static_signals[] = {
 
 static const struct frr_yang_module_info *const staticd_yang_modules[] = {
        &frr_filter_info,
+       &frr_interface_info,
        &frr_vrf_info,
+       &frr_routing_info,
+       &frr_staticd_info,
 };
 
 #define STATIC_VTY_PORT 2616
@@ -155,6 +162,9 @@ int main(int argc, char **argv, char **envp)
        static_zebra_init();
        static_vty_init();
 
+       hook_register(routing_conf_event,
+                     routing_control_plane_protocols_name_validate);
+
        snprintf(backup_config_file, sizeof(backup_config_file),
                 "%s/zebra.conf", frr_sysconfdir);
        staticd_di.backup_config_file = backup_config_file;
index 77ca4a34396d661595546d79811014975d75b5de..122cc9fce134a01acc29272c2ebae339203b426c 100644 (file)
@@ -25,4 +25,4 @@
 
 DEFINE_MGROUP(STATIC, "staticd")
 
-DEFINE_MTYPE(STATIC, STATIC_ROUTE, "Static Route");
+DEFINE_MTYPE(STATIC, STATIC_NEXTHOP, "Static Nexthop");
index 77a0db3b123ac09077f601901d75ba4b007aa400..e9cc7ba4691672e9112557c2c8fda6417f7db835 100644 (file)
@@ -23,6 +23,7 @@
 
 DECLARE_MGROUP(STATIC)
 
-DECLARE_MTYPE(STATIC_ROUTE);
+DECLARE_MTYPE(STATIC_NEXTHOP);
+DECLARE_MTYPE(STATIC_PATH);
 
 #endif
diff --git a/staticd/static_nb.c b/staticd/static_nb.c
new file mode 100644 (file)
index 0000000..419a6a5
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2018        Vmware
+ *                           Vishal Dhingra
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "northbound.h"
+#include "libfrr.h"
+#include "static_nb.h"
+
+
+/* clang-format off */
+
+const struct frr_yang_module_info frr_staticd_info = {
+       .name = "frr-staticd",
+       .nodes = {
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/tag",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_tag_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/table-id",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop",
+                       .cbs = {
+                               .apply_finish = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_apply_finish,
+                               .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_destroy,
+                               .pre_validate = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bh-type",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_bh_type_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_bh_type_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/onlink",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_destroy,
+
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/label",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/ttl",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/tag",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_tag_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/table-id",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop",
+                       .cbs = {
+                               .apply_finish = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_apply_finish,
+                               .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_destroy,
+                               .pre_validate = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/bh-type",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_bh_type_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_bh_type_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/onlink",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry",
+                       .cbs = {
+                               .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_create,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/label",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/ttl",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class",
+                       .cbs = {
+                               .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_modify,
+                               .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy,
+                       }
+               },
+               {
+                       .xpath = NULL,
+               },
+       }
+};
diff --git a/staticd/static_nb.h b/staticd/static_nb.h
new file mode 100644 (file)
index 0000000..9116ac8
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2018        Vmware
+ *                           Vishal Dhingra
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef _FRR_STATIC_NB_H_
+#define _FRR_STATIC_NB_H_
+
+extern const struct frr_yang_module_info frr_staticd_info;
+
+/* Mandatory callbacks. */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_tag_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_bh_type_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_bh_type_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_tag_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_bh_type_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_bh_type_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_create(
+       struct nb_cb_create_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_destroy(
+       struct nb_cb_destroy_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_modify(
+       struct nb_cb_modify_args *args);
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy(
+       struct nb_cb_destroy_args *args);
+
+/* Optional 'apply_finish' callbacks. */
+
+void routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_apply_finish(
+       struct nb_cb_apply_finish_args *args);
+void routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_apply_finish(
+       struct nb_cb_apply_finish_args *args);
+
+/* Optional 'pre_validate' callbacks. */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate(
+       struct nb_cb_pre_validate_args *args);
+
+/*
+ * Callback registered with routing_nb lib to validate only
+ * one instance of staticd is allowed
+ */
+int routing_control_plane_protocols_name_validate(
+       struct nb_cb_create_args *args);
+
+/* xpath macros */
+/* route-list */
+#define FRR_STATIC_ROUTE_INFO_KEY_XPATH                                        \
+       "/frr-routing:routing/control-plane-protocols/"                        \
+       "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/"              \
+       "frr-staticd:staticd/route-list[prefix='%s']"                          \
+       "path-list[distance='%u']"
+
+
+#define FRR_STATIC_ROUTE_PATH_TAG_XPATH "/tag"
+
+#define FRR_STATIC_ROUTE_PATH_TABLEID_XPATH "/table-id"
+
+/* route-list/frr-nexthops */
+#define FRR_STATIC_ROUTE_NH_KEY_XPATH                                          \
+       "/frr-nexthops/"                                                       \
+       "nexthop[nh-type='%s'][vrf='%s'][gateway='%s'][interface='%s']"
+
+#define FRR_STATIC_ROUTE_NH_ONLINK_XPATH "/onlink"
+
+#define FRR_STATIC_ROUTE_NH_BH_XPATH "/bh-type"
+
+#define FRR_STATIC_ROUTE_NH_LABEL_XPATH "/mpls-label-stack"
+
+#define FRR_STATIC_ROUTE_NHLB_KEY_XPATH "/entry[id='%u']/label"
+
+/* route-list/srclist */
+#define FRR_S_ROUTE_SRC_INFO_KEY_XPATH                                         \
+       "/frr-routing:routing/control-plane-protocols/"                        \
+       "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/"              \
+       "frr-staticd:staticd/route-list[prefix='%s']"                          \
+       "src-list[src-prefix='%s']/path-list[distance='%u']"
+
+/* route-list/frr-nexthops */
+#define FRR_DEL_S_ROUTE_NH_KEY_XPATH                                           \
+       FRR_STATIC_ROUTE_INFO_KEY_XPATH                                        \
+       FRR_STATIC_ROUTE_NH_KEY_XPATH
+
+/* route-list/src/src-list/frr-nexthops*/
+#define FRR_DEL_S_ROUTE_SRC_NH_KEY_XPATH                                       \
+       FRR_S_ROUTE_SRC_INFO_KEY_XPATH                                         \
+       FRR_STATIC_ROUTE_NH_KEY_XPATH
+
+#endif
diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c
new file mode 100644 (file)
index 0000000..282299e
--- /dev/null
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (C) 2018        Vmware
+ *                           Vishal Dhingra
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "northbound.h"
+#include "libfrr.h"
+#include "log.h"
+#include "lib_errors.h"
+#include "prefix.h"
+#include "table.h"
+#include "vrf.h"
+#include "nexthop.h"
+#include "srcdest_table.h"
+
+#include "static_vrf.h"
+#include "static_routes.h"
+#include "static_nb.h"
+
+
+static int static_path_list_create(struct nb_cb_create_args *args)
+{
+       struct route_node *rn;
+       struct static_path *pn;
+       uint8_t distance;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               rn = nb_running_get_entry(args->dnode, NULL, true);
+               distance = yang_dnode_get_uint8(args->dnode, "./distance");
+               pn = static_add_path(rn, distance);
+               nb_running_set_entry(args->dnode, pn);
+       }
+
+       return NB_OK;
+}
+
+static void static_path_list_destroy(struct nb_cb_destroy_args *args,
+                                    const struct lyd_node *rn_dnode,
+                                    struct stable_info *info)
+{
+       struct route_node *rn;
+       struct static_path *pn;
+
+       pn = nb_running_unset_entry(args->dnode);
+       rn = nb_running_get_entry(rn_dnode, NULL, true);
+       static_del_path(rn, pn, info->safi, info->svrf);
+}
+
+static void static_path_list_tag_modify(struct nb_cb_modify_args *args,
+                                       const struct lyd_node *rn_dnode,
+                                       struct stable_info *info)
+{
+       struct static_path *pn;
+       struct route_node *rn;
+       route_tag_t tag;
+
+       tag = yang_dnode_get_uint32(args->dnode, NULL);
+       pn = nb_running_get_entry(args->dnode, NULL, true);
+       pn->tag = tag;
+       rn = nb_running_get_entry(rn_dnode, NULL, true);
+
+       static_install_path(rn, pn, info->safi, info->svrf);
+}
+
+static int static_path_list_tableid_modify(struct nb_cb_modify_args *args,
+                                          const struct lyd_node *rn_dnode,
+                                          struct stable_info *info)
+{
+       struct static_path *pn;
+       struct route_node *rn;
+       uint32_t table_id;
+       const struct lyd_node *vrf_dnode;
+       const char *vrf;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               vrf_dnode = yang_dnode_get_parent(args->dnode,
+                                                 "control-plane-protocol");
+               vrf = yang_dnode_get_string(vrf_dnode, "./vrf");
+               table_id = yang_dnode_get_uint32(args->dnode, NULL);
+               if (table_id && (strcmp(vrf, vrf_get_default_name()) != 0)
+                   && !vrf_is_backend_netns()) {
+                       snprintf(args->errmsg, args->errmsg_len,
+                               "%% table param only available when running on netns-based vrfs");
+                       return NB_ERR_VALIDATION;
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               table_id = yang_dnode_get_uint32(args->dnode, NULL);
+               pn = nb_running_get_entry(args->dnode, NULL, true);
+               pn->table_id = table_id;
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               static_install_path(rn, pn, info->safi, info->svrf);
+               break;
+       }
+
+       return NB_OK;
+}
+
+static bool static_nexthop_create(struct nb_cb_create_args *args,
+                                 const struct lyd_node *rn_dnode,
+                                 struct stable_info *info)
+{
+       struct route_node *rn;
+       struct static_path *pn;
+       struct ipaddr ipaddr;
+       struct static_nexthop *nh;
+       int nh_type;
+       const char *ifname;
+       const char *nh_vrf;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               ifname = yang_dnode_get_string(args->dnode, "./interface");
+               if (ifname != NULL) {
+                       if (strcasecmp(ifname, "Null0") == 0
+                           || strcasecmp(ifname, "reject") == 0
+                           || strcasecmp(ifname, "blackhole") == 0) {
+                               snprintf(args->errmsg, args->errmsg_len,
+                                       "%s: Nexthop interface name can not be from reserved keywords(Null0, reject, blackhole)",
+                                       ifname);
+                               return NB_ERR_VALIDATION;
+                       }
+               }
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               yang_dnode_get_ip(&ipaddr, args->dnode, "./gateway");
+               nh_type = yang_dnode_get_enum(args->dnode, "./nh-type");
+               ifname = yang_dnode_get_string(args->dnode, "./interface");
+               nh_vrf = yang_dnode_get_string(args->dnode, "./vrf");
+               pn = nb_running_get_entry(args->dnode, NULL, true);
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+
+               if (!static_add_nexthop_validate(info->svrf, nh_type, &ipaddr))
+                       flog_warn(
+                               EC_LIB_NB_CB_CONFIG_VALIDATE,
+                               "Warning!! Local connected address is configured as Gateway IP((%s))",
+                               yang_dnode_get_string(args->dnode,
+                                                     "./gateway"));
+               nh = static_add_nexthop(rn, pn, info->safi, info->svrf, nh_type,
+                                       &ipaddr, ifname, nh_vrf);
+               if (!nh) {
+                       char buf[SRCDEST2STR_BUFFER];
+
+                       flog_warn(
+                               EC_LIB_NB_CB_CONFIG_APPLY,
+                               "%s : nh [%d:%s:%s:%s] nexthop creation failed",
+                               srcdest_rnode2str(rn, buf, sizeof(buf)),
+                               nh_type, ifname,
+                               yang_dnode_get_string(args->dnode, "./gateway"),
+                               nh_vrf);
+                       return NB_ERR;
+               }
+               nb_running_set_entry(args->dnode, nh);
+               break;
+       }
+
+       return NB_OK;
+}
+
+static bool static_nexthop_destroy(struct nb_cb_destroy_args *args,
+                                  const struct lyd_node *rn_dnode,
+                                  struct stable_info *info)
+{
+       struct route_node *rn;
+       struct static_path *pn;
+       const struct lyd_node *pn_dnode;
+       struct static_nexthop *nh;
+       int ret;
+
+       nh = nb_running_unset_entry(args->dnode);
+       pn_dnode = yang_dnode_get_parent(args->dnode, "path-list");
+       pn = nb_running_get_entry(pn_dnode, NULL, true);
+       rn = nb_running_get_entry(rn_dnode, NULL, true);
+
+       ret = static_delete_nexthop(rn, pn, info->safi, info->svrf, nh);
+       if (!ret) {
+               char buf[SRCDEST2STR_BUFFER];
+
+               flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
+                         "%s : nh [%d:%s:%s:%s] nexthop destroy failed",
+                         srcdest_rnode2str(rn, buf, sizeof(buf)),
+                         yang_dnode_get_enum(args->dnode, "./nh-type"),
+                         yang_dnode_get_string(args->dnode, "./interface"),
+                         yang_dnode_get_string(args->dnode, "./gateway"),
+                         yang_dnode_get_string(args->dnode, "./vrf"));
+               return NB_ERR;
+       }
+
+       return NB_OK;
+}
+
+static int nexthop_mpls_label_stack_entry_create(struct nb_cb_create_args *args)
+{
+       struct static_nexthop *nh;
+       uint32_t pos;
+       uint8_t index;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               nh = nb_running_get_entry(args->dnode, NULL, true);
+               pos = yang_get_list_pos(args->dnode);
+               if (!pos) {
+                       flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
+                                 "libyang returns invalid label position");
+                       return NB_ERR;
+               }
+               /* Mapping to array = list-index -1 */
+               index = pos - 1;
+               nh->snh_label.label[index] = 0;
+               nh->snh_label.num_labels++;
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int
+nexthop_mpls_label_stack_entry_destroy(struct nb_cb_destroy_args *args)
+{
+       struct static_nexthop *nh;
+       uint32_t pos;
+       uint8_t index;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               nh = nb_running_get_entry(args->dnode, NULL, true);
+               pos = yang_get_list_pos(args->dnode);
+               if (!pos) {
+                       flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
+                                 "libyang returns invalid label position");
+                       return NB_ERR;
+               }
+               index = pos - 1;
+               nh->snh_label.label[index] = 0;
+               nh->snh_label.num_labels--;
+               break;
+       }
+
+       return NB_OK;
+}
+
+static int static_nexthop_mpls_label_modify(struct nb_cb_modify_args *args)
+{
+       struct static_nexthop *nh;
+       uint32_t pos;
+       uint8_t index;
+
+       nh = nb_running_get_entry(args->dnode, NULL, true);
+       pos = yang_get_list_pos(args->dnode->parent);
+       if (!pos) {
+               flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
+                         "libyang returns invalid label position");
+               return NB_ERR;
+       }
+       /* Mapping to array = list-index -1 */
+       index = pos - 1;
+       nh->snh_label.label[index] = yang_dnode_get_uint32(args->dnode, NULL);
+
+       return NB_OK;
+}
+
+static int static_nexthop_onlink_modify(struct nb_cb_modify_args *args)
+{
+       struct static_nexthop *nh;
+
+       nh = nb_running_get_entry(args->dnode, NULL, true);
+       nh->onlink = yang_dnode_get_bool(args->dnode, NULL);
+
+       return NB_OK;
+}
+
+static int static_nexthop_bh_type_modify(struct nb_cb_modify_args *args)
+{
+       struct static_nexthop *nh;
+
+       nh = nb_running_get_entry(args->dnode, NULL, true);
+       nh->bh_type = yang_dnode_get_enum(args->dnode, NULL);
+
+       return NB_OK;
+}
+
+
+void routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct static_nexthop *nh;
+       struct static_path *pn;
+       struct route_node *rn;
+       const struct lyd_node *pn_dnode;
+       const struct lyd_node *rn_dnode;
+       const char *ifname;
+       const char *nh_vrf;
+       struct stable_info *info;
+       int nh_type;
+
+       nh_type = yang_dnode_get_enum(args->dnode, "./nh-type");
+       ifname = yang_dnode_get_string(args->dnode, "./interface");
+       nh_vrf = yang_dnode_get_string(args->dnode, "./vrf");
+
+       nh = nb_running_get_entry(args->dnode, NULL, true);
+
+       pn_dnode = yang_dnode_get_parent(args->dnode, "path-list");
+       pn = nb_running_get_entry(pn_dnode, NULL, true);
+
+       rn_dnode = yang_dnode_get_parent(pn_dnode, "route-list");
+       rn = nb_running_get_entry(rn_dnode, NULL, true);
+       info = route_table_get_info(rn->table);
+
+       static_install_nexthop(rn, pn, nh, info->safi, info->svrf, ifname,
+                              nh_type, nh_vrf);
+}
+
+
+void routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_apply_finish(
+       struct nb_cb_apply_finish_args *args)
+{
+       struct static_nexthop *nh;
+       struct static_path *pn;
+       struct route_node *rn;
+       struct route_node *src_rn;
+       const struct lyd_node *pn_dnode;
+       const struct lyd_node *rn_dnode;
+       const struct lyd_node *src_dnode;
+       const char *ifname;
+       const char *nh_vrf;
+       struct stable_info *info;
+       int nh_type;
+
+       nh_type = yang_dnode_get_enum(args->dnode, "./nh-type");
+       ifname = yang_dnode_get_string(args->dnode, "./interface");
+       nh_vrf = yang_dnode_get_string(args->dnode, "./vrf");
+
+       nh = nb_running_get_entry(args->dnode, NULL, true);
+
+       pn_dnode = yang_dnode_get_parent(args->dnode, "path-list");
+       pn = nb_running_get_entry(pn_dnode, NULL, true);
+
+       src_dnode = yang_dnode_get_parent(pn_dnode, "src-list");
+       src_rn = nb_running_get_entry(src_dnode, NULL, true);
+
+       rn_dnode = yang_dnode_get_parent(src_dnode, "route-list");
+       rn = nb_running_get_entry(rn_dnode, NULL, true);
+       info = route_table_get_info(rn->table);
+
+       static_install_nexthop(src_rn, pn, nh, info->safi, info->svrf, ifname,
+                              nh_type, nh_vrf);
+}
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate(
+       struct nb_cb_pre_validate_args *args)
+{
+       const struct lyd_node *mls_dnode;
+       uint32_t count;
+
+       mls_dnode = yang_dnode_get(args->dnode, "./mpls-label-stack");
+       count = yang_get_list_elements_count(yang_dnode_get_child(mls_dnode));
+
+       if (count > MPLS_MAX_LABELS) {
+               snprintf(args->errmsg, args->errmsg_len,
+                       "Too many labels, Enter %d or fewer",
+                       MPLS_MAX_LABELS);
+               return NB_ERR_VALIDATION;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_name_validate(
+       struct nb_cb_create_args *args)
+{
+       const char *name;
+
+       name = yang_dnode_get_string(args->dnode, "./name");
+       if (!strmatch(name, "staticd")) {
+               snprintf(args->errmsg, args->errmsg_len,
+                       "static routing supports only one instance with name staticd");
+               return NB_ERR_VALIDATION;
+       }
+       return NB_OK;
+}
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create(
+       struct nb_cb_create_args *args)
+{
+       struct vrf *vrf;
+       struct static_vrf *s_vrf;
+       struct route_node *rn;
+       const struct lyd_node *vrf_dnode;
+       struct prefix prefix;
+       afi_t afi;
+       safi_t safi = SAFI_UNICAST;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               vrf_dnode = yang_dnode_get_parent(args->dnode,
+                                                 "control-plane-protocol");
+               vrf = nb_running_get_entry(vrf_dnode, NULL, true);
+               s_vrf = vrf->info;
+
+               yang_dnode_get_prefix(&prefix, args->dnode, "./prefix");
+               afi = family2afi(prefix.family);
+
+               if (afi == AFI_IP) {
+                       if (IN_MULTICAST(ntohl(prefix.u.prefix4.s_addr)))
+                               safi = SAFI_MULTICAST;
+               } else {
+                       if (IN6_IS_ADDR_MULTICAST(&prefix.u.prefix6))
+                               safi = SAFI_MULTICAST;
+               }
+
+               rn = static_add_route(afi, safi, &prefix, NULL, s_vrf);
+               if (!rn) {
+                       flog_warn(
+                               EC_LIB_NB_CB_CONFIG_APPLY,
+                               "route node %s creation failed",
+                               yang_dnode_get_string(args->dnode, "./prefix"));
+                       return NB_ERR;
+               }
+               nb_running_set_entry(args->dnode, rn);
+               break;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct route_node *rn;
+       struct stable_info *info;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               rn = nb_running_unset_entry(args->dnode);
+               info = route_table_get_info(rn->table);
+               static_del_route(rn, info->safi, info->svrf);
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_create(
+       struct nb_cb_create_args *args)
+{
+       return static_path_list_create(args);
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       const struct lyd_node *rn_dnode;
+       struct route_node *rn;
+       struct stable_info *info;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+               static_path_list_destroy(args, rn_dnode, info);
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/tag
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_tag_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct stable_info *info;
+       struct route_node *rn;
+       const struct lyd_node *rn_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+               static_path_list_tag_modify(args, rn_dnode, info);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/table-id
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct route_node *rn;
+       const struct lyd_node *rn_dnode;
+       struct stable_info *info;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if (static_path_list_tableid_modify(args, NULL, NULL) != NB_OK)
+                       return NB_ERR_VALIDATION;
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+
+               if (static_path_list_tableid_modify(args, rn_dnode, info)
+                   != NB_OK)
+                       return NB_ERR_VALIDATION;
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create(
+       struct nb_cb_create_args *args)
+{
+       struct route_node *rn;
+       const struct lyd_node *rn_dnode;
+       struct stable_info *info;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
+               if (static_nexthop_create(args, rn_dnode, NULL) != NB_OK)
+                       return NB_ERR_VALIDATION;
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+
+               if (static_nexthop_create(args, rn_dnode, info) != NB_OK)
+                       return NB_ERR_VALIDATION;
+               break;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct route_node *rn;
+       const struct lyd_node *rn_dnode;
+       struct stable_info *info;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+
+               if (static_nexthop_destroy(args, rn_dnode, info) != NB_OK)
+                       return NB_ERR;
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/bh-type
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_bh_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               if (static_nexthop_bh_type_modify(args) != NB_OK)
+                       return NB_ERR;
+               break;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_bh_type_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       /* blackhole type has a boolean type with default value,
+        * so no need to do any operations in destroy callback
+        */
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/onlink
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               if (static_nexthop_onlink_modify(args) != NB_OK)
+                       return NB_ERR;
+
+               break;
+       }
+       return NB_OK;
+}
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_onlink_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       /* onlink has a boolean type with default value,
+        * so no need to do any operations in destroy callback
+        */
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+       return NB_OK;
+}
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_create(
+       struct nb_cb_create_args *args)
+{
+       return nexthop_mpls_label_stack_entry_create(args);
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       return nexthop_mpls_label_stack_entry_destroy(args);
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/label
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               if (static_nexthop_mpls_label_modify(args) != NB_OK)
+                       return NB_ERR;
+               break;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       /*
+        * No operation is required in this call back.
+        * nexthop_mpls_label_stack_entry_destroy() will take care
+        * to reset the label vaue.
+        */
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/ttl
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_create(
+       struct nb_cb_create_args *args)
+{
+       struct static_vrf *s_vrf;
+       struct route_node *rn;
+       struct route_node *src_rn;
+       struct prefix_ipv6 src_prefix = {};
+       struct stable_info *info;
+       afi_t afi;
+       safi_t safi = SAFI_UNICAST;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               rn = nb_running_get_entry(args->dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+               s_vrf = info->svrf;
+               yang_dnode_get_ipv6p(&src_prefix, args->dnode, "./src-prefix");
+               afi = family2afi(src_prefix.family);
+               src_rn =
+                       static_add_route(afi, safi, &rn->p, &src_prefix, s_vrf);
+               if (!src_rn) {
+                       flog_warn(EC_LIB_NB_CB_CONFIG_APPLY,
+                                 "src rn %s creation failed",
+                                 yang_dnode_get_string(args->dnode,
+                                                       "./src-prefix"));
+                       return NB_ERR;
+               }
+               nb_running_set_entry(args->dnode, src_rn);
+               break;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct route_node *src_rn;
+       struct route_node *rn;
+       struct stable_info *info;
+       const struct lyd_node *rn_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               src_rn = nb_running_unset_entry(args->dnode);
+               rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+               static_del_route(src_rn, info->safi, info->svrf);
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_create(
+       struct nb_cb_create_args *args)
+{
+       return static_path_list_create(args);
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct route_node *rn;
+       const struct lyd_node *rn_dnode;
+       const struct lyd_node *srn_dnode;
+       struct stable_info *info;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               srn_dnode = yang_dnode_get_parent(args->dnode, "src-list");
+               rn_dnode = yang_dnode_get_parent(srn_dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+               static_path_list_destroy(args, srn_dnode, info);
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/tag
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_tag_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct stable_info *info;
+       struct route_node *rn;
+       const struct lyd_node *srn_dnode;
+       const struct lyd_node *rn_dnode;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_ABORT:
+       case NB_EV_PREPARE:
+               break;
+       case NB_EV_APPLY:
+               srn_dnode = yang_dnode_get_parent(args->dnode, "src-list");
+               rn_dnode = yang_dnode_get_parent(srn_dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+               static_path_list_tag_modify(args, srn_dnode, info);
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/table-id
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct route_node *rn;
+       const struct lyd_node *rn_dnode;
+       const struct lyd_node *src_dnode;
+       struct stable_info *info;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if (static_path_list_tableid_modify(args, NULL, NULL) != NB_OK)
+                       return NB_ERR_VALIDATION;
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               src_dnode = yang_dnode_get_parent(args->dnode, "src-list");
+               rn_dnode = yang_dnode_get_parent(src_dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+
+               if (static_path_list_tableid_modify(args, src_dnode, info)
+                   != NB_OK)
+                       return NB_ERR_VALIDATION;
+
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create(
+       struct nb_cb_create_args *args)
+{
+       struct route_node *rn;
+       const struct lyd_node *rn_dnode;
+       const struct lyd_node *src_dnode;
+       struct stable_info *info;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
+               if (static_nexthop_create(args, rn_dnode, NULL) != NB_OK)
+                       return NB_ERR_VALIDATION;
+               break;
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               src_dnode = yang_dnode_get_parent(args->dnode, "src-list");
+               rn_dnode = yang_dnode_get_parent(src_dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+
+               if (static_nexthop_create(args, src_dnode, info) != NB_OK)
+                       return NB_ERR_VALIDATION;
+
+               break;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct route_node *rn;
+       const struct lyd_node *rn_dnode;
+       const struct lyd_node *src_dnode;
+       struct stable_info *info;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               src_dnode = yang_dnode_get_parent(args->dnode, "src-list");
+               rn_dnode = yang_dnode_get_parent(src_dnode, "route-list");
+               rn = nb_running_get_entry(rn_dnode, NULL, true);
+               info = route_table_get_info(rn->table);
+
+               if (static_nexthop_destroy(args, rn_dnode, info) != NB_OK)
+                       return NB_ERR;
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/bh-type
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_bh_type_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               if (static_nexthop_bh_type_modify(args) != NB_OK)
+                       return NB_ERR;
+               break;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_bh_type_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       /* blackhole type has a boolean type with default value,
+        * so no need to do any operations in destroy callback
+        */
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/onlink
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               if (static_nexthop_onlink_modify(args) != NB_OK)
+                       return NB_ERR;
+
+               break;
+       }
+       return NB_OK;
+}
+
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_onlink_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       /* onlink has a boolean type with default value,
+        * so no need to do any operations in destroy callback
+        */
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_create(
+       struct nb_cb_create_args *args)
+{
+       return nexthop_mpls_label_stack_entry_create(args);
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       return nexthop_mpls_label_stack_entry_destroy(args);
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/label
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               if (static_nexthop_mpls_label_modify(args) != NB_OK)
+                       return NB_ERR;
+               break;
+       }
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_label_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       /*
+        * No operation is required in this call back.
+        * nexthop_mpls_label_stack_entry_destroy() will take care
+        * to reset the label vaue.
+        */
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/ttl
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class
+ */
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_modify(
+       struct nb_cb_modify_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
+
+int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+       case NB_EV_APPLY:
+               break;
+       }
+
+       return NB_OK;
+}
index 1a2ddd7f051b922a94653603e19fb696ad639823..feb6e0f9935d7260f8892b70ad60d5095ae66cfa 100644 (file)
 #include "static_zebra.h"
 #include "static_nht.h"
 
-static void static_nht_update_rn(struct route_node *rn,
-                                struct prefix *nhp, uint32_t nh_num,
-                                vrf_id_t nh_vrf_id, struct vrf *vrf,
-                                safi_t safi)
+static void static_nht_update_path(struct route_node *rn,
+                                  struct static_path *pn, struct prefix *nhp,
+                                  uint32_t nh_num, vrf_id_t nh_vrf_id,
+                                  struct vrf *vrf, safi_t safi)
 {
-       struct static_route *si;
+       struct static_nexthop *nh;
 
-       for (si = rn->info; si; si = si->next) {
-               if (si->nh_vrf_id != nh_vrf_id)
+       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+               if (nh->nh_vrf_id != nh_vrf_id)
                        continue;
 
-               if (si->type != STATIC_IPV4_GATEWAY
-                   && si->type != STATIC_IPV4_GATEWAY_IFNAME
-                   && si->type != STATIC_IPV6_GATEWAY
-                   && si->type != STATIC_IPV6_GATEWAY_IFNAME)
+               if (nh->type != STATIC_IPV4_GATEWAY
+                   && nh->type != STATIC_IPV4_GATEWAY_IFNAME
+                   && nh->type != STATIC_IPV6_GATEWAY
+                   && nh->type != STATIC_IPV6_GATEWAY_IFNAME)
                        continue;
 
                if (nhp->family == AF_INET
-                   && nhp->u.prefix4.s_addr == si->addr.ipv4.s_addr)
-                       si->nh_valid = !!nh_num;
+                   && nhp->u.prefix4.s_addr == nh->addr.ipv4.s_addr)
+                       nh->nh_valid = !!nh_num;
 
                if (nhp->family == AF_INET6
-                   && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) == 0)
-                       si->nh_valid = !!nh_num;
+                   && memcmp(&nhp->u.prefix6, &nh->addr.ipv6, 16) == 0)
+                       nh->nh_valid = !!nh_num;
 
-               if (si->state == STATIC_START)
-                       static_zebra_route_add(rn, si, vrf->vrf_id, safi, true);
+               if (nh->state == STATIC_START)
+                       static_zebra_route_add(rn, pn, safi, true);
        }
 }
 
@@ -67,6 +67,8 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
        struct route_table *stable;
        struct static_vrf *svrf;
        struct route_node *rn;
+       struct static_path *pn;
+       struct static_route_info *si;
 
        svrf = vrf->info;
        if (!svrf)
@@ -78,17 +80,26 @@ static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp,
 
        if (sp) {
                rn = srcdest_rnode_lookup(stable, sp, NULL);
-               if (rn) {
-                       static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id,
-                                            vrf, safi);
+               if (rn && rn->info) {
+                       si = static_route_info_from_rnode(rn);
+                       frr_each(static_path_list, &si->path_list, pn) {
+                               static_nht_update_path(rn, pn, nhp, nh_num,
+                                                      nh_vrf_id, vrf, safi);
+                       }
                        route_unlock_node(rn);
                }
                return;
        }
 
-       for (rn = route_top(stable); rn; rn = route_next(rn))
-               static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id, vrf, safi);
-
+       for (rn = route_top(stable); rn; rn = route_next(rn)) {
+               si = static_route_info_from_rnode(rn);
+               if (!si)
+                       continue;
+               frr_each(static_path_list, &si->path_list, pn) {
+                       static_nht_update_path(rn, pn, nhp, nh_num, nh_vrf_id,
+                                              vrf, safi);
+               }
+       }
 }
 
 void static_nht_update(struct prefix *sp, struct prefix *nhp,
@@ -111,8 +122,10 @@ static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi,
 {
        struct static_vrf *svrf;
        struct route_table *stable;
-       struct static_route *si;
+       struct static_nexthop *nh;
+       struct static_path *pn;
        struct route_node *rn;
+       struct static_route_info *si;
 
        svrf = vrf->info;
        if (!svrf)
@@ -123,25 +136,33 @@ static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi,
                return;
 
        for (rn = route_top(stable); rn; rn = route_next(rn)) {
-               for (si = rn->info; si; si = si->next) {
-                       if (si->nh_vrf_id != nh_vrf_id)
-                               continue;
-
-                       if (nhp->family == AF_INET
-                           && nhp->u.prefix4.s_addr != si->addr.ipv4.s_addr)
-                               continue;
-
-                       if (nhp->family == AF_INET6
-                           && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) != 0)
-                               continue;
-
-                       /*
-                        * We've been told that a nexthop we depend
-                        * on has changed in some manner, so reset
-                        * the state machine to allow us to start
-                        * over.
-                        */
-                       si->state = STATIC_START;
+               si = static_route_info_from_rnode(rn);
+               if (!si)
+                       continue;
+               frr_each(static_path_list, &si->path_list, pn) {
+                       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+                               if (nh->nh_vrf_id != nh_vrf_id)
+                                       continue;
+
+                               if (nhp->family == AF_INET
+                                   && nhp->u.prefix4.s_addr
+                                              != nh->addr.ipv4.s_addr)
+                                       continue;
+
+                               if (nhp->family == AF_INET6
+                                   && memcmp(&nhp->u.prefix6, &nh->addr.ipv6,
+                                             16)
+                                              != 0)
+                                       continue;
+
+                               /*
+                                * We've been told that a nexthop we
+                                * depend on has changed in some manner,
+                                * so reset the state machine to allow
+                                * us to start over.
+                                */
+                               nh->state = STATIC_START;
+                       }
                }
        }
 }
@@ -164,8 +185,10 @@ static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi,
 {
        struct static_vrf *svrf;
        struct route_table *stable;
-       struct static_route *si;
        struct route_node *rn;
+       struct static_nexthop *nh;
+       struct static_path *pn;
+       struct static_route_info *si;
 
        svrf = vrf->info;
        if (!svrf)
@@ -178,9 +201,14 @@ static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi,
        rn = srcdest_rnode_lookup(stable, sp, NULL);
        if (!rn)
                return;
-
-       for (si = rn->info; si; si = si->next)
-               si->state = state;
+       si = rn->info;
+       if (si) {
+               frr_each(static_path_list, &si->path_list, pn) {
+                       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+                               nh->state = state;
+                       }
+               }
+       }
 
        route_unlock_node(rn);
 }
index e8d6a4289b971f3c6b6f97b310d9370fe537549f..829fe6cd69c1e87b5b0d3a42f1b9c5c28f1a98f7 100644 (file)
 #include "static_memory.h"
 #include "static_zebra.h"
 
-/* Install static route into rib. */
-static void static_install_route(struct route_node *rn,
-                                struct static_route *si_changed, safi_t safi)
-{
-       struct static_route *si;
+DEFINE_MTYPE_STATIC(STATIC, STATIC_ROUTE, "Static Route Info");
+DEFINE_MTYPE(STATIC, STATIC_PATH, "Static Path");
 
-       for (si = rn->info; si; si = si->next)
-               static_zebra_nht_register(rn, si, true);
+/* Install static path into rib. */
+void static_install_path(struct route_node *rn, struct static_path *pn,
+                        safi_t safi, struct static_vrf *svrf)
+{
+       struct static_nexthop *nh;
 
-       si = rn->info;
-       if (si)
-               static_zebra_route_add(rn, si_changed, si->vrf_id, safi, true);
+       frr_each(static_nexthop_list, &pn->nexthop_list, nh)
+               static_zebra_nht_register(rn, nh, true);
 
+       if (static_nexthop_list_count(&pn->nexthop_list) && svrf && svrf->vrf)
+               static_zebra_route_add(rn, pn, safi, true);
 }
 
-/* Uninstall static route from RIB. */
-static void static_uninstall_route(vrf_id_t vrf_id, safi_t safi,
-                                  struct route_node *rn,
-                                  struct static_route *si_changed)
+/* Uninstall static path from RIB. */
+static void static_uninstall_path(struct route_node *rn, struct static_path *pn,
+                                 safi_t safi, struct static_vrf *svrf)
 {
-
-       if (rn->info)
-               static_zebra_route_add(rn, si_changed, vrf_id, safi, true);
+       if (static_nexthop_list_count(&pn->nexthop_list))
+               static_zebra_route_add(rn, pn, safi, true);
        else
-               static_zebra_route_add(rn, si_changed, vrf_id, safi, false);
+               static_zebra_route_add(rn, pn, safi, false);
 }
 
-int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
-                    struct prefix_ipv6 *src_p, union g_addr *gate,
-                    const char *ifname, enum static_blackhole_type bh_type,
-                    route_tag_t tag, uint8_t distance, struct static_vrf *svrf,
-                    struct static_vrf *nh_svrf,
-                    struct static_nh_label *snh_label, uint32_t table_id,
-                    bool onlink)
+struct route_node *static_add_route(afi_t afi, safi_t safi, struct prefix *p,
+                                   struct prefix_ipv6 *src_p,
+                                   struct static_vrf *svrf)
 {
        struct route_node *rn;
-       struct static_route *si;
-       struct static_route *pp;
-       struct static_route *cp;
-       struct static_route *update = NULL;
+       struct static_route_info *si;
        struct route_table *stable = svrf->stable[afi][safi];
-       struct interface *ifp;
 
        if (!stable)
-               return -1;
-
-       if (!gate && (type == STATIC_IPV4_GATEWAY
-                     || type == STATIC_IPV4_GATEWAY_IFNAME
-                     || type == STATIC_IPV6_GATEWAY
-                     || type == STATIC_IPV6_GATEWAY_IFNAME))
-               return -1;
-
-       if (!ifname
-           && (type == STATIC_IFNAME || type == STATIC_IPV4_GATEWAY_IFNAME
-               || type == STATIC_IPV6_GATEWAY_IFNAME))
-               return -1;
+               return NULL;
 
        /* Lookup static route prefix. */
        rn = srcdest_rnode_get(stable, p, src_p);
 
-       /* Do nothing if there is a same static route.  */
-       for (si = rn->info; si; si = si->next) {
-               if (type == si->type
-                   && (!gate
-                       || ((afi == AFI_IP
-                            && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
-                           || (afi == AFI_IP6
-                               && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
-                   && (!strcmp(ifname ? ifname : "", si->ifname))
-                   && nh_svrf->vrf->vrf_id == si->nh_vrf_id) {
-                       if ((distance == si->distance) && (tag == si->tag)
-                           && (table_id == si->table_id)
-                           && !memcmp(&si->snh_label, snh_label,
-                                      sizeof(struct static_nh_label))
-                           && si->bh_type == bh_type && si->onlink == onlink) {
-                               route_unlock_node(rn);
-                               return 0;
-                       }
-                       update = si;
+       si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route_info));
+       static_route_info_init(si);
+
+       rn->info = si;
+
+       /* Mark as having FRR configuration */
+       vrf_set_user_cfged(svrf->vrf);
+
+       return rn;
+}
+
+/* To delete the srcnodes */
+static void static_del_src_route(struct route_node *rn, safi_t safi,
+                                struct static_vrf *svrf)
+{
+       struct static_path *pn;
+       struct static_route_info *si;
+
+       si = rn->info;
+
+       frr_each_safe(static_path_list, &si->path_list, pn) {
+               static_del_path(rn, pn, safi, svrf);
+       }
+
+       XFREE(MTYPE_STATIC_ROUTE, rn->info);
+       route_unlock_node(rn);
+       /* If no other FRR config for this VRF, mark accordingly. */
+       if (!static_vrf_has_config(svrf))
+               vrf_reset_user_cfged(svrf->vrf);
+}
+
+void static_del_route(struct route_node *rn, safi_t safi,
+                     struct static_vrf *svrf)
+{
+       struct static_path *pn;
+       struct static_route_info *si;
+       struct route_table *src_table;
+       struct route_node *src_node;
+
+       si = rn->info;
+
+       frr_each_safe(static_path_list, &si->path_list, pn) {
+               static_del_path(rn, pn, safi, svrf);
+       }
+
+       /* clean up for dst table */
+       src_table = srcdest_srcnode_table(rn);
+       if (src_table) {
+               /* This means the route_node is part of the top hierarchy
+                * and refers to a destination prefix.
+                */
+               for (src_node = route_top(src_table); src_node;
+                    src_node = route_next(src_node)) {
+                       static_del_src_route(src_node, safi, svrf);
                }
        }
+       XFREE(MTYPE_STATIC_ROUTE, rn->info);
+       route_unlock_node(rn);
+       /* If no other FRR config for this VRF, mark accordingly. */
+       if (!static_vrf_has_config(svrf))
+               vrf_reset_user_cfged(svrf->vrf);
+}
+
+bool static_add_nexthop_validate(struct static_vrf *svrf, static_types type,
+                                struct ipaddr *ipaddr)
+{
+       switch (type) {
+       case STATIC_IPV4_GATEWAY:
+       case STATIC_IPV4_GATEWAY_IFNAME:
+               if (if_lookup_exact_address(&ipaddr->ipaddr_v4, AF_INET,
+                                           svrf->vrf->vrf_id))
+                       return false;
+               break;
+       case STATIC_IPV6_GATEWAY:
+       case STATIC_IPV6_GATEWAY_IFNAME:
+               if (if_lookup_exact_address(&ipaddr->ipaddr_v6, AF_INET6,
+                                           svrf->vrf->vrf_id))
+                       return false;
+               break;
+       default:
+               break;
+       }
+
+       return true;
+}
+
+struct static_path *static_add_path(struct route_node *rn, uint8_t distance)
+{
+       struct static_path *pn;
+       struct static_route_info *si;
+
+       route_lock_node(rn);
+
+       /* Make new static route structure. */
+       pn = XCALLOC(MTYPE_STATIC_PATH, sizeof(struct static_path));
+
+       pn->distance = distance;
+       static_nexthop_list_init(&(pn->nexthop_list));
+
+       si = rn->info;
+       static_path_list_add_head(&(si->path_list), pn);
+
+       return pn;
+}
+
+void static_del_path(struct route_node *rn, struct static_path *pn, safi_t safi,
+                    struct static_vrf *svrf)
+{
+       struct static_route_info *si;
+       struct static_nexthop *nh;
+
+       si = rn->info;
+
+       static_path_list_del(&si->path_list, pn);
+
+       frr_each_safe(static_nexthop_list, &pn->nexthop_list, nh) {
+               static_delete_nexthop(rn, pn, safi, svrf, nh);
+       }
+
+       route_unlock_node(rn);
+
+       XFREE(MTYPE_STATIC_PATH, pn);
+}
+
+struct static_nexthop *
+static_add_nexthop(struct route_node *rn, struct static_path *pn, safi_t safi,
+                  struct static_vrf *svrf, static_types type,
+                  struct ipaddr *ipaddr, const char *ifname,
+                  const char *nh_vrf)
+{
+       struct static_nexthop *nh;
+       struct static_vrf *nh_svrf;
+       struct interface *ifp;
+       struct static_nexthop *cp;
+
+       route_lock_node(rn);
+
+       nh_svrf = static_vty_get_unknown_vrf(nh_vrf);
 
-       /* Distance or tag or label changed, delete existing first. */
-       if (update)
-               static_delete_route(afi, safi, type, p, src_p, gate, ifname,
-                                   update->tag, update->distance, svrf,
-                                   &update->snh_label, table_id);
+       if (!nh_svrf)
+               return NULL;
 
        /* Make new static route structure. */
-       si = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(struct static_route));
-
-       si->type = type;
-       si->distance = distance;
-       si->bh_type = bh_type;
-       si->tag = tag;
-       si->vrf_id = svrf->vrf->vrf_id;
-       si->nh_vrf_id = nh_svrf->vrf->vrf_id;
-       strlcpy(si->nh_vrfname, nh_svrf->vrf->name, sizeof(si->nh_vrfname));
-       si->table_id = table_id;
-       si->onlink = onlink;
+       nh = XCALLOC(MTYPE_STATIC_NEXTHOP, sizeof(struct static_nexthop));
+
+       nh->type = type;
+
+       nh->nh_vrf_id = nh_svrf->vrf->vrf_id;
+       strlcpy(nh->nh_vrfname, nh_svrf->vrf->name, sizeof(nh->nh_vrfname));
 
        if (ifname)
-               strlcpy(si->ifname, ifname, sizeof(si->ifname));
-       si->ifindex = IFINDEX_INTERNAL;
+               strlcpy(nh->ifname, ifname, sizeof(nh->ifname));
+       nh->ifindex = IFINDEX_INTERNAL;
 
        switch (type) {
        case STATIC_IPV4_GATEWAY:
        case STATIC_IPV4_GATEWAY_IFNAME:
-               si->addr.ipv4 = gate->ipv4;
+               nh->addr.ipv4 = ipaddr->ipaddr_v4;
                break;
        case STATIC_IPV6_GATEWAY:
        case STATIC_IPV6_GATEWAY_IFNAME:
-               si->addr.ipv6 = gate->ipv6;
+               nh->addr.ipv6 = ipaddr->ipaddr_v6;
                break;
-       case STATIC_IFNAME:
+       default:
                break;
        }
-
-       /* Save labels, if any. */
-       memcpy(&si->snh_label, snh_label, sizeof(struct static_nh_label));
-
        /*
         * Add new static route information to the tree with sort by
-        * distance value and gateway address.
+        * gateway address.
         */
-       for (pp = NULL, cp = rn->info; cp; pp = cp, cp = cp->next) {
-               if (si->distance < cp->distance)
-                       break;
-               if (si->distance > cp->distance)
-                       continue;
-               if (si->type == STATIC_IPV4_GATEWAY
+       frr_each(static_nexthop_list, &pn->nexthop_list, cp) {
+               if (nh->type == STATIC_IPV4_GATEWAY
                    && cp->type == STATIC_IPV4_GATEWAY) {
-                       if (ntohl(si->addr.ipv4.s_addr)
+                       if (ntohl(nh->addr.ipv4.s_addr)
                            < ntohl(cp->addr.ipv4.s_addr))
                                break;
-                       if (ntohl(si->addr.ipv4.s_addr)
+                       if (ntohl(nh->addr.ipv4.s_addr)
                            > ntohl(cp->addr.ipv4.s_addr))
                                continue;
                }
        }
+       static_nexthop_list_add_after(&(pn->nexthop_list), cp, nh);
 
-       /* Make linked list. */
-       if (pp)
-               pp->next = si;
-       else
-               rn->info = si;
-       if (cp)
-               cp->prev = si;
-       si->prev = pp;
-       si->next = cp;
+       if (nh_svrf->vrf->vrf_id == VRF_UNKNOWN)
+               return nh;
 
        /* check whether interface exists in system & install if it does */
-       switch (si->type) {
+       switch (nh->type) {
        case STATIC_IPV4_GATEWAY:
        case STATIC_IPV6_GATEWAY:
-               static_zebra_nht_register(rn, si, true);
                break;
        case STATIC_IPV4_GATEWAY_IFNAME:
        case STATIC_IPV6_GATEWAY_IFNAME:
-               ifp =  if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id);
+               ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id);
                if (ifp && ifp->ifindex != IFINDEX_INTERNAL)
-                       si->ifindex = ifp->ifindex;
+                       nh->ifindex = ifp->ifindex;
                else
-                       zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf",
-                                 ifname);
+                       zlog_warn(
+                               "Static Route using %s interface not installed because the interface does not exist in specified vrf",
+                               ifname);
 
-               static_zebra_nht_register(rn, si, true);
                break;
        case STATIC_BLACKHOLE:
-               static_install_route(rn, si, safi);
                break;
        case STATIC_IFNAME:
                ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id);
                if (ifp && ifp->ifindex != IFINDEX_INTERNAL) {
-                       si->ifindex = ifp->ifindex;
-                       static_install_route(rn, si, safi);
+                       nh->ifindex = ifp->ifindex;
                } else
-                       zlog_warn("Static Route using %s interface not installed because the interface does not exist in specified vrf",
-                                 ifname);
-
+                       zlog_warn(
+                               "Static Route using %s interface not installed because the interface does not exist in specified vrf",
+                               ifname);
                break;
        }
 
-       return 1;
+       return nh;
 }
 
-int static_delete_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
-                       struct prefix_ipv6 *src_p, union g_addr *gate,
-                       const char *ifname, route_tag_t tag, uint8_t distance,
-                       struct static_vrf *svrf,
-                       struct static_nh_label *snh_label,
-                       uint32_t table_id)
+void static_install_nexthop(struct route_node *rn, struct static_path *pn,
+                           struct static_nexthop *nh, safi_t safi,
+                           struct static_vrf *svrf, const char *ifname,
+                           static_types type, const char *nh_vrf)
 {
-       struct route_node *rn;
-       struct static_route *si;
-       struct route_table *stable;
+       struct static_vrf *nh_svrf;
+       struct interface *ifp;
 
-       /* Lookup table.  */
-       stable = static_vrf_static_table(afi, safi, svrf);
-       if (!stable)
-               return -1;
+       nh_svrf = static_vty_get_unknown_vrf(nh_vrf);
 
-       /* Lookup static route prefix. */
-       rn = srcdest_rnode_lookup(stable, p, src_p);
-       if (!rn)
-               return 0;
-
-       /* Find same static route is the tree */
-       for (si = rn->info; si; si = si->next)
-               if (type == si->type
-                   && (!gate
-                       || ((afi == AFI_IP
-                            && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
-                           || (afi == AFI_IP6
-                               && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
-                   && (!strcmp(ifname ? ifname : "", si->ifname))
-                   && (!tag || (tag == si->tag))
-                   && (table_id == si->table_id)
-                   && (!snh_label->num_labels
-                       || !memcmp(&si->snh_label, snh_label,
-                                  sizeof(struct static_nh_label))))
-                       break;
-
-       /* Can't find static route. */
-       if (!si) {
-               route_unlock_node(rn);
-               return 0;
+       if (!nh_svrf)
+               return;
+
+       if (nh_svrf->vrf->vrf_id == VRF_UNKNOWN)
+               return;
+
+       /* check whether interface exists in system & install if it does */
+       switch (nh->type) {
+       case STATIC_IPV4_GATEWAY:
+       case STATIC_IPV6_GATEWAY:
+               if (!static_zebra_nh_update(rn, nh))
+                       static_zebra_nht_register(rn, nh, true);
+               break;
+       case STATIC_IPV4_GATEWAY_IFNAME:
+       case STATIC_IPV6_GATEWAY_IFNAME:
+               if (!static_zebra_nh_update(rn, nh))
+                       static_zebra_nht_register(rn, nh, true);
+               break;
+       case STATIC_BLACKHOLE:
+               static_install_path(rn, pn, safi, svrf);
+               break;
+       case STATIC_IFNAME:
+               ifp = if_lookup_by_name(ifname, nh_svrf->vrf->vrf_id);
+               if (ifp && ifp->ifindex != IFINDEX_INTERNAL)
+                       static_install_path(rn, pn, safi, svrf);
+
+               break;
        }
+}
 
-       static_zebra_nht_register(rn, si, false);
+int static_delete_nexthop(struct route_node *rn, struct static_path *pn,
+                         safi_t safi, struct static_vrf *svrf,
+                         struct static_nexthop *nh)
+{
+       struct static_vrf *nh_svrf;
 
-       /* Unlink static route from linked list. */
-       if (si->prev)
-               si->prev->next = si->next;
-       else
-               rn->info = si->next;
-       if (si->next)
-               si->next->prev = si->prev;
+       nh_svrf = static_vrf_lookup_by_name(nh->nh_vrfname);
+
+       static_nexthop_list_del(&(pn->nexthop_list), nh);
+
+       if (nh_svrf->vrf->vrf_id == VRF_UNKNOWN)
+               goto EXIT;
 
+       static_zebra_nht_register(rn, nh, false);
        /*
         * If we have other si nodes then route replace
         * else delete the route
         */
-       static_uninstall_route(si->vrf_id, safi, rn, si);
-       route_unlock_node(rn);
-
-       /* Free static route configuration. */
-       XFREE(MTYPE_STATIC_ROUTE, si);
+       static_uninstall_path(rn, pn, safi, svrf);
 
+EXIT:
        route_unlock_node(rn);
+       /* Free static route configuration. */
+       XFREE(MTYPE_STATIC_NEXTHOP, nh);
 
        return 1;
 }
@@ -291,8 +363,10 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi,
 {
        struct route_table *stable;
        struct route_node *rn;
-       struct static_route *si;
+       struct static_nexthop *nh;
+       struct static_path *pn;
        struct vrf *vrf;
+       struct static_route_info *si;
 
        RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
                struct static_vrf *svrf;
@@ -302,26 +376,34 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi,
                stable = static_vrf_static_table(afi, safi, svrf);
                if (!stable)
                        continue;
-
                for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
-                       for (si = rn->info; si; si = si->next) {
-                               if (!si->ifname[0])
-                                       continue;
-                               if (up) {
-                                       if (strcmp(si->ifname, ifp->name))
-                                               continue;
-                                       if (si->nh_vrf_id != ifp->vrf_id)
-                                               continue;
-                                       si->ifindex = ifp->ifindex;
-                               } else {
-                                       if (si->ifindex != ifp->ifindex)
-                                               continue;
-                                       if (si->nh_vrf_id != ifp->vrf_id)
+                       si = static_route_info_from_rnode(rn);
+                       if (!si)
+                               continue;
+                       frr_each(static_path_list, &si->path_list, pn) {
+                               frr_each(static_nexthop_list,
+                                         &pn->nexthop_list, nh) {
+                                       if (!nh->ifname[0])
                                                continue;
-                                       si->ifindex = IFINDEX_INTERNAL;
+                                       if (up) {
+                                               if (strcmp(nh->ifname,
+                                                          ifp->name))
+                                                       continue;
+                                               if (nh->nh_vrf_id
+                                                   != ifp->vrf_id)
+                                                       continue;
+                                               nh->ifindex = ifp->ifindex;
+                                       } else {
+                                               if (nh->ifindex != ifp->ifindex)
+                                                       continue;
+                                               if (nh->nh_vrf_id
+                                                   != ifp->vrf_id)
+                                                       continue;
+                                               nh->ifindex = IFINDEX_INTERNAL;
+                                       }
+
+                                       static_install_path(rn, pn, safi, svrf);
                                }
-
-                               static_install_route(rn, si, safi);
                        }
                }
        }
@@ -343,26 +425,34 @@ static void static_fixup_vrf(struct static_vrf *svrf,
                             struct route_table *stable, afi_t afi, safi_t safi)
 {
        struct route_node *rn;
-       struct static_route *si;
+       struct static_nexthop *nh;
        struct interface *ifp;
+       struct static_path *pn;
+       struct static_route_info *si;
 
        for (rn = route_top(stable); rn; rn = route_next(rn)) {
-               for (si = rn->info; si; si = si->next) {
-                       if (strcmp(svrf->vrf->name, si->nh_vrfname) != 0)
-                               continue;
-
-                       si->nh_vrf_id = svrf->vrf->vrf_id;
-                       si->nh_registered = false;
-                       if (si->ifindex) {
-                               ifp = if_lookup_by_name(si->ifname,
-                                                       si->nh_vrf_id);
-                               if (ifp)
-                                       si->ifindex = ifp->ifindex;
-                               else
+               si = static_route_info_from_rnode(rn);
+               if (!si)
+                       continue;
+               frr_each(static_path_list, &si->path_list, pn) {
+                       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+                               if (strcmp(svrf->vrf->name, nh->nh_vrfname)
+                                   != 0)
                                        continue;
-                       }
 
-                       static_install_route(rn, si, safi);
+                               nh->nh_vrf_id = svrf->vrf->vrf_id;
+                               nh->nh_registered = false;
+                               if (nh->ifindex) {
+                                       ifp = if_lookup_by_name(nh->ifname,
+                                                               nh->nh_vrf_id);
+                                       if (ifp)
+                                               nh->ifindex = ifp->ifindex;
+                                       else
+                                               continue;
+                               }
+
+                               static_install_path(rn, pn, safi, svrf);
+                       }
                }
        }
 }
@@ -377,26 +467,31 @@ static void static_fixup_vrf(struct static_vrf *svrf,
  * safi -> the safi in question
  */
 static void static_enable_vrf(struct static_vrf *svrf,
-                             struct route_table *stable,
-                             afi_t afi, safi_t safi)
+                             struct route_table *stable, afi_t afi,
+                             safi_t safi)
 {
        struct route_node *rn;
-       struct static_route *si;
+       struct static_nexthop *nh;
        struct interface *ifp;
-       struct vrf *vrf = svrf->vrf;
+       struct static_path *pn;
+       struct static_route_info *si;
 
        for (rn = route_top(stable); rn; rn = route_next(rn)) {
-               for (si = rn->info; si; si = si->next) {
-                       si->vrf_id = vrf->vrf_id;
-                       if (si->ifindex) {
-                               ifp = if_lookup_by_name(si->ifname,
-                                                       si->nh_vrf_id);
-                               if (ifp)
-                                       si->ifindex = ifp->ifindex;
-                               else
-                                       continue;
+               si = static_route_info_from_rnode(rn);
+               if (!si)
+                       continue;
+               frr_each(static_path_list, &si->path_list, pn) {
+                       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+                               if (nh->ifindex) {
+                                       ifp = if_lookup_by_name(nh->ifname,
+                                                               nh->nh_vrf_id);
+                                       if (ifp)
+                                               nh->ifindex = ifp->ifindex;
+                                       else
+                                               continue;
+                               }
+                               static_install_path(rn, pn, safi, svrf);
                        }
-                       static_install_route(rn, si, safi);
                }
        }
 }
@@ -452,14 +547,22 @@ static void static_cleanup_vrf(struct static_vrf *svrf,
                               afi_t afi, safi_t safi)
 {
        struct route_node *rn;
-       struct static_route *si;
+       struct static_nexthop *nh;
+       struct static_path *pn;
+       struct static_route_info *si;
 
        for (rn = route_top(stable); rn; rn = route_next(rn)) {
-               for (si = rn->info; si; si = si->next) {
-                       if (strcmp(svrf->vrf->name, si->nh_vrfname) != 0)
-                               continue;
+               si = static_route_info_from_rnode(rn);
+               if (!si)
+                       continue;
+               frr_each(static_path_list, &si->path_list, pn) {
+                       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+                               if (strcmp(svrf->vrf->name, nh->nh_vrfname)
+                                   != 0)
+                                       continue;
 
-                       static_uninstall_route(si->vrf_id, safi, rn, si);
+                               static_uninstall_path(rn, pn, safi, svrf);
+                       }
                }
        }
 }
@@ -476,11 +579,23 @@ static void static_disable_vrf(struct route_table *stable,
                               afi_t afi, safi_t safi)
 {
        struct route_node *rn;
-       struct static_route *si;
+       struct static_nexthop *nh;
+       struct static_path *pn;
+       struct stable_info *info;
+       struct static_route_info *si;
 
-       for (rn = route_top(stable); rn; rn = route_next(rn))
-               for (si = rn->info; si; si = si->next)
-                       static_uninstall_route(si->vrf_id, safi, rn, si);
+       info = route_table_get_info(stable);
+
+       for (rn = route_top(stable); rn; rn = route_next(rn)) {
+               si = static_route_info_from_rnode(rn);
+               if (!si)
+                       continue;
+               frr_each(static_path_list, &si->path_list, pn) {
+                       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+                               static_uninstall_path(rn, pn, safi, info->svrf);
+                       }
+               }
+       }
 }
 
 /*
@@ -535,17 +650,27 @@ static void static_fixup_intf_nh(struct route_table *stable,
                                 afi_t afi, safi_t safi)
 {
        struct route_node *rn;
-       struct static_route *si;
+       struct stable_info *info;
+       struct static_nexthop *nh;
+       struct static_path *pn;
+       struct static_route_info *si;
+
+       info = route_table_get_info(stable);
 
        for (rn = route_top(stable); rn; rn = route_next(rn)) {
-               for (si = rn->info; si; si = si->next) {
-                       if (si->nh_vrf_id != ifp->vrf_id)
-                               continue;
+               si = static_route_info_from_rnode(rn);
+               if (!si)
+                       continue;
+               frr_each(static_path_list, &si->path_list, pn) {
+                       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+                               if (nh->nh_vrf_id != ifp->vrf_id)
+                                       continue;
 
-                       if (si->ifindex != ifp->ifindex)
-                               continue;
+                               if (nh->ifindex != ifp->ifindex)
+                                       continue;
 
-                       static_install_route(rn, si, safi);
+                               static_install_path(rn, pn, safi, info->svrf);
+                       }
                }
        }
 }
@@ -589,3 +714,40 @@ void static_ifindex_update(struct interface *ifp, bool up)
        static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_UNICAST);
        static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST);
 }
+
+void static_get_nh_type(static_types stype, char *type, size_t size)
+{
+       switch (stype) {
+       case STATIC_IFNAME:
+               strlcpy(type, "ifindex", size);
+               break;
+       case STATIC_IPV4_GATEWAY:
+               strlcpy(type, "ip4", size);
+               break;
+       case STATIC_IPV4_GATEWAY_IFNAME:
+               strlcpy(type, "ip4-ifindex", size);
+               break;
+       case STATIC_BLACKHOLE:
+               strlcpy(type, "blackhole", size);
+               break;
+       case STATIC_IPV6_GATEWAY:
+               strlcpy(type, "ip6", size);
+               break;
+       case STATIC_IPV6_GATEWAY_IFNAME:
+               strlcpy(type, "ip6-ifindex", size);
+               break;
+       };
+}
+
+struct stable_info *static_get_stable_info(struct route_node *rn)
+{
+       struct route_table *table;
+
+       table = srcdest_rnode_table(rn);
+       return table->info;
+}
+
+void static_route_info_init(struct static_route_info *si)
+{
+       static_path_list_init(&(si->path_list));
+}
index 6414947b1601245a0dcc9b1cbf4d88605ea7a2c6..89ef54402335f5b7f71f126932d7a5db7485579f 100644 (file)
@@ -21,6 +21,7 @@
 #define __STATIC_ROUTES_H__
 
 #include "lib/mpls.h"
+#include "table.h"
 
 /* Static route label information */
 struct static_nh_label {
@@ -35,13 +36,17 @@ enum static_blackhole_type {
        STATIC_BLACKHOLE_REJECT
 };
 
+/*
+ * The order for below macros should be in sync with
+ * yang model typedef nexthop-type
+ */
 typedef enum {
-       STATIC_IFNAME,
+       STATIC_IFNAME = 1,
        STATIC_IPV4_GATEWAY,
        STATIC_IPV4_GATEWAY_IFNAME,
-       STATIC_BLACKHOLE,
        STATIC_IPV6_GATEWAY,
        STATIC_IPV6_GATEWAY_IFNAME,
+       STATIC_BLACKHOLE,
 } static_types;
 
 /*
@@ -64,14 +69,37 @@ enum static_install_states {
        STATIC_NOT_INSTALLED,
 };
 
+PREDECL_DLIST(static_path_list);
+PREDECL_DLIST(static_nexthop_list);
+
+/* Static route information */
+struct static_route_info {
+       /* path list */
+       struct static_path_list_head path_list;
+};
+
+/* Static path information */
+struct static_path {
+       /* Linkage for static path lists */
+       struct static_path_list_item list;
+       /* Administrative distance. */
+       uint8_t distance;
+       /* Tag */
+       route_tag_t tag;
+       /* Table-id */
+       uint32_t table_id;
+       /* Nexthop list */
+       struct static_nexthop_list_head nexthop_list;
+};
+
+DECLARE_DLIST(static_path_list, struct static_path, list);
+
 /* Static route information. */
-struct static_route {
+struct static_nexthop {
        /* For linked list. */
-       struct static_route *prev;
-       struct static_route *next;
+       struct static_nexthop_list_item list;
 
        /* VRF identifier. */
-       vrf_id_t vrf_id;
        vrf_id_t nh_vrf_id;
        char nh_vrfname[VRF_NAMSIZ + 1];
 
@@ -81,12 +109,6 @@ struct static_route {
         */
        enum static_install_states state;
 
-       /* Administrative distance. */
-       uint8_t distance;
-
-       /* Tag */
-       route_tag_t tag;
-
        /* Flag for this static route's type. */
        static_types type;
 
@@ -104,8 +126,6 @@ struct static_route {
        /* Label information */
        struct static_nh_label snh_label;
 
-       uint32_t table_id;
-
        /*
         * Whether to pretend the nexthop is directly attached to the specified
         * link. Only meaningful when both a gateway address and interface name
@@ -114,32 +134,64 @@ struct static_route {
        bool onlink;
 };
 
+DECLARE_DLIST(static_nexthop_list, struct static_nexthop, list);
+
+
+/*
+ * rib_dest_from_rnode
+ */
+static inline struct static_route_info *
+static_route_info_from_rnode(struct route_node *rn)
+{
+       return (struct static_route_info *)(rn->info);
+}
+
 extern bool mpls_enabled;
 
 extern struct zebra_privs_t static_privs;
 
 void static_fixup_vrf_ids(struct static_vrf *svrf);
 
-extern int static_add_route(afi_t afi, safi_t safi, uint8_t type,
-                           struct prefix *p, struct prefix_ipv6 *src_p,
-                           union g_addr *gate, const char *ifname,
-                           enum static_blackhole_type bh_type, route_tag_t tag,
-                           uint8_t distance, struct static_vrf *svrf,
-                           struct static_vrf *nh_svrf,
-                           struct static_nh_label *snh_label,
-                           uint32_t table_id, bool onlink);
-
-extern int static_delete_route(afi_t afi, safi_t safi, uint8_t type,
-                              struct prefix *p, struct prefix_ipv6 *src_p,
-                              union g_addr *gate, const char *ifname,
-                              route_tag_t tag, uint8_t distance,
-                              struct static_vrf *svrf,
-                              struct static_nh_label *snh_label,
-                              uint32_t table_id);
+extern struct static_nexthop *
+static_add_nexthop(struct route_node *rn, struct static_path *pn, safi_t safi,
+                  struct static_vrf *svrf, static_types type,
+                  struct ipaddr *ipaddr, const char *ifname,
+                  const char *nh_vrf);
+extern void static_install_nexthop(struct route_node *rn,
+                                  struct static_path *pn,
+                                  struct static_nexthop *nh, safi_t safi,
+                                  struct static_vrf *svrf, const char *ifname,
+                                  static_types type, const char *nh_vrf);
+
+extern int static_delete_nexthop(struct route_node *rn, struct static_path *pn,
+                                safi_t safi, struct static_vrf *svrf,
+                                struct static_nexthop *nh);
 
 extern void static_cleanup_vrf_ids(struct static_vrf *disable_svrf);
 
 extern void static_install_intf_nh(struct interface *ifp);
 
 extern void static_ifindex_update(struct interface *ifp, bool up);
+
+extern void static_install_path(struct route_node *rn, struct static_path *pn,
+                               safi_t safi, struct static_vrf *svrf);
+
+extern struct route_node *static_add_route(afi_t afi, safi_t safi,
+                                          struct prefix *p,
+                                          struct prefix_ipv6 *src_p,
+                                          struct static_vrf *svrf);
+extern void static_del_route(struct route_node *rn, safi_t safi,
+                            struct static_vrf *svrf);
+
+extern struct static_path *static_add_path(struct route_node *rn,
+                                          uint8_t distance);
+extern void static_del_path(struct route_node *rn, struct static_path *pn,
+                           safi_t safi, struct static_vrf *svrf);
+
+extern void static_get_nh_type(static_types stype, char *type, size_t size);
+extern bool static_add_nexthop_validate(struct static_vrf *svrf,
+                                       static_types type,
+                                       struct ipaddr *ipaddr);
+extern struct stable_info *static_get_stable_info(struct route_node *rn);
+extern void static_route_info_init(struct static_route_info *si);
 #endif
index 6c065932a10a4757fcc519932edc97bbd874fbe3..39b86787ff60543573fead3f61fca12d7f45b1c7 100644 (file)
 #include "static_zebra.h"
 #include "static_vty.h"
 
+DEFINE_MTYPE_STATIC(STATIC, STATIC_RTABLE_INFO, "Static Route Table Info");
+
 static void zebra_stable_node_cleanup(struct route_table *table,
                                      struct route_node *node)
 {
-       struct static_route *si, *next;
-
-       if (node->info)
-               for (si = node->info; si; si = next) {
-                       next = si->next;
-                       XFREE(MTYPE_STATIC_ROUTE, si);
+       struct static_nexthop *nh;
+       struct static_path *pn;
+       struct static_route_info *si;
+
+       si = node->info;
+
+       if (si) {
+               frr_each_safe(static_path_list, &si->path_list, pn) {
+                       frr_each_safe(static_nexthop_list, &pn->nexthop_list,
+                                      nh) {
+                               static_nexthop_list_del(&pn->nexthop_list, nh);
+                               XFREE(MTYPE_STATIC_NEXTHOP, nh);
+                       }
+                       static_path_list_del(&si->path_list, pn);
+                       XFREE(MTYPE_STATIC_PATH, pn);
                }
+       }
 }
 
 static struct static_vrf *static_vrf_alloc(void)
 {
        struct route_table *table;
        struct static_vrf *svrf;
+       struct stable_info *info;
        safi_t safi;
        afi_t afi;
 
-       svrf = XCALLOC(MTYPE_TMP, sizeof(struct static_vrf));
+       svrf = XCALLOC(MTYPE_STATIC_RTABLE_INFO, sizeof(struct static_vrf));
 
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
@@ -57,6 +70,14 @@ static struct static_vrf *static_vrf_alloc(void)
                                table = srcdest_table_init();
                        else
                                table = route_table_init();
+
+                       info = XCALLOC(MTYPE_STATIC_RTABLE_INFO,
+                                      sizeof(struct stable_info));
+                       info->svrf = svrf;
+                       info->afi = afi;
+                       info->safi = safi;
+                       route_table_set_info(table, info);
+
                        table->cleanup = zebra_stable_node_cleanup;
                        svrf->stable[afi][safi] = table;
                }
@@ -81,12 +102,6 @@ static int static_vrf_enable(struct vrf *vrf)
 
        static_fixup_vrf_ids(vrf->info);
 
-       /*
-        * We may have static routes that are now possible to
-        * insert into the appropriate tables
-        */
-       static_config_install_delayed_routes(vrf->info);
-
        return 0;
 }
 
@@ -102,16 +117,19 @@ static int static_vrf_delete(struct vrf *vrf)
        struct static_vrf *svrf;
        safi_t safi;
        afi_t afi;
+       void *info;
 
        svrf = vrf->info;
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
                        table = svrf->stable[afi][safi];
+                       info = route_table_get_info(table);
                        route_table_finish(table);
+                       XFREE(MTYPE_STATIC_RTABLE_INFO, info);
                        svrf->stable[afi][safi] = NULL;
                }
        }
-       XFREE(MTYPE_TMP, svrf);
+       XFREE(MTYPE_STATIC_RTABLE_INFO, svrf);
        return 0;
 }
 
@@ -210,3 +228,25 @@ void static_vrf_terminate(void)
 {
        vrf_terminate();
 }
+
+struct static_vrf *static_vty_get_unknown_vrf(const char *vrf_name)
+{
+       struct static_vrf *svrf;
+       struct vrf *vrf;
+
+       svrf = static_vrf_lookup_by_name(vrf_name);
+
+       if (svrf)
+               return svrf;
+
+       vrf = vrf_get(VRF_UNKNOWN, vrf_name);
+       if (!vrf)
+               return NULL;
+       svrf = vrf->info;
+       if (!svrf)
+               return NULL;
+       /* Mark as having FRR configuration */
+       vrf_set_user_cfged(vrf);
+
+       return svrf;
+}
index 6951e56712f56f7ec61a28903d85b39b6570758a..12ad1b255af0a40dd610bc4d57a599218ef90744 100644 (file)
@@ -26,6 +26,14 @@ struct static_vrf {
        struct route_table *stable[AFI_MAX][SAFI_MAX];
 };
 
+struct stable_info {
+       struct static_vrf *svrf;
+       afi_t afi;
+       safi_t safi;
+};
+
+#define GET_STABLE_VRF_ID(info) info->svrf->vrf->vrf_id
+
 struct static_vrf *static_vrf_lookup_by_name(const char *vrf_name);
 struct static_vrf *static_vrf_lookup_by_id(vrf_id_t vrf_id);
 
@@ -36,4 +44,6 @@ void static_vrf_init(void);
 struct route_table *static_vrf_static_table(afi_t afi, safi_t safi,
                                            struct static_vrf *svrf);
 extern void static_vrf_terminate(void);
+
+struct static_vrf *static_vty_get_unknown_vrf(const char *vrf_name);
 #endif
index 75bce82eef3d739af8a5a06ff1c22d57917e33e4..311462db7ab29824bb794befd7484227a3e86b3d 100644 (file)
 #include "table.h"
 #include "srcdest_table.h"
 #include "mpls.h"
+#include "northbound.h"
+#include "libfrr.h"
+#include "routing_nb.h"
+#include "northbound_cli.h"
 
 #include "static_vrf.h"
 #include "static_memory.h"
 #ifndef VTYSH_EXTRACT_PL
 #include "staticd/static_vty_clippy.c"
 #endif
+#include "static_nb.h"
 
 #define STATICD_STR "Static route daemon\n"
 
-static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty,
-                                                    const char *vrf_name)
+static int static_route_leak(struct vty *vty, const char *svrf,
+                            const char *nh_svrf, afi_t afi, safi_t safi,
+                            const char *negate, const char *dest_str,
+                            const char *mask_str, const char *src_str,
+                            const char *gate_str, const char *ifname,
+                            const char *flag_str, const char *tag_str,
+                            const char *distance_str, const char *label_str,
+                            const char *table_str, bool onlink)
 {
-       struct static_vrf *svrf;
-       struct vrf *vrf;
-
-       svrf = static_vrf_lookup_by_name(vrf_name);
-
-       if (svrf)
-               return svrf;
-
-       vrf = vrf_get(VRF_UNKNOWN, vrf_name);
-       if (!vrf) {
-               vty_out(vty, "%% Could not create vrf %s\n", vrf_name);
-               return NULL;
-       }
-       svrf = vrf->info;
-       if (!svrf) {
-               vty_out(vty, "%% Could not create vrf-info %s\n",
-                       vrf_name);
-               return NULL;
-       }
-       /* Mark as having FRR configuration */
-       vrf_set_user_cfged(vrf);
-
-       return svrf;
-}
-
-struct static_hold_route {
-       char *vrf_name;
-       char *nhvrf_name;
-       afi_t afi;
-       safi_t safi;
-       char *dest_str;
-       char *mask_str;
-       char *src_str;
-       char *gate_str;
-       char *ifname;
-       char *flag_str;
-       char *tag_str;
-       char *distance_str;
-       char *label_str;
-       char *table_str;
-       bool onlink;
-
-       /* processed & masked destination, used for config display */
-       struct prefix dest;
-};
-
-static struct list *static_list;
-
-static int static_list_compare_helper(const char *s1, const char *s2)
-{
-       /* extra (!s1 && !s2) to keep SA happy */
-       if (s1 == s2 || (!s1 && !s2))
-               return 0;
-
-       if (!s1 && s2)
-               return -1;
-
-       if (s1 && !s2)
-               return 1;
-
-       return strcmp(s1, s2);
-}
-
-static void static_list_delete(struct static_hold_route *shr)
-{
-       XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
-       XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
-       XFREE(MTYPE_STATIC_ROUTE, shr->dest_str);
-       XFREE(MTYPE_STATIC_ROUTE, shr->mask_str);
-       XFREE(MTYPE_STATIC_ROUTE, shr->src_str);
-       XFREE(MTYPE_STATIC_ROUTE, shr->gate_str);
-       XFREE(MTYPE_STATIC_ROUTE, shr->ifname);
-       XFREE(MTYPE_STATIC_ROUTE, shr->flag_str);
-       XFREE(MTYPE_STATIC_ROUTE, shr->tag_str);
-       XFREE(MTYPE_STATIC_ROUTE, shr->distance_str);
-       XFREE(MTYPE_STATIC_ROUTE, shr->label_str);
-       XFREE(MTYPE_STATIC_ROUTE, shr->table_str);
-
-       XFREE(MTYPE_STATIC_ROUTE, shr);
-}
-
-static int static_list_compare(void *arg1, void *arg2)
-{
-       struct static_hold_route *shr1 = arg1;
-       struct static_hold_route *shr2 = arg2;
        int ret;
-
-       ret = strcmp(shr1->vrf_name, shr2->vrf_name);
-       if (ret)
-               return ret;
-
-       ret = strcmp(shr1->nhvrf_name, shr2->nhvrf_name);
-       if (ret)
-               return ret;
-
-       ret = shr1->afi - shr2->afi;
-       if (ret)
-               return ret;
-
-       ret = shr1->safi - shr2->safi;
-       if (ret)
-               return ret;
-
-       ret = prefix_cmp(&shr1->dest, &shr2->dest);
-       if (ret)
-               return ret;
-
-       ret = static_list_compare_helper(shr1->src_str, shr2->src_str);
-       if (ret)
-               return ret;
-
-       ret = static_list_compare_helper(shr1->gate_str, shr2->gate_str);
-       if (ret)
-               return ret;
-
-       ret = static_list_compare_helper(shr1->ifname, shr2->ifname);
-       if (ret)
-               return ret;
-
-       ret = static_list_compare_helper(shr1->flag_str, shr2->flag_str);
-       if (ret)
-               return ret;
-
-       ret = static_list_compare_helper(shr1->tag_str, shr2->tag_str);
-       if (ret)
-               return ret;
-
-       ret = static_list_compare_helper(shr1->distance_str,
-                                        shr2->distance_str);
-       if (ret)
-               return ret;
-
-       ret = static_list_compare_helper(shr1->table_str,
-                                        shr2->table_str);
-       if (ret)
-               return ret;
-
-       return static_list_compare_helper(shr1->label_str, shr2->label_str);
-}
-
-
-/* General function for static route. */
-static int zebra_static_route_holdem(
-       struct static_vrf *svrf, struct static_vrf *nh_svrf, afi_t afi,
-       safi_t safi, const char *negate, struct prefix *dest,
-       const char *dest_str, const char *mask_str, const char *src_str,
-       const char *gate_str, const char *ifname, const char *flag_str,
-       const char *tag_str, const char *distance_str, const char *label_str,
-       const char *table_str, bool onlink)
-{
-       struct static_hold_route *shr, *lookup;
-       struct listnode *node;
-
-       zlog_warn("Static Route to %s not installed currently because dependent config not fully available",
-                 dest_str);
-
-       shr = XCALLOC(MTYPE_STATIC_ROUTE, sizeof(*shr));
-       shr->vrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, svrf->vrf->name);
-       shr->nhvrf_name = XSTRDUP(MTYPE_STATIC_ROUTE, nh_svrf->vrf->name);
-       shr->afi = afi;
-       shr->safi = safi;
-       shr->onlink = onlink;
-       if (dest)
-               prefix_copy(&shr->dest, dest);
-       if (dest_str)
-               shr->dest_str = XSTRDUP(MTYPE_STATIC_ROUTE, dest_str);
-       if (mask_str)
-               shr->mask_str = XSTRDUP(MTYPE_STATIC_ROUTE, mask_str);
-       if (src_str)
-               shr->src_str = XSTRDUP(MTYPE_STATIC_ROUTE, src_str);
-       if (gate_str)
-               shr->gate_str = XSTRDUP(MTYPE_STATIC_ROUTE, gate_str);
-       if (ifname)
-               shr->ifname = XSTRDUP(MTYPE_STATIC_ROUTE, ifname);
-       if (flag_str)
-               shr->flag_str = XSTRDUP(MTYPE_STATIC_ROUTE, flag_str);
-       if (tag_str)
-               shr->tag_str = XSTRDUP(MTYPE_STATIC_ROUTE, tag_str);
-       if (distance_str)
-               shr->distance_str = XSTRDUP(MTYPE_STATIC_ROUTE, distance_str);
-       if (label_str)
-               shr->label_str = XSTRDUP(MTYPE_STATIC_ROUTE, label_str);
-       if (table_str)
-               shr->table_str = XSTRDUP(MTYPE_STATIC_ROUTE, table_str);
-
-       for (ALL_LIST_ELEMENTS_RO(static_list, node, lookup)) {
-               if (static_list_compare(shr, lookup) == 0)
-                       break;
-       }
-
-       if (lookup) {
-               if (negate) {
-                       listnode_delete(static_list, lookup);
-                       static_list_delete(shr);
-                       static_list_delete(lookup);
-
-                       return CMD_SUCCESS;
-               }
-
-               /*
-                * If a person enters the same line again
-                * we need to silently accept it
-                */
-               goto shr_cleanup;
-       }
-
-       if (!negate) {
-               listnode_add_sort(static_list, shr);
-               return CMD_SUCCESS;
-       }
-
- shr_cleanup:
-       XFREE(MTYPE_STATIC_ROUTE, shr->nhvrf_name);
-       XFREE(MTYPE_STATIC_ROUTE, shr->vrf_name);
-       XFREE(MTYPE_STATIC_ROUTE, shr);
-
-       return CMD_SUCCESS;
-}
-
-static int static_route_leak(
-       struct vty *vty, struct static_vrf *svrf, struct static_vrf *nh_svrf,
-       afi_t afi, safi_t safi, const char *negate, const char *dest_str,
-       const char *mask_str, const char *src_str, const char *gate_str,
-       const char *ifname, const char *flag_str, const char *tag_str,
-       const char *distance_str, const char *label_str, const char *table_str,
-       bool onlink)
-{
-       int ret;
-       uint8_t distance;
        struct prefix p, src;
-       struct prefix_ipv6 *src_p = NULL;
-       union g_addr gate;
-       union g_addr *gatep = NULL;
        struct in_addr mask;
-       enum static_blackhole_type bh_type = 0;
-       route_tag_t tag = 0;
        uint8_t type;
-       struct static_nh_label snh_label;
+       const char *bh_type;
+       char xpath_prefix[XPATH_MAXLEN];
+       char xpath_nexthop[XPATH_MAXLEN];
+       char xpath_mpls[XPATH_MAXLEN];
+       char xpath_label[XPATH_MAXLEN];
+       char ab_xpath[XPATH_MAXLEN];
+       char buf_prefix[PREFIX_STRLEN];
+       char buf_src_prefix[PREFIX_STRLEN];
+       char buf_nh_type[PREFIX_STRLEN];
+       char buf_tag[PREFIX_STRLEN];
+       char buf_tableid[PREFIX_STRLEN];
+       uint8_t label_stack_id = 0;
+       const char *buf_gate_str;
+       uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
+       route_tag_t tag = 0;
        uint32_t table_id = 0;
+       const struct lyd_node *dnode;
+
+       memset(buf_src_prefix, 0, PREFIX_STRLEN);
+       memset(buf_nh_type, 0, PREFIX_STRLEN);
 
        ret = str2prefix(dest_str, &p);
        if (ret <= 0) {
@@ -322,7 +118,6 @@ static int static_route_leak(
                                                __func__, src_str);
                                return CMD_WARNING_CONFIG_FAILED;
                        }
-                       src_p = (struct prefix_ipv6 *)&src;
                }
                break;
        default:
@@ -332,29 +127,29 @@ static int static_route_leak(
        /* Apply mask for given prefix. */
        apply_mask(&p);
 
-       if (svrf->vrf->vrf_id == VRF_UNKNOWN
-           || nh_svrf->vrf->vrf_id == VRF_UNKNOWN) {
-               vrf_set_user_cfged(svrf->vrf);
-               return zebra_static_route_holdem(
-                       svrf, nh_svrf, afi, safi, negate, &p, dest_str,
-                       mask_str, src_str, gate_str, ifname, flag_str, tag_str,
-                       distance_str, label_str, table_str, onlink);
-       }
+       prefix2str(&p, buf_prefix, sizeof(buf_prefix));
 
-       if (table_str) {
-               /* table configured. check consistent with vrf config
-                */
-               if (svrf->vrf->data.l.table_id != RT_TABLE_MAIN) {
-                       if (vty)
-                               vty_out(vty,
-                                   "%% Table %s overlaps vrf table %u\n",
-                                   table_str, svrf->vrf->data.l.table_id);
-                       else
-                               zlog_warn("%s: Table %s overlaps vrf table %u",
-                                         __func__, table_str,
-                                         svrf->vrf->data.l.table_id);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
+       if (src_str)
+               prefix2str(&src, buf_src_prefix, sizeof(buf_src_prefix));
+       if (gate_str)
+               buf_gate_str = gate_str;
+       else
+               buf_gate_str = "";
+
+       if (gate_str == NULL && ifname == NULL)
+               type = STATIC_BLACKHOLE;
+       else if (gate_str && ifname) {
+               if (afi == AFI_IP)
+                       type = STATIC_IPV4_GATEWAY_IFNAME;
+               else
+                       type = STATIC_IPV6_GATEWAY_IFNAME;
+       } else if (ifname)
+               type = STATIC_IFNAME;
+       else {
+               if (afi == AFI_IP)
+                       type = STATIC_IPV4_GATEWAY;
+               else
+                       type = STATIC_IPV6_GATEWAY;
        }
 
        /* Administrative distance. */
@@ -367,169 +162,156 @@ static int static_route_leak(
        if (tag_str)
                tag = strtoul(tag_str, NULL, 10);
 
-       /* Labels */
-       memset(&snh_label, 0, sizeof(struct static_nh_label));
-       if (label_str) {
-               if (!mpls_enabled) {
-                       if (vty)
-                               vty_out(vty,
-                                       "%% MPLS not turned on in kernel, ignoring command\n");
-                       else
-                               zlog_warn(
-                                       "%s: MPLS not turned on in kernel ignoring static route to %s",
-                                       __func__, dest_str);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-               int rc = mpls_str2label(label_str, &snh_label.num_labels,
-                                       snh_label.label);
-               if (rc < 0) {
-                       switch (rc) {
-                       case -1:
-                               if (vty)
-                                       vty_out(vty, "%% Malformed label(s)\n");
-                               else
-                                       zlog_warn(
-                                               "%s: Malformed labels specified for route %s",
-                                               __func__, dest_str);
-                               break;
-                       case -2:
-                               if (vty)
-                                       vty_out(vty,
-                                               "%% Cannot use reserved label(s) (%d-%d)\n",
-                                               MPLS_LABEL_RESERVED_MIN,
-                                               MPLS_LABEL_RESERVED_MAX);
-                               else
-                                       zlog_warn(
-                                               "%s: Cannot use reserved labels (%d-%d) for %s",
-                                               __func__,
-                                               MPLS_LABEL_RESERVED_MIN,
-                                               MPLS_LABEL_RESERVED_MAX,
-                                               dest_str);
-                               break;
-                       case -3:
-                               if (vty)
-                                       vty_out(vty,
-                                               "%% Too many labels. Enter %d or fewer\n",
-                                               MPLS_MAX_LABELS);
-                               else
-                                       zlog_warn(
-                                               "%s: Too many labels, Enter %d or fewer for %s",
-                                               __func__, MPLS_MAX_LABELS,
-                                               dest_str);
-                               break;
-                       }
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-       }
-
        /* TableID */
        if (table_str)
                table_id = atol(table_str);
 
-       /* Null0 static route.  */
-       if (ifname != NULL) {
-               if (strcasecmp(ifname, "Null0") == 0
-                   || strcasecmp(ifname, "reject") == 0
-                   || strcasecmp(ifname, "blackhole") == 0) {
-                       if (vty)
-                               vty_out(vty,
-                                       "%% Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)\n");
-                       else
-                               zlog_warn(
-                                       "%s: %s: Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)",
-                                       __func__, dest_str);
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-       }
-
-       /* Route flags */
-       if (flag_str) {
-               switch (flag_str[0]) {
-               case 'r':
-                       bh_type = STATIC_BLACKHOLE_REJECT;
-                       break;
-               case 'b':
-                       bh_type = STATIC_BLACKHOLE_DROP;
-                       break;
-               case 'N':
-                       bh_type = STATIC_BLACKHOLE_NULL;
-                       break;
-               default:
-                       if (vty)
-                               vty_out(vty, "%% Malformed flag %s \n",
-                                       flag_str);
-                       else
-                               zlog_warn("%s: Malformed flag %s for %s",
-                                         __func__, flag_str, dest_str);
-                       return CMD_WARNING_CONFIG_FAILED;
+       static_get_nh_type(type, buf_nh_type, PREFIX_STRLEN);
+       if (!negate) {
+               /* route + path procesing */
+               if (src_str)
+                       snprintf(xpath_prefix, sizeof(xpath_prefix),
+                                FRR_S_ROUTE_SRC_INFO_KEY_XPATH,
+                                "frr-staticd:staticd", "staticd", svrf,
+                                buf_prefix,
+                                buf_src_prefix, distance);
+               else
+                       snprintf(xpath_prefix, sizeof(xpath_prefix),
+                                FRR_STATIC_ROUTE_INFO_KEY_XPATH,
+                                "frr-staticd:staticd", "staticd", svrf,
+                                buf_prefix,
+                                distance);
+
+               nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
+
+               /* Tag processing */
+               snprintf(buf_tag, sizeof(buf_tag), "%u", tag);
+               strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath));
+               strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TAG_XPATH,
+                       sizeof(ab_xpath));
+               nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tag);
+
+               /* Table-Id processing */
+               snprintf(buf_tableid, sizeof(buf_tableid), "%u", table_id);
+               strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath));
+               strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TABLEID_XPATH,
+                       sizeof(ab_xpath));
+               nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tableid);
+               /* nexthop processing */
+
+               snprintf(ab_xpath, sizeof(ab_xpath),
+                        FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type, nh_svrf,
+                        buf_gate_str, ifname);
+               strlcpy(xpath_nexthop, xpath_prefix, sizeof(xpath_nexthop));
+               strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop));
+               nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_CREATE, NULL);
+
+               if (type == STATIC_BLACKHOLE) {
+                       strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
+                       strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_BH_XPATH,
+                               sizeof(ab_xpath));
+
+                       /* Route flags */
+                       if (flag_str) {
+                               switch (flag_str[0]) {
+                               case 'r':
+                                       bh_type = "reject";
+                                       break;
+                               case 'b':
+                                       bh_type = "unspec";
+                                       break;
+                               case 'N':
+                                       bh_type = "null";
+                                       break;
+                               default:
+                                       bh_type = NULL;
+                                       break;
+                               }
+                               nb_cli_enqueue_change(vty, ab_xpath,
+                                                     NB_OP_MODIFY, bh_type);
+                       } else {
+                               nb_cli_enqueue_change(vty, ab_xpath,
+                                                     NB_OP_MODIFY, "null");
+                       }
                }
-       }
-
-       if (gate_str) {
-               if (inet_pton(afi2family(afi), gate_str, &gate) != 1) {
-                       if (vty)
-                               vty_out(vty,
-                                       "%% Malformed nexthop address %s\n",
-                                       gate_str);
+               if (type == STATIC_IPV4_GATEWAY_IFNAME
+                   || type == STATIC_IPV6_GATEWAY_IFNAME) {
+                       strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
+                       strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_ONLINK_XPATH,
+                               sizeof(ab_xpath));
+
+                       if (onlink)
+                               nb_cli_enqueue_change(vty, ab_xpath,
+                                                     NB_OP_MODIFY, "true");
                        else
-                               zlog_warn(
-                                       "%s: Malformed nexthop address %s for %s",
-                                       __func__, gate_str, dest_str);
-                       return CMD_WARNING_CONFIG_FAILED;
+                               nb_cli_enqueue_change(vty, ab_xpath,
+                                                     NB_OP_MODIFY, "false");
                }
-               gatep = &gate;
-
-               if (afi == AFI_IP && !negate) {
-                       if (if_lookup_exact_address(&gatep->ipv4, AF_INET,
-                                                       svrf->vrf->vrf_id))
-                               if (vty)
-                                       vty_out(vty,
-                                               "%% Warning!! Local connected address is configured as Gateway IP(%s)\n",
-                                               gate_str);
-               } else if (afi == AFI_IP6 && !negate) {
-                       if (if_lookup_exact_address(&gatep->ipv6, AF_INET6,
-                                                       svrf->vrf->vrf_id))
-                               if (vty)
-                                       vty_out(vty,
-                                               "%% Warning!! Local connected address is configured as Gateway IPv6(%s)\n",
-                                               gate_str);
+               if (label_str) {
+                       /* copy of label string (start) */
+                       char *ostr;
+                       /* pointer to next segment */
+                       char *nump;
+
+                       strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
+                       strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
+                               sizeof(xpath_mpls));
+
+                       nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
+                                             NULL);
+
+                       ostr = XSTRDUP(MTYPE_TMP, label_str);
+                       while ((nump = strsep(&ostr, "/")) != NULL) {
+                               snprintf(ab_xpath, sizeof(ab_xpath),
+                                        FRR_STATIC_ROUTE_NHLB_KEY_XPATH,
+                                        label_stack_id);
+                               strlcpy(xpath_label, xpath_mpls,
+                                       sizeof(xpath_label));
+                               strlcat(xpath_label, ab_xpath,
+                                       sizeof(xpath_label));
+                               nb_cli_enqueue_change(vty, xpath_label,
+                                                     NB_OP_MODIFY, nump);
+                               label_stack_id++;
+                       }
+                       XFREE(MTYPE_TMP, ostr);
+               } else {
+                       strlcpy(xpath_mpls, xpath_nexthop, sizeof(xpath_mpls));
+                       strlcat(xpath_mpls, FRR_STATIC_ROUTE_NH_LABEL_XPATH,
+                               sizeof(xpath_mpls));
+                       nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
+                                             NULL);
                }
-
-       }
-
-       if (gate_str == NULL && ifname == NULL)
-               type = STATIC_BLACKHOLE;
-       else if (gate_str && ifname) {
-               if (afi == AFI_IP)
-                       type = STATIC_IPV4_GATEWAY_IFNAME;
-               else
-                       type = STATIC_IPV6_GATEWAY_IFNAME;
-       } else if (ifname)
-               type = STATIC_IFNAME;
-       else {
-               if (afi == AFI_IP)
-                       type = STATIC_IPV4_GATEWAY;
-               else
-                       type = STATIC_IPV6_GATEWAY;
-       }
-
-       if (!negate) {
-               static_add_route(afi, safi, type, &p, src_p, gatep, ifname,
-                                bh_type, tag, distance, svrf, nh_svrf,
-                                &snh_label, table_id, onlink);
-               /* Mark as having FRR configuration */
-               vrf_set_user_cfged(svrf->vrf);
+               ret = nb_cli_apply_changes(vty, xpath_prefix);
        } else {
-               static_delete_route(afi, safi, type, &p, src_p, gatep, ifname,
-                                   tag, distance, svrf, &snh_label, table_id);
-               /* If no other FRR config for this VRF, mark accordingly. */
-               if (!static_vrf_has_config(svrf))
-                       vrf_reset_user_cfged(svrf->vrf);
+               if (src_str)
+                       snprintf(ab_xpath, sizeof(ab_xpath),
+                                FRR_DEL_S_ROUTE_SRC_NH_KEY_XPATH,
+                                "frr-staticd:staticd", "staticd", svrf,
+                                buf_prefix,
+                                buf_src_prefix, distance, buf_nh_type, nh_svrf,
+                                buf_gate_str, ifname);
+               else
+                       snprintf(ab_xpath, sizeof(ab_xpath),
+                                FRR_DEL_S_ROUTE_NH_KEY_XPATH,
+                                "frr-staticd:staticd", "staticd", svrf,
+                                buf_prefix,
+                                distance, buf_nh_type, nh_svrf, buf_gate_str,
+                                ifname);
+
+               dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
+               if (!dnode)
+                       return ret;
+
+               dnode = yang_get_subtree_with_no_sibling(dnode);
+               assert(dnode);
+               yang_dnode_get_path(dnode, ab_xpath, XPATH_MAXLEN);
+
+               nb_cli_enqueue_change(vty, ab_xpath, NB_OP_DESTROY, NULL);
+               ret = nb_cli_apply_changes(vty, ab_xpath);
        }
 
-       return CMD_SUCCESS;
+       return ret;
 }
-
 static int static_route(struct vty *vty, afi_t afi, safi_t safi,
                        const char *negate, const char *dest_str,
                        const char *mask_str, const char *src_str,
@@ -538,77 +320,28 @@ static int static_route(struct vty *vty, afi_t afi, safi_t safi,
                        const char *distance_str, const char *vrf_name,
                        const char *label_str, const char *table_str)
 {
-       struct static_vrf *svrf;
-
-       /* VRF id */
-       svrf = static_vrf_lookup_by_name(vrf_name);
-
-       /* When trying to delete, the VRF must exist. */
-       if (negate && !svrf) {
-               vty_out(vty, "%% vrf %s is not defined\n", vrf_name);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       if (!vrf_name)
+               vrf_name = VRF_DEFAULT_NAME;
 
-       /* When trying to create, create the VRF if it doesn't exist.
-        * Note: The VRF isn't active until we hear about it from the kernel.
-        */
-       if (!svrf) {
-               svrf = static_vty_get_unknown_vrf(vty, vrf_name);
-               if (!svrf)
-                       return CMD_WARNING_CONFIG_FAILED;
-       }
-       return static_route_leak(vty, svrf, svrf, afi, safi, negate, dest_str,
-                                mask_str, src_str, gate_str, ifname, flag_str,
-                                tag_str, distance_str, label_str, table_str,
-                                false);
-}
-
-void static_config_install_delayed_routes(struct static_vrf *svrf)
-{
-       struct listnode *node, *nnode;
-       struct static_hold_route *shr;
-       struct static_vrf *osvrf, *nh_svrf;
-       int installed;
-
-       for (ALL_LIST_ELEMENTS(static_list, node, nnode, shr)) {
-               osvrf = static_vrf_lookup_by_name(shr->vrf_name);
-               nh_svrf = static_vrf_lookup_by_name(shr->nhvrf_name);
-
-               if (osvrf != svrf && nh_svrf != svrf)
-                       continue;
-
-               if (osvrf->vrf->vrf_id == VRF_UNKNOWN
-                   || nh_svrf->vrf->vrf_id == VRF_UNKNOWN)
-                       continue;
-
-               installed = static_route_leak(
-                       NULL, osvrf, nh_svrf, shr->afi, shr->safi, NULL,
-                       shr->dest_str, shr->mask_str, shr->src_str,
-                       shr->gate_str, shr->ifname, shr->flag_str, shr->tag_str,
-                       shr->distance_str, shr->label_str, shr->table_str,
-                       shr->onlink);
-
-               if (installed != CMD_SUCCESS)
-                       zlog_debug(
-                               "%s: Attempt to install %s as a route and it was rejected",
-                               __func__, shr->dest_str);
-               listnode_delete(static_list, shr);
-               static_list_delete(shr);
-       }
+       return static_route_leak(vty, vrf_name, vrf_name, afi, safi, negate,
+                                dest_str, mask_str, src_str, gate_str, ifname,
+                                flag_str, tag_str, distance_str, label_str,
+                                table_str, false);
 }
 
 /* Write static route configuration. */
 int static_config(struct vty *vty, struct static_vrf *svrf, afi_t afi,
                  safi_t safi, const char *cmd)
 {
-       struct static_hold_route *shr;
-       struct listnode *node;
        char spacing[100];
        struct route_node *rn;
-       struct static_route *si;
+       struct static_nexthop *nh;
+       struct static_path *pn;
        struct route_table *stable;
+       struct static_route_info *si;
        char buf[SRCDEST2STR_BUFFER];
        int write = 0;
+       struct stable_info *info;
 
        stable = svrf->stable[afi][safi];
        if (stable == NULL)
@@ -617,120 +350,99 @@ int static_config(struct vty *vty, struct static_vrf *svrf, afi_t afi,
        snprintf(spacing, sizeof(spacing), "%s%s",
                 (svrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ", cmd);
 
-       /*
-        * Static routes for vrfs not fully inited
-        */
-       for (ALL_LIST_ELEMENTS_RO(static_list, node, shr)) {
-               if (shr->afi != afi || shr->safi != safi)
+       for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
+               si = static_route_info_from_rnode(rn);
+               if (!si)
                        continue;
-
-               if (strcmp(svrf->vrf->name, shr->vrf_name) != 0)
-                       continue;
-
-               char dest_str[PREFIX_STRLEN];
-
-               prefix2str(&shr->dest, dest_str, sizeof(dest_str));
-
-               vty_out(vty, "%s ", spacing);
-               if (shr->dest_str)
-                       vty_out(vty, "%s ", dest_str);
-               if (shr->src_str)
-                       vty_out(vty, "from %s ", shr->src_str);
-               if (shr->gate_str)
-                       vty_out(vty, "%s ", shr->gate_str);
-               if (shr->ifname)
-                       vty_out(vty, "%s ", shr->ifname);
-               if (shr->flag_str)
-                       vty_out(vty, "%s ", shr->flag_str);
-               if (shr->tag_str)
-                       vty_out(vty, "tag %s ", shr->tag_str);
-               if (shr->distance_str)
-                       vty_out(vty, "%s ", shr->distance_str);
-               if (shr->label_str)
-                       vty_out(vty, "label %s ", shr->label_str);
-               if (shr->table_str)
-                       vty_out(vty, "table %s", shr->table_str);
-               if (strcmp(shr->vrf_name, shr->nhvrf_name) != 0)
-                       vty_out(vty, "nexthop-vrf %s ", shr->nhvrf_name);
-               if (shr->onlink)
-                       vty_out(vty, "onlink");
-               vty_out(vty, "\n");
-       }
-
-       for (rn = route_top(stable); rn; rn = srcdest_route_next(rn))
-               for (si = rn->info; si; si = si->next) {
-                       vty_out(vty, "%s %s", spacing,
-                               srcdest_rnode2str(rn, buf, sizeof(buf)));
-
-                       switch (si->type) {
-                       case STATIC_IPV4_GATEWAY:
-                               vty_out(vty, " %s", inet_ntoa(si->addr.ipv4));
-                               break;
-                       case STATIC_IPV6_GATEWAY:
-                               vty_out(vty, " %s",
-                                       inet_ntop(AF_INET6, &si->addr.ipv6, buf,
-                                                 sizeof(buf)));
-                               break;
-                       case STATIC_IFNAME:
-                               vty_out(vty, " %s", si->ifname);
-                               break;
-                       case STATIC_BLACKHOLE:
-                               switch (si->bh_type) {
-                               case STATIC_BLACKHOLE_DROP:
-                                       vty_out(vty, " blackhole");
+               info = static_get_stable_info(rn);
+               frr_each(static_path_list, &si->path_list, pn) {
+                       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+                               vty_out(vty, "%s %s", spacing,
+                                       srcdest_rnode2str(rn, buf,
+                                                         sizeof(buf)));
+
+                               switch (nh->type) {
+                               case STATIC_IPV4_GATEWAY:
+                                       vty_out(vty, " %s",
+                                               inet_ntoa(nh->addr.ipv4));
                                        break;
-                               case STATIC_BLACKHOLE_NULL:
-                                       vty_out(vty, " Null0");
+                               case STATIC_IPV6_GATEWAY:
+                                       vty_out(vty, " %s",
+                                               inet_ntop(AF_INET6,
+                                                         &nh->addr.ipv6, buf,
+                                                         sizeof(buf)));
                                        break;
-                               case STATIC_BLACKHOLE_REJECT:
-                                       vty_out(vty, " reject");
+                               case STATIC_IFNAME:
+                                       vty_out(vty, " %s", nh->ifname);
+                                       break;
+                               case STATIC_BLACKHOLE:
+                                       switch (nh->bh_type) {
+                                       case STATIC_BLACKHOLE_DROP:
+                                               vty_out(vty, " blackhole");
+                                               break;
+                                       case STATIC_BLACKHOLE_NULL:
+                                               vty_out(vty, " Null0");
+                                               break;
+                                       case STATIC_BLACKHOLE_REJECT:
+                                               vty_out(vty, " reject");
+                                               break;
+                                       }
+                                       break;
+                               case STATIC_IPV4_GATEWAY_IFNAME:
+                                       vty_out(vty, " %s %s",
+                                               inet_ntop(AF_INET,
+                                                         &nh->addr.ipv4, buf,
+                                                         sizeof(buf)),
+                                               nh->ifname);
+                                       break;
+                               case STATIC_IPV6_GATEWAY_IFNAME:
+                                       vty_out(vty, " %s %s",
+                                               inet_ntop(AF_INET6,
+                                                         &nh->addr.ipv6, buf,
+                                                         sizeof(buf)),
+                                               nh->ifname);
                                        break;
                                }
-                               break;
-                       case STATIC_IPV4_GATEWAY_IFNAME:
-                               vty_out(vty, " %s %s",
-                                       inet_ntop(AF_INET, &si->addr.ipv4, buf,
-                                                 sizeof(buf)),
-                                       si->ifname);
-                               break;
-                       case STATIC_IPV6_GATEWAY_IFNAME:
-                               vty_out(vty, " %s %s",
-                                       inet_ntop(AF_INET6, &si->addr.ipv6, buf,
-                                                 sizeof(buf)),
-                                       si->ifname);
-                               break;
-                       }
 
-                       if (si->tag)
-                               vty_out(vty, " tag %" ROUTE_TAG_PRI, si->tag);
-
-                       if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT)
-                               vty_out(vty, " %d", si->distance);
-
-                       /* Label information */
-                       if (si->snh_label.num_labels)
-                               vty_out(vty, " label %s",
-                                       mpls_label2str(si->snh_label.num_labels,
-                                                      si->snh_label.label, buf,
-                                                      sizeof(buf), 0));
-
-                       if (si->nh_vrf_id != si->vrf_id)
-                               vty_out(vty, " nexthop-vrf %s", si->nh_vrfname);
-
-                       /*
-                        * table ID from VRF overrides configured
-                        */
-                       if (si->table_id &&
-                           svrf->vrf->data.l.table_id == RT_TABLE_MAIN)
-                               vty_out(vty, " table %u", si->table_id);
-
-                       if (si->onlink)
-                               vty_out(vty, " onlink");
-
-                       vty_out(vty, "\n");
-
-                       write = 1;
+                               if (pn->tag)
+                                       vty_out(vty, " tag %" ROUTE_TAG_PRI,
+                                               pn->tag);
+
+                               if (pn->distance
+                                   != ZEBRA_STATIC_DISTANCE_DEFAULT)
+                                       vty_out(vty, " %u", pn->distance);
+
+                               /* Label information */
+                               if (nh->snh_label.num_labels)
+                                       vty_out(vty, " label %s",
+                                               mpls_label2str(
+                                                       nh->snh_label
+                                                               .num_labels,
+                                                       nh->snh_label.label,
+                                                       buf, sizeof(buf), 0));
+
+                               if (nh->nh_vrf_id != GET_STABLE_VRF_ID(info))
+                                       vty_out(vty, " nexthop-vrf %s",
+                                               nh->nh_vrfname);
+
+                               /*
+                                * table ID from VRF overrides
+                                * configured
+                                */
+                               if (pn->table_id
+                                   && svrf->vrf->data.l.table_id
+                                              == RT_TABLE_MAIN)
+                                       vty_out(vty, " table %u", pn->table_id);
+
+                               if (nh->onlink)
+                                       vty_out(vty, " onlink");
+
+                               vty_out(vty, "\n");
+
+                               write = 1;
+                       }
                }
+       }
        return write;
 }
 
@@ -815,23 +527,24 @@ DEFPY(ip_route_blackhole_vrf,
       "Table to configure\n"
       "The table number to configure\n")
 {
-       VTY_DECLVAR_CONTEXT(vrf, vrf);
-       struct static_vrf *svrf = vrf->info;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
 
-       if (table_str && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
+       vrf_dnode =
+               yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+       if (!vrf_dnode) {
+               vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
-
+       vrfname = yang_dnode_get_string(vrf_dnode, "./name");
        /*
         * Coverity is complaining that prefix could
         * be dereferenced, but we know that prefix will
         * valid.  Add an assert to make it happy
         */
        assert(prefix);
-       return static_route_leak(vty, svrf, svrf, AFI_IP, SAFI_UNICAST, no,
-                                prefix, mask_str, NULL, NULL, NULL, flag,
+       return static_route_leak(vty, vrfname, vrfname, AFI_IP, SAFI_UNICAST,
+                                no, prefix, mask_str, NULL, NULL, NULL, flag,
                                 tag_str, distance_str, label, table_str,
                                 false);
 }
@@ -869,38 +582,22 @@ DEFPY(ip_route_address_interface,
       VRF_CMD_HELP_STR
       "Treat the nexthop as directly attached to the interface\n")
 {
-       struct static_vrf *svrf;
-       struct static_vrf *nh_svrf;
+       const char *nh_vrf;
        const char *flag = NULL;
 
        if (ifname && !strncasecmp(ifname, "Null0", 5)) {
                flag = "Null0";
                ifname = NULL;
        }
-
-       svrf = static_vty_get_unknown_vrf(vty, vrf);
-       if (!svrf) {
-               vty_out(vty, "%% vrf %s is not defined\n", vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       if (table_str && vrf && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       if (!vrf)
+               vrf = VRF_DEFAULT_NAME;
 
        if (nexthop_vrf)
-               nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+               nh_vrf = nexthop_vrf;
        else
-               nh_svrf = svrf;
+               nh_vrf = vrf;
 
-       if (!nh_svrf) {
-               vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return static_route_leak(vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no,
+       return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
                                 prefix, mask_str, NULL, gate_str, ifname, flag,
                                 tag_str, distance_str, label, table_str,
                                 !!onlink);
@@ -937,33 +634,29 @@ DEFPY(ip_route_address_interface_vrf,
       VRF_CMD_HELP_STR
       "Treat the nexthop as directly attached to the interface\n")
 {
-       VTY_DECLVAR_CONTEXT(vrf, vrf);
+       const char *nh_vrf;
        const char *flag = NULL;
-       struct static_vrf *svrf = vrf->info;
-       struct static_vrf *nh_svrf;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
 
-       if (table_str && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
+       vrf_dnode =
+               yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+       if (!vrf_dnode) {
+               vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
+       vrfname = yang_dnode_get_string(vrf_dnode, "./name");
 
        if (ifname && !strncasecmp(ifname, "Null0", 5)) {
                flag = "Null0";
                ifname = NULL;
        }
-
        if (nexthop_vrf)
-               nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+               nh_vrf = nexthop_vrf;
        else
-               nh_svrf = svrf;
-
-       if (!nh_svrf) {
-               vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+               nh_vrf = vrfname;
 
-       return static_route_leak(vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no,
+       return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
                                 prefix, mask_str, NULL, gate_str, ifname, flag,
                                 tag_str, distance_str, label, table_str,
                                 !!onlink);
@@ -999,41 +692,26 @@ DEFPY(ip_route,
       "The table number to configure\n"
       VRF_CMD_HELP_STR)
 {
-       struct static_vrf *svrf;
-       struct static_vrf *nh_svrf;
+       const char *nh_vrf;
        const char *flag = NULL;
 
-       if (table_str && vrf && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
        if (ifname && !strncasecmp(ifname, "Null0", 5)) {
                flag = "Null0";
                ifname = NULL;
        }
 
-       svrf = static_vty_get_unknown_vrf(vty, vrf);
-       if (!svrf) {
-               vty_out(vty, "%% vrf %s is not defined\n", vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       if (!vrf)
+               vrf = VRF_DEFAULT_NAME;
 
        if (nexthop_vrf)
-               nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+               nh_vrf = nexthop_vrf;
        else
-               nh_svrf = svrf;
+               nh_vrf = vrf;
 
-       if (!nh_svrf) {
-               vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       return static_route_leak(
-               vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
-               NULL, gate_str, ifname, flag, tag_str, distance_str, label,
-               table_str, false);
+       return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
+                                prefix, mask_str, NULL, gate_str, ifname, flag,
+                                tag_str, distance_str, label, table_str,
+                                false);
 }
 
 DEFPY(ip_route_vrf,
@@ -1064,36 +742,33 @@ DEFPY(ip_route_vrf,
       "The table number to configure\n"
       VRF_CMD_HELP_STR)
 {
-       VTY_DECLVAR_CONTEXT(vrf, vrf);
-       struct static_vrf *svrf = vrf->info;
-       struct static_vrf *nh_svrf;
+       const char *nh_vrf;
        const char *flag = NULL;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
 
-       if (table_str && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
+       vrf_dnode =
+               yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+       if (!vrf_dnode) {
+               vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+
        if (ifname && !strncasecmp(ifname, "Null0", 5)) {
                flag = "Null0";
                ifname = NULL;
        }
-
        if (nexthop_vrf)
-               nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+               nh_vrf = nexthop_vrf;
        else
-               nh_svrf = svrf;
-
-       if (!nh_svrf) {
-               vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+               nh_vrf = vrfname;
 
-       return static_route_leak(
-               vty, svrf, nh_svrf, AFI_IP, SAFI_UNICAST, no, prefix, mask_str,
-               NULL, gate_str, ifname, flag, tag_str, distance_str, label,
-               table_str, false);
+       return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
+                                prefix, mask_str, NULL, gate_str, ifname, flag,
+                                tag_str, distance_str, label, table_str,
+                                false);
 }
 
 DEFPY(ipv6_route_blackhole,
@@ -1159,14 +834,16 @@ DEFPY(ipv6_route_blackhole_vrf,
       "Table to configure\n"
       "The table number to configure\n")
 {
-       VTY_DECLVAR_CONTEXT(vrf, vrf);
-       struct static_vrf *svrf = vrf->info;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
 
-       if (table_str && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
+       vrf_dnode =
+               yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+       if (!vrf_dnode) {
+               vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
+       vrfname = yang_dnode_get_string(vrf_dnode, "./name");
 
        /*
         * Coverity is complaining that prefix could
@@ -1174,10 +851,11 @@ DEFPY(ipv6_route_blackhole_vrf,
         * valid.  Add an assert to make it happy
         */
        assert(prefix);
-       return static_route_leak(
-               vty, svrf, svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
-               from_str, NULL, NULL, flag, tag_str, distance_str, label,
-               table_str, false);
+
+       return static_route_leak(vty, vrfname, vrfname, AFI_IP6, SAFI_UNICAST,
+                                no, prefix_str, NULL, from_str, NULL, NULL,
+                                flag, tag_str, distance_str, label, table_str,
+                                false);
 }
 
 DEFPY(ipv6_route_address_interface,
@@ -1213,41 +891,26 @@ DEFPY(ipv6_route_address_interface,
       VRF_CMD_HELP_STR
       "Treat the nexthop as directly attached to the interface\n")
 {
-       struct static_vrf *svrf;
-       struct static_vrf *nh_svrf;
+       const char *nh_vrf;
        const char *flag = NULL;
 
-       if (table_str && vrf && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
-               return CMD_WARNING_CONFIG_FAILED;
+       if (ifname && !strncasecmp(ifname, "Null0", 5)) {
+               flag = "Null0";
+               ifname = NULL;
        }
 
-       svrf = static_vty_get_unknown_vrf(vty, vrf);
-       if (!svrf) {
-               vty_out(vty, "%% vrf %s is not defined\n", vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       if (!vrf)
+               vrf = VRF_DEFAULT_NAME;
 
        if (nexthop_vrf)
-               nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+               nh_vrf = nexthop_vrf;
        else
-               nh_svrf = svrf;
-
-       if (!nh_svrf) {
-               vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+               nh_vrf = vrf;
 
-       if (ifname && !strncasecmp(ifname, "Null0", 5)) {
-               flag = "Null0";
-               ifname = NULL;
-       }
-
-       return static_route_leak(
-               vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
-               from_str, gate_str, ifname, flag, tag_str, distance_str, label,
-               table_str, !!onlink);
+       return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
+                                prefix_str, NULL, from_str, gate_str, ifname,
+                                flag, tag_str, distance_str, label, table_str,
+                                !!onlink);
 }
 
 DEFPY(ipv6_route_address_interface_vrf,
@@ -1281,36 +944,32 @@ DEFPY(ipv6_route_address_interface_vrf,
       VRF_CMD_HELP_STR
       "Treat the nexthop as directly attached to the interface\n")
 {
-       VTY_DECLVAR_CONTEXT(vrf, vrf);
-       struct static_vrf *svrf = vrf->info;
-       struct static_vrf *nh_svrf;
+       const char *nh_vrf;
        const char *flag = NULL;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
 
-       if (table_str && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
+       vrf_dnode =
+               yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+       if (!vrf_dnode) {
+               vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
+       vrfname = yang_dnode_get_string(vrf_dnode, "./name");
 
        if (nexthop_vrf)
-               nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+               nh_vrf = nexthop_vrf;
        else
-               nh_svrf = svrf;
-
-       if (!nh_svrf) {
-               vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+               nh_vrf = vrfname;
 
        if (ifname && !strncasecmp(ifname, "Null0", 5)) {
                flag = "Null0";
                ifname = NULL;
        }
-
-       return static_route_leak(
-               vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
-               from_str, gate_str, ifname, flag, tag_str, distance_str, label,
-               table_str, !!onlink);
+       return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
+                                no, prefix_str, NULL, from_str, gate_str,
+                                ifname, flag, tag_str, distance_str, label,
+                                table_str, !!onlink);
 }
 
 DEFPY(ipv6_route,
@@ -1343,41 +1002,25 @@ DEFPY(ipv6_route,
       "The table number to configure\n"
       VRF_CMD_HELP_STR)
 {
-       struct static_vrf *svrf;
-       struct static_vrf *nh_svrf;
+       const char *nh_vrf;
        const char *flag = NULL;
 
-       if (table_str && vrf && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-
-       svrf = static_vty_get_unknown_vrf(vty, vrf);
-       if (!svrf) {
-               vty_out(vty, "%% vrf %s is not defined\n", vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+       if (!vrf)
+               vrf = VRF_DEFAULT_NAME;
 
        if (nexthop_vrf)
-               nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+               nh_vrf = nexthop_vrf;
        else
-               nh_svrf = svrf;
-
-       if (!nh_svrf) {
-               vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+               nh_vrf = vrf;
 
        if (ifname && !strncasecmp(ifname, "Null0", 5)) {
                flag = "Null0";
                ifname = NULL;
        }
-
-       return static_route_leak(
-               vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
-               from_str, gate_str, ifname, flag, tag_str, distance_str, label,
-               table_str, false);
+       return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
+                                prefix_str, NULL, from_str, gate_str, ifname,
+                                flag, tag_str, distance_str, label, table_str,
+                                false);
 }
 
 DEFPY(ipv6_route_vrf,
@@ -1408,36 +1051,32 @@ DEFPY(ipv6_route_vrf,
       "The table number to configure\n"
       VRF_CMD_HELP_STR)
 {
-       VTY_DECLVAR_CONTEXT(vrf, vrf);
-       struct static_vrf *svrf = vrf->info;
-       struct static_vrf *nh_svrf;
+       const char *nh_vrf;
        const char *flag = NULL;
+       const struct lyd_node *vrf_dnode;
+       const char *vrfname;
 
-       if (table_str && !vrf_is_backend_netns()) {
-               vty_out(vty,
-                       "%% table param only available when running on netns-based vrfs\n");
+       vrf_dnode =
+               yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
+       if (!vrf_dnode) {
+               vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
+       vrfname = yang_dnode_get_string(vrf_dnode, "./name");
 
        if (nexthop_vrf)
-               nh_svrf = static_vty_get_unknown_vrf(vty, nexthop_vrf);
+               nh_vrf = nexthop_vrf;
        else
-               nh_svrf = svrf;
-
-       if (!nh_svrf) {
-               vty_out(vty, "%% nexthop vrf %s is not defined\n", nexthop_vrf);
-               return CMD_WARNING_CONFIG_FAILED;
-       }
+               nh_vrf = vrfname;
 
        if (ifname && !strncasecmp(ifname, "Null0", 5)) {
                flag = "Null0";
                ifname = NULL;
        }
-
-       return static_route_leak(
-               vty, svrf, nh_svrf, AFI_IP6, SAFI_UNICAST, no, prefix_str, NULL,
-               from_str, gate_str, ifname, flag, tag_str, distance_str, label,
-               table_str, false);
+       return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
+                                no, prefix_str, NULL, from_str, gate_str,
+                                ifname, flag, tag_str, distance_str, label,
+                                table_str, false);
 }
 DEFPY(debug_staticd,
       debug_staticd_cmd,
@@ -1500,8 +1139,4 @@ void static_vty_init(void)
        install_element(VIEW_NODE, &show_debugging_static_cmd);
        install_element(VIEW_NODE, &debug_staticd_cmd);
        install_element(CONFIG_NODE, &debug_staticd_cmd);
-
-       static_list = list_new();
-       static_list->cmp = (int (*)(void *, void *))static_list_compare;
-       static_list->del = (void (*)(void *))static_list_delete;
 }
index 2f65c08b8b61c43b928687b7169cea582fc4ca92..7ffc8d9c98b3756b3bc1d5897f5690a74bdce4d3 100644 (file)
@@ -19,8 +19,6 @@
 #ifndef __STATIC_VTY_H__
 #define __STATIC_VTY_H__
 
-void static_config_install_delayed_routes(struct static_vrf *svrf);
-
 int static_config(struct vty *vty, struct static_vrf *svrf,
                  afi_t afi, safi_t safi, const char *cmd);
 
index c42f632ffb5eb7d61bfaaf67c2d88b4767e332c4..d8a4b7f0cbbf4c9687396928064117b683eb2ca5 100644 (file)
@@ -89,7 +89,6 @@ static int static_ifp_up(struct interface *ifp)
                struct static_vrf *svrf = static_vrf_lookup_by_id(ifp->vrf_id);
 
                static_fixup_vrf_ids(svrf);
-               static_config_install_delayed_routes(svrf);
        }
 
        /* Install any static reliant on this interface coming up */
@@ -265,8 +264,8 @@ static void static_nht_hash_free(void *data)
        XFREE(MTYPE_TMP, nhtd);
 }
 
-void static_zebra_nht_register(struct route_node *rn,
-                              struct static_route *si, bool reg)
+void static_zebra_nht_register(struct route_node *rn, struct static_nexthop *nh,
+                              bool reg)
 {
        struct static_nht_data *nhtd, lookup;
        uint32_t cmd;
@@ -276,14 +275,14 @@ void static_zebra_nht_register(struct route_node *rn,
        cmd = (reg) ?
                ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
 
-       if (si->nh_registered && reg)
+       if (nh->nh_registered && reg)
                return;
 
-       if (!si->nh_registered && !reg)
+       if (!nh->nh_registered && !reg)
                return;
 
        memset(&p, 0, sizeof(p));
-       switch (si->type) {
+       switch (nh->type) {
        case STATIC_IFNAME:
        case STATIC_BLACKHOLE:
                return;
@@ -291,23 +290,23 @@ void static_zebra_nht_register(struct route_node *rn,
        case STATIC_IPV4_GATEWAY_IFNAME:
                p.family = AF_INET;
                p.prefixlen = IPV4_MAX_BITLEN;
-               p.u.prefix4 = si->addr.ipv4;
+               p.u.prefix4 = nh->addr.ipv4;
                afi = AFI_IP;
                break;
        case STATIC_IPV6_GATEWAY:
        case STATIC_IPV6_GATEWAY_IFNAME:
                p.family = AF_INET6;
                p.prefixlen = IPV6_MAX_BITLEN;
-               p.u.prefix6 = si->addr.ipv6;
+               p.u.prefix6 = nh->addr.ipv6;
                afi = AFI_IP6;
                break;
        }
 
        memset(&lookup, 0, sizeof(lookup));
        lookup.nh = &p;
-       lookup.nh_vrf_id = si->nh_vrf_id;
+       lookup.nh_vrf_id = nh->nh_vrf_id;
 
-       si->nh_registered = reg;
+       nh->nh_registered = reg;
 
        if (reg) {
                nhtd = hash_get(static_nht_hash, &lookup,
@@ -318,8 +317,8 @@ void static_zebra_nht_register(struct route_node *rn,
                        zlog_debug("Registered nexthop(%pFX) for %pRN %d", &p,
                                   rn, nhtd->nh_num);
                if (nhtd->refcount > 1 && nhtd->nh_num) {
-                       static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num,
-                                         afi, si->nh_vrf_id);
+                       static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num, afi,
+                                         nh->nh_vrf_id);
                        return;
                }
        } else {
@@ -335,25 +334,72 @@ void static_zebra_nht_register(struct route_node *rn,
                static_nht_hash_free(nhtd);
        }
 
-       if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
+       if (zclient_send_rnh(zclient, cmd, &p, false, nh->nh_vrf_id) < 0)
                zlog_warn("%s: Failure to send nexthop to zebra", __func__);
 }
+/*
+ * When nexthop gets updated via configuration then use the
+ * already registered NH and resend the route to zebra
+ */
+int static_zebra_nh_update(struct route_node *rn, struct static_nexthop *nh)
+{
+       struct static_nht_data *nhtd, lookup = {};
+       struct prefix p = {};
+       afi_t afi = AFI_IP;
+
+       if (!nh->nh_registered)
+               return 0;
+
+       switch (nh->type) {
+       case STATIC_IFNAME:
+       case STATIC_BLACKHOLE:
+               return 0;
+       case STATIC_IPV4_GATEWAY:
+       case STATIC_IPV4_GATEWAY_IFNAME:
+               p.family = AF_INET;
+               p.prefixlen = IPV4_MAX_BITLEN;
+               p.u.prefix4 = nh->addr.ipv4;
+               afi = AFI_IP;
+               break;
+       case STATIC_IPV6_GATEWAY:
+       case STATIC_IPV6_GATEWAY_IFNAME:
+               p.family = AF_INET6;
+               p.prefixlen = IPV6_MAX_BITLEN;
+               p.u.prefix6 = nh->addr.ipv6;
+               afi = AFI_IP6;
+               break;
+       }
+
+       lookup.nh = &p;
+       lookup.nh_vrf_id = nh->nh_vrf_id;
+
+       nhtd = hash_lookup(static_nht_hash, &lookup);
+       if (nhtd && nhtd->nh_num) {
+               nh->state = STATIC_START;
+               static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num, afi,
+                                 nh->nh_vrf_id);
+               return 1;
+       }
+       return 0;
+}
 
 extern void static_zebra_route_add(struct route_node *rn,
-                                  struct static_route *si_changed,
-                                  vrf_id_t vrf_id, safi_t safi, bool install)
+                                  struct static_path *pn, safi_t safi,
+                                  bool install)
 {
-       struct static_route *si = rn->info;
+       struct static_nexthop *nh;
        const struct prefix *p, *src_pp;
        struct zapi_nexthop *api_nh;
        struct zapi_route api;
        uint32_t nh_num = 0;
+       struct stable_info *info;
 
        p = src_pp = NULL;
        srcdest_rnode_prefixes(rn, &p, &src_pp);
 
        memset(&api, 0, sizeof(api));
-       api.vrf_id = vrf_id;
+       info = static_get_stable_info(rn);
+       api.vrf_id = GET_STABLE_VRF_ID(info);
        api.type = ZEBRA_ROUTE_STATIC;
        api.safi = safi;
        memcpy(&api.prefix, p, sizeof(api.prefix));
@@ -365,71 +411,65 @@ extern void static_zebra_route_add(struct route_node *rn,
        SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
        SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
        SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
-       if (si_changed->distance) {
+       if (pn->distance) {
                SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
-               api.distance = si_changed->distance;
+               api.distance = pn->distance;
        }
-       if (si_changed->tag) {
+       if (pn->tag) {
                SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
-               api.tag = si_changed->tag;
+               api.tag = pn->tag;
        }
-       if (si_changed->table_id != 0) {
+       if (pn->table_id != 0) {
                SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
-               api.tableid = si_changed->table_id;
+               api.tableid = pn->table_id;
        }
-       for (/*loaded above*/; si; si = si->next) {
+       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
                api_nh = &api.nexthops[nh_num];
-               if (si->nh_vrf_id == VRF_UNKNOWN)
-                       continue;
-
-               if (si->distance != si_changed->distance)
-                       continue;
-
-               if (si->table_id != si_changed->table_id)
+               if (nh->nh_vrf_id == VRF_UNKNOWN)
                        continue;
 
-               api_nh->vrf_id = si->nh_vrf_id;
-               if (si->onlink)
+               api_nh->vrf_id = nh->nh_vrf_id;
+               if (nh->onlink)
                        SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
 
-               si->state = STATIC_SENT_TO_ZEBRA;
+               nh->state = STATIC_SENT_TO_ZEBRA;
 
-               switch (si->type) {
+               switch (nh->type) {
                case STATIC_IFNAME:
-                       if (si->ifindex == IFINDEX_INTERNAL)
+                       if (nh->ifindex == IFINDEX_INTERNAL)
                                continue;
-                       api_nh->ifindex = si->ifindex;
+                       api_nh->ifindex = nh->ifindex;
                        api_nh->type = NEXTHOP_TYPE_IFINDEX;
                        break;
                case STATIC_IPV4_GATEWAY:
-                       if (!si->nh_valid)
+                       if (!nh->nh_valid)
                                continue;
                        api_nh->type = NEXTHOP_TYPE_IPV4;
-                       api_nh->gate = si->addr;
+                       api_nh->gate = nh->addr;
                        break;
                case STATIC_IPV4_GATEWAY_IFNAME:
-                       if (si->ifindex == IFINDEX_INTERNAL)
+                       if (nh->ifindex == IFINDEX_INTERNAL)
                                continue;
-                       api_nh->ifindex = si->ifindex;
+                       api_nh->ifindex = nh->ifindex;
                        api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
-                       api_nh->gate = si->addr;
+                       api_nh->gate = nh->addr;
                        break;
                case STATIC_IPV6_GATEWAY:
-                       if (!si->nh_valid)
+                       if (!nh->nh_valid)
                                continue;
                        api_nh->type = NEXTHOP_TYPE_IPV6;
-                       api_nh->gate = si->addr;
+                       api_nh->gate = nh->addr;
                        break;
                case STATIC_IPV6_GATEWAY_IFNAME:
-                       if (si->ifindex == IFINDEX_INTERNAL)
+                       if (nh->ifindex == IFINDEX_INTERNAL)
                                continue;
                        api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
-                       api_nh->ifindex = si->ifindex;
-                       api_nh->gate = si->addr;
+                       api_nh->ifindex = nh->ifindex;
+                       api_nh->gate = nh->addr;
                        break;
                case STATIC_BLACKHOLE:
                        api_nh->type = NEXTHOP_TYPE_BLACKHOLE;
-                       switch (si->bh_type) {
+                       switch (nh->bh_type) {
                        case STATIC_BLACKHOLE_DROP:
                        case STATIC_BLACKHOLE_NULL:
                                api_nh->bh_type = BLACKHOLE_NULL;
@@ -440,13 +480,13 @@ extern void static_zebra_route_add(struct route_node *rn,
                        break;
                }
 
-               if (si->snh_label.num_labels) {
+               if (nh->snh_label.num_labels) {
                        int i;
 
                        SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
-                       api_nh->label_num = si->snh_label.num_labels;
+                       api_nh->label_num = nh->snh_label.num_labels;
                        for (i = 0; i < api_nh->label_num; i++)
-                               api_nh->labels[i] = si->snh_label.label[i];
+                               api_nh->labels[i] = nh->snh_label.label[i];
                }
                nh_num++;
        }
index 962dc3908fa9e05fb00b756a9967a788cc701d9d..9f93f3ee631084d7b4c83b48d2f5ff69198e935f 100644 (file)
 extern struct thread_master *master;
 
 extern void static_zebra_nht_register(struct route_node *rn,
-                                     struct static_route *si, bool reg);
+                                     struct static_nexthop *nh, bool reg);
 
 extern void static_zebra_route_add(struct route_node *rn,
-                                  struct static_route *si_changed,
-                                  vrf_id_t vrf_id, safi_t safi, bool install);
+                                  struct static_path *pn, safi_t safi,
+                                  bool install);
 extern void static_zebra_init(void);
 extern void static_zebra_vrf_register(struct vrf *vrf);
 extern void static_zebra_vrf_unregister(struct vrf *vrf);
+extern int static_zebra_nh_update(struct route_node *rn,
+                                 struct static_nexthop *nh);
 
 #endif
index f2b3d11f29b0deb5fb2b21823f3fcbd97d23f8b3..eba7f270bb10824bd7c41bfb163107beda6c5d08 100644 (file)
@@ -18,6 +18,8 @@ staticd_libstatic_a_SOURCES = \
        staticd/static_zebra.c \
        staticd/static_vrf.c \
        staticd/static_vty.c \
+       staticd/static_nb.c \
+       staticd/static_nb_config.c \
        # end
 
 noinst_HEADERS += \
@@ -28,6 +30,7 @@ noinst_HEADERS += \
        staticd/static_routes.h \
        staticd/static_vty.h \
        staticd/static_vrf.h \
+       staticd/static_nb.h \
        # end
 
 clippy_scan += \
@@ -36,3 +39,7 @@ clippy_scan += \
 
 staticd_staticd_SOURCES = staticd/static_main.c
 staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la $(LIBCAP)
+
+nodist_staticd_staticd_SOURCES = \
+       yang/frr-staticd.yang.c \
+       # end