mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 01:03:15 +00:00 
			
		
		
		
	bgpd: Implement ACCEPT_OWN extended community
TL;DR: rfc7611. Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
This commit is contained in:
		
							parent
							
								
									984eb32b58
								
							
						
					
					
						commit
						46dbf9d0c0
					
				| @ -23,6 +23,7 @@ | ||||
| 
 | ||||
| #include "lib/json.h" | ||||
| #include "bgpd/bgp_route.h" | ||||
| #include "bgpd/bgp_attr.h" | ||||
| 
 | ||||
| /* Communities attribute.  */ | ||||
| struct community { | ||||
| @ -109,4 +110,30 @@ extern void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate *aggregate, | ||||
| 						struct community *community); | ||||
| extern void bgp_aggr_community_remove(void *arg); | ||||
| 
 | ||||
| /* This implies that when propagating routes into a VRF, the ACCEPT_OWN
 | ||||
|  * community SHOULD NOT be propagated. | ||||
|  */ | ||||
| static inline void community_strip_accept_own(struct attr *attr) | ||||
| { | ||||
| 	struct community *old_com = bgp_attr_get_community(attr); | ||||
| 	struct community *new_com = NULL; | ||||
| 	uint32_t val = COMMUNITY_ACCEPT_OWN; | ||||
| 
 | ||||
| 	if (old_com && community_include(old_com, val)) { | ||||
| 		new_com = community_dup(old_com); | ||||
| 		val = htonl(val); | ||||
| 		community_del_val(new_com, &val); | ||||
| 
 | ||||
| 		if (!old_com->refcnt) | ||||
| 			community_free(&old_com); | ||||
| 
 | ||||
| 		if (!new_com->size) { | ||||
| 			community_free(&new_com); | ||||
| 			bgp_attr_set_community(attr, NULL); | ||||
| 		} else { | ||||
| 			bgp_attr_set_community(attr, new_com); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #endif /* _QUAGGA_BGP_COMMUNITY_H */ | ||||
|  | ||||
| @ -42,6 +42,7 @@ | ||||
| #include "bgpd/bgp_packet.h" | ||||
| #include "bgpd/bgp_vty.h" | ||||
| #include "bgpd/bgp_vpn.h" | ||||
| #include "bgpd/bgp_community.h" | ||||
| #include "bgpd/bgp_ecommunity.h" | ||||
| #include "bgpd/bgp_zebra.h" | ||||
| #include "bgpd/bgp_nexthop.h" | ||||
| @ -996,6 +997,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, | ||||
| 		if (nexthop_self_flag) | ||||
| 			bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF); | ||||
| 
 | ||||
| 		if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN)) | ||||
| 			bgp_path_info_set_flag(bn, bpi, BGP_PATH_ACCEPT_OWN); | ||||
| 
 | ||||
| 		if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi, | ||||
| 					      source_bpi, bpi, bgp_orig, p, | ||||
| 					      debug)) | ||||
| @ -1036,6 +1040,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, | ||||
| 	if (nexthop_self_flag) | ||||
| 		bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF); | ||||
| 
 | ||||
| 	if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN)) | ||||
| 		bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN); | ||||
| 
 | ||||
| 	bgp_path_info_extra_get(new); | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -1217,6 +1224,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp,	     /* to */ | ||||
| 		XFREE(MTYPE_ECOMMUNITY_STR, s); | ||||
| 	} | ||||
| 
 | ||||
| 	community_strip_accept_own(&static_attr); | ||||
| 
 | ||||
| 	/* Nexthop */ | ||||
| 	/* if policy nexthop not set, use 0 */ | ||||
| 	if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags, | ||||
| @ -1362,7 +1371,7 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp,	     /* to */ | ||||
| 	 * because of loop checking. | ||||
| 	 */ | ||||
| 	if (new_info) | ||||
| 		vpn_leak_to_vrf_update(from_bgp, new_info); | ||||
| 		vpn_leak_to_vrf_update(from_bgp, new_info, NULL); | ||||
| } | ||||
| 
 | ||||
