diff options
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 3c5922b85a..0b5063a083 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 77ca4a3439..122cc9fce1 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 77a0db3b12..e9cc7ba469 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 0000000000..419a6a5366 --- /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 0000000000..9116ac8e51 --- /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 0000000000..282299eefe --- /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 1a2ddd7f05..feb6e0f993 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 e8d6a4289b..829fe6cd69 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 6414947b16..89ef544023 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 6c065932a1..39b86787ff 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 6951e56712..12ad1b255a 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 75bce82eef..311462db7a 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 2f65c08b8b..7ffc8d9c98 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 c42f632ffb..d8a4b7f0cb 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 962dc3908f..9f93f3ee63 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 f2b3d11f29..eba7f270bb 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  | 
