diff options
| author | Rajasekar Raja <rajasekarr@nvidia.com> | 2024-11-27 00:04:51 -0800 | 
|---|---|---|
| committer | Rajasekar Raja <rajasekarr@nvidia.com> | 2024-12-09 08:46:16 -0800 | 
| commit | 0f2cb2731053a678c85115abda008dc1d012e591 (patch) | |
| tree | bcfbe52b31f60d814bc2a406319bf58dafba4354 | |
| parent | 07a80709c728d87abc2d15393a719d4232b1f33b (diff) | |
bgpd: backpressure - Optimize EVPN L3VNI remote routes processing
Anytime BGP gets a L3 VNI ADD/DEL from zebra,
 - Walking the entire global routing table per L3VNI is very expensive.
 - The next read (say of another VNI ADD/DEL) from the socket does
   not proceed unless this walk is complete.
So for triggers where a bulk of L3VNI's are flapped, this results in
huge output buffer FIFO growth spiking up the memory in zebra since bgp
is slow/busy processing the first message.
To avoid this, idea is to hookup the BGP-VRF off the struct bgp_master
and maintain a struct bgp FIFO list which is processed later on, where
we walk a chunk of BGP-VRFs and do the remote route install/uninstall.
Ticket :#3864372
Signed-off-by: Rajasekar Raja <rajasekarr@nvidia.com>
| -rw-r--r-- | bgpd/bgp_evpn.c | 250 | ||||
| -rw-r--r-- | bgpd/bgp_evpn.h | 1 | ||||
| -rw-r--r-- | bgpd/bgp_main.c | 1 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 9 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.c | 25 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.h | 1 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 25 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 11 | ||||
| -rw-r--r-- | tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py | 12 | ||||
| -rw-r--r-- | tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py | 15 | 
10 files changed, 287 insertions, 63 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index f4bae58724..c9b5640b0b 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -79,6 +79,8 @@ static void bgp_evpn_remote_ip_hash_unlink_nexthop(struct hash_bucket *bucket,  						   void *args);  static struct in_addr zero_vtep_ip; +static void bgp_evpn_local_l3vni_del_post_processing(struct bgp *bgp_vrf); +  /*   * Private functions.   */ @@ -3882,14 +3884,6 @@ int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,  	const struct prefix_evpn *evp =  		(const struct prefix_evpn *)bgp_dest_get_prefix(pi->net); -	/* Consider "valid" remote routes applicable for -	 * this VRF. -	 */ -	if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID) -	      && pi->type == ZEBRA_ROUTE_BGP -	      && pi->sub_type == BGP_ROUTE_NORMAL)) -		return 0; -  	if (is_route_matching_for_vrf(bgp_vrf, pi)) {  		if (bgp_evpn_route_rmac_self_check(bgp_vrf, evp, pi))  			return 0; @@ -3916,26 +3910,66 @@ int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf,  	return ret;  } +#define BGP_PROC_L3VNI_LIMIT 10 +static int install_uninstall_evpn_remote_route_per_l3vni(struct bgp_path_info *pi, +							 const struct prefix_evpn *evp) +{ +	int ret = 0; +	uint8_t vni_iter = 0; +	bool is_install = false; +	struct bgp *bgp_to_proc = NULL; +	struct bgp *bgp_to_proc_next = NULL; + +	for (bgp_to_proc = zebra_l3_vni_first(&bm->zebra_l3_vni_head); +	     bgp_to_proc && vni_iter < BGP_PROC_L3VNI_LIMIT; bgp_to_proc = bgp_to_proc_next) { +		bgp_to_proc_next = zebra_l3_vni_next(&bm->zebra_l3_vni_head, bgp_to_proc); +		vni_iter++; +		is_install = !!CHECK_FLAG(bgp_to_proc->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_INSTALL); + +		ret = bgp_evpn_route_entry_install_if_vrf_match(bgp_to_proc, pi, is_install); +		if (ret) { +			flog_err(EC_BGP_EVPN_FAIL, +				 "%u: Failed to %s EVPN %s route in L3VNI %u during BP", +				 bgp_to_proc->vrf_id, is_install ? "install" : "uninstall", +				 bgp_evpn_route_type_str[evp->prefix.route_type].str, +				 bgp_to_proc->l3vni); +			zebra_l3_vni_del(&bm->zebra_l3_vni_head, bgp_to_proc); +			if (!is_install) +				bgp_evpn_local_l3vni_del_post_processing(bgp_to_proc); + +			return ret; +		} +	} + +	return 0; +}  /*   * Install or uninstall mac-ip routes are appropriate for this   * particular VRF.   */ -static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, bool install) +int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, bool install)  {  	afi_t afi;  	safi_t safi;  	struct bgp_dest *rd_dest, *dest;  	struct bgp_table *table;  	struct bgp_path_info *pi; -	int ret; +	int ret = 0;  	struct bgp *bgp_evpn = NULL; +	uint8_t count = 0;  	afi = AFI_L2VPN;  	safi = SAFI_EVPN;  	bgp_evpn = bgp_get_evpn(); -	if (!bgp_evpn) +	if (!bgp_evpn) { +		zlog_warn("%s: No BGP EVPN instance found...", __func__); +  		return -1; +	} +	if (BGP_DEBUG(zebra, ZEBRA)) +		zlog_debug("%s: Total %u L3VNI BGP-VRFs pending to be processed for remote route installation", +			   __func__, (uint32_t)zebra_l3_vni_count(&bm->zebra_l3_vni_head));  	/* Walk entire global routing table and evaluate routes which could be  	 * imported into this VRF. Note that we need to loop through all global  	 * routes to determine which route matches the import rt on vrf @@ -3952,30 +3986,73 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, bool install)  				(const struct prefix_evpn *)bgp_dest_get_prefix(  					dest); -			/* if not mac-ip route skip this route */ -			if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE -			      || evp->prefix.route_type -					 == BGP_EVPN_IP_PREFIX_ROUTE)) -				continue; - -			/* if not a mac+ip route skip this route */ -			if (!(is_evpn_prefix_ipaddr_v4(evp) -			      || is_evpn_prefix_ipaddr_v6(evp))) +			/* Proceed only for MAC-IP and IP-Prefix routes */ +			switch (evp->prefix.route_type) { +			case BGP_EVPN_MAC_IP_ROUTE: +			case BGP_EVPN_IP_PREFIX_ROUTE: +				if (!(is_evpn_prefix_ipaddr_v4(evp) || +				      is_evpn_prefix_ipaddr_v6(evp))) +					continue; +				break; +			case BGP_EVPN_AD_ROUTE: +			case BGP_EVPN_IMET_ROUTE: +			case BGP_EVPN_ES_ROUTE:  				continue; +			}  			for (pi = bgp_dest_get_bgp_path_info(dest); pi;  			     pi = pi->next) { -				ret = bgp_evpn_route_entry_install_if_vrf_match( -					bgp_vrf, pi, install); -				if (ret) { -					bgp_dest_unlock_node(rd_dest); -					bgp_dest_unlock_node(dest); -					return ret; +				/* Consider "valid" remote routes applicable for +				 * this VRF */ +				if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID) && +				      pi->type == ZEBRA_ROUTE_BGP && +				      pi->sub_type == BGP_ROUTE_NORMAL)) +					continue; + +				if (!bgp_vrf) { +					ret = install_uninstall_evpn_remote_route_per_l3vni(pi, evp); +					if (ret) { +						bgp_dest_unlock_node(rd_dest); +						bgp_dest_unlock_node(dest); + +						return ret; +					} +				} else { +					ret = bgp_evpn_route_entry_install_if_vrf_match(bgp_vrf, pi, +											install); +					if (ret) { +						flog_err(EC_BGP_EVPN_FAIL, +							 "%u: Failed to %s EVPN %s route in L3VNI %u", +							 bgp_vrf->vrf_id, +							 install ? "install" : "uninstall", +							 bgp_evpn_route_type_str[evp->prefix.route_type] +								 .str, +							 bgp_vrf->l3vni); +						bgp_dest_unlock_node(rd_dest); +						bgp_dest_unlock_node(dest); + +						return ret; +					}  				}  			}  		}  	} +	if (!bgp_vrf) { +		while (count < BGP_PROC_L3VNI_LIMIT) { +			struct bgp *bgp_to_proc = zebra_l3_vni_pop(&bm->zebra_l3_vni_head); + +			if (!bgp_to_proc) +				return 0; + +			if (CHECK_FLAG(bgp_to_proc->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_DELETE)) +				bgp_evpn_local_l3vni_del_post_processing(bgp_to_proc); + +			UNSET_FLAG(bgp_to_proc->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_INSTALL); +			count++; +		} +	} +  	return 0;  } @@ -6856,6 +6933,53 @@ static void link_l2vni_hash_to_l3vni(struct hash_bucket *bucket,  		bgpevpn_link_to_l3vni(vpn);  } +static void bgp_evpn_l3vni_remote_route_processing(struct bgp *bgp, bool install) +{ +	/* +	 * Anytime BGP gets a Bulk of L3 VNI ADD/DEL from zebra, +	 *  - Walking the entire global routing table per VNI is very expensive. +	 *  - The next read (say of another VNI ADD/DEL) from the socket does +	 *    not proceed unless this walk is complete. +	 * This results in huge output buffer FIFO growth spiking up the +	 * memory in zebra. +	 * +	 * To avoid this, idea is to hookup the BGP-VRF off the struct +	 * bgp_master and maintain a struct bgp FIFO list which is processed +	 * later on, where we walk a chunk of BGP-VRFs and do the remote route +	 * install/uninstall. +	 */ +	if (!CHECK_FLAG(bgp->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_INSTALL) && +	    !CHECK_FLAG(bgp->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_DELETE)) +		zebra_l3_vni_add_tail(&bm->zebra_l3_vni_head, bgp); + +	if (install) { +		SET_FLAG(bgp->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_INSTALL); +		UNSET_FLAG(bgp->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_DELETE); +	} else { +		SET_FLAG(bgp->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_DELETE); +		UNSET_FLAG(bgp->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_INSTALL); +	} + +	if (BGP_DEBUG(zebra, ZEBRA)) +		zlog_debug("Scheduling L3VNI %s to be processed later for %s VNI %u", +			   install ? "ADD" : "DEL", bgp->name_pretty, bgp->l3vni); +	/* +	 * If there are no BGP-VRFs's in the bm L3VNI FIFO list i.e. an update +	 * for an already processed L3VNI comes in, schedule the remote route +	 * install immediately. +	 * +	 * In all other cases, it is ok to schedule the remote route un/install +	 * after a small sleep. This is to give benefit of doubt in case more +	 * L3VNI events come. +	 */ +	if (zebra_l3_vni_count(&bm->zebra_l3_vni_head)) +		event_add_timer_msec(bm->master, bgp_zebra_process_remote_routes_for_l3vrf, NULL, +				     20, &bm->t_bgp_zebra_l3_vni); +	else +		event_add_event(bm->master, bgp_zebra_process_remote_routes_for_l3vrf, NULL, 0, +				&bm->t_bgp_zebra_l3_vni); +} +  int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id,  			     struct ethaddr *svi_rmac,  			     struct ethaddr *vrr_rmac, @@ -7001,52 +7125,36 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id,  	/* advertise type-5 routes if needed */  	update_advertise_vrf_routes(bgp_vrf); -	/* install all remote routes belonging to this l3vni into correspondng -	 * vrf */ -	install_routes_for_vrf(bgp_vrf); +	bgp_evpn_l3vni_remote_route_processing(bgp_vrf, true);  	return 0;  } -int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id) +static void bgp_evpn_local_l3vni_del_post_processing(struct bgp *bgp_vrf)  { -	struct bgp *bgp_vrf = NULL; /* bgp vrf instance */  	struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */  	struct listnode *node = NULL;  	struct listnode *next = NULL;  	struct bgpevpn *vpn = NULL; -	bgp_vrf = bgp_lookup_by_vrf_id(vrf_id); -	if (!bgp_vrf) { -		flog_err( -			EC_BGP_NO_DFLT, -			"Cannot process L3VNI %u Del - Could not find BGP instance", -			l3vni); -		return -1; -	} -  	bgp_evpn = bgp_get_evpn();  	if (!bgp_evpn) { -		flog_err( -			EC_BGP_NO_DFLT, -			"Cannot process L3VNI %u Del - Could not find EVPN BGP instance", -			l3vni); -		return -1; +		flog_err(EC_BGP_NO_DFLT, +			 "Cannot process L3VNI %u Del - Could not find EVPN BGP instance", +			 bgp_vrf->l3vni); +		return;  	}  	if (CHECK_FLAG(bgp_evpn->flags, BGP_FLAG_DELETE_IN_PROGRESS)) {  		flog_err(EC_BGP_NO_DFLT, -			  "Cannot process L3VNI %u ADD - EVPN BGP instance is shutting down", -			  l3vni); -		return -1; +			 "Cannot process L3VNI %u ADD - EVPN BGP instance is shutting down", +			 bgp_vrf->l3vni); +		return;  	} -	/* Remove remote routes from BGT VRF even if BGP_VRF_AUTO is configured, -	 * bgp_delete would not remove/decrement bgp_path_info of the ip_prefix -	 * routes. This will uninstalling the routes from zebra and decremnt the -	 * bgp info count. -	 */ -	uninstall_routes_for_vrf(bgp_vrf); +	if (BGP_DEBUG(zebra, ZEBRA)) +		zlog_debug("In %s for L3VNI %u after remote route installation", __func__, +			   bgp_vrf->l3vni);  	/* delete/withdraw all type-5 routes */  	delete_withdraw_vrf_routes(bgp_vrf); @@ -7092,10 +7200,44 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)  		bgpevpn_unlink_from_l3vni(vpn);  	UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY); +	UNSET_FLAG(bgp_vrf->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_DELETE);  	/* Delete the instance if it was autocreated */  	if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))  		bgp_delete(bgp_vrf); +} + +int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id) +{ +	struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */ +	struct bgp *bgp_vrf = NULL;  /* bgp vrf instance */ + +	bgp_vrf = bgp_lookup_by_vrf_id(vrf_id); +	if (!bgp_vrf) { +		flog_err(EC_BGP_NO_DFLT, +			 "Cannot process L3VNI %u Del - Could not find BGP instance", l3vni); +		return -1; +	} + +	bgp_evpn = bgp_get_evpn(); +	if (!bgp_evpn) { +		flog_err(EC_BGP_NO_DFLT, +			 "Cannot process L3VNI %u Del - Could not find EVPN BGP instance", l3vni); +		return -1; +	} + +	if (CHECK_FLAG(bgp_evpn->flags, BGP_FLAG_DELETE_IN_PROGRESS)) { +		flog_err(EC_BGP_NO_DFLT, +			 "Cannot process L3VNI %u ADD - EVPN BGP instance is shutting down", l3vni); +		return -1; +	} + +	/* +	 * Move all the l3vni_delete operation post the remote route +	 * installation processing i.e. add the L3VNI DELETE item on the +	 * BGP-VRFs FIFO and move on. +	 */ +	bgp_evpn_l3vni_remote_route_processing(bgp_vrf, false);  	return 0;  } diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 75dde616ce..8bbc5d3c37 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -201,4 +201,5 @@ int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, const struct prefix_e  				      struct bgp_path_info *parent_pi);  extern void bgp_zebra_evpn_pop_items_from_announce_fifo(struct bgpevpn *vpn);  extern int install_uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn, bool install); +extern int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, bool install);  #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 9d89fd6f96..9ca20c949a 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -208,6 +208,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)  	zebra_announce_fini(&bm->zebra_announce_head);  	zebra_l2_vni_fini(&bm->zebra_l2_vni_head); +	zebra_l3_vni_fini(&bm->zebra_l3_vni_head);  	/* reverse bgp_dump_init */  	bgp_dump_finish(); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index bb0c69ca56..2fc5dc847f 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1696,8 +1696,13 @@ DEFUN (no_router_bgp,  		}  		if (bgp->l3vni) { -			vty_out(vty, "%% Please unconfigure l3vni %u\n", -				bgp->l3vni); +			if (CHECK_FLAG(bgp->flags, BGP_FLAG_L3VNI_SCHEDULE_FOR_DELETE)) +				vty_out(vty, +					"%% L3VNI %u is scheduled to be deleted. Please give it few secs and retry the command\n", +					bgp->l3vni); +			else +				vty_out(vty, "%% Please unconfigure l3vni %u\n", bgp->l3vni); +  			return CMD_WARNING_CONFIG_FAILED;  		} diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 90e2d5af7b..6b7398fbc9 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -3046,6 +3046,31 @@ void bgp_zebra_process_remote_routes_for_l2vni(struct event *e)  				     20, &bm->t_bgp_zebra_l2_vni);  } +void bgp_zebra_process_remote_routes_for_l3vrf(struct event *e) +{ +	/* +	 * Install/Uninstall all remote routes belonging to l3vni +	 * +	 * NOTE: +	 *  - At this point it does not matter whether we call +	 *    install_routes_for_vrf/uninstall_routes_for_vrf. +	 *  - Since we pass struct bgp as NULL, +	 *      * we iterate the bm FIFO list +	 *      * the second variable (true) is ignored as well and +	 *        calculated based on the BGP-VRFs flags for ADD/DELETE. +	 */ +	install_uninstall_routes_for_vrf(NULL, true); + +	/* +	 * If there are L3VNIs still pending to be processed, schedule them +	 * after a small sleep so that CPU can be used for other purposes. +	 */ +	if (zebra_l3_vni_count(&bm->zebra_l3_vni_head)) { +		event_add_timer_msec(bm->master, bgp_zebra_process_remote_routes_for_l3vrf, NULL, +				     20, &bm->t_bgp_zebra_l3_vni); +	} +} +  static int bgp_zebra_process_local_es_add(ZAPI_CALLBACK_ARGS)  {  	esi_t esi; diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 993d002998..7e9d57cb85 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -136,4 +136,5 @@ extern enum zclient_send_status  bgp_zebra_withdraw_actual(struct bgp_dest *dest, struct bgp_path_info *info,  			  struct bgp *bgp);  extern void bgp_zebra_process_remote_routes_for_l2vni(struct event *e); +extern void bgp_zebra_process_remote_routes_for_l3vrf(struct event *e);  #endif /* _QUAGGA_BGP_ZEBRA_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 44640c84f2..d580da4e1a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3972,8 +3972,10 @@ int bgp_delete(struct bgp *bgp)  	struct bgp_dest *dest_next = NULL;  	struct bgp_table *dest_table = NULL;  	struct graceful_restart_info *gr_info; -	uint32_t b_ann_cnt = 0, b_l2_cnt = 0; -	uint32_t a_ann_cnt = 0, a_l2_cnt = 0; +	uint32_t b_ann_cnt = 0, b_l2_cnt = 0, b_l3_cnt = 0; +	uint32_t a_ann_cnt = 0, a_l2_cnt = 0, a_l3_cnt = 0; +	struct bgp *bgp_to_proc = NULL; +	struct bgp *bgp_to_proc_next = NULL;  	assert(bgp); @@ -4007,13 +4009,21 @@ int bgp_delete(struct bgp *bgp)  		}  	} +	b_l3_cnt = zebra_l3_vni_count(&bm->zebra_l3_vni_head); +	for (bgp_to_proc = zebra_l3_vni_first(&bm->zebra_l3_vni_head); bgp_to_proc; +	     bgp_to_proc = bgp_to_proc_next) { +		bgp_to_proc_next = zebra_l3_vni_next(&bm->zebra_l3_vni_head, bgp_to_proc); +		if (bgp_to_proc == bgp) +			zebra_l3_vni_del(&bm->zebra_l3_vni_head, bgp_to_proc); +	} +  	if (BGP_DEBUG(zebra, ZEBRA)) {  		a_ann_cnt = zebra_announce_count(&bm->zebra_announce_head);  		a_l2_cnt = zebra_l2_vni_count(&bm->zebra_l2_vni_head); -		zlog_debug("FIFO Cleanup Count during BGP %s deletion :: " -			   "Zebra Announce - before %u after %u :: " -			   "BGP L2_VNI - before %u after %u", -			   bgp->name_pretty, b_ann_cnt, a_ann_cnt, b_l2_cnt, a_l2_cnt); +		a_l3_cnt = zebra_l3_vni_count(&bm->zebra_l3_vni_head); +		zlog_debug("BGP %s deletion FIFO cnt Zebra_Ann before %u after %u, L2_VNI before %u after, %u L3_VNI before %u after %u", +			   bgp->name_pretty, b_ann_cnt, a_ann_cnt, b_l2_cnt, a_l2_cnt, b_l3_cnt, +			   a_l3_cnt);  	}  	bgp_soft_reconfig_table_task_cancel(bgp, NULL, NULL); @@ -8514,6 +8524,7 @@ void bgp_master_init(struct event_loop *master, const int buffer_size,  	zebra_announce_init(&bm->zebra_announce_head);  	zebra_l2_vni_init(&bm->zebra_l2_vni_head); +	zebra_l3_vni_init(&bm->zebra_l3_vni_head);  	bm->bgp = list_new();  	bm->listen_sockets = list_new();  	bm->port = BGP_PORT_DEFAULT; @@ -8538,6 +8549,7 @@ void bgp_master_init(struct event_loop *master, const int buffer_size,  	bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME;  	bm->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME;  	bm->t_bgp_zebra_l2_vni = NULL; +	bm->t_bgp_zebra_l3_vni = NULL;  	bgp_mac_init();  	/* init the rd id space. @@ -8786,6 +8798,7 @@ void bgp_terminate(void)  	EVENT_OFF(bm->t_bgp_start_label_manager);  	EVENT_OFF(bm->t_bgp_zebra_route);  	EVENT_OFF(bm->t_bgp_zebra_l2_vni); +	EVENT_OFF(bm->t_bgp_zebra_l3_vni);  	bgp_mac_finish();  } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index fd2bd95e5f..f66b41abe9 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -20,6 +20,7 @@  PREDECL_LIST(zebra_announce);  PREDECL_LIST(zebra_l2_vni); +PREDECL_LIST(zebra_l3_vni);  /* For union sockunion.  */  #include "queue.h" @@ -209,6 +210,10 @@ struct bgp_master {  	/* To preserve ordering of processing of L2 VNIs in BGP */  	struct zebra_l2_vni_head zebra_l2_vni_head; +	struct event *t_bgp_zebra_l3_vni; +	/* To preserve ordering of processing of BGP-VRFs for L3 VNIs */ +	struct zebra_l3_vni_head zebra_l3_vni_head; +  	QOBJ_FIELDS;  };  DECLARE_QOBJ_TYPE(bgp_master); @@ -559,6 +564,8 @@ struct bgp {  #define BGP_FLAG_INSTANCE_HIDDEN	 (1ULL << 39)  /* Prohibit BGP from enabling IPv6 RA on interfaces */  #define BGP_FLAG_IPV6_NO_AUTO_RA (1ULL << 40) +#define BGP_FLAG_L3VNI_SCHEDULE_FOR_INSTALL (1ULL << 41) +#define BGP_FLAG_L3VNI_SCHEDULE_FOR_DELETE  (1ULL << 42)  	/* BGP default address-families.  	 * New peers inherit enabled afi/safis from bgp instance. @@ -873,10 +880,14 @@ struct bgp {  	uint64_t node_already_on_queue;  	uint64_t node_deferred_on_queue; +	struct zebra_l3_vni_item zl3vni; +  	QOBJ_FIELDS;  };  DECLARE_QOBJ_TYPE(bgp); +DECLARE_LIST(zebra_l3_vni, struct bgp, zl3vni); +  struct bgp_interface {  #define BGP_INTERFACE_MPLS_BGP_FORWARDING (1 << 0)  /* L3VPN multi domain switching */ diff --git a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py index 45868663a8..cb3104a522 100644 --- a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py +++ b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_chaos_topo1.py @@ -21,6 +21,8 @@ import sys  import time  import pytest  import platform +import functools +from lib import topotest  from copy import deepcopy @@ -539,6 +541,16 @@ def test_RT_verification_auto_p0(request):      result = create_vrf_cfg(tgen, topo, input_dict=input_dict_vni)      assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) +    expected = {"numL3Vnis": 0} +    test_func = functools.partial( +        topotest.router_json_cmp, +        tgen.gears["e1"], +        "show bgp l2vpn evpn vni json", +        expected, +    ) +    _, result = topotest.run_and_expect(test_func, None, count=5, wait=3) +    assert result is None, "Testcase {} :Failed \n Error: {}".format(tc_name, result) +      input_dict_2 = {}      for dut in ["e1"]:          temp = {dut: {"bgp": []}} diff --git a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py index beb4de432e..52181a75dc 100644 --- a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py +++ b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py @@ -25,6 +25,8 @@ import sys  import time  import pytest  import platform +import functools +from lib import topotest  from copy import deepcopy @@ -1124,7 +1126,6 @@ def test_active_standby_evpn_implementation_p1(request):      )      for addr_type in ADDR_TYPES: -          logger.info("Verifying only ipv4 routes")          if addr_type != "ipv4":              continue @@ -2050,6 +2051,18 @@ def test_bgp_attributes_for_evpn_address_family_p1(request, attribute):              tc_name, result          ) +        expected = {"numL3Vnis": 0} +        test_func = functools.partial( +            topotest.router_json_cmp, +            tgen.gears["d1"], +            "show bgp l2vpn evpn vni json", +            expected, +        ) +        _, result = topotest.run_and_expect(test_func, None, count=5, wait=3) +        assert result is None, "Testcase {} :Failed \n Error: {}".format( +            tc_name, result +        ) +          input_dict_2 = {}          for dut in ["d1"]:              temp = {dut: {"bgp": []}}  | 