| void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp,		/* to */ | ||||
| @ -1518,10 +1527,40 @@ void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp,	     /* to */ | ||||
| 			      struct bgp *from_bgp,	   /* from */ | ||||
| 			      struct bgp_path_info *path_vpn) /* route */ | ||||
| static struct bgp *bgp_lookup_by_rd(struct bgp_path_info *bpi, | ||||
| 				    struct prefix_rd *rd, afi_t afi) | ||||
| { | ||||
| 	struct listnode *node, *nnode; | ||||
| 	struct bgp *bgp; | ||||
| 
 | ||||
| 	if (!rd) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	/* If ACCEPT_OWN is not enabled for this path - return. */ | ||||
| 	if (!CHECK_FLAG(bpi->flags, BGP_PATH_ACCEPT_OWN)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { | ||||
| 		if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (!CHECK_FLAG(bgp->vpn_policy[afi].flags, | ||||
| 				BGP_VPN_POLICY_TOVPN_RD_SET)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/* Check if we have source VRF by RD value */ | ||||
| 		if (memcmp(&bgp->vpn_policy[afi].tovpn_rd.val, rd->val, | ||||
| 			   ECOMMUNITY_SIZE) == 0) | ||||
| 			return bgp; | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp,   /* to */ | ||||
| 					  struct bgp *from_bgp, /* from */ | ||||
| 					  struct bgp_path_info *path_vpn, | ||||
| 					  struct prefix_rd *prd) | ||||
| { | ||||
| 	const struct prefix *p = bgp_dest_get_prefix(path_vpn->net); | ||||
| 	afi_t afi = family2afi(p->family); | ||||
| @ -1558,9 +1597,22 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp,	     /* to */ | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* A route MUST NOT ever be accepted back into its source VRF, even if
 | ||||
| 	 * it carries one or more RTs that match that VRF. | ||||
| 	 */ | ||||
| 	if (prd && memcmp(&prd->val, &to_bgp->vpn_policy[afi].tovpn_rd.val, | ||||
| 			  ECOMMUNITY_SIZE) == 0) { | ||||
| 		if (debug) | ||||
| 			zlog_debug( | ||||
| 				"%s: skipping import, match RD (%pRD) of src VRF (%s) and the prefix (%pFX)", | ||||
| 				__func__, prd, to_bgp->name_pretty, p); | ||||
| 
 | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	if (debug) | ||||
| 		zlog_debug("%s: updating %pFX to vrf %s", __func__, p, | ||||
| 			   to_bgp->name_pretty); | ||||
| 		zlog_debug("%s: updating RD %pRD, %pFX to vrf %s", __func__, | ||||
| 			   prd, p, to_bgp->name_pretty); | ||||
| 
 | ||||
| 	/* shallow copy */ | ||||
| 	static_attr = *path_vpn->attr; | ||||
| @ -1585,6 +1637,8 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp,	     /* to */ | ||||
| 			ecommunity_free(&old_ecom); | ||||
| 	} | ||||
| 
 | ||||
| 	community_strip_accept_own(&static_attr); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Nexthop: stash and clear | ||||
| 	 * | ||||
| @ -1711,9 +1765,16 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp,	     /* to */ | ||||
| 	/*
 | ||||
| 	 * For VRF-2-VRF route-leaking, | ||||
| 	 * the source will be the originating VRF. | ||||
| 	 * | ||||
| 	 * If ACCEPT_OWN mechanism is enabled, then we SHOULD(?) | ||||
| 	 * get the source VRF (BGP) by looking at the RD. | ||||
| 	 */ | ||||
| 	struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi); | ||||
| 
 | ||||
| 	if (path_vpn->extra && path_vpn->extra->bgp_orig) | ||||
| 		src_vrf = path_vpn->extra->bgp_orig; | ||||
| 	else if (src_bgp) | ||||
| 		src_vrf = src_bgp; | ||||
| 	else | ||||
| 		src_vrf = from_bgp; | ||||
| 
 | ||||
| @ -1723,8 +1784,9 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp,	     /* to */ | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool vpn_leak_to_vrf_update(struct bgp *from_bgp,	   /* from */ | ||||
| 			    struct bgp_path_info *path_vpn) /* route */ | ||||
| bool vpn_leak_to_vrf_update(struct bgp *from_bgp, | ||||
| 			    struct bgp_path_info *path_vpn, | ||||
| 			    struct prefix_rd *prd) | ||||
| { | ||||
| 	struct listnode *mnode, *mnnode; | ||||
| 	struct bgp *bgp; | ||||
| @ -1741,7 +1803,7 @@ bool vpn_leak_to_vrf_update(struct bgp *from_bgp,	   /* from */ | ||||
| 		if (!path_vpn->extra | ||||
| 		    || path_vpn->extra->bgp_orig != bgp) { /* no loop */ | ||||
| 			leak_success |= vpn_leak_to_vrf_update_onevrf( | ||||
| 				bgp, from_bgp, path_vpn); | ||||
| 				bgp, from_bgp, path_vpn, prd); | ||||
| 		} | ||||
| 	} | ||||
| 	return leak_success; | ||||
| @ -1897,7 +1959,7 @@ void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from, | ||||
| 					continue; | ||||
| 
 | ||||
| 				vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from, | ||||
| 							      bpi); | ||||
| 							      bpi, NULL); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -72,7 +72,8 @@ extern void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp, | ||||
| 				       afi_t afi); | ||||
| 
 | ||||
| extern bool vpn_leak_to_vrf_update(struct bgp *from_bgp, | ||||
| 				   struct bgp_path_info *path_vpn); | ||||
| 				   struct bgp_path_info *path_vpn, | ||||
| 				   struct prefix_rd *prd); | ||||
| 
 | ||||
| extern void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp, | ||||
| 				     struct bgp_path_info *path_vpn); | ||||
|  | ||||
| @ -139,7 +139,8 @@ static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc, | ||||
| 	 */ | ||||
| 	return (bgp_zebra_num_connects() == 0 || | ||||
| 		(bnc && (bnc->nexthop_num > 0 && | ||||
| 			 (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) || | ||||
| 			 (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) || | ||||
| 			  CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) || | ||||
| 			  bnc->bgp->srv6_enabled || | ||||
| 			  bgp_isvalid_nexthop_for_ebgp(bnc, path) || | ||||
| 			  bgp_isvalid_nexthop_for_mplsovergre(bnc, path))))); | ||||
|  | ||||
							
								
								
									
										147
									
								
								bgpd/bgp_route.c
									
									
									
									
									
								
							
							
						
						
									
										147
									
								
								bgpd/bgp_route.c
									
									
									
									
									
								
							| @ -103,10 +103,6 @@ DEFINE_HOOK(bgp_rpki_prefix_status, | ||||
| 	     const struct prefix *prefix), | ||||
| 	    (peer, attr, prefix)); | ||||
| 
 | ||||
| /* Render dest to prefix_rd based on safi */ | ||||
| static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, | ||||
| 						safi_t safi); | ||||
| 
 | ||||
| /* Extern from bgp_dump.c */ | ||||
| extern const char *bgp_origin_str[]; | ||||
| extern const char *bgp_origin_long_str[]; | ||||
| @ -881,6 +877,49 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* If a BGP speaker supports ACCEPT_OWN and is configured for the
 | ||||
