diff options
author | vdhingra <vdhingra@vmware.com> | 2020-04-24 14:38:43 +0200 |
---|---|---|
committer | vdhingra <vdhingra@vmware.com> | 2020-07-16 17:33:00 +0200 |
commit | 88fa5104a04af60b7d1107f02ee84fb9c0a15abe (patch) | |
tree | c2bbeecd9a5c384b7a615032c5fe13a1ff495c36 /staticd | |
parent | lib : basic-routing backend configuration northbound code (diff) | |
download | frr-88fa5104a04af60b7d1107f02ee84fb9c0a15abe.tar.xz frr-88fa5104a04af60b7d1107f02ee84fb9c0a15abe.zip |
staticd : Configuration northbound implementation
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>
Diffstat (limited to 'staticd')
-rw-r--r-- | staticd/static_main.c | 10 | ||||
-rw-r--r-- | staticd/static_memory.c | 2 | ||||
-rw-r--r-- | staticd/static_memory.h | 3 | ||||
-rw-r--r-- | staticd/static_nb.c | 188 | ||||
-rw-r--r-- | staticd/static_nb.h | 166 | ||||
-rw-r--r-- | staticd/static_nb_config.c | 1234 | ||||
-rw-r--r-- | staticd/static_nht.c | 122 | ||||
-rw-r--r-- | staticd/static_routes.c | 626 | ||||
-rw-r--r-- | staticd/static_routes.h | 112 | ||||
-rw-r--r-- | staticd/static_vrf.c | 68 | ||||
-rw-r--r-- | staticd/static_vrf.h | 10 | ||||
-rw-r--r-- | staticd/static_vty.c | 1163 | ||||
-rw-r--r-- | staticd/static_vty.h | 2 | ||||
-rw-r--r-- | staticd/static_zebra.c | 142 | ||||
-rw-r--r-- | staticd/static_zebra.h | 8 | ||||
-rw-r--r-- | staticd/subdir.am | 7 |
16 files changed, 2718 insertions, 1145 deletions
diff --git a/staticd/static_main.c b/staticd/static_main.c index 3c5922b85..0b5063a08 100644 --- a/staticd/static_main.c +++ b/staticd/static_main.c @@ -31,12 +31,14 @@ #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; diff --git a/staticd/static_memory.c b/staticd/static_memory.c index 77ca4a343..122cc9fce 100644 --- a/staticd/static_memory.c +++ b/staticd/static_memory.c @@ -25,4 +25,4 @@ DEFINE_MGROUP(STATIC, "staticd") -DEFINE_MTYPE(STATIC, STATIC_ROUTE, "Static Route"); +DEFINE_MTYPE(STATIC, STATIC_NEXTHOP, "Static Nexthop"); diff --git a/staticd/static_memory.h b/staticd/static_memory.h index 77a0db3b1..e9cc7ba46 100644 --- a/staticd/static_memory.h +++ b/staticd/static_memory.h @@ -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 index 000000000..419a6a536 --- /dev/null +++ b/staticd/static_nb.c @@ -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 index 000000000..9116ac8e5 --- /dev/null +++ b/staticd/static_nb.h @@ -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 index 000000000..282299eef --- /dev/null +++ b/staticd/static_nb_config.c @@ -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; +} diff --git a/staticd/static_nht.c b/staticd/static_nht.c index 1a2ddd7f0..feb6e0f99 100644 --- a/staticd/static_nht.c +++ b/staticd/static_nht.c @@ -30,33 +30,33 @@ #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); } diff --git a/staticd/static_routes.c b/staticd/static_routes.c index e8d6a4289..829fe6cd6 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -32,256 +32,328 @@ #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)); +} diff --git a/staticd/static_routes.h b/staticd/static_routes.h index 6414947b1..89ef54402 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -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 diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c index 6c065932a..39b86787f 100644 --- a/staticd/static_vrf.c +++ b/staticd/static_vrf.c @@ -30,26 +30,39 @@ #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; +} diff --git a/staticd/static_vrf.h b/staticd/static_vrf.h index 6951e5671..12ad1b255 100644 --- a/staticd/static_vrf.h +++ b/staticd/static_vrf.h @@ -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 diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 75bce82ee..311462db7 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -27,6 +27,10 @@ #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" @@ -36,251 +40,43 @@ #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; } diff --git a/staticd/static_vty.h b/staticd/static_vty.h index 2f65c08b8..7ffc8d9c9 100644 --- a/staticd/static_vty.h +++ b/staticd/static_vty.h @@ -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); diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index c42f632ff..d8a4b7f0c 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -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++; } diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h index 962dc3908..9f93f3ee6 100644 --- a/staticd/static_zebra.h +++ b/staticd/static_zebra.h @@ -22,13 +22,15 @@ 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 diff --git a/staticd/subdir.am b/staticd/subdir.am index f2b3d11f2..eba7f270b 100644 --- a/staticd/subdir.am +++ b/staticd/subdir.am @@ -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 |