| 	 * extensions defined in this document, the following step is inserted | ||||
| 	 * after the LOCAL_PREF comparison step in the BGP decision process: | ||||
| 	 *	When comparing a pair of routes for a BGP destination, the | ||||
| 	 *	route with the ACCEPT_OWN community attached is preferred over | ||||
| 	 *	the route that does not have the community. | ||||
| 	 * This extra step MUST only be invoked during the best path selection | ||||
| 	 * process of VPN-IP routes. | ||||
| 	 */ | ||||
| 	if (safi == SAFI_MPLS_VPN && | ||||
| 	    (CHECK_FLAG(new->peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN) || | ||||
| 	     CHECK_FLAG(exist->peer->af_flags[afi][safi], | ||||
| 			PEER_FLAG_ACCEPT_OWN))) { | ||||
| 		bool new_accept_own = false; | ||||
| 		bool exist_accept_own = false; | ||||
| 		uint32_t accept_own = COMMUNITY_ACCEPT_OWN; | ||||
| 
 | ||||
| 		if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) | ||||
| 			new_accept_own = community_include( | ||||
| 				bgp_attr_get_community(newattr), accept_own); | ||||
| 		if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) | ||||
| 			exist_accept_own = community_include( | ||||
| 				bgp_attr_get_community(existattr), accept_own); | ||||
| 
 | ||||
| 		if (new_accept_own && !exist_accept_own) { | ||||
| 			*reason = bgp_path_selection_accept_own; | ||||
| 			if (debug) | ||||
| 				zlog_debug( | ||||
| 					"%s: %s wins over %s due to accept-own", | ||||
| 					pfx_buf, new_buf, exist_buf); | ||||
| 			return 1; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!new_accept_own && exist_accept_own) { | ||||
| 			*reason = bgp_path_selection_accept_own; | ||||
| 			if (debug) | ||||
| 				zlog_debug( | ||||
| 					"%s: %s loses to %s due to accept-own", | ||||
| 					pfx_buf, new_buf, exist_buf); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* 3. Local route check. We prefer:
 | ||||
| 	 *  - BGP_ROUTE_STATIC | ||||
| 	 *  - BGP_ROUTE_AGGREGATE | ||||
| @ -3883,6 +3922,60 @@ static void bgp_attr_add_no_export_community(struct attr *attr) | ||||
| 	bgp_attr_set_community(attr, new); | ||||
| } | ||||
| 
 | ||||
| static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi, | ||||
| 			   struct attr *attr, const struct prefix *prefix, | ||||
| 			   int *sub_type) | ||||
| { | ||||
| 	struct listnode *node, *nnode; | ||||
| 	struct bgp *bgp; | ||||
| 	bool accept_own_found = false; | ||||
| 
 | ||||
| 	if (safi != SAFI_MPLS_VPN) | ||||
| 		return false; | ||||
| 
 | ||||
| 	/* Processing of the ACCEPT_OWN community is enabled by configuration */ | ||||
| 	if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	/* The route in question carries the ACCEPT_OWN community */ | ||||
| 	if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) { | ||||
| 		struct community *comm = bgp_attr_get_community(attr); | ||||
| 
 | ||||
| 		if (community_include(comm, COMMUNITY_ACCEPT_OWN)) | ||||
| 			accept_own_found = true; | ||||
| 	} | ||||
| 
 | ||||
| 	/* The route in question is targeted to one or more destination VRFs
 | ||||
| 	 * on the router (as determined by inspecting the Route Target(s)). | ||||
| 	 */ | ||||
| 	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { | ||||
| 		if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (accept_own_found && | ||||
| 		    ecommunity_include( | ||||
| 			    bgp->vpn_policy[afi] | ||||
| 				    .rtlist[BGP_VPN_POLICY_DIR_TOVPN], | ||||
| 			    bgp_attr_get_ecommunity(attr))) { | ||||
| 			if (bgp_debug_update(peer, prefix, NULL, 1)) | ||||
| 				zlog_debug( | ||||
| 					"%pBP prefix %pFX has ORIGINATOR_ID, but it's accepted due to ACCEPT_OWN", | ||||
| 					peer, prefix); | ||||
| 
 | ||||
| 			/* Treat this route as imported, because it's leaked
 | ||||
| 			 * already from another VRF, and we got an updated | ||||
| 			 * version from route-reflector with ACCEPT_OWN | ||||
| 			 * community. | ||||
| 			 */ | ||||
| 			*sub_type = BGP_ROUTE_IMPORTED; | ||||
| 
 | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, | ||||
| 	       struct attr *attr, afi_t afi, safi_t safi, int type, | ||||
| 	       int sub_type, struct prefix_rd *prd, mpls_label_t *label, | ||||
| @ -3996,12 +4089,20 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Route reflector originator ID check.  */ | ||||
| 	/* Route reflector originator ID check. If ACCEPT_OWN mechanism is
 | ||||
| 	 * enabled, then take care of that too. | ||||
| 	 */ | ||||
| 	bool accept_own = false; | ||||
| 
 | ||||
| 	if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID) | ||||
| 	    && IPV4_ADDR_SAME(&bgp->router_id, &attr->originator_id)) { | ||||
| 		peer->stat_pfx_originator_loop++; | ||||
| 		reason = "originator is us;"; | ||||
| 		goto filtered; | ||||
| 		accept_own = | ||||
| 			bgp_accept_own(peer, afi, safi, attr, p, &sub_type); | ||||
| 		if (!accept_own) { | ||||
| 			peer->stat_pfx_originator_loop++; | ||||
| 			reason = "originator is us;"; | ||||
| 			goto filtered; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* Route reflector cluster ID check.  */ | ||||
| @ -4499,8 +4600,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, | ||||
| 				bgp_path_info_unset_flag(dest, pi, | ||||
| 							 BGP_PATH_VALID); | ||||
| 			} | ||||
| 		} else | ||||
| 		} else { | ||||
| 			if (accept_own) | ||||
| 				bgp_path_info_set_flag(dest, pi, | ||||
| 						       BGP_PATH_ACCEPT_OWN); | ||||
| 
 | ||||
| 			bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID); | ||||
| 		} | ||||
| 
 | ||||
| #ifdef ENABLE_BGP_VNC | ||||
| 		if (safi == SAFI_MPLS_VPN) { | ||||
| @ -4550,8 +4656,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, | ||||
| 		} | ||||
| 		if ((SAFI_MPLS_VPN == safi) | ||||
| 		    && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) { | ||||
| 
 | ||||
| 			leak_success = vpn_leak_to_vrf_update(bgp, pi); | ||||
| 			leak_success = vpn_leak_to_vrf_update(bgp, pi, prd); | ||||
| 		} | ||||
| 
 | ||||
| #ifdef ENABLE_BGP_VNC | ||||
| @ -4659,8 +4764,12 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, | ||||
| 			} | ||||
| 			bgp_path_info_unset_flag(dest, new, BGP_PATH_VALID); | ||||
| 		} | ||||
| 	} else | ||||
| 	} else { | ||||
| 		if (accept_own) | ||||
| 			bgp_path_info_set_flag(dest, new, BGP_PATH_ACCEPT_OWN); | ||||
| 
 | ||||
| 		bgp_path_info_set_flag(dest, new, BGP_PATH_VALID); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Addpath ID */ | ||||
| 	new->addpath_rx_id = addpath_id; | ||||
| @ -4706,7 +4815,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, | ||||
| 	} | ||||
| 	if ((SAFI_MPLS_VPN == safi) | ||||
| 	    && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) { | ||||
| 		leak_success = vpn_leak_to_vrf_update(bgp, new); | ||||
| 		leak_success = vpn_leak_to_vrf_update(bgp, new, prd); | ||||
| 	} | ||||
| #ifdef ENABLE_BGP_VNC | ||||
| 	if (SAFI_MPLS_VPN == safi) { | ||||
| @ -6427,7 +6536,8 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p, | ||||
| 
 | ||||
| 			if (SAFI_MPLS_VPN == safi | ||||
| 			    && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { | ||||
| 				vpn_leak_to_vrf_update(bgp, pi); | ||||
| 				vpn_leak_to_vrf_update(bgp, pi, | ||||
| 						       &bgp_static->prd); | ||||
| 			} | ||||
| #ifdef ENABLE_BGP_VNC | ||||
| 			rfapiProcessUpdate(pi->peer, NULL, p, &bgp_static->prd, | ||||
| @ -6467,7 +6577,7 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p, | ||||
| 
 | ||||
| 	if (SAFI_MPLS_VPN == safi | ||||
| 	    && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { | ||||
| 		vpn_leak_to_vrf_update(bgp, new); | ||||
| 		vpn_leak_to_vrf_update(bgp, new, &bgp_static->prd); | ||||
| 	} | ||||
| #ifdef ENABLE_BGP_VNC | ||||
| 	rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd, new->attr, afi, | ||||
| @ -8826,6 +8936,8 @@ const char *bgp_path_selection_reason2str(enum bgp_path_selection_reason reason) | ||||
| 		return "Weight"; | ||||
| 	case bgp_path_selection_local_pref: | ||||
| 		return "Local Pref"; | ||||
| 	case bgp_path_selection_accept_own: | ||||
| 		return "Accept Own"; | ||||
| 	case bgp_path_selection_local_route: | ||||
| 		return "Local Route"; | ||||
| 	case bgp_path_selection_confed_as_path: | ||||
| @ -11902,8 +12014,8 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd, | ||||
| /*
 | ||||
|  * Return rd based on safi | ||||
|  */ | ||||
| static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, | ||||
| 						safi_t safi) | ||||
| const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, | ||||
| 					 safi_t safi) | ||||
| { | ||||
| 	switch (safi) { | ||||
| 	case SAFI_MPLS_VPN: | ||||
| @ -11912,7 +12024,6 @@ static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, | ||||
| 		return (struct prefix_rd *)(bgp_dest_get_prefix(dest)); | ||||
| 	default: | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -289,7 +289,7 @@ struct bgp_path_info { | ||||
| 	int lock; | ||||
| 
 | ||||
| 	/* BGP information status.  */ | ||||
| 	uint16_t flags; | ||||
| 	uint32_t flags; | ||||
| #define BGP_PATH_IGP_CHANGED (1 << 0) | ||||
| #define BGP_PATH_DAMPED (1 << 1) | ||||
| #define BGP_PATH_HISTORY (1 << 2) | ||||
| @ -306,6 +306,7 @@ struct bgp_path_info { | ||||
| #define BGP_PATH_RIB_ATTR_CHG (1 << 13) | ||||
| #define BGP_PATH_ANNC_NH_SELF (1 << 14) | ||||
| #define BGP_PATH_LINK_BW_CHG (1 << 15) | ||||
| #define BGP_PATH_ACCEPT_OWN (1 << 16) | ||||
| 
 | ||||
| 	/* BGP route type.  This can be static, RIP, OSPF, BGP etc.  */ | ||||
| 	uint8_t type; | ||||
| @ -852,4 +853,6 @@ extern void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr); | ||||
| const char * | ||||
| bgp_path_selection_reason2str(enum bgp_path_selection_reason reason); | ||||
| extern bool bgp_addpath_encode_rx(struct peer *peer, afi_t afi, safi_t safi); | ||||
| extern const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, | ||||
| 						safi_t safi); | ||||
| #endif /* _QUAGGA_BGP_ROUTE_H */ | ||||
|  | ||||
| @ -63,6 +63,7 @@ enum bgp_path_selection_reason { | ||||
| 	bgp_path_selection_evpn_lower_ip, | ||||
| 	bgp_path_selection_weight, | ||||
| 	bgp_path_selection_local_pref, | ||||
| 	bgp_path_selection_accept_own, | ||||
| 	bgp_path_selection_local_route, | ||||
| 	bgp_path_selection_confed_as_path, | ||||
| 	bgp_path_selection_as_path, | ||||
|  | ||||
| @ -8327,6 +8327,32 @@ ALIAS_HIDDEN( | ||||
| 	"Only give warning message when limit is exceeded\n" | ||||
| 	"Force checking all received routes not only accepted\n") | ||||
| 
 | ||||
| /* "neighbor accept-own" */ | ||||
| DEFPY (neighbor_accept_own, | ||||
|        neighbor_accept_own_cmd, | ||||
|        "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor accept-own", | ||||
|        NO_STR | ||||
|        NEIGHBOR_STR | ||||
|        NEIGHBOR_ADDR_STR2 | ||||
|        "Enable handling of self-originated VPN routes containing ACCEPT_OWN community\n") | ||||
| { | ||||
| 	struct peer *peer; | ||||
| 	afi_t afi = bgp_node_afi(vty); | ||||
| 	safi_t safi = bgp_node_safi(vty); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	peer = peer_and_group_lookup_vty(vty, neighbor); | ||||
| 	if (!peer) | ||||
| 		return CMD_WARNING_CONFIG_FAILED; | ||||
| 
 | ||||
| 	if (no) | ||||
| 		ret = peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ACCEPT_OWN); | ||||
| 	else | ||||
| 		ret = peer_af_flag_set(peer, afi, safi, PEER_FLAG_ACCEPT_OWN); | ||||
| 
 | ||||
| 	return bgp_vty_return(vty, ret); | ||||
| } | ||||
| 
 | ||||
| /* "neighbor soo" */ | ||||
| DEFPY (neighbor_soo, | ||||
|        neighbor_soo_cmd, | ||||
| @ -17362,6 +17388,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* accept-own */ | ||||
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ACCEPT_OWN)) | ||||
| 		vty_out(vty, "  neighbor %s accept-own\n", addr); | ||||
| 
 | ||||
| 	/* soo */ | ||||
| 	if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOO)) { | ||||
| 		char *soo_str = ecommunity_ecom2str( | ||||
| @ -19571,6 +19601,10 @@ void bgp_vty_init(void) | ||||
| 	install_element(BGP_EVPN_NODE, &neighbor_allowas_in_cmd); | ||||
| 	install_element(BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd); | ||||
| 
 | ||||
| 	/* neighbor accept-own */ | ||||
| 	install_element(BGP_VPNV4_NODE, &neighbor_accept_own_cmd); | ||||
| 	install_element(BGP_VPNV6_NODE, &neighbor_accept_own_cmd); | ||||
| 
 | ||||
| 	/* "neighbor soo" */ | ||||
| 	install_element(BGP_IPV4_NODE, &neighbor_soo_cmd); | ||||
| 	install_element(BGP_IPV4_NODE, &no_neighbor_soo_cmd); | ||||
|  | ||||
| @ -4313,6 +4313,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = { | ||||
| 	{PEER_FLAG_WEIGHT, 0, peer_change_reset_in}, | ||||
| 	{PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_reset}, | ||||
| 	{PEER_FLAG_SOO, 0, peer_change_reset}, | ||||
| 	{PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset}, | ||||
| 	{0, 0, 0}}; | ||||
| 
 | ||||
| /* Proper action set. */ | ||||
|  | ||||
| @ -1462,6 +1462,7 @@ struct peer { | ||||
| #define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 29) | ||||
| #define PEER_FLAG_SOO (1ULL << 30) | ||||
| #define PEER_FLAG_ORR_GROUP (1ULL << 31) /* Optimal-Route-Reflection */ | ||||
| #define PEER_FLAG_ACCEPT_OWN (1ULL << 32) | ||||
| 
 | ||||
| 	/* BGP Optimal Route Reflection Group name */ | ||||
| 	char *orr_group_name[AFI_MAX][SAFI_MAX]; | ||||
|  | ||||
| @ -1670,6 +1670,23 @@ Configuring Peers | ||||
|    turning on this command will allow BGP to install v4 routes with | ||||
|    v6 nexthops if you do not have v4 configured on interfaces. | ||||
| 
 | ||||
| .. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> accept-own | ||||
| 
 | ||||
|    Enable handling of self-originated VPN routes containing ``accept-own`` community. | ||||
| 
 | ||||
|    This feature allows you to handle self-originated VPN routes, which a BGP speaker | ||||
|    receives from a route-reflector. A 'self-originated' route is one that was | ||||
|    originally advertised by the speaker itself. As per :rfc:`4271`, a BGP speaker rejects | ||||
|    advertisements that originated the speaker itself. However, the BGP ACCEPT_OWN | ||||
|    mechanism enables a router to accept the prefixes it has advertised, when reflected | ||||
|    from a route-reflector that modifies certain attributes of the prefix. | ||||
| 
 | ||||
|    A special community called ``accept-own`` is attached to the prefix by the | ||||
|    route-reflector, which is a signal to the receiving router to bypass the ORIGINATOR_ID | ||||
|    and NEXTHOP/MP_REACH_NLRI check. | ||||
| 
 | ||||
|    Default: disabled. | ||||
| 
 | ||||
| .. clicmd:: bgp fast-external-failover | ||||
| 
 | ||||
|    This command causes bgp to take down ebgp peers immediately | ||||
|  | ||||
							
								
								
									
										0
									
								
								tests/topotests/bgp_accept_own/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/topotests/bgp_accept_own/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										12
									
								
								tests/topotests/bgp_accept_own/ce1/bgpd.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/topotests/bgp_accept_own/ce1/bgpd.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| ! | ||||
| debug bgp updates | ||||
| ! | ||||
| router bgp 65010 | ||||
|  no bgp ebgp-requires-policy | ||||
|  neighbor 192.168.1.2 remote-as external | ||||
|  neighbor 192.168.1.2 timers 1 3 | ||||
|  neighbor 192.168.1.2 timers connect 1 | ||||
|  address-family ipv4 unicast | ||||
|   redistribute connected | ||||
|  exit-address-family | ||||
| ! | ||||
							
								
								
									
										9
									
								
								tests/topotests/bgp_accept_own/ce1/zebra.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/topotests/bgp_accept_own/ce1/zebra.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| ! | ||||
| interface lo | ||||
|  ip address 172.16.255.1/32 | ||||
| ! | ||||
| interface ce1-eth0 | ||||
|  ip address 192.168.1.1/24 | ||||
| ! | ||||
| ip forwarding | ||||
| ! | ||||
							
								
								
									
										12
									
								
								tests/topotests/bgp_accept_own/ce2/bgpd.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/topotests/bgp_accept_own/ce2/bgpd.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| ! | ||||
| debug bgp updates | ||||
| ! | ||||
| router bgp 65020 | ||||
|  no bgp ebgp-requires-policy | ||||
|  neighbor 192.168.2.2 remote-as external | ||||
|  neighbor 192.168.2.2 timers 1 3 | ||||
|  neighbor 192.168.2.2 timers connect 1 | ||||
|  address-family ipv4 unicast | ||||
|   redistribute connected | ||||
|  exit-address-family | ||||
| ! | ||||
							
								
								
									
										9
									
								
								tests/topotests/bgp_accept_own/ce2/zebra.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/topotests/bgp_accept_own/ce2/zebra.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| ! | ||||
| interface lo | ||||
|  ip address 172.16.255.2/32 | ||||
| ! | ||||
| interface ce2-eth0 | ||||
|  ip address 192.168.2.1/24 | ||||
| ! | ||||
| ip forwarding | ||||
| ! | ||||
							
								
								
									
										49
									
								
								tests/topotests/bgp_accept_own/pe1/bgpd.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								tests/topotests/bgp_accept_own/pe1/bgpd.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| ! | ||||
| debug bgp updates | ||||
| debug bgp vpn leak-from-vrf | ||||
| debug bgp vpn leak-to-vrf | ||||
| debug bgp nht | ||||
| ! | ||||
| router bgp 65001 | ||||
|  bgp router-id 10.10.10.10 | ||||
|  no bgp ebgp-requires-policy | ||||
|  no bgp default ipv4-unicast | ||||
|  neighbor 10.10.10.101 remote-as internal | ||||
|  neighbor 10.10.10.101 update-source 10.10.10.10 | ||||
|  neighbor 10.10.10.101 timers 1 3 | ||||
|  neighbor 10.10.10.101 timers connect 1 | ||||
|  address-family ipv4 vpn | ||||
|   neighbor 10.10.10.101 activate | ||||
|   neighbor 10.10.10.101 attribute-unchanged | ||||
|  exit-address-family | ||||
| ! | ||||
| router bgp 65001 vrf Customer | ||||
|  bgp router-id 192.168.1.2 | ||||
|  no bgp ebgp-requires-policy | ||||
|  neighbor 192.168.1.1 remote-as external | ||||
|  neighbor 192.168.1.1 timers 1 3 | ||||
|  neighbor 192.168.1.1 timers connect 1 | ||||
|  address-family ipv4 unicast | ||||
|   label vpn export 10 | ||||
|   rd vpn export 192.168.1.2:2 | ||||
|   rt vpn import 192.168.1.2:2 | ||||
|   rt vpn export 192.168.1.2:2 | ||||
|   export vpn | ||||
|   import vpn | ||||
|  exit-address-family | ||||
| ! | ||||
| router bgp 65001 vrf Service | ||||
|  bgp router-id 192.168.2.2 | ||||
|  no bgp ebgp-requires-policy | ||||
|  neighbor 192.168.2.1 remote-as external | ||||
|  neighbor 192.168.2.1 timers 1 3 | ||||
|  neighbor 192.168.2.1 timers connect 1 | ||||
|  address-family ipv4 unicast | ||||
|   label vpn export 20 | ||||
|   rd vpn export 192.168.2.2:2 | ||||
|   rt vpn import 192.168.2.2:2 | ||||
|   rt vpn export 192.168.2.2:2 | ||||
|   export vpn | ||||
|   import vpn | ||||
|  exit-address-family | ||||
| ! | ||||
							
								
								
									
										12
									
								
								tests/topotests/bgp_accept_own/pe1/ldpd.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/topotests/bgp_accept_own/pe1/ldpd.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| mpls ldp | ||||
|  router-id 10.10.10.10 | ||||
|  ! | ||||
|  address-family ipv4 | ||||
|   discovery transport-address 10.10.10.10 | ||||
|   ! | ||||
|   interface pe1-eth2 | ||||
|   exit | ||||
|   ! | ||||
|  exit-address-family | ||||
|  ! | ||||
| exit | ||||
							
								
								
									
										7
									
								
								tests/topotests/bgp_accept_own/pe1/ospfd.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/topotests/bgp_accept_own/pe1/ospfd.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| interface pe1-eth2 | ||||
|  ip ospf dead-interval 4 | ||||
|  ip ospf hello-interval 1 | ||||
| ! | ||||
| router ospf | ||||
|  router-id 10.10.10.10 | ||||
|  network 0.0.0.0/0 area 0 | ||||
							
								
								
									
										15
									
								
								tests/topotests/bgp_accept_own/pe1/zebra.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								tests/topotests/bgp_accept_own/pe1/zebra.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| ! | ||||
| interface lo | ||||
|  ip address 10.10.10.10/32 | ||||
| ! | ||||
| interface pe1-eth0 vrf Customer | ||||
|  ip address 192.168.1.2/24 | ||||
| ! | ||||
| interface pe1-eth1 vrf Service | ||||
|  ip address 192.168.2.2/24 | ||||
| ! | ||||
| interface pe1-eth2 | ||||
|  ip address 10.0.1.1/24 | ||||
| ! | ||||
| ip forwarding | ||||
| ! | ||||
							
								
								
									
										25
									
								
								tests/topotests/bgp_accept_own/rr1/bgpd.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								tests/topotests/bgp_accept_own/rr1/bgpd.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| ! | ||||
| debug bgp updates | ||||
| ! | ||||
| router bgp 65001 | ||||
|  bgp router-id 10.10.10.101 | ||||
|  bgp route-reflector allow-outbound-policy | ||||
|  no bgp ebgp-requires-policy | ||||
|  no bgp default ipv4-unicast | ||||
|  neighbor 10.10.10.10 remote-as internal | ||||
|  neighbor 10.10.10.10 update-source 10.10.10.101 | ||||
|  neighbor 10.10.10.10 timers 1 3 | ||||
|  neighbor 10.10.10.10 timers connect 1 | ||||
|  address-family ipv4 vpn | ||||
|   neighbor 10.10.10.10 activate | ||||
|   neighbor 10.10.10.10 route-reflector-client | ||||
|   neighbor 10.10.10.10 route-map pe1 out | ||||
|  exit-address-family | ||||
| ! | ||||
| route-map pe1 permit 10 | ||||
|  set extcommunity rt 192.168.1.2:2 192.168.2.2:2 | ||||
|  set community 65001:111 accept-own additive | ||||
|  set ip next-hop unchanged | ||||
| route-map pe1 permit 20 | ||||
| exit | ||||
| ! | ||||
							
								
								
									
										12
									
								
								tests/topotests/bgp_accept_own/rr1/ldpd.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/topotests/bgp_accept_own/rr1/ldpd.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| mpls ldp | ||||
|  router-id 10.10.10.101 | ||||
|  ! | ||||
|  address-family ipv4 | ||||
|   discovery transport-address 10.10.10.101 | ||||
|   ! | ||||
|   interface rr1-eth0 | ||||
|   exit | ||||
|   ! | ||||
|  exit-address-family | ||||
|  ! | ||||
| exit | ||||
							
								
								
									
										7
									
								
								tests/topotests/bgp_accept_own/rr1/ospfd.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/topotests/bgp_accept_own/rr1/ospfd.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| interface rr1-eth0 | ||||
|  ip ospf dead-interval 4 | ||||
|  ip ospf hello-interval 1 | ||||
| ! | ||||
| router ospf | ||||
|  router-id 10.10.10.101 | ||||
|  network 0.0.0.0/0 area 0 | ||||
							
								
								
									
										9
									
								
								tests/topotests/bgp_accept_own/rr1/zebra.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/topotests/bgp_accept_own/rr1/zebra.conf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| ! | ||||
| interface lo | ||||
|  ip address 10.10.10.101/32 | ||||
| ! | ||||
| interface rr1-eth0 | ||||
|  ip address 10.0.1.2/24 | ||||
| ! | ||||
| ip forwarding | ||||
| ! | ||||
							
								
								
									
										198
									
								
								tests/topotests/bgp_accept_own/test_bgp_accept_own.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								tests/topotests/bgp_accept_own/test_bgp_accept_own.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,198 @@ | ||||
| #!/usr/bin/env python | ||||
| 
 | ||||
| # | ||||
| # Copyright (c) 2022 by | ||||
| # Donatas Abraitis <donatas@opensourcerouting.org> | ||||
| # | ||||
| # Permission to use, copy, modify, and/or distribute this software | ||||
| # for any purpose with or without fee is hereby granted, provided | ||||
| # that the above copyright notice and this permission notice appear | ||||
| # in all copies. | ||||
| # | ||||
| # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES | ||||
| # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
| # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR | ||||
| # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY | ||||
| # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | ||||
| # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | ||||
| # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||||
| # OF THIS SOFTWARE. | ||||
| # | ||||
| 
 | ||||
| """ | ||||
| 
 | ||||
| """ | ||||
| 
 | ||||
| import os | ||||
| import sys | ||||
| import json | ||||
| import pytest | ||||
| import functools | ||||
| 
 | ||||
| CWD = os.path.dirname(os.path.realpath(__file__)) | ||||
| sys.path.append(os.path.join(CWD, "../")) | ||||
| 
 | ||||
| # pylint: disable=C0413 | ||||
| from lib import topotest | ||||
| from lib.topogen import Topogen, TopoRouter, get_topogen | ||||
| from lib.common_config import step | ||||
| 
 | ||||
| pytestmark = [pytest.mark.bgpd] | ||||
| 
 | ||||
| 
 | ||||
| def build_topo(tgen): | ||||
|     tgen.add_router("ce1") | ||||
|     tgen.add_router("ce2") | ||||
|     tgen.add_router("pe1") | ||||
|     tgen.add_router("rr1") | ||||
| 
 | ||||
|     switch = tgen.add_switch("s1") | ||||
|     switch.add_link(tgen.gears["ce1"]) | ||||
|     switch.add_link(tgen.gears["pe1"]) | ||||
| 
 | ||||
|     switch = tgen.add_switch("s2") | ||||
|     switch.add_link(tgen.gears["ce2"]) | ||||
|     switch.add_link(tgen.gears["pe1"]) | ||||
| 
 | ||||
|     switch = tgen.add_switch("s3") | ||||
|     switch.add_link(tgen.gears["pe1"]) | ||||
|     switch.add_link(tgen.gears["rr1"]) | ||||
| 
 | ||||
| 
 | ||||
| def setup_module(mod): | ||||
|     tgen = Topogen(build_topo, mod.__name__) | ||||
|     tgen.start_topology() | ||||
| 
 | ||||
|     pe1 = tgen.gears["pe1"] | ||||
|     rr1 = tgen.gears["rr1"] | ||||
| 
 | ||||
|     pe1.run("ip link add Customer type vrf table 1001") | ||||
|     pe1.run("ip link set up dev Customer") | ||||
|     pe1.run("ip link set pe1-eth0 master Customer") | ||||
|     pe1.run("ip link add Service type vrf table 1002") | ||||
|     pe1.run("ip link set up dev Service") | ||||
|     pe1.run("ip link set pe1-eth1 master Service") | ||||
|     pe1.run("sysctl -w net.mpls.conf.pe1-eth2.input=1") | ||||
|     rr1.run("sysctl -w net.mpls.conf.rr1-eth0.input=1") | ||||
| 
 | ||||
|     router_list = tgen.routers() | ||||
| 
 | ||||
|     for i, (rname, router) in enumerate(router_list.items(), 1): | ||||
|         router.load_config( | ||||
|             TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) | ||||
|         ) | ||||
|         router.load_config( | ||||
|             TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) | ||||
|         ) | ||||
|         router.load_config( | ||||
|             TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) | ||||
|         ) | ||||
|         router.load_config( | ||||
|             TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)) | ||||
|         ) | ||||
| 
 | ||||
|     tgen.start_router() | ||||
| 
 | ||||
| 
 | ||||
| def teardown_module(mod): | ||||
|     tgen = get_topogen() | ||||
|     tgen.stop_topology() | ||||
| 
 | ||||
| 
 | ||||
| def test_bgp_accept_own(): | ||||
|     tgen = get_topogen() | ||||
| 
 | ||||
|     if tgen.routers_have_failure(): | ||||
|         pytest.skip(tgen.errors) | ||||
| 
 | ||||
|     pe1 = tgen.gears["pe1"] | ||||
|     ce2 = tgen.gears["ce2"] | ||||
| 
 | ||||
|     step("Check if routes are not installed in PE1 from RR1 (due to ORIGINATOR_ID)") | ||||
| 
 | ||||
|     def _bgp_check_received_routes_due_originator_id(): | ||||
|         output = json.loads(pe1.vtysh_cmd("show bgp ipv4 vpn summary json")) | ||||
|         expected = {"peers": {"10.10.10.101": {"pfxRcd": 0, "pfxSnt": 4}}} | ||||
|         return topotest.json_cmp(output, expected) | ||||
| 
 | ||||
|     test_func = functools.partial(_bgp_check_received_routes_due_originator_id) | ||||
|     _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) | ||||
|     assert result is None, "Failed, received routes from RR1 regardless ORIGINATOR_ID" | ||||
| 
 | ||||
|     step("Enable ACCEPT_OWN for RR1") | ||||
| 
 | ||||
|     pe1.vtysh_cmd( | ||||
|         """ | ||||
|     configure terminal | ||||
|     router bgp 65001 | ||||
|      address-family ipv4 vpn | ||||
|       neighbor 10.10.10.101 accept-own | ||||
|     """ | ||||
|     ) | ||||
| 
 | ||||
|     step("Check if we received routes due to ACCEPT_OWN from RR1") | ||||
| 
 | ||||
|     def _bgp_check_received_routes_with_modified_rts(): | ||||
|         output = json.loads(pe1.vtysh_cmd("show bgp ipv4 vpn summary json")) | ||||
|         expected = {"peers": {"10.10.10.101": {"pfxRcd": 4, "pfxSnt": 4}}} | ||||
|         return topotest.json_cmp(output, expected) | ||||
| 
 | ||||
|     test_func = functools.partial(_bgp_check_received_routes_with_modified_rts) | ||||
|     _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) | ||||
|     assert ( | ||||
|         result is None | ||||
|     ), "Failed, didn't receive routes from RR1 with ACCEPT_OWN enabled" | ||||
| 
 | ||||
|     step( | ||||
|         "Check if 172.16.255.1/32 is imported into vrf Service due to modified RT list at RR1" | ||||
|     ) | ||||
| 
 | ||||
|     def _bgp_check_received_routes_with_changed_rts(): | ||||
|         output = json.loads( | ||||
|             pe1.vtysh_cmd("show bgp vrf Service ipv4 unicast 172.16.255.1/32 json") | ||||
|         ) | ||||
|         expected = { | ||||
|             "paths": [ | ||||
|                 { | ||||
|                     "community": { | ||||
|                         "string": "65001:111" | ||||
|                     }, | ||||
|                     "extendedCommunity": { | ||||
|                         "string": "RT:192.168.1.2:2 RT:192.168.2.2:2" | ||||
|                     }, | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|         return topotest.json_cmp(output, expected) | ||||
| 
 | ||||
|     test_func = functools.partial(_bgp_check_received_routes_with_changed_rts) | ||||
|     _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) | ||||
|     assert ( | ||||
|         result is None | ||||
|     ), "Failed, routes are not imported from RR1 with modified RT list" | ||||
| 
 | ||||
|     step("Check if 172.16.255.1/32 is announced to CE2") | ||||
| 
 | ||||
|     def _bgp_check_received_routes_from_pe(): | ||||
|         output = json.loads(ce2.vtysh_cmd("show ip route 172.16.255.1/32 json")) | ||||
|         expected = { | ||||
|             "172.16.255.1/32": [ | ||||
|                 { | ||||
|                     "protocol": "bgp", | ||||
|                     "installed": True, | ||||
|                     "nexthops": [{"ip": "192.168.2.2"}], | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|         return topotest.json_cmp(output, expected) | ||||
| 
 | ||||
|     test_func = functools.partial(_bgp_check_received_routes_from_pe) | ||||
|     _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) | ||||
|     assert ( | ||||
|         result is None | ||||
|     ), "Failed, didn't receive 172.16.255.1/32 from PE1" | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     args = ["-s"] + sys.argv[1:] | ||||
|     sys.exit(pytest.main(args)) | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Donatas Abraitis
						Donatas Abraitis