diff options
244 files changed, 10552 insertions, 846 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index cac3ab1ca7..8817263cef 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -729,7 +729,8 @@ bool attrhash_cmp(const void *p1, const void *p2)  		    && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex  		    && attr1->distance == attr2->distance  		    && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn) -		    && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn)) +		    && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) +		    && attr1->srte_color == attr2->srte_color)  			return true;  	} @@ -1631,16 +1632,20 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args)  	   external peer, then this attribute MUST be ignored by the  	   receiving speaker. */  	if (peer->sort == BGP_PEER_EBGP) { -		stream_forward_getp(peer->curr, length); +		STREAM_FORWARD_GETP(peer->curr, length);  		return BGP_ATTR_PARSE_PROCEED;  	} -	attr->local_pref = stream_getl(peer->curr); +	STREAM_GETL(peer->curr, attr->local_pref);  	/* Set the local-pref flag. */  	attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);  	return BGP_ATTR_PARSE_PROCEED; + +stream_failure: +	return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +				  args->total);  }  /* Atomic aggregate. */ @@ -3023,7 +3028,7 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,  			size_t lfl =  				CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1;  			/* Rewind to end of flag field */ -			stream_forward_getp(BGP_INPUT(peer), -(1 + lfl)); +			stream_rewind_getp(BGP_INPUT(peer), (1 + lfl));  			/* Type */  			stream_get(&ndata[0], BGP_INPUT(peer), 1);  			/* Length */ diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index c57cf81007..e6e953364b 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -24,6 +24,7 @@  #include "mpls.h"  #include "bgp_attr_evpn.h"  #include "bgpd/bgp_encap_types.h" +#include "srte.h"  /* Simple bit mapping. */  #define BITMAP_NBBY 8 @@ -290,6 +291,9 @@ struct attr {  	/* EVPN ES */  	esi_t esi; + +	/* SR-TE Color */ +	uint32_t srte_color;  };  /* rmap_change_flags definition */ diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 28e93c4096..14dcf2b593 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1105,6 +1105,13 @@ void bgp_fsm_change_status(struct peer *peer, int status)  	peer->ostatus = peer->status;  	peer->status = status; +	/* Reset received keepalives counter on every FSM change */ +	peer->rtt_keepalive_rcv = 0; + +	/* Fire backward transition hook if that's the case */ +	if (peer->ostatus > peer->status) +		hook_call(peer_backward_transition, peer); +  	/* Save event that caused status change. */  	peer->last_major_event = peer->cur_event; @@ -1268,8 +1275,6 @@ int bgp_stop(struct peer *peer)  				   peer->host);  		update_group_remove_peer_afs(peer); -		hook_call(peer_backward_transition, peer); -  		/* Reset peer synctime */  		peer->synctime = 0;  	} @@ -1872,6 +1877,30 @@ static int bgp_establish(struct peer *peer)  			}  		} +	if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) { +		if ((bgp_peer_gr_mode_get(peer) == PEER_GR) +		    || ((bgp_peer_gr_mode_get(peer) == PEER_GLOBAL_INHERIT) +			&& (bgp_global_gr_mode_get(peer->bgp) == GLOBAL_GR))) { +			FOREACH_AFI_SAFI (afi, safi) +				/* Send route processing complete +				   message to RIB */ +				bgp_zebra_update( +					afi, safi, peer->bgp->vrf_id, +					ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); +		} +	} else { +		/* Peer sends R-bit. In this case, we need to send +		 * ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE to Zebra. */ +		if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV)) { +			FOREACH_AFI_SAFI (afi, safi) +				/* Send route processing complete +				   message to RIB */ +				bgp_zebra_update( +					afi, safi, peer->bgp->vrf_id, +					ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); +		} +	} +  	peer->nsf_af_count = nsf_af_count;  	if (nsf_af_count) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 86fc4bc0a3..5ef3cf736d 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -101,11 +101,9 @@ void encode_label(mpls_label_t label, mpls_label_t *label_pnt)  int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,  		       struct bgp_nlri *packet)  { -	uint8_t *pnt; -	uint8_t *lim;  	struct prefix p; -	int psize = 0; -	int prefixlen; +	uint8_t psize = 0; +	uint8_t prefixlen;  	uint16_t type;  	struct rd_as rd_as;  	struct rd_ip rd_ip; @@ -115,13 +113,14 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,  	safi_t safi;  	int addpath_encoded;  	uint32_t addpath_id; +	int ret = 0;  	/* Make prefix_rd */  	prd.family = AF_UNSPEC;  	prd.prefixlen = 64; -	pnt = packet->nlri; -	lim = pnt + packet->length; +	struct stream *data = stream_new(packet->length); +	stream_put(data, packet->nlri, packet->length);  	afi = packet->afi;  	safi = packet->safi;  	addpath_id = 0; @@ -132,23 +131,26 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,  			       PEER_CAP_ADDPATH_AF_TX_RCV));  #define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */ -	for (; pnt < lim; pnt += psize) { +	while (STREAM_READABLE(data) > 0) {  		/* Clear prefix structure. */  		memset(&p, 0, sizeof(struct prefix));  		if (addpath_encoded) { - -			/* When packet overflow occurs return immediately. */ -			if (pnt + BGP_ADDPATH_ID_LEN > lim) -				return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; - -			memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN); +			STREAM_GET(&addpath_id, data, BGP_ADDPATH_ID_LEN);  			addpath_id = ntohl(addpath_id); -			pnt += BGP_ADDPATH_ID_LEN; +		} + +		if (STREAM_READABLE(data) < 1) { +			flog_err( +				EC_BGP_UPDATE_RCV, +				"%s [Error] Update packet error / VPN (truncated NLRI of size %u; no prefix length)", +				peer->host, packet->length); +			ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; +			goto done;  		}  		/* Fetch prefix length. */ -		prefixlen = *pnt++; +		STREAM_GETC(data, prefixlen);  		p.family = afi2family(packet->afi);  		psize = PSIZE(prefixlen); @@ -157,16 +159,18 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,  				EC_BGP_UPDATE_RCV,  				"%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)",  				peer->host, prefixlen); -			return BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH; +			ret = BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH; +			goto done;  		}  		/* sanity check against packet data */ -		if ((pnt + psize) > lim) { +		if (STREAM_READABLE(data) < psize) {  			flog_err(  				EC_BGP_UPDATE_RCV,  				"%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)", -				peer->host, prefixlen, (uint)(lim - pnt)); -			return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; +				peer->host, prefixlen, packet->length); +			ret = BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; +			goto done;  		}  		/* sanity check against storage for the IP address portion */ @@ -177,7 +181,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,  				peer->host,  				prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,  				sizeof(p.u)); -			return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; +			ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; +			goto done;  		}  		/* Sanity check against max bitlen of the address family */ @@ -188,30 +193,48 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,  				peer->host,  				prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,  				p.family, prefix_blen(&p)); -			return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; +			ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; +			goto done;  		}  		/* Copy label to prefix. */ -		memcpy(&label, pnt, BGP_LABEL_BYTES); +		if (STREAM_READABLE(data) < BGP_LABEL_BYTES) { +			flog_err( +				EC_BGP_UPDATE_RCV, +				"%s [Error] Update packet error / VPN (truncated NLRI of size %u; no label)", +				peer->host, packet->length); +			ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; +			goto done; +		} + +		STREAM_GET(&label, data, BGP_LABEL_BYTES);  		bgp_set_valid_label(&label);  		/* Copy routing distinguisher to rd. */ -		memcpy(&prd.val, pnt + BGP_LABEL_BYTES, 8); +		if (STREAM_READABLE(data) < 8) { +			flog_err( +				EC_BGP_UPDATE_RCV, +				"%s [Error] Update packet error / VPN (truncated NLRI of size %u; no RD)", +				peer->host, packet->length); +			ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; +			goto done; +		} +		STREAM_GET(&prd.val, data, 8);  		/* Decode RD type. */ -		type = decode_rd_type(pnt + BGP_LABEL_BYTES); +		type = decode_rd_type(prd.val);  		switch (type) {  		case RD_TYPE_AS: -			decode_rd_as(pnt + 5, &rd_as); +			decode_rd_as(&prd.val[2], &rd_as);  			break;  		case RD_TYPE_AS4: -			decode_rd_as4(pnt + 5, &rd_as); +			decode_rd_as4(&prd.val[2], &rd_as);  			break;  		case RD_TYPE_IP: -			decode_rd_ip(pnt + 5, &rd_ip); +			decode_rd_ip(&prd.val[2], &rd_ip);  			break;  #ifdef ENABLE_BGP_VNC @@ -224,11 +247,9 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,  			break; /* just report */  		} -		p.prefixlen = -			prefixlen -			- VPN_PREFIXLEN_MIN_BYTES * 8; /* exclude label & RD */ -		memcpy(p.u.val, pnt + VPN_PREFIXLEN_MIN_BYTES, -		       psize - VPN_PREFIXLEN_MIN_BYTES); +		/* exclude label & RD */ +		p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8; +		STREAM_GET(p.u.val, data, psize - VPN_PREFIXLEN_MIN_BYTES);  		if (attr) {  			bgp_update(peer, &p, addpath_id, attr, packet->afi, @@ -241,15 +262,27 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,  		}  	}  	/* Packet length consistency check. */ -	if (pnt != lim) { +	if (STREAM_READABLE(data) != 0) {  		flog_err(  			EC_BGP_UPDATE_RCV,  			"%s [Error] Update packet error / VPN (%td data remaining after parsing)", -			peer->host, lim - pnt); +			peer->host, STREAM_READABLE(data));  		return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH;  	} -	return 0; +	goto done; + +stream_failure: +	flog_err( +		EC_BGP_UPDATE_RCV, +		"%s [Error] Update packet error / VPN (NLRI of size %u - length error)", +		peer->host, packet->length); +	ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; + +done: +	stream_free(data); +	return ret; +  #undef VPN_PREFIXLEN_MIN_BYTES  } diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index c324f259ba..cae11ae7bd 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -160,12 +160,26 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)  	 */  	frr_with_privs(&bgpd_privs) {  		for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) -			if (listener->su.sa.sa_family -			    == peer->su.sa.sa_family) { +			if (listener->su.sa.sa_family == +			    peer->su.sa.sa_family) {  				uint16_t prefixlen =  					peer->su.sa.sa_family == AF_INET -						? IPV4_MAX_PREFIXLEN -						: IPV6_MAX_PREFIXLEN; +					? IPV4_MAX_PREFIXLEN +					: IPV6_MAX_PREFIXLEN; + +				/* +				 * if we have stored a BGP vrf instance in the +				 * listener it must match the bgp instance in +				 * the peer otherwise the peer bgp instance +				 * must be the default vrf or a view instance +				 */ +				if (!listener->bgp) { +					if (peer->bgp->vrf_id != VRF_DEFAULT +					    && peer->bgp->inst_type +						       != BGP_INSTANCE_TYPE_VIEW) +						continue; +				} else if (listener->bgp != peer->bgp) +					continue;  				ret = bgp_md5_set_socket(listener->fd,  							 &peer->su, prefixlen, @@ -176,7 +190,7 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)  	return ret;  } -int bgp_md5_set_prefix(struct prefix *p, const char *password) +int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p, const char *password)  {  	int ret = 0;  	union sockunion su; @@ -186,7 +200,9 @@ int bgp_md5_set_prefix(struct prefix *p, const char *password)  	/* Set or unset the password on the listen socket(s). */  	frr_with_privs(&bgpd_privs) {  		for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) -			if (listener->su.sa.sa_family == p->family) { +			if (listener->su.sa.sa_family == p->family +			    && ((bgp->vrf_id == VRF_DEFAULT) +				|| (listener->bgp == bgp))) {  				prefix2sockunion(p, &su);  				ret = bgp_md5_set_socket(listener->fd, &su,  							 p->prefixlen, @@ -198,9 +214,9 @@ int bgp_md5_set_prefix(struct prefix *p, const char *password)  	return ret;  } -int bgp_md5_unset_prefix(struct prefix *p) +int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p)  { -	return bgp_md5_set_prefix(p, NULL); +	return bgp_md5_set_prefix(bgp, p, NULL);  }  int bgp_md5_set(struct peer *peer) @@ -812,8 +828,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen,  	listener->fd = sock;  	listener->name = XSTRDUP(MTYPE_BGP_LISTENER, bgp->name); -	/* this socket needs a change of ns. record bgp back pointer */ -	if (bgp->vrf_id != VRF_DEFAULT && vrf_is_backend_netns()) +	/* this socket is in a vrf record bgp back pointer */ +	if (bgp->vrf_id != VRF_DEFAULT +	    && bgp->inst_type != BGP_INSTANCE_TYPE_VIEW)  		listener->bgp = bgp;  	memcpy(&listener->su, sa, salen); diff --git a/bgpd/bgp_network.h b/bgpd/bgp_network.h index 018efbc08e..0b5cc17523 100644 --- a/bgpd/bgp_network.h +++ b/bgpd/bgp_network.h @@ -31,8 +31,9 @@ extern void bgp_close(void);  extern int bgp_connect(struct peer *);  extern int bgp_getsockname(struct peer *); -extern int bgp_md5_set_prefix(struct prefix *p, const char *password); -extern int bgp_md5_unset_prefix(struct prefix *p); +extern int bgp_md5_set_prefix(struct bgp *bgp, struct prefix *p, +			      const char *password); +extern int bgp_md5_unset_prefix(struct bgp *bgp, struct prefix *p);  extern int bgp_md5_set(struct peer *);  extern int bgp_md5_unset(struct peer *);  extern int bgp_set_socket_ttl(struct peer *, int fd); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 5cc0d60529..ed026a2fff 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -35,7 +35,6 @@  #include "filter.h"  #include "bgpd/bgpd.h" -#include "bgpd/bgp_table.h"  #include "bgpd/bgp_route.h"  #include "bgpd/bgp_attr.h"  #include "bgpd/bgp_nexthop.h" @@ -48,10 +47,20 @@  DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Address Intf String"); -char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size) +int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a, +			      const struct bgp_nexthop_cache *b)  { -	prefix2str(bgp_dest_get_prefix(bnc->dest), buf, size); -	return buf; +	if (a->srte_color < b->srte_color) +		return -1; +	if (a->srte_color > b->srte_color) +		return 1; + +	return prefix_cmp(&a->prefix, &b->prefix); +} + +const char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size) +{ +	return prefix2str(&bnc->prefix, buf, size);  }  void bnc_nexthop_free(struct bgp_nexthop_cache *bnc) @@ -59,32 +68,62 @@ void bnc_nexthop_free(struct bgp_nexthop_cache *bnc)  	nexthops_free(bnc->nexthop);  } -struct bgp_nexthop_cache *bnc_new(void) +struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree, +				  struct prefix *prefix, uint32_t srte_color)  {  	struct bgp_nexthop_cache *bnc;  	bnc = XCALLOC(MTYPE_BGP_NEXTHOP_CACHE,  		      sizeof(struct bgp_nexthop_cache)); +	bnc->prefix = *prefix; +	bnc->srte_color = srte_color; +	bnc->tree = tree;  	LIST_INIT(&(bnc->paths)); +	bgp_nexthop_cache_add(tree, bnc); +  	return bnc;  } +bool bnc_existing_for_prefix(struct bgp_nexthop_cache *bnc) +{ +	struct bgp_nexthop_cache *bnc_tmp; + +	frr_each (bgp_nexthop_cache, bnc->tree, bnc_tmp) { +		if (bnc_tmp == bnc) +			continue; +		if (prefix_cmp(&bnc->prefix, &bnc_tmp->prefix) == 0) +			return true; +	} +	return false; +} +  void bnc_free(struct bgp_nexthop_cache *bnc)  {  	bnc_nexthop_free(bnc); +	bgp_nexthop_cache_del(bnc->tree, bnc);  	XFREE(MTYPE_BGP_NEXTHOP_CACHE, bnc);  } +struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree, +				   struct prefix *prefix, uint32_t srte_color) +{ +	struct bgp_nexthop_cache bnc = {}; + +	if (!tree) +		return NULL; + +	bnc.prefix = *prefix; +	bnc.srte_color = srte_color; +	return bgp_nexthop_cache_find(tree, &bnc); +} +  /* Reset and free all BGP nexthop cache. */ -static void bgp_nexthop_cache_reset(struct bgp_table *table) +static void bgp_nexthop_cache_reset(struct bgp_nexthop_cache_head *tree)  { -	struct bgp_dest *dest;  	struct bgp_nexthop_cache *bnc; -	for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { -		bnc = bgp_dest_get_bgp_nexthop_info(dest); -		if (!bnc) -			continue; +	while (bgp_nexthop_cache_count(tree) > 0) { +		bnc = bgp_nexthop_cache_first(tree);  		while (!LIST_EMPTY(&(bnc->paths))) {  			struct bgp_path_info *path = LIST_FIRST(&(bnc->paths)); @@ -93,8 +132,6 @@ static void bgp_nexthop_cache_reset(struct bgp_table *table)  		}  		bnc_free(bnc); -		bgp_dest_set_bgp_nexthop_info(dest, NULL); -		bgp_dest_unlock_node(dest);  	}  } @@ -773,20 +810,21 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,  }  static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, -			     struct bgp_dest *dest,  			     struct bgp_nexthop_cache *bnc,  			     bool specific)  {  	char buf[PREFIX2STR_BUFFER];  	time_t tbuf;  	struct peer *peer; -	const struct prefix *p = bgp_dest_get_prefix(dest);  	peer = (struct peer *)bnc->nht_info; +	if (bnc->srte_color) +		vty_out(vty, " SR-TE color %u -", bnc->srte_color);  	if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {  		vty_out(vty, " %s valid [IGP metric %d], #paths %d", -			inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)), +			inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, +				  buf, sizeof(buf)),  			bnc->metric, bnc->path_count);  		if (peer)  			vty_out(vty, ", peer %s", peer->host); @@ -794,7 +832,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,  		bgp_show_nexthops_detail(vty, bgp, bnc);  	} else {  		vty_out(vty, " %s invalid, #paths %d", -			inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)), +			inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, +				  buf, sizeof(buf)),  			bnc->path_count);  		if (peer)  			vty_out(vty, ", peer %s", peer->host); @@ -816,29 +855,21 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,  static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp,  			      bool import_table)  { -	struct bgp_dest *dest;  	struct bgp_nexthop_cache *bnc;  	afi_t afi; -	struct bgp_table **table; +	struct bgp_nexthop_cache_head(*tree)[AFI_MAX];  	if (import_table)  		vty_out(vty, "Current BGP import check cache:\n");  	else  		vty_out(vty, "Current BGP nexthop cache:\n");  	if (import_table) -		table = bgp->import_check_table; +		tree = &bgp->import_check_table;  	else -		table = bgp->nexthop_cache_table; +		tree = &bgp->nexthop_cache_table;  	for (afi = AFI_IP; afi < AFI_MAX; afi++) { -		if (!table || !table[afi]) -			continue; -		for (dest = bgp_table_top(table[afi]); dest; -		     dest = bgp_route_next(dest)) { -			bnc = bgp_dest_get_bgp_nexthop_info(dest); -			if (!bnc) -				continue; -			bgp_show_nexthop(vty, bgp, dest, bnc, false); -		} +		frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) +			bgp_show_nexthop(vty, bgp, bnc, false);  	}  } @@ -859,27 +890,21 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,  	if (nhopip_str) {  		struct prefix nhop; -		struct bgp_table **table; -		struct bgp_dest *dest; +		struct bgp_nexthop_cache_head (*tree)[AFI_MAX];  		struct bgp_nexthop_cache *bnc;  		if (!str2prefix(nhopip_str, &nhop)) {  			vty_out(vty, "nexthop address is malformed\n");  			return CMD_WARNING;  		} -		table = import_table ? \ -			bgp->import_check_table : bgp->nexthop_cache_table; -		dest = bgp_node_lookup(table[family2afi(nhop.family)], &nhop); -		if (!dest) { -			vty_out(vty, "specified nexthop is not found\n"); -			return CMD_SUCCESS; -		} -		bnc = bgp_dest_get_bgp_nexthop_info(dest); +		tree = import_table ? &bgp->import_check_table +				    : &bgp->nexthop_cache_table; +		bnc = bnc_find(tree[family2afi(nhop.family)], &nhop, 0);  		if (!bnc) {  			vty_out(vty, "specified nexthop does not have entry\n");  			return CMD_SUCCESS;  		} -		bgp_show_nexthop(vty, bgp, dest, bnc, true); +		bgp_show_nexthop(vty, bgp, bnc, true);  	} else  		bgp_show_nexthops(vty, bgp, import_table); @@ -966,12 +991,10 @@ void bgp_scan_init(struct bgp *bgp)  	afi_t afi;  	for (afi = AFI_IP; afi < AFI_MAX; afi++) { -		bgp->nexthop_cache_table[afi] = -			bgp_table_init(bgp, afi, SAFI_UNICAST); +		bgp_nexthop_cache_init(&bgp->nexthop_cache_table[afi]); +		bgp_nexthop_cache_init(&bgp->import_check_table[afi]);  		bgp->connected_table[afi] = bgp_table_init(bgp, afi,  			SAFI_UNICAST); -		bgp->import_check_table[afi] = -			bgp_table_init(bgp, afi, SAFI_UNICAST);  	}  } @@ -988,16 +1011,12 @@ void bgp_scan_finish(struct bgp *bgp)  	for (afi = AFI_IP; afi < AFI_MAX; afi++) {  		/* Only the current one needs to be reset. */ -		bgp_nexthop_cache_reset(bgp->nexthop_cache_table[afi]); -		bgp_table_unlock(bgp->nexthop_cache_table[afi]); -		bgp->nexthop_cache_table[afi] = NULL; +		bgp_nexthop_cache_reset(&bgp->nexthop_cache_table[afi]); +		bgp_nexthop_cache_reset(&bgp->import_check_table[afi]);  		bgp->connected_table[afi]->route_table->cleanup =  			bgp_connected_cleanup;  		bgp_table_unlock(bgp->connected_table[afi]);  		bgp->connected_table[afi] = NULL; - -		bgp_table_unlock(bgp->import_check_table[afi]); -		bgp->import_check_table[afi] = NULL;  	}  } diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 416ab2a739..c4b913faf4 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -24,6 +24,7 @@  #include "if.h"  #include "queue.h"  #include "prefix.h" +#include "bgp_table.h"  #define NEXTHOP_FAMILY(nexthop_len)                                            \  	(((nexthop_len) == 4 || (nexthop_len) == 12                            \ @@ -36,8 +37,13 @@  #define BGP_MP_NEXTHOP_FAMILY NEXTHOP_FAMILY +PREDECL_RBTREE_UNIQ(bgp_nexthop_cache); +  /* BGP nexthop cache value structure. */  struct bgp_nexthop_cache { +	/* RB-tree entry. */ +	struct bgp_nexthop_cache_item entry; +  	/* IGP route's metric. */  	uint32_t metric; @@ -61,13 +67,22 @@ struct bgp_nexthop_cache {  #define BGP_NEXTHOP_METRIC_CHANGED    (1 << 1)  #define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2) -	struct bgp_dest *dest; +	/* Back pointer to the cache tree this entry belongs to. */ +	struct bgp_nexthop_cache_head *tree; + +	uint32_t srte_color; +	struct prefix prefix;  	void *nht_info; /* In BGP, peer session */  	LIST_HEAD(path_list, bgp_path_info) paths;  	unsigned int path_count;  	struct bgp *bgp;  }; +extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a, +				     const struct bgp_nexthop_cache *b); +DECLARE_RBTREE_UNIQ(bgp_nexthop_cache, struct bgp_nexthop_cache, entry, +		    bgp_nexthop_cache_compare); +  /* Own tunnel-ip address structure */  struct tip_addr {  	struct in_addr addr; @@ -79,6 +94,12 @@ struct bgp_addrv6 {  	struct list *ifp_name_list;  }; +/* Forward declaration(s). */ +struct peer; +struct update_subgroup; +struct bgp_dest; +struct attr; +  extern void bgp_connected_add(struct bgp *bgp, struct connected *c);  extern void bgp_connected_delete(struct bgp *bgp, struct connected *c);  extern bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop, @@ -94,10 +115,16 @@ extern int bgp_config_write_scan_time(struct vty *);  extern bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,  			     uint8_t sub_type, struct attr *attr,  			     struct bgp_dest *dest); -extern struct bgp_nexthop_cache *bnc_new(void); +extern struct bgp_nexthop_cache *bnc_new(struct bgp_nexthop_cache_head *tree, +					 struct prefix *prefix, +					 uint32_t srte_color); +extern bool bnc_existing_for_prefix(struct bgp_nexthop_cache *bnc);  extern void bnc_free(struct bgp_nexthop_cache *bnc); +extern struct bgp_nexthop_cache *bnc_find(struct bgp_nexthop_cache_head *tree, +					  struct prefix *prefix, +					  uint32_t srte_color);  extern void bnc_nexthop_free(struct bgp_nexthop_cache *bnc); -extern char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size); +extern const char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size);  extern void bgp_scan_init(struct bgp *bgp);  extern void bgp_scan_finish(struct bgp *bgp);  extern void bgp_scan_vty_init(void); diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index a780fb7347..9573d118e5 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -72,15 +72,14 @@ static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)  	if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) {  		if (BGP_DEBUG(nht, NHT)) {  			char buf[PREFIX2STR_BUFFER]; -			zlog_debug("bgp_unlink_nexthop: freeing bnc %s(%s)", +			zlog_debug("bgp_unlink_nexthop: freeing bnc %s(%u)(%s)",  				   bnc_str(bnc, buf, PREFIX2STR_BUFFER), -				   bnc->bgp->name_pretty); +				   bnc->srte_color, bnc->bgp->name_pretty);  		} -		unregister_zebra_rnh(bnc, -				     CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)); -		bgp_dest_set_bgp_nexthop_info(bnc->dest, NULL); -		bgp_dest_unlock_node(bnc->dest); -		bnc->dest = NULL; +		/* only unregister if this is the last nh for this prefix*/ +		if (!bnc_existing_for_prefix(bnc)) +			unregister_zebra_rnh( +				bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));  		bnc_free(bnc);  	}  } @@ -100,16 +99,13 @@ void bgp_unlink_nexthop(struct bgp_path_info *path)  void bgp_unlink_nexthop_by_peer(struct peer *peer)  {  	struct prefix p; -	struct bgp_dest *dest;  	struct bgp_nexthop_cache *bnc;  	afi_t afi = family2afi(peer->su.sa.sa_family);  	if (!sockunion2hostprefix(&peer->su, &p))  		return; -	dest = bgp_node_get(peer->bgp->nexthop_cache_table[afi], &p); - -	bnc = bgp_dest_get_bgp_nexthop_info(dest); +	bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0);  	if (!bnc)  		return; @@ -127,11 +123,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,  			    afi_t afi, struct bgp_path_info *pi,  			    struct peer *peer, int connected)  { -	struct bgp_dest *dest; +	struct bgp_nexthop_cache_head *tree = NULL;  	struct bgp_nexthop_cache *bnc;  	struct prefix p; +	uint32_t srte_color = 0;  	int is_bgp_static_route = 0; -	const struct prefix *bnc_p;  	if (pi) {  		is_bgp_static_route = ((pi->type == ZEBRA_ROUTE_BGP) @@ -155,6 +151,8 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,  		 * addr */  		if (make_prefix(afi, pi, &p) < 0)  			return 1; + +		srte_color = pi->attr->srte_color;  	} else if (peer) {  		if (!sockunion2hostprefix(&peer->su, &p)) {  			if (BGP_DEBUG(nht, NHT)) { @@ -168,29 +166,24 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,  		return 0;  	if (is_bgp_static_route) -		dest = bgp_node_get(bgp_nexthop->import_check_table[afi], &p); +		tree = &bgp_nexthop->import_check_table[afi];  	else -		dest = bgp_node_get(bgp_nexthop->nexthop_cache_table[afi], &p); +		tree = &bgp_nexthop->nexthop_cache_table[afi]; -	bnc = bgp_dest_get_bgp_nexthop_info(dest); +	bnc = bnc_find(tree, &p, srte_color);  	if (!bnc) { -		bnc = bnc_new(); -		bgp_dest_set_bgp_nexthop_info(dest, bnc); -		bnc->dest = dest; +		bnc = bnc_new(tree, &p, srte_color);  		bnc->bgp = bgp_nexthop; -		bgp_dest_lock_node(dest);  		if (BGP_DEBUG(nht, NHT)) {  			char buf[PREFIX2STR_BUFFER]; -			zlog_debug("Allocated bnc %s(%s) peer %p", +			zlog_debug("Allocated bnc %s(%u)(%s) peer %p",  				   bnc_str(bnc, buf, PREFIX2STR_BUFFER), -				   bnc->bgp->name_pretty, peer); +				   bnc->srte_color, bnc->bgp->name_pretty, +				   peer);  		}  	} -	bnc_p = bgp_dest_get_prefix(bnc->dest); - -	bgp_dest_unlock_node(dest);  	if (is_bgp_static_route) {  		SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); @@ -236,7 +229,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,  		SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);  		SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);  	} else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED) -		   && !is_default_host_route(bnc_p)) +		   && !is_default_host_route(&bnc->prefix))  		register_zebra_rnh(bnc, is_bgp_static_route);  	if (pi && pi->nexthop != bnc) { @@ -269,7 +262,6 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,  void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)  { -	struct bgp_dest *dest;  	struct bgp_nexthop_cache *bnc;  	struct prefix p; @@ -279,26 +271,15 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)  	if (!sockunion2hostprefix(&peer->su, &p))  		return; -	dest = bgp_node_lookup( -		peer->bgp->nexthop_cache_table[family2afi(p.family)], &p); -	if (!dest) { -		if (BGP_DEBUG(nht, NHT)) -			zlog_debug( -				"Cannot find connected NHT node for peer %s(%s)", -				peer->host, peer->bgp->name_pretty); -		return; -	} - -	bnc = bgp_dest_get_bgp_nexthop_info(dest); +	bnc = bnc_find(&peer->bgp->nexthop_cache_table[family2afi(p.family)], +		       &p, 0);  	if (!bnc) {  		if (BGP_DEBUG(nht, NHT))  			zlog_debug( -				"Cannot find connected NHT node for peer %s(%s) on route_node as expected", +				"Cannot find connected NHT node for peer %s(%s)",  				peer->host, peer->bgp->name_pretty); -		bgp_dest_unlock_node(dest);  		return;  	} -	bgp_dest_unlock_node(dest);  	if (bnc->nht_info != peer) {  		if (BGP_DEBUG(nht, NHT)) @@ -317,95 +298,40 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)  				"Freeing connected NHT node %p for peer %s(%s)",  				bnc, peer->host, bnc->bgp->name_pretty);  		unregister_zebra_rnh(bnc, 0); -		bgp_dest_set_bgp_nexthop_info(bnc->dest, NULL); -		bgp_dest_unlock_node(bnc->dest);  		bnc_free(bnc);  	}  } -void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) +static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, +				       struct zapi_route *nhr)  { -	struct bgp_dest *dest = NULL; -	struct bgp_nexthop_cache *bnc;  	struct nexthop *nexthop;  	struct nexthop *oldnh;  	struct nexthop *nhlist_head = NULL;  	struct nexthop *nhlist_tail = NULL;  	int i; -	struct bgp *bgp; -	struct zapi_route nhr; - -	bgp = bgp_lookup_by_vrf_id(vrf_id); -	if (!bgp) { -		flog_err( -			EC_BGP_NH_UPD, -			"parse nexthop update: instance not found for vrf_id %u", -			vrf_id); -		return; -	} -	if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { -		if (BGP_DEBUG(nht, NHT)) -			zlog_debug("%s[%s]: Failure to decode nexthop update", -				   __func__, bgp->name_pretty); -		return; -	} - -	if (command == ZEBRA_NEXTHOP_UPDATE) -		dest = bgp_node_lookup( -			bgp->nexthop_cache_table[family2afi(nhr.prefix.family)], -			&nhr.prefix); -	else if (command == ZEBRA_IMPORT_CHECK_UPDATE) -		dest = bgp_node_lookup( -			bgp->import_check_table[family2afi(nhr.prefix.family)], -			&nhr.prefix); - -	if (!dest) { -		if (BGP_DEBUG(nht, NHT)) { -			char buf[PREFIX2STR_BUFFER]; -			prefix2str(&nhr.prefix, buf, sizeof(buf)); -			zlog_debug("parse nexthop update(%s(%s)): rn not found", -				   buf, bgp->name_pretty); -		} -		return; -	} - -	bnc = bgp_dest_get_bgp_nexthop_info(dest); -	if (!bnc) { -		if (BGP_DEBUG(nht, NHT)) { -			char buf[PREFIX2STR_BUFFER]; - -			prefix2str(&nhr.prefix, buf, sizeof(buf)); -			zlog_debug( -				"parse nexthop update(%s(%s)): bnc node info not found", -				buf, bgp->name_pretty); -		} -		bgp_dest_unlock_node(dest); -		return; -	} - -	bgp_dest_unlock_node(dest);  	bnc->last_update = bgp_clock();  	bnc->change_flags = 0;  	/* debug print the input */  	if (BGP_DEBUG(nht, NHT)) {  		char buf[PREFIX2STR_BUFFER]; -		prefix2str(&nhr.prefix, buf, sizeof(buf)); +		prefix2str(&nhr->prefix, buf, sizeof(buf));  		zlog_debug( -			"%s(%u): Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x", -			bnc->bgp->name_pretty, vrf_id, buf, nhr.metric, -			bnc->metric, nhr.nexthop_num, bnc->nexthop_num, -			bnc->flags); +			"%s(%u): Rcvd NH update %s(%u) - metric %d/%d #nhops %d/%d flags 0x%x", +			bnc->bgp->name_pretty, bnc->bgp->vrf_id, buf, +			bnc->srte_color, nhr->metric, bnc->metric, +			nhr->nexthop_num, bnc->nexthop_num, bnc->flags);  	} -	if (nhr.metric != bnc->metric) +	if (nhr->metric != bnc->metric)  		bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED; -	if (nhr.nexthop_num != bnc->nexthop_num) +	if (nhr->nexthop_num != bnc->nexthop_num)  		bnc->change_flags |= BGP_NEXTHOP_CHANGED; -	if (nhr.nexthop_num) { +	if (nhr->nexthop_num) {  		struct peer *peer = bnc->nht_info;  		/* notify bgp fsm if nbr ip goes from invalid->valid */ @@ -413,15 +339,15 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)  			UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);  		bnc->flags |= BGP_NEXTHOP_VALID; -		bnc->metric = nhr.metric; -		bnc->nexthop_num = nhr.nexthop_num; +		bnc->metric = nhr->metric; +		bnc->nexthop_num = nhr->nexthop_num;  		bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */ -		for (i = 0; i < nhr.nexthop_num; i++) { +		for (i = 0; i < nhr->nexthop_num; i++) {  			int num_labels = 0; -			nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]); +			nexthop = nexthop_from_zapi_nexthop(&nhr->nexthops[i]);  			/*  			 * Turn on RA for the v6 nexthops @@ -431,7 +357,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)  			if (peer && !peer->ifp  			    && CHECK_FLAG(peer->flags,  					  PEER_FLAG_CAPABILITY_ENHE) -			    && nhr.prefix.family == AF_INET6 +			    && nhr->prefix.family == AF_INET6  			    && nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {  				struct interface *ifp; @@ -485,7 +411,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)  		bnc->nexthop = nhlist_head;  	} else {  		bnc->flags &= ~BGP_NEXTHOP_VALID; -		bnc->nexthop_num = nhr.nexthop_num; +		bnc->nexthop_num = nhr->nexthop_num;  		/* notify bgp fsm if nbr ip goes from valid->invalid */  		UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); @@ -497,26 +423,88 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)  	evaluate_paths(bnc);  } +void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) +{ +	struct bgp_nexthop_cache_head *tree = NULL; +	struct bgp_nexthop_cache *bnc; +	struct bgp *bgp; +	struct zapi_route nhr; +	afi_t afi; + +	bgp = bgp_lookup_by_vrf_id(vrf_id); +	if (!bgp) { +		flog_err( +			EC_BGP_NH_UPD, +			"parse nexthop update: instance not found for vrf_id %u", +			vrf_id); +		return; +	} + +	if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { +		if (BGP_DEBUG(nht, NHT)) +			zlog_debug("%s[%s]: Failure to decode nexthop update", +				   __PRETTY_FUNCTION__, bgp->name_pretty); +		return; +	} + +	afi = family2afi(nhr.prefix.family); +	if (command == ZEBRA_NEXTHOP_UPDATE) +		tree = &bgp->nexthop_cache_table[afi]; +	else if (command == ZEBRA_IMPORT_CHECK_UPDATE) +		tree = &bgp->import_check_table[afi]; + +	bnc = bnc_find(tree, &nhr.prefix, nhr.srte_color); +	if (!bnc) { +		if (BGP_DEBUG(nht, NHT)) { +			char buf[PREFIX2STR_BUFFER]; + +			prefix2str(&nhr.prefix, buf, sizeof(buf)); +			zlog_debug( +				"parse nexthop update(%s(%u)(%s)): bnc info not found", +				buf, nhr.srte_color, bgp->name_pretty); +		} +		return; +	} + +	bgp_process_nexthop_update(bnc, &nhr); + +	/* +	 * HACK: if any BGP route is dependant on an SR-policy that doesn't +	 * exist, zebra will never send NH updates relative to that policy. In +	 * that case, whenever we receive an update about a colorless NH, update +	 * the corresponding colorful NHs that share the same endpoint but that +	 * are inactive. This ugly hack should work around the problem at the +	 * cost of a performance pernalty. Long term, what should be done is to +	 * make zebra's RNH subsystem aware of SR-TE colors (like bgpd is), +	 * which should provide a better infrastructure to solve this issue in +	 * a more efficient and elegant way. +	 */ +	if (nhr.srte_color == 0) { +		struct bgp_nexthop_cache *bnc_iter; + +		frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], +			  bnc_iter) { +			if (!prefix_same(&bnc->prefix, &bnc_iter->prefix) +			    || bnc_iter->srte_color == 0 +			    || CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID)) +				continue; + +			bgp_process_nexthop_update(bnc_iter, &nhr); +		} +	} +} +  /*   * Cleanup nexthop registration and status information for BGP nexthops   * pertaining to this VRF. This is invoked upon VRF deletion.   */  void bgp_cleanup_nexthops(struct bgp *bgp)  { -	afi_t afi; -	struct bgp_dest *dest; -	struct bgp_nexthop_cache *bnc; - -	for (afi = AFI_IP; afi < AFI_MAX; afi++) { -		if (!bgp->nexthop_cache_table[afi]) -			continue; - -		for (dest = bgp_table_top(bgp->nexthop_cache_table[afi]); dest; -		     dest = bgp_route_next(dest)) { -			bnc = bgp_dest_get_bgp_nexthop_info(dest); -			if (!bnc) -				continue; +	for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) { +		struct bgp_nexthop_cache *bnc; +		frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], +			  bnc) {  			/* Clear relevant flags. */  			UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);  			UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); @@ -609,7 +597,6 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)   */  static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)  { -	const struct prefix *p;  	bool exact_match = false;  	int ret; @@ -631,23 +618,18 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)  				"%s: We have not connected yet, cannot send nexthops",  				__func__);  	} -	p = bgp_dest_get_prefix(bnc->dest);  	if ((command == ZEBRA_NEXTHOP_REGISTER  	     || command == ZEBRA_IMPORT_ROUTE_REGISTER)  	    && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)  		|| CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))  		exact_match = true; -	if (BGP_DEBUG(zebra, ZEBRA)) { -		char buf[PREFIX2STR_BUFFER]; - -		prefix2str(p, buf, PREFIX2STR_BUFFER); -		zlog_debug("%s: sending cmd %s for %s (vrf %s)", -			__func__, zserv_command_string(command), buf, -			bnc->bgp->name_pretty); -	} +	if (BGP_DEBUG(zebra, ZEBRA)) +		zlog_debug("%s: sending cmd %s for %pFX (vrf %s)", __func__, +			   zserv_command_string(command), &bnc->prefix, +			   bnc->bgp->name_pretty); -	ret = zclient_send_rnh(zclient, command, p, exact_match, +	ret = zclient_send_rnh(zclient, command, &bnc->prefix, exact_match,  			       bnc->bgp->vrf_id);  	/* TBD: handle the failure */  	if (ret < 0) @@ -725,8 +707,8 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)  		char buf[PREFIX2STR_BUFFER];  		bnc_str(bnc, buf, PREFIX2STR_BUFFER);  		zlog_debug( -			"NH update for %s %s flags 0x%x chgflags 0x%x - evaluate paths", -			buf, bnc->bgp->name_pretty, bnc->flags, +			"NH update for %s(%u)(%s) - flags 0x%x chgflags 0x%x - evaluate paths", +			buf, bnc->srte_color, bnc->bgp->name_pretty, bnc->flags,  			bnc->change_flags);  	} @@ -814,7 +796,8 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)  			path->extra->igpmetric = 0;  		if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED) -		    || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) +		    || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED) +		    || path->attr->srte_color != 0)  			SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED);  		path_valid = !!CHECK_FLAG(path->flags, BGP_PATH_VALID); @@ -901,21 +884,11 @@ void path_nh_map(struct bgp_path_info *path, struct bgp_nexthop_cache *bnc,   */  void bgp_nht_register_nexthops(struct bgp *bgp)  { -	struct bgp_dest *dest; -	struct bgp_nexthop_cache *bnc; -	afi_t afi; - -	for (afi = AFI_IP; afi < AFI_MAX; afi++) { -		if (!bgp->nexthop_cache_table[afi]) -			continue; - -		for (dest = bgp_table_top(bgp->nexthop_cache_table[afi]); dest; -		     dest = bgp_route_next(dest)) { -			bnc = bgp_dest_get_bgp_nexthop_info(dest); - -			if (!bnc) -				continue; +	for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) { +		struct bgp_nexthop_cache *bnc; +		frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], +			  bnc) {  			register_zebra_rnh(bnc, 0);  		}  	} @@ -924,7 +897,6 @@ void bgp_nht_register_nexthops(struct bgp *bgp)  void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)  {  	struct bgp *bgp; -	struct bgp_dest *dest;  	struct bgp_nexthop_cache *bnc;  	struct nexthop *nhop;  	struct interface *ifp; @@ -934,10 +906,6 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)  		return;  	bgp = peer->bgp; - -	if (!bgp->nexthop_cache_table[AFI_IP6]) -		return; -  	if (!sockunion2hostprefix(&peer->su, &p)) {  		zlog_warn("%s: Unable to convert sockunion to prefix for %s",  			  __func__, peer->host); @@ -946,11 +914,8 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)  	if (p.family != AF_INET6)  		return; -	dest = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p); -	if (!dest) -		return; -	bnc = bgp_dest_get_bgp_nexthop_info(dest); +	bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);  	if (!bnc)  		return; @@ -973,7 +938,6 @@ void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)  void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)  {  	struct bgp *bgp; -	struct bgp_dest *dest;  	struct bgp_nexthop_cache *bnc;  	struct nexthop *nhop;  	struct interface *ifp; @@ -984,9 +948,6 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)  	bgp = peer->bgp; -	if (!bgp->nexthop_cache_table[AFI_IP6]) -		return; -  	if (!sockunion2hostprefix(&peer->su, &p)) {  		zlog_warn("%s: Unable to convert sockunion to prefix for %s",  			  __func__, peer->host); @@ -996,11 +957,7 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)  	if (p.family != AF_INET6)  		return; -	dest = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p); -	if (!dest) -		return; - -	bnc = bgp_dest_get_bgp_nexthop_info(dest); +	bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);  	if (!bnc)  		return; diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 732c8e6753..6cfcb9cc3d 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -1102,6 +1102,9 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)  		zlog_debug("%s rcv OPEN w/ OPTION parameter len: %u",  			   peer->host, length); +	/* Unset any previously received GR capability. */ +	UNSET_FLAG(peer->cap, PEER_CAP_RESTART_RCV); +  	while (stream_get_getp(s) < end) {  		uint8_t opt_type;  		uint8_t opt_length; diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 0d81403803..15dba37667 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1432,6 +1432,27 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size)  	bgp_update_implicit_eors(peer); +	peer->rtt = sockopt_tcp_rtt(peer->fd); + +	/* If the peer's RTT is higher than expected, shutdown +	 * the peer automatically. +	 */ +	if (CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN) +	    && peer->rtt > peer->rtt_expected) { + +		peer->rtt_keepalive_rcv++; + +		if (peer->rtt_keepalive_rcv > peer->rtt_keepalive_conf) { +			zlog_warn( +				"%s shutdown due to high round-trip-time (%dms > %dms)", +				peer->host, peer->rtt, peer->rtt_expected); +			peer_flag_set(peer, PEER_FLAG_SHUTDOWN); +		} +	} else { +		if (peer->rtt_keepalive_rcv) +			peer->rtt_keepalive_rcv--; +	} +  	return Receive_KEEPALIVE_message;  } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 91acbf6c6d..8eaee36c2e 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3605,6 +3605,12 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,  		goto filtered;  	} +	/* Update Overlay Index */ +	if (afi == AFI_L2VPN) { +		overlay_index_update(&new_attr, +				     evpn == NULL ? NULL : &evpn->gw_ip); +	} +  	attr_new = bgp_attr_intern(&new_attr);  	/* If maximum prefix count is configured and current prefix @@ -3850,12 +3856,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,  			}  		}  #endif -		/* Update Overlay Index */ -		if (afi == AFI_L2VPN) { -			overlay_index_update( -				pi->attr, -				evpn == NULL ? NULL : &evpn->gw_ip); -		}  		/* Update bgp route dampening information.  */  		if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 6d81cfaab4..09cc775d47 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1668,6 +1668,45 @@ static const struct route_map_rule_cmd route_match_tag_cmd = {  	route_map_rule_tag_free,  }; +static enum route_map_cmd_result_t +route_set_srte_color(void *rule, const struct prefix *prefix, +		     route_map_object_t type, void *object) +{ +	uint32_t *srte_color = rule; +	struct bgp_path_info *path; + +	if (type != RMAP_BGP) +		return RMAP_OKAY; + +	path = object; + +	path->attr->srte_color = *srte_color; +	path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR); + +	return RMAP_OKAY; +} + +/* Route map `sr-te color' compile function */ +static void *route_set_srte_color_compile(const char *arg) +{ +	uint32_t *color; + +	color = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t)); +	*color = atoi(arg); + +	return color; +} + +/* Free route map's compiled `sr-te color' value. */ +static void route_set_srte_color_free(void *rule) +{ +	XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for sr-te color set. */ +struct route_map_rule_cmd route_set_srte_color_cmd = { +	"sr-te color", route_set_srte_color, route_set_srte_color_compile, +	route_set_srte_color_free};  /* Set nexthop to object.  ojbect must be pointer to struct attr. */  struct rmap_ip_nexthop_set { @@ -5686,6 +5725,9 @@ void bgp_route_map_init(void)  	route_map_match_tag_hook(generic_match_add);  	route_map_no_match_tag_hook(generic_match_delete); +	route_map_set_srte_color_hook(generic_set_add); +	route_map_no_set_srte_color_hook(generic_set_delete); +  	route_map_set_ip_nexthop_hook(generic_set_add);  	route_map_no_set_ip_nexthop_hook(generic_set_delete); @@ -5728,6 +5770,7 @@ void bgp_route_map_init(void)  	route_map_install_match(&route_match_vrl_source_vrf_cmd);  	route_map_install_set(&route_set_table_id_cmd); +	route_map_install_set(&route_set_srte_color_cmd);  	route_map_install_set(&route_set_ip_nexthop_cmd);  	route_map_install_set(&route_set_local_pref_cmd);  	route_map_install_set(&route_set_weight_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e94a31b685..47c5237aa6 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1642,16 +1642,91 @@ DEFUN (no_bgp_maxmed_onstartup,  	return CMD_SUCCESS;  } -static int bgp_update_delay_config_vty(struct vty *vty, const char *delay, -				       const char *wait) +static int bgp_global_update_delay_config_vty(struct vty *vty, +					      uint16_t update_delay, +					      uint16_t establish_wait) +{ +	struct listnode *node, *nnode; +	struct bgp *bgp; +	bool vrf_cfg = false; + +	/* +	 * See if update-delay is set per-vrf and warn user to delete it +	 * Note that we only need to check this if this is the first time +	 * setting the global config. +	 */ +	if (bm->v_update_delay == BGP_UPDATE_DELAY_DEF) { +		for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { +			if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) { +				vty_out(vty, +					"%% update-delay configuration found in vrf %s\n", +					bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT +						? VRF_DEFAULT_NAME +						: bgp->name); +				vrf_cfg = true; +			} +		} +	} + +	if (vrf_cfg) { +		vty_out(vty, +			"%%Failed: global update-delay config not permitted\n"); +		return CMD_WARNING; +	} + +	if (!establish_wait) { /* update-delay <delay> */ +		bm->v_update_delay = update_delay; +		bm->v_establish_wait = bm->v_update_delay; +	} else { +		/* update-delay <delay> <establish-wait> */ +		if (update_delay < establish_wait) { +			vty_out(vty, +				"%%Failed: update-delay less than the establish-wait!\n"); +			return CMD_WARNING_CONFIG_FAILED; +		} + +		bm->v_update_delay = update_delay; +		bm->v_establish_wait = establish_wait; +	} + +	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { +		bgp->v_update_delay = bm->v_update_delay; +		bgp->v_establish_wait = bm->v_establish_wait; +	} + +	return CMD_SUCCESS; +} + +static int bgp_global_update_delay_deconfig_vty(struct vty *vty) +{ +	struct listnode *node, *nnode; +	struct bgp *bgp; + +	bm->v_update_delay = BGP_UPDATE_DELAY_DEF; +	bm->v_establish_wait = bm->v_update_delay; + +	for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { +		bgp->v_update_delay = bm->v_update_delay; +		bgp->v_establish_wait = bm->v_establish_wait; +	} + +	return CMD_SUCCESS; +} + +static int bgp_update_delay_config_vty(struct vty *vty, uint16_t update_delay, +				       uint16_t establish_wait)  {  	VTY_DECLVAR_CONTEXT(bgp, bgp); -	uint16_t update_delay; -	uint16_t establish_wait; -	update_delay = strtoul(delay, NULL, 10); +	/* if configured globally, per-instance config is not allowed */ +	if (bm->v_update_delay) { +		vty_out(vty, +			"%%Failed: per-vrf update-delay config not permitted with global update-delay\n"); +		return CMD_WARNING_CONFIG_FAILED; +	} + -	if (!wait) /* update-delay <delay> */ +	if (!establish_wait) /* update-delay <delay> */  	{  		bgp->v_update_delay = update_delay;  		bgp->v_establish_wait = bgp->v_update_delay; @@ -1659,7 +1734,6 @@ static int bgp_update_delay_config_vty(struct vty *vty, const char *delay,  	}  	/* update-delay <delay> <establish-wait> */ -	establish_wait = atoi(wait);  	if (update_delay < establish_wait) {  		vty_out(vty,  			"%%Failed: update-delay less than the establish-wait!\n"); @@ -1676,6 +1750,12 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty)  {  	VTY_DECLVAR_CONTEXT(bgp, bgp); +	/* If configured globally, cannot remove from one bgp instance */ +	if (bm->v_update_delay) { +		vty_out(vty, +			"%%Failed: bgp update-delay configured globally. Delete per-vrf not permitted\n"); +		return CMD_WARNING_CONFIG_FAILED; +	}  	bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;  	bgp->v_establish_wait = bgp->v_update_delay; @@ -1684,7 +1764,8 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty)  void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp)  { -	if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) { +	/* If configured globally, no need to display per-instance value */ +	if (bgp->v_update_delay != bm->v_update_delay) {  		vty_out(vty, " update-delay %d", bgp->v_update_delay);  		if (bgp->v_update_delay != bgp->v_establish_wait)  			vty_out(vty, " %d", bgp->v_establish_wait); @@ -1692,39 +1773,51 @@ void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp)  	}  } +/* Global update-delay configuration */ +DEFPY (bgp_global_update_delay, +       bgp_global_update_delay_cmd, +       "bgp update-delay (0-3600)$delay [(1-3600)$wait]", +       BGP_STR +       "Force initial delay for best-path and updates for all bgp instances\n" +       "Max delay in seconds\n" +       "Establish wait in seconds\n") +{ +	return bgp_global_update_delay_config_vty(vty, delay, wait); +} -/* Update-delay configuration */ -DEFUN (bgp_update_delay, -       bgp_update_delay_cmd, -       "update-delay (0-3600)", +/* Global update-delay deconfiguration */ +DEFPY (no_bgp_global_update_delay, +       no_bgp_global_update_delay_cmd, +       "no bgp update-delay [(0-3600) [(1-3600)]]", +       NO_STR +       BGP_STR         "Force initial delay for best-path and updates\n" -       "Seconds\n") +       "Max delay in seconds\n" +       "Establish wait in seconds\n")  { -	int idx_number = 1; -	return bgp_update_delay_config_vty(vty, argv[idx_number]->arg, NULL); +	return bgp_global_update_delay_deconfig_vty(vty);  } -DEFUN (bgp_update_delay_establish_wait, -       bgp_update_delay_establish_wait_cmd, -       "update-delay (0-3600) (1-3600)", +/* Update-delay configuration */ + +DEFPY (bgp_update_delay, +       bgp_update_delay_cmd, +       "update-delay (0-3600)$delay [(1-3600)$wait]",         "Force initial delay for best-path and updates\n" -       "Seconds\n" -       "Seconds\n") +       "Max delay in seconds\n" +       "Establish wait in seconds\n")  { -	int idx_number = 1; -	int idx_number_2 = 2; -	return bgp_update_delay_config_vty(vty, argv[idx_number]->arg, -					   argv[idx_number_2]->arg); +	return bgp_update_delay_config_vty(vty, delay, wait);  }  /* Update-delay deconfiguration */ -DEFUN (no_bgp_update_delay, +DEFPY (no_bgp_update_delay,         no_bgp_update_delay_cmd,         "no update-delay [(0-3600) [(1-3600)]]",         NO_STR         "Force initial delay for best-path and updates\n" -       "Seconds\n" -       "Seconds\n") +       "Max delay in seconds\n" +       "Establish wait in seconds\n")  {  	return bgp_update_delay_deconfig_vty(vty);  } @@ -4480,6 +4573,64 @@ ALIAS(no_neighbor_shutdown_msg, no_neighbor_shutdown_cmd,        NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2        "Administratively shut down this neighbor\n") +DEFUN(neighbor_shutdown_rtt, +      neighbor_shutdown_rtt_cmd, +      "neighbor <A.B.C.D|X:X::X:X|WORD> shutdown rtt (1-65535) [count (1-255)]", +      NEIGHBOR_STR +      NEIGHBOR_ADDR_STR2 +      "Administratively shut down this neighbor\n" +      "Shutdown if round-trip-time is higher than expected\n" +      "Round-trip-time in milliseconds\n" +      "Specify the number of keepalives before shutdown\n" +      "The number of keepalives with higher RTT to shutdown\n") +{ +	int idx_peer = 1; +	int idx_rtt = 4; +	int idx_count = 0; +	struct peer *peer; + +	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); + +	if (!peer) +		return CMD_WARNING_CONFIG_FAILED; + +	peer->rtt_expected = strtol(argv[idx_rtt]->arg, NULL, 10); + +	if (argv_find(argv, argc, "count", &idx_count)) +		peer->rtt_keepalive_conf = +			strtol(argv[idx_count + 1]->arg, NULL, 10); + +	return peer_flag_set_vty(vty, argv[idx_peer]->arg, +				 PEER_FLAG_RTT_SHUTDOWN); +} + +DEFUN(no_neighbor_shutdown_rtt, +      no_neighbor_shutdown_rtt_cmd, +      "no neighbor <A.B.C.D|X:X::X:X|WORD> shutdown rtt [(1-65535) [count (1-255)]]", +      NO_STR +      NEIGHBOR_STR +      NEIGHBOR_ADDR_STR2 +      "Administratively shut down this neighbor\n" +      "Shutdown if round-trip-time is higher than expected\n" +      "Round-trip-time in milliseconds\n" +      "Specify the number of keepalives before shutdown\n" +      "The number of keepalives with higher RTT to shutdown\n") +{ +	int idx_peer = 2; +	struct peer *peer; + +	peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); + +	if (!peer) +		return CMD_WARNING_CONFIG_FAILED; + +	peer->rtt_expected = 0; +	peer->rtt_keepalive_conf = 1; + +	return peer_flag_unset_vty(vty, argv[idx_peer]->arg, +				   PEER_FLAG_RTT_SHUTDOWN); +} +  /* neighbor capability dynamic. */  DEFUN (neighbor_capability_dynamic,         neighbor_capability_dynamic_cmd, @@ -14829,6 +14980,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,  			vty_out(vty, " neighbor %s shutdown\n", addr);  	} +	if (peergroup_flag_check(peer, PEER_FLAG_RTT_SHUTDOWN)) +		vty_out(vty, " neighbor %s shutdown rtt %u count %u\n", addr, +			peer->rtt_expected, peer->rtt_keepalive_conf); +  	/* bfd */  	if (peer->bfd_info) {  		if (!peer_group_active(peer) || !g_peer->bfd_info) { @@ -15367,6 +15522,13 @@ int bgp_config_write(struct vty *vty)  		vty_out(vty, "bgp route-map delay-timer %u\n",  			bm->rmap_update_timer); +	if (bm->v_update_delay != BGP_UPDATE_DELAY_DEF) { +		vty_out(vty, "bgp update-delay %d", bm->v_update_delay); +		if (bm->v_update_delay != bm->v_establish_wait) +			vty_out(vty, " %d", bm->v_establish_wait); +		vty_out(vty, "\n"); +	} +  	/* BGP configuration. */  	for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { @@ -15881,6 +16043,10 @@ void bgp_vty_init(void)  	install_element(CONFIG_NODE, &bgp_set_route_map_delay_timer_cmd);  	install_element(CONFIG_NODE, &no_bgp_set_route_map_delay_timer_cmd); +	/* global bgp update-delay command */ +	install_element(CONFIG_NODE, &bgp_global_update_delay_cmd); +	install_element(CONFIG_NODE, &no_bgp_global_update_delay_cmd); +  	/* Dummy commands (Currently not supported) */  	install_element(BGP_NODE, &no_synchronization_cmd);  	install_element(BGP_NODE, &no_auto_summary_cmd); @@ -15921,7 +16087,6 @@ void bgp_vty_init(void)  	/* bgp update-delay command */  	install_element(BGP_NODE, &bgp_update_delay_cmd);  	install_element(BGP_NODE, &no_bgp_update_delay_cmd); -	install_element(BGP_NODE, &bgp_update_delay_establish_wait_cmd);  	install_element(BGP_NODE, &bgp_wpkt_quanta_cmd);  	install_element(BGP_NODE, &bgp_rpkt_quanta_cmd); @@ -16628,6 +16793,8 @@ void bgp_vty_init(void)  	install_element(BGP_NODE, &no_neighbor_shutdown_cmd);  	install_element(BGP_NODE, &neighbor_shutdown_msg_cmd);  	install_element(BGP_NODE, &no_neighbor_shutdown_msg_cmd); +	install_element(BGP_NODE, &neighbor_shutdown_rtt_cmd); +	install_element(BGP_NODE, &no_neighbor_shutdown_rtt_cmd);  	/* "neighbor capability extended-nexthop" commands.*/  	install_element(BGP_NODE, &neighbor_capability_enhe_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index dba114f86a..15bd6d33b8 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1265,6 +1265,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,  		api.tableid = info->attr->rmap_table_id;  	} +	if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) +		SET_FLAG(api.message, ZAPI_MESSAGE_SRTE); +  	/* Metric is currently based on the best-path only */  	metric = info->attr->med; @@ -1303,6 +1306,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,  				continue;  		}  		api_nh = &api.nexthops[valid_nh_count]; + +		if (CHECK_FLAG(info->attr->flag, +			       ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) +			api_nh->srte_color = info->attr->srte_color; +  		if (nh_family == AF_INET) {  			if (bgp_debug_zebra(&api.prefix)) {  				if (mpinfo->extra) { diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index aade3f0404..b654e85206 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1604,6 +1604,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,  	/* Default TTL set. */  	peer->ttl = (peer->sort == BGP_PEER_IBGP) ? MAXTTL : BGP_DEFAULT_TTL; +	/* Default configured keepalives count for shutdown rtt command */ +	peer->rtt_keepalive_conf = 1; +  	SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);  	if (afi && safi) { @@ -2284,9 +2287,9 @@ int peer_delete(struct peer *peer)  	/* Password configuration */  	if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSWORD)) {  		XFREE(MTYPE_PEER_PASSWORD, peer->password); -  		if (!accept_peer && !BGP_PEER_SU_UNSPEC(peer) -		    && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) +		    && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) +		    && !CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR))  			bgp_md5_unset(peer);  	} @@ -2668,7 +2671,7 @@ int peer_group_listen_range_add(struct peer_group *group, struct prefix *range)  	/* Update passwords for new ranges */  	if (group->conf->password) -		bgp_md5_set_prefix(prefix, group->conf->password); +		bgp_md5_set_prefix(group->bgp, prefix, group->conf->password);  	return 0;  } @@ -2715,7 +2718,7 @@ int peer_group_listen_range_del(struct peer_group *group, struct prefix *range)  	/* Remove passwords for deleted ranges */  	if (group->conf->password) -		bgp_md5_unset_prefix(prefix); +		bgp_md5_unset_prefix(group->bgp, prefix);  	return 0;  } @@ -2966,7 +2969,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,  		bgp->gr_info[afi][safi].route_list = list_new();  	} -	bgp->v_update_delay = BGP_UPDATE_DELAY_DEF; +	bgp->v_update_delay = bm->v_update_delay; +	bgp->v_establish_wait = bm->v_establish_wait;  	bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;  	bgp->default_subgroup_pkt_queue_max =  		BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX; @@ -3865,6 +3869,7 @@ struct peer_flag_action {  static const struct peer_flag_action peer_flag_action_list[] = {  	{PEER_FLAG_PASSIVE, 0, peer_change_reset},  	{PEER_FLAG_SHUTDOWN, 0, peer_change_reset}, +	{PEER_FLAG_RTT_SHUTDOWN, 0, peer_change_none},  	{PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none},  	{PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none},  	{PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none}, @@ -3967,6 +3972,7 @@ static void peer_flag_modify_action(struct peer *peer, uint32_t flag)  				peer_nsf_stop(peer);  			UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); +  			if (peer->t_pmax_restart) {  				BGP_TIMER_OFF(peer->t_pmax_restart);  				if (bgp_debug_neighbor_events(peer)) @@ -5621,9 +5627,9 @@ int peer_password_set(struct peer *peer, const char *password)  	struct prefix *lr;  	for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP], ln, lr)) -		bgp_md5_set_prefix(lr, password); +		bgp_md5_set_prefix(peer->bgp, lr, password);  	for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP6], ln, lr)) -		bgp_md5_set_prefix(lr, password); +		bgp_md5_set_prefix(peer->bgp, lr, password);  	return ret;  } @@ -5659,7 +5665,6 @@ int peer_password_unset(struct peer *peer)  		/* Attempt to uninstall password on socket. */  		if (!BGP_PEER_SU_UNSPEC(peer))  			bgp_md5_unset(peer); -  		/* Skip peer-group mechanics for regular peers. */  		return 0;  	} @@ -5694,9 +5699,9 @@ int peer_password_unset(struct peer *peer)  	struct prefix *lr;  	for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP], ln, lr)) -		bgp_md5_unset_prefix(lr); +		bgp_md5_unset_prefix(peer->bgp, lr);  	for (ALL_LIST_ELEMENTS_RO(peer->group->listen_range[AFI_IP6], ln, lr)) -		bgp_md5_unset_prefix(lr); +		bgp_md5_unset_prefix(peer->bgp, lr);  	return 0;  } @@ -7001,6 +7006,8 @@ void bgp_master_init(struct thread_master *master, const int buffer_size)  	bm->start_time = bgp_clock();  	bm->t_rmap_update = NULL;  	bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER; +	bm->v_update_delay = BGP_UPDATE_DELAY_DEF; +	bm->v_establish_wait = BGP_UPDATE_DELAY_DEF;  	bm->terminating = false;  	bm->socket_buffer = buffer_size; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 6fc3f08836..2aa0690025 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -42,6 +42,7 @@  #include "vxlan.h"  #include "bgp_labelpool.h"  #include "bgp_addpath_types.h" +#include "bgp_nexthop.h"  #define BGP_MAX_HOSTNAME 64	/* Linux max, is larger than most other sys */  #define BGP_PEER_MAX_HASH_SIZE 16384 @@ -168,6 +169,10 @@ struct bgp_master {  	/* EVPN multihoming */  	struct bgp_evpn_mh_info *mh_info; +	/* global update-delay timer values */ +	uint16_t v_update_delay; +	uint16_t v_establish_wait; +  	bool terminating;	/* global flag that sigint terminate seen */  	QOBJ_FIELDS  }; @@ -482,11 +487,11 @@ struct bgp {  	/* BGP per AF peer count */  	uint32_t af_peer_count[AFI_MAX][SAFI_MAX]; -	/* Route table for next-hop lookup cache. */ -	struct bgp_table *nexthop_cache_table[AFI_MAX]; +	/* Tree for next-hop lookup cache. */ +	struct bgp_nexthop_cache_head nexthop_cache_table[AFI_MAX]; -	/* Route table for import-check */ -	struct bgp_table *import_check_table[AFI_MAX]; +	/* Tree for import-check */ +	struct bgp_nexthop_cache_head import_check_table[AFI_MAX];  	struct bgp_table *connected_table[AFI_MAX]; @@ -967,6 +972,9 @@ struct peer {  	int fd;		     /* File descriptor */  	int ttl;	     /* TTL of TCP connection to the peer. */  	int rtt;	     /* Estimated round-trip-time from TCP_INFO */ +	int rtt_expected; /* Expected round-trip-time for a peer */ +	uint8_t rtt_keepalive_rcv; /* Received count for RTT shutdown */ +	uint8_t rtt_keepalive_conf; /* Configured count for RTT shutdown */  	int gtsm_hops;       /* minimum hopcount to peer */  	char *desc;	  /* Description of the peer. */  	unsigned short port; /* Destination port for peer */ @@ -996,41 +1004,41 @@ struct peer {  	/* Capability flags (reset in bgp_stop) */  	uint32_t cap; -#define PEER_CAP_REFRESH_ADV                (1 << 0) /* refresh advertised */ -#define PEER_CAP_REFRESH_OLD_RCV            (1 << 1) /* refresh old received */ -#define PEER_CAP_REFRESH_NEW_RCV            (1 << 2) /* refresh rfc received */ -#define PEER_CAP_DYNAMIC_ADV                (1 << 3) /* dynamic advertised */ -#define PEER_CAP_DYNAMIC_RCV                (1 << 4) /* dynamic received */ -#define PEER_CAP_RESTART_ADV                (1 << 5) /* restart advertised */ -#define PEER_CAP_RESTART_RCV                (1 << 6) /* restart received */ -#define PEER_CAP_AS4_ADV                    (1 << 7) /* as4 advertised */ -#define PEER_CAP_AS4_RCV                    (1 << 8) /* as4 received */ -#define PEER_CAP_RESTART_BIT_ADV            (1 << 9) /* sent restart state */ -#define PEER_CAP_RESTART_BIT_RCV            (1 << 10) /* peer restart state */ -#define PEER_CAP_ADDPATH_ADV                (1 << 11) /* addpath advertised */ -#define PEER_CAP_ADDPATH_RCV                (1 << 12) /* addpath received */ -#define PEER_CAP_ENHE_ADV                   (1 << 13) /* Extended nexthop advertised */ -#define PEER_CAP_ENHE_RCV                   (1 << 14) /* Extended nexthop received */ -#define PEER_CAP_HOSTNAME_ADV               (1 << 15) /* hostname advertised */ -#define PEER_CAP_HOSTNAME_RCV               (1 << 16) /* hostname received */ +#define PEER_CAP_REFRESH_ADV                (1U << 0) /* refresh advertised */ +#define PEER_CAP_REFRESH_OLD_RCV            (1U << 1) /* refresh old received */ +#define PEER_CAP_REFRESH_NEW_RCV            (1U << 2) /* refresh rfc received */ +#define PEER_CAP_DYNAMIC_ADV                (1U << 3) /* dynamic advertised */ +#define PEER_CAP_DYNAMIC_RCV                (1U << 4) /* dynamic received */ +#define PEER_CAP_RESTART_ADV                (1U << 5) /* restart advertised */ +#define PEER_CAP_RESTART_RCV                (1U << 6) /* restart received */ +#define PEER_CAP_AS4_ADV                    (1U << 7) /* as4 advertised */ +#define PEER_CAP_AS4_RCV                    (1U << 8) /* as4 received */ +#define PEER_CAP_RESTART_BIT_ADV            (1U << 9) /* sent restart state */ +#define PEER_CAP_RESTART_BIT_RCV            (1U << 10) /* peer restart state */ +#define PEER_CAP_ADDPATH_ADV                (1U << 11) /* addpath advertised */ +#define PEER_CAP_ADDPATH_RCV                (1U << 12) /* addpath received */ +#define PEER_CAP_ENHE_ADV                   (1U << 13) /* Extended nexthop advertised */ +#define PEER_CAP_ENHE_RCV                   (1U << 14) /* Extended nexthop received */ +#define PEER_CAP_HOSTNAME_ADV               (1U << 15) /* hostname advertised */ +#define PEER_CAP_HOSTNAME_RCV               (1U << 16) /* hostname received */  	/* Capability flags (reset in bgp_stop) */  	uint32_t af_cap[AFI_MAX][SAFI_MAX]; -#define PEER_CAP_ORF_PREFIX_SM_ADV          (1 << 0) /* send-mode advertised */ -#define PEER_CAP_ORF_PREFIX_RM_ADV          (1 << 1) /* receive-mode advertised */ -#define PEER_CAP_ORF_PREFIX_SM_RCV          (1 << 2) /* send-mode received */ -#define PEER_CAP_ORF_PREFIX_RM_RCV          (1 << 3) /* receive-mode received */ -#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV      (1 << 4) /* send-mode received */ -#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV      (1 << 5) /* receive-mode received */ -#define PEER_CAP_RESTART_AF_RCV             (1 << 6) /* graceful restart afi/safi received */ -#define PEER_CAP_RESTART_AF_PRESERVE_RCV    (1 << 7) /* graceful restart afi/safi F-bit received */ -#define PEER_CAP_ADDPATH_AF_TX_ADV          (1 << 8) /* addpath tx advertised */ -#define PEER_CAP_ADDPATH_AF_TX_RCV          (1 << 9) /* addpath tx received */ -#define PEER_CAP_ADDPATH_AF_RX_ADV          (1 << 10) /* addpath rx advertised */ -#define PEER_CAP_ADDPATH_AF_RX_RCV          (1 << 11) /* addpath rx received */ -#define PEER_CAP_ENHE_AF_ADV                (1 << 12) /* Extended nexthopi afi/safi advertised */ -#define PEER_CAP_ENHE_AF_RCV                (1 << 13) /* Extended nexthop afi/safi received */ -#define PEER_CAP_ENHE_AF_NEGO               (1 << 14) /* Extended nexthop afi/safi negotiated */ +#define PEER_CAP_ORF_PREFIX_SM_ADV          (1U << 0) /* send-mode advertised */ +#define PEER_CAP_ORF_PREFIX_RM_ADV          (1U << 1) /* receive-mode advertised */ +#define PEER_CAP_ORF_PREFIX_SM_RCV          (1U << 2) /* send-mode received */ +#define PEER_CAP_ORF_PREFIX_RM_RCV          (1U << 3) /* receive-mode received */ +#define PEER_CAP_ORF_PREFIX_SM_OLD_RCV      (1U << 4) /* send-mode received */ +#define PEER_CAP_ORF_PREFIX_RM_OLD_RCV      (1U << 5) /* receive-mode received */ +#define PEER_CAP_RESTART_AF_RCV             (1U << 6) /* graceful restart afi/safi received */ +#define PEER_CAP_RESTART_AF_PRESERVE_RCV    (1U << 7) /* graceful restart afi/safi F-bit received */ +#define PEER_CAP_ADDPATH_AF_TX_ADV          (1U << 8) /* addpath tx advertised */ +#define PEER_CAP_ADDPATH_AF_TX_RCV          (1U << 9) /* addpath tx received */ +#define PEER_CAP_ADDPATH_AF_RX_ADV          (1U << 10) /* addpath rx advertised */ +#define PEER_CAP_ADDPATH_AF_RX_RCV          (1U << 11) /* addpath rx received */ +#define PEER_CAP_ENHE_AF_ADV                (1U << 12) /* Extended nexthopi afi/safi advertised */ +#define PEER_CAP_ENHE_AF_RCV                (1U << 13) /* Extended nexthop afi/safi received */ +#define PEER_CAP_ENHE_AF_NEGO               (1U << 14) /* Extended nexthop afi/safi negotiated */  	/* Global configuration flags. */  	/* @@ -1089,34 +1097,35 @@ struct peer {  	 * flags_invert) must be respected.  	 */  	uint32_t flags; -#define PEER_FLAG_PASSIVE                   (1 << 0) /* passive mode */ -#define PEER_FLAG_SHUTDOWN                  (1 << 1) /* shutdown */ -#define PEER_FLAG_DONT_CAPABILITY           (1 << 2) /* dont-capability */ -#define PEER_FLAG_OVERRIDE_CAPABILITY       (1 << 3) /* override-capability */ -#define PEER_FLAG_STRICT_CAP_MATCH          (1 << 4) /* strict-match */ -#define PEER_FLAG_DYNAMIC_CAPABILITY        (1 << 5) /* dynamic capability */ -#define PEER_FLAG_DISABLE_CONNECTED_CHECK   (1 << 6) /* disable-connected-check */ -#define PEER_FLAG_LOCAL_AS_NO_PREPEND       (1 << 7) /* local-as no-prepend */ -#define PEER_FLAG_LOCAL_AS_REPLACE_AS       (1 << 8) /* local-as no-prepend replace-as */ -#define PEER_FLAG_DELETE                    (1 << 9) /* mark the peer for deleting */ -#define PEER_FLAG_CONFIG_NODE               (1 << 10) /* the node to update configs on */ -#define PEER_FLAG_LONESOUL                  (1 << 11) -#define PEER_FLAG_DYNAMIC_NEIGHBOR          (1 << 12) /* dynamic neighbor */ -#define PEER_FLAG_CAPABILITY_ENHE           (1 << 13) /* Extended next-hop (rfc 5549)*/ -#define PEER_FLAG_IFPEER_V6ONLY             (1 << 14) /* if-based peer is v6 only */ -#define PEER_FLAG_IS_RFAPI_HD               (1 << 15) /* attached to rfapi HD */ -#define PEER_FLAG_ENFORCE_FIRST_AS          (1 << 16) /* enforce-first-as */ -#define PEER_FLAG_ROUTEADV                  (1 << 17) /* route advertise */ -#define PEER_FLAG_TIMER                     (1 << 18) /* keepalive & holdtime */ -#define PEER_FLAG_TIMER_CONNECT             (1 << 19) /* connect timer */ -#define PEER_FLAG_PASSWORD                  (1 << 20) /* password */ -#define PEER_FLAG_LOCAL_AS                  (1 << 21) /* local-as */ -#define PEER_FLAG_UPDATE_SOURCE             (1 << 22) /* update-source */ +#define PEER_FLAG_PASSIVE                   (1U << 0) /* passive mode */ +#define PEER_FLAG_SHUTDOWN                  (1U << 1) /* shutdown */ +#define PEER_FLAG_DONT_CAPABILITY           (1U << 2) /* dont-capability */ +#define PEER_FLAG_OVERRIDE_CAPABILITY       (1U << 3) /* override-capability */ +#define PEER_FLAG_STRICT_CAP_MATCH          (1U << 4) /* strict-match */ +#define PEER_FLAG_DYNAMIC_CAPABILITY        (1U << 5) /* dynamic capability */ +#define PEER_FLAG_DISABLE_CONNECTED_CHECK   (1U << 6) /* disable-connected-check */ +#define PEER_FLAG_LOCAL_AS_NO_PREPEND       (1U << 7) /* local-as no-prepend */ +#define PEER_FLAG_LOCAL_AS_REPLACE_AS       (1U << 8) /* local-as no-prepend replace-as */ +#define PEER_FLAG_DELETE                    (1U << 9) /* mark the peer for deleting */ +#define PEER_FLAG_CONFIG_NODE               (1U << 10) /* the node to update configs on */ +#define PEER_FLAG_LONESOUL                  (1U << 11) +#define PEER_FLAG_DYNAMIC_NEIGHBOR          (1U << 12) /* dynamic neighbor */ +#define PEER_FLAG_CAPABILITY_ENHE           (1U << 13) /* Extended next-hop (rfc 5549)*/ +#define PEER_FLAG_IFPEER_V6ONLY             (1U << 14) /* if-based peer is v6 only */ +#define PEER_FLAG_IS_RFAPI_HD               (1U << 15) /* attached to rfapi HD */ +#define PEER_FLAG_ENFORCE_FIRST_AS          (1U << 16) /* enforce-first-as */ +#define PEER_FLAG_ROUTEADV                  (1U << 17) /* route advertise */ +#define PEER_FLAG_TIMER                     (1U << 18) /* keepalive & holdtime */ +#define PEER_FLAG_TIMER_CONNECT             (1U << 19) /* connect timer */ +#define PEER_FLAG_PASSWORD                  (1U << 20) /* password */ +#define PEER_FLAG_LOCAL_AS                  (1U << 21) /* local-as */ +#define PEER_FLAG_UPDATE_SOURCE             (1U << 22) /* update-source */  	/* BGP-GR Peer related  flags */ -#define PEER_FLAG_GRACEFUL_RESTART_HELPER   (1 << 23) /* Helper */ -#define PEER_FLAG_GRACEFUL_RESTART          (1 << 24) /* Graceful Restart */ -#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1 << 25) /* Global-Inherit */ +#define PEER_FLAG_GRACEFUL_RESTART_HELPER   (1U << 23) /* Helper */ +#define PEER_FLAG_GRACEFUL_RESTART          (1U << 24) /* Graceful Restart */ +#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1U << 25) /* Global-Inherit */ +#define PEER_FLAG_RTT_SHUTDOWN (1U << 26) /* shutdown rtt */  	/*  	 *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART @@ -1130,9 +1139,9 @@ struct peer {  	uint8_t nsf_af_count;  	uint8_t peer_gr_new_status_flag; -#define PEER_GRACEFUL_RESTART_NEW_STATE_HELPER   (1 << 0) -#define PEER_GRACEFUL_RESTART_NEW_STATE_RESTART  (1 << 1) -#define PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT  (1 << 2) +#define PEER_GRACEFUL_RESTART_NEW_STATE_HELPER   (1U << 0) +#define PEER_GRACEFUL_RESTART_NEW_STATE_RESTART  (1U << 1) +#define PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT  (1U << 2)  	/* outgoing message sent in CEASE_ADMIN_SHUTDOWN notify */  	char *tx_shutdown_message; @@ -1154,33 +1163,33 @@ struct peer {  	uint32_t af_flags_override[AFI_MAX][SAFI_MAX];  	uint32_t af_flags_invert[AFI_MAX][SAFI_MAX];  	uint32_t af_flags[AFI_MAX][SAFI_MAX]; -#define PEER_FLAG_SEND_COMMUNITY            (1 << 0) /* send-community */ -#define PEER_FLAG_SEND_EXT_COMMUNITY        (1 << 1) /* send-community ext. */ -#define PEER_FLAG_NEXTHOP_SELF              (1 << 2) /* next-hop-self */ -#define PEER_FLAG_REFLECTOR_CLIENT          (1 << 3) /* reflector-client */ -#define PEER_FLAG_RSERVER_CLIENT            (1 << 4) /* route-server-client */ -#define PEER_FLAG_SOFT_RECONFIG             (1 << 5) /* soft-reconfiguration */ -#define PEER_FLAG_AS_PATH_UNCHANGED         (1 << 6) /* transparent-as */ -#define PEER_FLAG_NEXTHOP_UNCHANGED         (1 << 7) /* transparent-next-hop */ -#define PEER_FLAG_MED_UNCHANGED             (1 << 8) /* transparent-next-hop */ -#define PEER_FLAG_DEFAULT_ORIGINATE         (1 << 9) /* default-originate */ -#define PEER_FLAG_REMOVE_PRIVATE_AS         (1 << 10) /* remove-private-as */ -#define PEER_FLAG_ALLOWAS_IN                (1 << 11) /* set allowas-in */ -#define PEER_FLAG_ORF_PREFIX_SM             (1 << 12) /* orf capability send-mode */ -#define PEER_FLAG_ORF_PREFIX_RM             (1 << 13) /* orf capability receive-mode */ -#define PEER_FLAG_MAX_PREFIX                (1 << 14) /* maximum prefix */ -#define PEER_FLAG_MAX_PREFIX_WARNING        (1 << 15) /* maximum prefix warning-only */ -#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED   (1 << 16) /* leave link-local nexthop unchanged */ -#define PEER_FLAG_FORCE_NEXTHOP_SELF        (1 << 17) /* next-hop-self force */ -#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL     (1 << 18) /* remove-private-as all */ -#define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1 << 19) /* remove-private-as replace-as */ -#define PEER_FLAG_AS_OVERRIDE               (1 << 20) /* as-override */ -#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE (1 << 21) /* remove-private-as all replace-as */ -#define PEER_FLAG_WEIGHT                    (1 << 24) /* weight */ -#define PEER_FLAG_ALLOWAS_IN_ORIGIN         (1 << 25) /* allowas-in origin */ -#define PEER_FLAG_SEND_LARGE_COMMUNITY      (1 << 26) /* Send large Communities */ -#define PEER_FLAG_MAX_PREFIX_OUT            (1 << 27) /* outgoing maximum prefix */ -#define PEER_FLAG_MAX_PREFIX_FORCE          (1 << 28) /* maximum-prefix <num> force */ +#define PEER_FLAG_SEND_COMMUNITY            (1U << 0) /* send-community */ +#define PEER_FLAG_SEND_EXT_COMMUNITY        (1U << 1) /* send-community ext. */ +#define PEER_FLAG_NEXTHOP_SELF              (1U << 2) /* next-hop-self */ +#define PEER_FLAG_REFLECTOR_CLIENT          (1U << 3) /* reflector-client */ +#define PEER_FLAG_RSERVER_CLIENT            (1U << 4) /* route-server-client */ +#define PEER_FLAG_SOFT_RECONFIG             (1U << 5) /* soft-reconfiguration */ +#define PEER_FLAG_AS_PATH_UNCHANGED         (1U << 6) /* transparent-as */ +#define PEER_FLAG_NEXTHOP_UNCHANGED         (1U << 7) /* transparent-next-hop */ +#define PEER_FLAG_MED_UNCHANGED             (1U << 8) /* transparent-next-hop */ +#define PEER_FLAG_DEFAULT_ORIGINATE         (1U << 9) /* default-originate */ +#define PEER_FLAG_REMOVE_PRIVATE_AS         (1U << 10) /* remove-private-as */ +#define PEER_FLAG_ALLOWAS_IN                (1U << 11) /* set allowas-in */ +#define PEER_FLAG_ORF_PREFIX_SM             (1U << 12) /* orf capability send-mode */ +#define PEER_FLAG_ORF_PREFIX_RM             (1U << 13) /* orf capability receive-mode */ +#define PEER_FLAG_MAX_PREFIX                (1U << 14) /* maximum prefix */ +#define PEER_FLAG_MAX_PREFIX_WARNING        (1U << 15) /* maximum prefix warning-only */ +#define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED   (1U << 16) /* leave link-local nexthop unchanged */ +#define PEER_FLAG_FORCE_NEXTHOP_SELF        (1U << 17) /* next-hop-self force */ +#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL     (1U << 18) /* remove-private-as all */ +#define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1U << 19) /* remove-private-as replace-as */ +#define PEER_FLAG_AS_OVERRIDE               (1U << 20) /* as-override */ +#define PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE (1U << 21) /* remove-private-as all replace-as */ +#define PEER_FLAG_WEIGHT                    (1U << 24) /* weight */ +#define PEER_FLAG_ALLOWAS_IN_ORIGIN         (1U << 25) /* allowas-in origin */ +#define PEER_FLAG_SEND_LARGE_COMMUNITY      (1U << 26) /* Send large Communities */ +#define PEER_FLAG_MAX_PREFIX_OUT            (1U << 27) /* outgoing maximum prefix */ +#define PEER_FLAG_MAX_PREFIX_FORCE          (1U << 28) /* maximum-prefix <num> force */  	enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX]; @@ -1195,22 +1204,22 @@ struct peer {  	/* Peer status flags. */  	uint16_t sflags; -#define PEER_STATUS_ACCEPT_PEER	      (1 << 0) /* accept peer */ -#define PEER_STATUS_PREFIX_OVERFLOW   (1 << 1) /* prefix-overflow */ -#define PEER_STATUS_CAPABILITY_OPEN   (1 << 2) /* capability open send */ -#define PEER_STATUS_HAVE_ACCEPT       (1 << 3) /* accept peer's parent */ -#define PEER_STATUS_GROUP             (1 << 4) /* peer-group conf */ -#define PEER_STATUS_NSF_MODE          (1 << 5) /* NSF aware peer */ -#define PEER_STATUS_NSF_WAIT          (1 << 6) /* wait comeback peer */ +#define PEER_STATUS_ACCEPT_PEER	      (1U << 0) /* accept peer */ +#define PEER_STATUS_PREFIX_OVERFLOW   (1U << 1) /* prefix-overflow */ +#define PEER_STATUS_CAPABILITY_OPEN   (1U << 2) /* capability open send */ +#define PEER_STATUS_HAVE_ACCEPT       (1U << 3) /* accept peer's parent */ +#define PEER_STATUS_GROUP             (1U << 4) /* peer-group conf */ +#define PEER_STATUS_NSF_MODE          (1U << 5) /* NSF aware peer */ +#define PEER_STATUS_NSF_WAIT          (1U << 6) /* wait comeback peer */  	/* Peer status af flags (reset in bgp_stop) */  	uint16_t af_sflags[AFI_MAX][SAFI_MAX]; -#define PEER_STATUS_ORF_PREFIX_SEND   (1 << 0) /* prefix-list send peer */ -#define PEER_STATUS_ORF_WAIT_REFRESH  (1 << 1) /* wait refresh received peer */ -#define PEER_STATUS_PREFIX_THRESHOLD  (1 << 2) /* exceed prefix-threshold */ -#define PEER_STATUS_PREFIX_LIMIT      (1 << 3) /* exceed prefix-limit */ -#define PEER_STATUS_EOR_SEND          (1 << 4) /* end-of-rib send to peer */ -#define PEER_STATUS_EOR_RECEIVED      (1 << 5) /* end-of-rib received from peer */ +#define PEER_STATUS_ORF_PREFIX_SEND   (1U << 0) /* prefix-list send peer */ +#define PEER_STATUS_ORF_WAIT_REFRESH  (1U << 1) /* wait refresh received peer */ +#define PEER_STATUS_PREFIX_THRESHOLD  (1U << 2) /* exceed prefix-threshold */ +#define PEER_STATUS_PREFIX_LIMIT      (1U << 3) /* exceed prefix-limit */ +#define PEER_STATUS_EOR_SEND          (1U << 4) /* end-of-rib send to peer */ +#define PEER_STATUS_EOR_RECEIVED      (1U << 5) /* end-of-rib received from peer */  	/* Configured timer values. */  	_Atomic uint32_t holdtime; @@ -1244,9 +1253,9 @@ struct peer {  	/* Thread flags. */  	_Atomic uint32_t thread_flags; -#define PEER_THREAD_WRITES_ON         (1 << 0) -#define PEER_THREAD_READS_ON          (1 << 1) -#define PEER_THREAD_KEEPALIVES_ON     (1 << 2) +#define PEER_THREAD_WRITES_ON         (1U << 0) +#define PEER_THREAD_READS_ON          (1U << 1) +#define PEER_THREAD_KEEPALIVES_ON     (1U << 2)  	/* workqueues */  	struct work_queue *clear_node_queue; @@ -1337,11 +1346,11 @@ struct peer {  	 *   whether the filter in filter (struct bgp_filter) is peer-specific.  	 */  	uint8_t filter_override[AFI_MAX][SAFI_MAX][FILTER_MAX]; -#define PEER_FT_DISTRIBUTE_LIST       (1 << 0) /* distribute-list */ -#define PEER_FT_FILTER_LIST           (1 << 1) /* filter-list */ -#define PEER_FT_PREFIX_LIST           (1 << 2) /* prefix-list */ -#define PEER_FT_ROUTE_MAP             (1 << 3) /* route-map */ -#define PEER_FT_UNSUPPRESS_MAP        (1 << 4) /* unsuppress-map */ +#define PEER_FT_DISTRIBUTE_LIST       (1U << 0) /* distribute-list */ +#define PEER_FT_FILTER_LIST           (1U << 1) /* filter-list */ +#define PEER_FT_PREFIX_LIST           (1U << 2) /* prefix-list */ +#define PEER_FT_ROUTE_MAP             (1U << 3) /* route-map */ +#define PEER_FT_UNSUPPRESS_MAP        (1U << 4) /* unsuppress-map */  	/* ORF Prefix-list */  	struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX]; @@ -1372,39 +1381,39 @@ struct peer {  	/* peer reset cause */  	uint8_t last_reset; -#define PEER_DOWN_RID_CHANGE             1 /* bgp router-id command */ -#define PEER_DOWN_REMOTE_AS_CHANGE       2 /* neighbor remote-as command */ -#define PEER_DOWN_LOCAL_AS_CHANGE        3 /* neighbor local-as command */ -#define PEER_DOWN_CLID_CHANGE            4 /* bgp cluster-id command */ -#define PEER_DOWN_CONFED_ID_CHANGE       5 /* bgp confederation id command */ -#define PEER_DOWN_CONFED_PEER_CHANGE     6 /* bgp confederation peer command */ -#define PEER_DOWN_RR_CLIENT_CHANGE       7 /* neighbor rr-client command */ -#define PEER_DOWN_RS_CLIENT_CHANGE       8 /* neighbor rs-client command */ -#define PEER_DOWN_UPDATE_SOURCE_CHANGE   9 /* neighbor update-source command */ -#define PEER_DOWN_AF_ACTIVATE           10 /* neighbor activate command */ -#define PEER_DOWN_USER_SHUTDOWN         11 /* neighbor shutdown command */ -#define PEER_DOWN_USER_RESET            12 /* clear ip bgp command */ -#define PEER_DOWN_NOTIFY_RECEIVED       13 /* notification received */ -#define PEER_DOWN_NOTIFY_SEND           14 /* notification send */ -#define PEER_DOWN_CLOSE_SESSION         15 /* tcp session close */ -#define PEER_DOWN_NEIGHBOR_DELETE       16 /* neghbor delete */ -#define PEER_DOWN_RMAP_BIND             17 /* neghbor peer-group command */ -#define PEER_DOWN_RMAP_UNBIND           18 /* no neighbor peer-group command */ -#define PEER_DOWN_CAPABILITY_CHANGE     19 /* neighbor capability command */ -#define PEER_DOWN_PASSIVE_CHANGE        20 /* neighbor passive command */ -#define PEER_DOWN_MULTIHOP_CHANGE       21 /* neighbor multihop command */ -#define PEER_DOWN_NSF_CLOSE_SESSION     22 /* NSF tcp session close */ -#define PEER_DOWN_V6ONLY_CHANGE         23 /* if-based peering v6only toggled */ -#define PEER_DOWN_BFD_DOWN              24 /* BFD down */ -#define PEER_DOWN_IF_DOWN               25 /* Interface down */ -#define PEER_DOWN_NBR_ADDR_DEL          26 /* Peer address lost */ -#define PEER_DOWN_WAITING_NHT           27 /* Waiting for NHT to resolve */ -#define PEER_DOWN_NBR_ADDR              28 /* Waiting for peer IPv6 IP Addr */ -#define PEER_DOWN_VRF_UNINIT            29 /* Associated VRF is not init yet */ -#define PEER_DOWN_NOAFI_ACTIVATED       30 /* No AFI/SAFI activated for peer */ -#define PEER_DOWN_AS_SETS_REJECT        31 /* Reject routes with AS_SET */ -#define PEER_DOWN_WAITING_OPEN          32 /* Waiting for open to succeed */ -#define PEER_DOWN_PFX_COUNT             33 /* Reached received prefix count */ +#define PEER_DOWN_RID_CHANGE             1U /* bgp router-id command */ +#define PEER_DOWN_REMOTE_AS_CHANGE       2U /* neighbor remote-as command */ +#define PEER_DOWN_LOCAL_AS_CHANGE        3U /* neighbor local-as command */ +#define PEER_DOWN_CLID_CHANGE            4U /* bgp cluster-id command */ +#define PEER_DOWN_CONFED_ID_CHANGE       5U /* bgp confederation id command */ +#define PEER_DOWN_CONFED_PEER_CHANGE     6U /* bgp confederation peer command */ +#define PEER_DOWN_RR_CLIENT_CHANGE       7U /* neighbor rr-client command */ +#define PEER_DOWN_RS_CLIENT_CHANGE       8U /* neighbor rs-client command */ +#define PEER_DOWN_UPDATE_SOURCE_CHANGE   9U /* neighbor update-source command */ +#define PEER_DOWN_AF_ACTIVATE           10U /* neighbor activate command */ +#define PEER_DOWN_USER_SHUTDOWN         11U /* neighbor shutdown command */ +#define PEER_DOWN_USER_RESET            12U /* clear ip bgp command */ +#define PEER_DOWN_NOTIFY_RECEIVED       13U /* notification received */ +#define PEER_DOWN_NOTIFY_SEND           14U /* notification send */ +#define PEER_DOWN_CLOSE_SESSION         15U /* tcp session close */ +#define PEER_DOWN_NEIGHBOR_DELETE       16U /* neghbor delete */ +#define PEER_DOWN_RMAP_BIND             17U /* neghbor peer-group command */ +#define PEER_DOWN_RMAP_UNBIND           18U /* no neighbor peer-group command */ +#define PEER_DOWN_CAPABILITY_CHANGE     19U /* neighbor capability command */ +#define PEER_DOWN_PASSIVE_CHANGE        20U /* neighbor passive command */ +#define PEER_DOWN_MULTIHOP_CHANGE       21U /* neighbor multihop command */ +#define PEER_DOWN_NSF_CLOSE_SESSION     22U /* NSF tcp session close */ +#define PEER_DOWN_V6ONLY_CHANGE         23U /* if-based peering v6only toggled */ +#define PEER_DOWN_BFD_DOWN              24U /* BFD down */ +#define PEER_DOWN_IF_DOWN               25U /* Interface down */ +#define PEER_DOWN_NBR_ADDR_DEL          26U /* Peer address lost */ +#define PEER_DOWN_WAITING_NHT           27U /* Waiting for NHT to resolve */ +#define PEER_DOWN_NBR_ADDR              28U /* Waiting for peer IPv6 IP Addr */ +#define PEER_DOWN_VRF_UNINIT            29U /* Associated VRF is not init yet */ +#define PEER_DOWN_NOAFI_ACTIVATED       30U /* No AFI/SAFI activated for peer */ +#define PEER_DOWN_AS_SETS_REJECT        31U /* Reject routes with AS_SET */ +#define PEER_DOWN_WAITING_OPEN          32U /* Waiting for open to succeed */ +#define PEER_DOWN_PFX_COUNT             33U /* Reached received prefix count */  	/*  	 * Remember to update peer_down_str in bgp_fsm.c when you add  	 * a new value to the last_reset reason @@ -1415,15 +1424,15 @@ struct peer {  	/* The kind of route-map Flags.*/  	uint16_t rmap_type; -#define PEER_RMAP_TYPE_IN             (1 << 0) /* neighbor route-map in */ -#define PEER_RMAP_TYPE_OUT            (1 << 1) /* neighbor route-map out */ -#define PEER_RMAP_TYPE_NETWORK        (1 << 2) /* network route-map */ -#define PEER_RMAP_TYPE_REDISTRIBUTE   (1 << 3) /* redistribute route-map */ -#define PEER_RMAP_TYPE_DEFAULT        (1 << 4) /* default-originate route-map */ -#define PEER_RMAP_TYPE_NOSET          (1 << 5) /* not allow to set commands */ -#define PEER_RMAP_TYPE_IMPORT         (1 << 6) /* neighbor route-map import */ -#define PEER_RMAP_TYPE_EXPORT         (1 << 7) /* neighbor route-map export */ -#define PEER_RMAP_TYPE_AGGREGATE      (1 << 8) /* aggregate-address route-map */ +#define PEER_RMAP_TYPE_IN             (1U << 0) /* neighbor route-map in */ +#define PEER_RMAP_TYPE_OUT            (1U << 1) /* neighbor route-map out */ +#define PEER_RMAP_TYPE_NETWORK        (1U << 2) /* network route-map */ +#define PEER_RMAP_TYPE_REDISTRIBUTE   (1U << 3) /* redistribute route-map */ +#define PEER_RMAP_TYPE_DEFAULT        (1U << 4) /* default-originate route-map */ +#define PEER_RMAP_TYPE_NOSET          (1U << 5) /* not allow to set commands */ +#define PEER_RMAP_TYPE_IMPORT         (1U << 6) /* neighbor route-map import */ +#define PEER_RMAP_TYPE_EXPORT         (1U << 7) /* neighbor route-map export */ +#define PEER_RMAP_TYPE_AGGREGATE      (1U << 8) /* aggregate-address route-map */  	/* peer specific BFD information */  	struct bfd_info *bfd_info; @@ -1537,6 +1546,7 @@ struct bgp_nlri {  #define BGP_ATTR_IPV6_EXT_COMMUNITIES           25  #define BGP_ATTR_LARGE_COMMUNITIES              32  #define BGP_ATTR_PREFIX_SID                     40 +#define BGP_ATTR_SRTE_COLOR                     51  #ifdef ENABLE_BGP_VNC_ATTR  #define BGP_ATTR_VNC                           255  #endif diff --git a/configure.ac b/configure.ac index ae116ef754..715efbcdae 100755 --- a/configure.ac +++ b/configure.ac @@ -1728,8 +1728,8 @@ AC_SUBST([SNMP_CFLAGS])  dnl ---------------  dnl libyang  dnl --------------- -PKG_CHECK_MODULES([LIBYANG], [libyang >= 0.16.105], , [ -  AC_MSG_ERROR([libyang (>= 0.16.105) was not found on your system.]) +PKG_CHECK_MODULES([LIBYANG], [libyang >= 1.0.184], , [ +  AC_MSG_ERROR([libyang (>= 1.0.184) was not found on your system.])  ])  ac_cflags_save="$CFLAGS"  CFLAGS="$CFLAGS $LIBYANG_CFLAGS" diff --git a/debian/control b/debian/control index f4275471d5..fca6956760 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends:   libsnmp-dev,   libssh-dev <!pkg.frr.nortrlib>,   libsystemd-dev <!pkg.frr.nosystemd>, - libyang-dev (>= 0.16.74), + libyang-dev (>= 1.0.184),   pkg-config,   python3,   python3-dev, diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst index f50b8cf72d..56f6f4f14e 100644 --- a/doc/developer/building-libyang.rst +++ b/doc/developer/building-libyang.rst @@ -5,12 +5,16 @@ library.  **Option 1: Binary Install** -The FRR project builds binary ``libyang`` packages, which we offer for download -`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_. +The FRR project builds some binary ``libyang`` packages. + +RPM packages are at our `RPM repository <rpm.frrouting.org>`_ + +DEB packages are available as CI artifacts `here +<https://ci1.netdef.org/browse/LIBYANG-LY1REL-DEB10AMD64-4/artifact>`_.  .. warning:: -   ``libyang`` version 0.16.105 or newer is required to build FRR. +   ``libyang`` version 1.0.184 or newer is required to build FRR.  .. note:: @@ -50,8 +54,3 @@ The FRR project builds binary ``libyang`` packages, which we offer for download           -D CMAKE_BUILD_TYPE:String="Release" ..     make     sudo make install - -When building ``libyang`` version ``0.16.x`` it's also necessary to pass the -``-DENABLE_CACHE=OFF`` parameter to ``cmake`` to work around a -`known bug <https://github.com/CESNET/libyang/issues/752>`_ in libyang. - diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst index 9355141aa4..28b21533c0 100644 --- a/doc/developer/lists.rst +++ b/doc/developer/lists.rst @@ -497,6 +497,7 @@ API for hash tables        Items that compare as equal cannot be inserted.  Refer to the notes        about sorted structures in the previous section. +  .. c:function:: void Z_init_size(struct Z_head *, size_t size)     Same as :c:func:`Z_init()` but preset the minimum hash table to @@ -506,6 +507,66 @@ Hash tables also support :c:func:`Z_add()` and :c:func:`Z_find()` with  the same semantics as noted above. :c:func:`Z_find_gteq()` and  :c:func:`Z_find_lt()` are **not** provided for hash tables. +Hash table invariants +^^^^^^^^^^^^^^^^^^^^^ + +There are several ways to injure yourself using the hash table API. + +First, note that there are two functions related to computing uniqueness of +objects inserted into the hash table. There is a hash function and a comparison +function. The hash function computes the hash of the object. Our hash table +implementation uses `chaining +<https://en.wikipedia.org/wiki/Hash_table#Separate_chaining_with_linked_lists>`_. +This means that your hash function does not have to be perfect; multiple +objects having the same computed hash will be placed into a linked list +corresponding to that key. The closer to perfect the hash function, the better +performance, as items will be more evenly distributed and the chain length will +not be long on any given lookup, minimizing the number of list operations +required to find the correct item. However, the comparison function *must* be +perfect, in the sense that any two unique items inserted into the hash table +must compare not equal. At insertion time, if you try to insert an item that +compares equal to an existing item the insertion will not happen and +``hash_get()`` will return the existing item. However, this invariant *must* be +maintained while the object is in the hash table. Suppose you insert items +``A`` and ``B`` into the hash table which both hash to the same value ``1234`` +but do not compare equal. They will be placed in a chain like so:: + +   1234 : A -> B + +Now suppose you do something like this elsewhere in the code:: + +   *A = *B + +I.e. you copy all fields of ``B`` into ``A``, such that the comparison function +now says that they are equal based on their contents. At this point when you +look up ``B`` in the hash table, ``hash_get()`` will search the chain for the +first item that compares equal to ``B``, which will be ``A``. This leads to +insidious bugs. + +.. warning:: + +   Never modify the values looked at by the comparison or hash functions after +   inserting an item into a hash table. + +A similar situation can occur with the hash allocation function. ``hash_get()`` +accepts a function pointer that it will call to get the item that should be +inserted into the list if the provided item is not already present. There is a +builtin function, ``hash_alloc_intern``, that will simply return the item you +provided; if you always want to store the value you pass to ``hash_get`` you +should use this one. If you choose to provide a different one, that function +*must* return a new item that hashes and compares equal to the one you provided +to ``hash_get()``. If it does not the behavior of the hash table is undefined. + +.. warning:: + +   Always make sure your hash allocation function returns a value that hashes +   and compares equal to the item you provided to ``hash_get()``. + +Finally, if you maintain pointers to items you have inserted into a hash table, +then before deallocating them you must release them from the hash table. This +is basic memory management but worth repeating as bugs have arisen from failure +to do this. +  API for heaps  ------------- diff --git a/doc/figures/nodes.dot b/doc/figures/nodes.dot index b548b5529a..4ce147b2c4 100644 --- a/doc/figures/nodes.dot +++ b/doc/figures/nodes.dot @@ -47,7 +47,7 @@ digraph climodes {  	CONFIG_NODE -> OSPF_NODE [ label="router ospf [(1-65535)] [vrf NAME]" ];  	CONFIG_NODE -> OSPF6_NODE [ label="router ospf6" ];  	CONFIG_NODE -> LDP_NODE [ label="mpls ldp" ]; -	CONFIG_NODE -> ISIS_NODE [ label="router isis WORD" ]; +	CONFIG_NODE -> ISIS_NODE [ label="router isis WORD [vrf NAME]" ];  	CONFIG_NODE -> RMAP_NODE [ label="route-map WORD <deny|permit> (1-65535)" ];  	CONFIG_NODE -> PW_NODE [ label="pseudowire IFNAME" ];  	CONFIG_NODE -> VTY_NODE [ label="line vty" ]; diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 4a5bdc2428..63f3d05a93 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1103,6 +1103,41 @@ Redistribution     Redistribute VNC direct (not via zebra) routes to BGP process. +.. index:: bgp update-delay MAX-DELAY +.. clicmd:: bgp update-delay MAX-DELAY + +.. index:: bgp update-delay MAX-DELAY ESTABLISH-WAIT +.. clicmd:: bgp update-delay MAX-DELAY ESTABLISH-WAIT + +   This feature is used to enable read-only mode on BGP process restart or when +   a BGP process is cleared using 'clear ip bgp \*'. Note that this command is +   configured at the global level and applies to all bgp instances/vrfs.  It +   cannot be used at the same time as the "update-delay" command described below, +   which is entered in each bgp instance/vrf desired to delay update installation +   and advertisements. The global and per-vrf approaches to defining update-delay +   are mutually exclusive. + +   When applicable, read-only mode would begin as soon as the first peer reaches +   Established status and a timer for max-delay seconds is started.  During this +   mode BGP doesn't run any best-path or generate any updates to its peers. This +   mode continues until: + +   1. All the configured peers, except the shutdown peers, have sent explicit EOR +      (End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached +      Established is considered an implicit-EOR. +      If the establish-wait optional value is given, then BGP will wait for +      peers to reach established from the beginning of the update-delay till the +      establish-wait period is over, i.e. the minimum set of established peers for +      which EOR is expected would be peers established during the establish-wait +      window, not necessarily all the configured neighbors. +   2. max-delay period is over. + +   On hitting any of the above two conditions, BGP resumes the decision process +   and generates updates to its peers. + +   Default max-delay is 0, i.e. the feature is off by default. + +  .. index:: update-delay MAX-DELAY  .. clicmd:: update-delay MAX-DELAY @@ -1110,12 +1145,17 @@ Redistribution  .. clicmd:: update-delay MAX-DELAY ESTABLISH-WAIT     This feature is used to enable read-only mode on BGP process restart or when -   BGP process is cleared using 'clear ip bgp \*'. When applicable, read-only -   mode would begin as soon as the first peer reaches Established status and a -   timer for max-delay seconds is started. - -   During this mode BGP doesn't run any best-path or generate any updates to its -   peers. This mode continues until: +   a BGP process is cleared using 'clear ip bgp \*'.  Note that this command is +   configured under the specific bgp instance/vrf that the feaure is enabled for. +   It cannot be used at the same time as the global "bgp update-delay" described +   above, which is entered at the global level and applies to all bgp instances. +   The global and per-vrf approaches to defining update-delay are mutually +   exclusive. + +   When applicable, read-only mode would begin as soon as the first peer reaches +   Established status and a timer for max-delay seconds is started.  During this +   mode BGP doesn't run any best-path or generate any updates to its peers. This +   mode continues until:     1. All the configured peers, except the shutdown peers, have sent explicit EOR        (End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached @@ -1216,14 +1256,14 @@ Defining Peers     The time in milliseconds that BGP will delay before deciding what peers     can be put into an update-group together in order to generate a single     update for them.  The default time is 1000. -    +  .. _bgp-configuring-peers:  Configuring Peers  ^^^^^^^^^^^^^^^^^ -.. index:: [no] neighbor PEER shutdown [message MSG...] -.. clicmd:: [no] neighbor PEER shutdown [message MSG...] +.. index:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]] +.. clicmd:: [no] neighbor PEER shutdown [message MSG...] [rtt (1-65535) [count (1-255)]]     Shutdown the peer. We can delete the neighbor's configuration by     ``no neighbor PEER remote-as ASN`` but all configuration of the neighbor @@ -1232,6 +1272,12 @@ Configuring Peers     Optionally you can specify a shutdown message `MSG`. +   Also, you can specify optionally _rtt_ in milliseconds to automatically +   shutdown the peer if round-trip-time becomes higher than defined. + +   Additional _count_ parameter is the number of keepalive messages to count +   before shutdown the peer if round-trip-time becomes higher than defined. +  .. index:: [no] neighbor PEER disable-connected-check  .. clicmd:: [no] neighbor PEER disable-connected-check diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 1155b49eb1..8cbbe0809f 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -33,8 +33,8 @@ ISIS router  To start the ISIS process you have to specify the ISIS router. As of this  writing, *isisd* does not support multiple ISIS processes. -.. index:: [no] router isis WORD -.. clicmd:: [no] router isis WORD +.. index:: [no] router isis WORD [vrf NAME] +.. clicmd:: [no] router isis WORD [vrf NAME]     Enable or disable the ISIS process by specifying the ISIS domain with     'WORD'.  *isisd* does not yet support multiple ISIS processes but you must @@ -202,8 +202,8 @@ ISIS interface  .. _ip-router-isis-word: -.. index:: [no] <ip|ipv6> router isis WORD -.. clicmd:: [no] <ip|ipv6> router isis WORD +.. index:: [no] <ip|ipv6> router isis WORD [vrf NAME] +.. clicmd:: [no] <ip|ipv6> router isis WORD [vrf NAME]     Activate ISIS adjacency on this interface. Note that the name of ISIS     instance must be the same as the one used to configure the ISIS process (see @@ -751,3 +751,22 @@ A Segment Routing configuration, with IPv4, IPv6, SRGB and MSD configuration.      segment-routing prefix 2001:db8:1000::1/128 index 101 explicit-null     ! +ISIS Vrf Configuration Examples +=============================== + +A simple vrf example: + +.. code-block:: frr + +   ! +   interface eth0 vrf RED +    ip router isis FOO vrf RED +    isis network point-to-point +    isis circuit-type level-2-only +   ! +   router isis FOO vrf RED +    net 47.0023.0000.0000.0000.0000.0000.0000.1900.0004.00 +    metric-style wide +    is-type level-2-only + + diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index f557cbe022..fa5fc248a8 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -329,6 +329,12 @@ Route Map Set Command     Set the BGP table to a given table identifier +.. index:: set sr-te color (1-4294967295) +.. clicmd:: set sr-te color (1-4294967295) + +   Set the color of a SR-TE Policy to be applied to a learned route. The SR-TE +   Policy is uniquely determined by the color and the BGP nexthop. +  .. _route-map-call-command:  Route Map Call Command diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 985e07820f..1214c01a12 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1244,21 +1244,24 @@ static int isis_interface_config_write(struct vty *vty)  #else  static int isis_interface_config_write(struct vty *vty)  { -	struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); +	struct vrf *vrf = NULL;  	int write = 0; -	struct interface *ifp; -	struct lyd_node *dnode; -	FOR_ALL_INTERFACES (vrf, ifp) { -		dnode = yang_dnode_get( -			running_config->dnode, -			"/frr-interface:lib/interface[name='%s'][vrf='%s']", -			ifp->name, vrf->name); -		if (dnode == NULL) -			continue; +	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { +		struct interface *ifp; -		write++; -		nb_cli_show_dnode_cmds(vty, dnode, false); +		FOR_ALL_INTERFACES (vrf, ifp) { +			struct lyd_node *dnode; +			dnode = yang_dnode_get( +				running_config->dnode, +				"/frr-interface:lib/interface[name='%s'][vrf='%s']", +				ifp->name, vrf->name); +			if (dnode == NULL) +				continue; + +			write++; +			nb_cli_show_dnode_cmds(vty, dnode, false); +		}  	}  	return write;  } @@ -1268,6 +1271,7 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area,  					 struct interface *ifp)  {  	struct isis_circuit *circuit = circuit_scan_by_ifp(ifp); +  	if (circuit && circuit->area)  		return NULL;  	circuit = isis_csm_state_change(ISIS_ENABLE, circuit, area); @@ -1446,7 +1450,7 @@ int isis_if_delete_hook(struct interface *ifp)  	/* Clean up the circuit data */  	if (ifp && ifp->info) {  		circuit = ifp->info; -		isis_csm_state_change(IF_DOWN_FROM_Z, circuit, circuit->area); +		isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);  	}  	return 0; @@ -1454,10 +1458,15 @@ int isis_if_delete_hook(struct interface *ifp)  static int isis_ifp_create(struct interface *ifp)  { -	if (if_is_operative(ifp)) +	struct vrf *vrf = NULL; + +	if (if_is_operative(ifp)) { +		vrf = vrf_lookup_by_id(ifp->vrf_id); +		if (vrf) +			isis_global_instance_create(vrf->name);  		isis_csm_state_change(IF_UP_FROM_Z, circuit_scan_by_ifp(ifp),  				      ifp); - +	}  	hook_call(isis_if_new_hook, ifp);  	return 0; diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 4d02758003..31fe41db82 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -46,16 +46,21 @@  /*   * XPath: /frr-isisd:isis/instance   */ -DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag", -	   ROUTER_STR -	   "ISO IS-IS\n" -	   "ISO Routing area tag\n") +DEFPY_YANG_NOSH(router_isis, router_isis_cmd, +		"router isis WORD$tag [vrf NAME$vrf_name]", +		ROUTER_STR +		"ISO IS-IS\n" +		"ISO Routing area tag\n" VRF_CMD_HELP_STR)  {  	int ret;  	char base_xpath[XPATH_MAXLEN]; +	if (!vrf_name) +		vrf_name = VRF_DEFAULT_NAME; +  	snprintf(base_xpath, XPATH_MAXLEN, -		 "/frr-isisd:isis/instance[area-tag='%s']", tag); +		 "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag, +		 vrf_name);  	nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);  	/* default value in yang for is-type is level-1, but in FRR  	 * the first instance is assigned is-type level-1-2. We @@ -77,25 +82,30 @@ DEFPY_YANG_NOSH(router_isis, router_isis_cmd, "router isis WORD$tag",  	return ret;  } -DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag", -      NO_STR ROUTER_STR -      "ISO IS-IS\n" -      "ISO Routing area tag\n") +DEFPY_YANG(no_router_isis, no_router_isis_cmd, +	   "no router isis WORD$tag [vrf NAME$vrf_name]", +	   NO_STR ROUTER_STR +	   "ISO IS-IS\n" +	   "ISO Routing area tag\n" VRF_CMD_HELP_STR)  {  	char temp_xpath[XPATH_MAXLEN];  	struct listnode *node, *nnode;  	struct isis_circuit *circuit = NULL;  	struct isis_area *area = NULL; -	if (!yang_dnode_exists(vty->candidate_config->dnode, -			       "/frr-isisd:isis/instance[area-tag='%s']", -			       tag)) { +	if (!vrf_name) +		vrf_name = VRF_DEFAULT_NAME; + +	if (!yang_dnode_exists( +		    vty->candidate_config->dnode, +		    "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag, +		    vrf_name)) {  		vty_out(vty, "ISIS area %s not found.\n", tag);  		return CMD_ERR_NOTHING_TODO;  	}  	nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); -	area = isis_area_lookup(tag, VRF_DEFAULT); +	area = isis_area_lookup_by_vrf(tag, vrf_name);  	if (area && area->circuit_list && listcount(area->circuit_list)) {  		for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,  				       circuit)) { @@ -114,15 +124,23 @@ DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",  	}  	return nb_cli_apply_changes( -		vty, "/frr-isisd:isis/instance[area-tag='%s']", tag); +		vty, "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag, +		vrf_name);  }  void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,  			  bool show_defaults)  { +	const char *vrf = NULL; + +	vrf = yang_dnode_get_string(dnode, "./vrf"); +  	vty_out(vty, "!\n"); -	vty_out(vty, "router isis %s\n", +	vty_out(vty, "router isis %s ",  		yang_dnode_get_string(dnode, "./area-tag")); +	if (!strmatch(vrf, VRF_DEFAULT_NAME)) +		vty_out(vty, "vrf %s", yang_dnode_get_string(dnode, "./vrf")); +	vty_out(vty, "\n");  }  /* @@ -131,16 +149,18 @@ void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,   * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv6-routing   * XPath: /frr-isisd:isis/instance   */ -DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag", -      "Interface Internet Protocol config commands\n" -      "IP router interface commands\n" -      "IS-IS routing protocol\n" -      "Routing process tag\n") +DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, +	   "ip router isis WORD$tag [vrf NAME$vrf_name]", +	   "Interface Internet Protocol config commands\n" +	   "IP router interface commands\n" +	   "IS-IS routing protocol\n" +	   "Routing process tag\n" VRF_CMD_HELP_STR)  {  	char temp_xpath[XPATH_MAXLEN];  	const char *circ_type;  	struct isis_area *area = NULL;  	struct interface *ifp; +	struct vrf *vrf;  	/* area will be created if it is not present. make sure the yang model  	 * is synced with FRR and call the appropriate NB cb. @@ -150,16 +170,26 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",  		return CMD_SUCCESS;  	}  	ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); -	if (ifp) -		area = isis_area_lookup(tag, ifp->vrf_id); +	if (!vrf_name && ifp->vrf_id == VRF_DEFAULT) +		vrf_name = VRF_DEFAULT_NAME; + +	if (ifp->vrf_id != VRF_DEFAULT) { +		vrf = vrf_lookup_by_id(ifp->vrf_id); +		if (vrf && !vrf_name) +			vrf_name = vrf->name; +	} +	area = isis_area_lookup_by_vrf(tag, vrf_name);  	if (!area) { +		isis_global_instance_create(vrf_name);  		snprintf(temp_xpath, XPATH_MAXLEN, -			 "/frr-isisd:isis/instance[area-tag='%s']", tag); +			 "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", +			 tag, vrf_name);  		nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag); -		snprintf(temp_xpath, XPATH_MAXLEN, -			 "/frr-isisd:isis/instance[area-tag='%s']/is-type", -			 tag); +		snprintf( +			temp_xpath, XPATH_MAXLEN, +			"/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type", +			tag, vrf_name);  		nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,  				      listcount(im->isis) == 0 ? "level-1-2"  							       : NULL); @@ -167,6 +197,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",  				      NULL);  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",  				      NB_OP_MODIFY, tag); + +		nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY, +				      vrf_name);  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",  				      NB_OP_MODIFY, "true");  		nb_cli_enqueue_change( @@ -192,6 +225,9 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",  				      NULL);  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",  				      NB_OP_MODIFY, tag); +		nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY, +				      vrf_name); +  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing",  				      NB_OP_MODIFY, "true");  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", @@ -206,16 +242,18 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "ip router isis WORD$tag",  	return nb_cli_apply_changes(vty, NULL);  } -DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag", -      "Interface Internet Protocol config commands\n" -      "IP router interface commands\n" -      "IS-IS routing protocol\n" -      "Routing process tag\n") +DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, +	   "ipv6 router isis WORD$tag [vrf NAME$vrf_name]", +	   "Interface Internet Protocol config commands\n" +	   "IP router interface commands\n" +	   "IS-IS routing protocol\n" +	   "Routing process tag\n" VRF_CMD_HELP_STR)  {  	char temp_xpath[XPATH_MAXLEN];  	const char *circ_type; -	struct isis_area *area = NULL;  	struct interface *ifp; +	struct isis_area *area; +	struct vrf *vrf;  	/* area will be created if it is not present. make sure the yang model  	 * is synced with FRR and call the appropriate NB cb. @@ -225,16 +263,25 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",  		return CMD_SUCCESS;  	ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); -	if (ifp) -		area = isis_area_lookup(tag, ifp->vrf_id); +	if (!vrf_name && ifp->vrf_id == VRF_DEFAULT) +		vrf_name = VRF_DEFAULT_NAME; +	if (ifp->vrf_id != VRF_DEFAULT) { +		vrf = vrf_lookup_by_id(ifp->vrf_id); +		if (vrf && !vrf_name) +			vrf_name = vrf->name; +	} +	area = isis_area_lookup_by_vrf(tag, vrf_name);  	if (!area) { +		isis_global_instance_create(vrf_name);  		snprintf(temp_xpath, XPATH_MAXLEN, -			 "/frr-isisd:isis/instance[area-tag='%s']", tag); +			 "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", +			 tag, vrf_name);  		nb_cli_enqueue_change(vty, temp_xpath, NB_OP_CREATE, tag); -		snprintf(temp_xpath, XPATH_MAXLEN, -			 "/frr-isisd:isis/instance[area-tag='%s']/is-type", -			 tag); +		snprintf( +			temp_xpath, XPATH_MAXLEN, +			"/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/is-type", +			tag, vrf_name);  		nb_cli_enqueue_change(vty, temp_xpath, NB_OP_MODIFY,  				      listcount(im->isis) == 0 ? "level-1-2"  							       : NULL); @@ -242,6 +289,9 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",  				      NULL);  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",  				      NB_OP_MODIFY, tag); +		nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY, +				      vrf_name); +  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",  				      NB_OP_MODIFY, "true");  		nb_cli_enqueue_change( @@ -267,6 +317,8 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",  				      NULL);  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag",  				      NB_OP_MODIFY, tag); +		nb_cli_enqueue_change(vty, "./frr-isisd:isis/vrf", NB_OP_MODIFY, +				      vrf_name);  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing",  				      NB_OP_MODIFY, "true");  		nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", @@ -282,13 +334,13 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "ipv6 router isis WORD$tag",  }  DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd, -      "no <ip|ipv6>$ip router isis [WORD]$tag", -      NO_STR -      "Interface Internet Protocol config commands\n" -      "IP router interface commands\n" -      "IP router interface commands\n" -      "IS-IS routing protocol\n" -      "Routing process tag\n") +	   "no <ip|ipv6>$ip router isis [WORD]$tag [vrf NAME$vrf_name]", +	   NO_STR +	   "Interface Internet Protocol config commands\n" +	   "IP router interface commands\n" +	   "IP router interface commands\n" +	   "IS-IS routing protocol\n" +	   "Routing process tag\n")  {  	const struct lyd_node *dnode; @@ -324,19 +376,33 @@ DEFPY_YANG(no_ip_router_isis, no_ip_router_isis_cmd,  void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode,  			   bool show_defaults)  { +	const char *vrf; + +	vrf = yang_dnode_get_string(dnode, "../vrf"); +  	if (!yang_dnode_get_bool(dnode, NULL))  		vty_out(vty, " no"); -	vty_out(vty, " ip router isis %s\n", +	vty_out(vty, " ip router isis %s ",  		yang_dnode_get_string(dnode, "../area-tag")); +	if (!strmatch(vrf, VRF_DEFAULT_NAME)) +		vty_out(vty, "vrf %s", vrf); +	vty_out(vty, "\n");  }  void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode,  			   bool show_defaults)  { +	const char *vrf; + +	vrf = yang_dnode_get_string(dnode, "../vrf"); +  	if (!yang_dnode_get_bool(dnode, NULL))  		vty_out(vty, " no"); -	vty_out(vty, " ipv6 router isis %s\n", +	vty_out(vty, " ipv6 router isis %s ",  		yang_dnode_get_string(dnode, "../area-tag")); +	if (!strmatch(vrf, VRF_DEFAULT_NAME)) +		vty_out(vty, "vrf %s", vrf); +	vty_out(vty, "\n");  }  /* diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 6352303c23..26f5227aae 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -236,13 +236,12 @@ int main(int argc, char **argv, char **envp)  	/* thread master */  	isis_master_init(frr_init());  	master = im->master; -  	/*  	 *  initializations  	 */  	isis_error_init();  	access_list_init(); -	vrf_init(NULL, NULL, NULL, NULL, NULL); +	isis_vrf_init();  	prefix_list_init();  	isis_init();  	isis_circuit_init(); @@ -261,7 +260,7 @@ int main(int argc, char **argv, char **envp)  	mt_init();  	/* create the global 'isis' instance */ -	isis_global_instance_create(); +	isis_global_instance_create(VRF_DEFAULT_NAME);  	isis_zebra_init(master, instance);  	isis_bfd_init(); diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index 2b8b02e3f1..33b0b4d02c 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -551,6 +551,13 @@ const struct frr_yang_module_info frr_isisd_info = {  			},  		},  		{ +			.xpath = "/frr-interface:lib/interface/frr-isisd:isis/vrf", +			.cbs = { +				.modify = lib_interface_isis_vrf_modify, +			}, +		}, + +		{  			.xpath = "/frr-interface:lib/interface/frr-isisd:isis/circuit-type",  			.cbs = {  				.cli_show = cli_show_ip_isis_circ_type, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index a9401bc86a..a79cb8ff57 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -168,6 +168,7 @@ int isis_instance_mpls_te_router_address_destroy(  int lib_interface_isis_create(struct nb_cb_create_args *args);  int lib_interface_isis_destroy(struct nb_cb_destroy_args *args);  int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args); +int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args);  int lib_interface_isis_ipv4_routing_modify(struct nb_cb_modify_args *args);  int lib_interface_isis_ipv6_routing_modify(struct nb_cb_modify_args *args);  int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args); diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index d722868414..170fe92c28 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -53,16 +53,19 @@ int isis_instance_create(struct nb_cb_create_args *args)  {  	struct isis_area *area;  	const char *area_tag; +	const char *vrf_name;  	if (args->event != NB_EV_APPLY)  		return NB_OK; - +	vrf_name = yang_dnode_get_string(args->dnode, "./vrf");  	area_tag = yang_dnode_get_string(args->dnode, "./area-tag"); -	area = isis_area_lookup(area_tag, VRF_DEFAULT); +	isis_global_instance_create(vrf_name); +	area = isis_area_lookup_by_vrf(area_tag, vrf_name);  	if (area)  		return NB_ERR_INCONSISTENCY; -	area = isis_area_create(area_tag, VRF_DEFAULT_NAME); +	area = isis_area_create(area_tag, vrf_name); +  	/* save area in dnode to avoid looking it up all the time */  	nb_running_set_entry(args->dnode, area); @@ -75,7 +78,6 @@ int isis_instance_destroy(struct nb_cb_destroy_args *args)  	if (args->event != NB_EV_APPLY)  		return NB_OK; -  	area = nb_running_unset_entry(args->dnode);  	isis_area_destroy(area); @@ -116,7 +118,6 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)  		area = nb_running_get_entry(args->dnode, NULL, true);  		if (area == NULL)  			return NB_ERR_VALIDATION; -  		addr.addr_len = dotformat2buff(buff, net_title);  		memcpy(addr.area_addr, buff, addr.addr_len);  		if (addr.area_addr[addr.addr_len - 1] != 0) { @@ -148,6 +149,7 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args)  	case NB_EV_APPLY:  		area = nb_running_get_entry(args->dnode, NULL, true);  		addrr = args->resource->ptr; +		assert(area);  		if (area->isis->sysid_set == 0) {  			/* @@ -1830,8 +1832,10 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)  {  	struct isis_area *area = NULL;  	struct interface *ifp; -	struct isis_circuit *circuit; +	struct isis_circuit *circuit = NULL; +	struct vrf *vrf;  	const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag"); +	const char *vrf_name = yang_dnode_get_string(args->dnode, "./vrf");  	uint32_t min_mtu, actual_mtu;  	switch (args->event) { @@ -1846,8 +1850,17 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)  		/* zebra might not know yet about the MTU - nothing we can do */  		if (!ifp || ifp->mtu == 0)  			break; +		vrf = vrf_lookup_by_id(ifp->vrf_id); +		if (ifp->vrf_id != VRF_DEFAULT && vrf +		    && strcmp(vrf->name, vrf_name) != 0) { +			snprintf(args->errmsg, args->errmsg_len, +				 "interface %s not in vrf %s\n", ifp->name, +				 vrf_name); +			return NB_ERR_VALIDATION; +		}  		actual_mtu =  			if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu; +  		area = isis_area_lookup(area_tag, ifp->vrf_id);  		if (area)  			min_mtu = area->lsp_mtu; @@ -1866,9 +1879,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)  		}  		break;  	case NB_EV_APPLY: -		ifp = nb_running_get_entry(args->dnode, NULL, true); -		if (ifp) -			area = isis_area_lookup(area_tag, ifp->vrf_id); +		area = isis_area_lookup_by_vrf(area_tag, vrf_name);  		/* The area should have already be created. We are  		 * setting the priority of the global isis area creation  		 * slightly lower, so it should be executed first, but I @@ -1881,7 +1892,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args)  				__func__, area_tag);  			abort();  		} - +		ifp = nb_running_get_entry(args->dnode, NULL, true);  		circuit = isis_circuit_create(area, ifp);  		assert(circuit  		       && (circuit->state == C_STATE_CONF @@ -1957,6 +1968,44 @@ int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args)  }  /* + * XPath: /frr-interface:lib/interface/frr-isisd:isis/vrf + */ +int lib_interface_isis_vrf_modify(struct nb_cb_modify_args *args) +{ +	struct interface *ifp; +	struct vrf *vrf; +	const char *ifname, *vrfname, *vrf_name; +	struct isis_circuit *circuit; + +	if (args->event == NB_EV_VALIDATE) { +		/* libyang doesn't like relative paths across module boundaries +		 */ +		ifname = yang_dnode_get_string(args->dnode->parent->parent, +					       "./name"); +		vrfname = yang_dnode_get_string(args->dnode->parent->parent, +						"./vrf"); +		vrf = vrf_lookup_by_name(vrfname); +		assert(vrf); +		ifp = if_lookup_by_name(ifname, vrf->vrf_id); + +		if (!ifp) +			return NB_OK; + +		vrf_name = yang_dnode_get_string(args->dnode, NULL); +		circuit = circuit_scan_by_ifp(ifp); +		if (circuit && circuit->area && circuit->area->isis +		    && strcmp(circuit->area->isis->name, vrf_name)) { +			snprintf(args->errmsg, args->errmsg_len, +				 "ISIS circuit is already defined on vrf  %s", +				 circuit->area->isis->name); +			return NB_ERR_VALIDATION; +		} +	} + +	return NB_OK; +} + +/*   * XPath: /frr-interface:lib/interface/frr-isisd:isis/circuit-type   */  int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args) diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 3aa21a9aed..a50eb607d9 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -577,6 +577,20 @@ int isis_zebra_label_manager_connect(void)  	return 0;  } +void isis_zebra_vrf_register(struct isis *isis) +{ +	if (!zclient || zclient->sock < 0 || !isis) +		return; + +	if (isis->vrf_id != VRF_UNKNOWN) { +		if (IS_DEBUG_EVENTS) +			zlog_debug("%s: Register VRF %s id %u", __func__, +				   isis->name, isis->vrf_id); +		zclient_send_reg_requests(zclient, isis->vrf_id); +	} +} + +  static void isis_zebra_connected(struct zclient *zclient)  {  	zclient_send_reg_requests(zclient, VRF_DEFAULT); diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index 4449b63c2e..768919ff46 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -57,5 +57,6 @@ bool isis_zebra_label_manager_ready(void);  int isis_zebra_label_manager_connect(void);  int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);  int isis_zebra_release_label_range(uint32_t start, uint32_t end); +void isis_zebra_vrf_register(struct isis *isis);  #endif /* _ZEBRA_ISIS_ZEBRA_H */ diff --git a/isisd/isisd.c b/isisd/isisd.c index aca98bf651..2a2c71b1fd 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -35,6 +35,7 @@  #include "prefix.h"  #include "table.h"  #include "qobj.h" +#include "zclient.h"  #include "vrf.h"  #include "spf_backoff.h"  #include "lib/northbound_cli.h" @@ -167,29 +168,32 @@ void isis_master_init(struct thread_master *master)  	im->master = master;  } -void isis_global_instance_create() +void isis_global_instance_create(const char *vrf_name)  {  	struct isis *isis; -	isis = isis_lookup_by_vrfid(VRF_DEFAULT); +	isis = isis_lookup_by_vrfname(vrf_name);  	if (isis == NULL) { -		isis = isis_new(VRF_DEFAULT); +		isis = isis_new(vrf_name);  		isis_add(isis);  	}  } -struct isis *isis_new(vrf_id_t vrf_id) +struct isis *isis_new(const char *vrf_name)  {  	struct vrf *vrf;  	struct isis *isis;  	isis = XCALLOC(MTYPE_ISIS, sizeof(struct isis)); -	isis->vrf_id = vrf_id; -	vrf = vrf_lookup_by_id(vrf_id); +	vrf = vrf_lookup_by_name(vrf_name);  	if (vrf) { +		isis->vrf_id = vrf->vrf_id;  		isis_vrf_link(isis, vrf);  		isis->name = XSTRDUP(MTYPE_ISIS, vrf->name); +	} else { +		isis->vrf_id = VRF_UNKNOWN; +		isis->name = XSTRDUP(MTYPE_ISIS, vrf_name);  	}  	if (IS_DEBUG_EVENTS) @@ -223,15 +227,20 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)  		if (vrf) {  			isis = isis_lookup_by_vrfid(vrf->vrf_id);  			if (isis == NULL) { -				isis = isis_new(vrf->vrf_id); +				isis = isis_new(vrf_name); +				isis_add(isis); +			} +		} else { +			isis = isis_lookup_by_vrfid(VRF_UNKNOWN); +			if (isis == NULL) { +				isis = isis_new(vrf_name);  				isis_add(isis);  			} -		} else -			return NULL; +		}  	} else {  		isis = isis_lookup_by_vrfid(VRF_DEFAULT);  		if (isis == NULL) { -			isis = isis_new(VRF_DEFAULT); +			isis = isis_new(VRF_DEFAULT_NAME);  			isis_add(isis);  		}  	} @@ -336,6 +345,24 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)  	return area;  } +struct isis_area *isis_area_lookup_by_vrf(const char *area_tag, +					  const char *vrf_name) +{ +	struct isis_area *area; +	struct listnode *node; +	struct isis *isis = NULL; + +	isis = isis_lookup_by_vrfname(vrf_name); +	if (isis == NULL) +		return NULL; + +	for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) +		if (strcmp(area->area_tag, area_tag) == 0) +			return area; + +	return NULL; +} +  struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id)  {  	struct isis_area *area; @@ -449,6 +476,95 @@ void isis_area_destroy(struct isis_area *area)  } +/* This is hook function for vrf create called as part of vrf_init */ +static int isis_vrf_new(struct vrf *vrf) +{ +	if (IS_DEBUG_EVENTS) +		zlog_debug("%s: VRF Created: %s(%u)", __func__, vrf->name, +			   vrf->vrf_id); + +	return 0; +} + +/* This is hook function for vrf delete call as part of vrf_init */ +static int isis_vrf_delete(struct vrf *vrf) +{ +	if (IS_DEBUG_EVENTS) +		zlog_debug("%s: VRF Deletion: %s(%u)", __func__, vrf->name, +			   vrf->vrf_id); + +	return 0; +} + +static int isis_vrf_enable(struct vrf *vrf) +{ +	struct isis *isis; +	vrf_id_t old_vrf_id; + +	if (IS_DEBUG_EVENTS) +		zlog_debug("%s: VRF %s id %u enabled", __func__, vrf->name, +			   vrf->vrf_id); + +	isis = isis_lookup_by_vrfname(vrf->name); +	if (isis) { +		if (isis->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) { +			XFREE(MTYPE_ISIS, isis->name); +			isis->name = NULL; +		} +		old_vrf_id = isis->vrf_id; +		/* We have instance configured, link to VRF and make it "up". */ +		isis_vrf_link(isis, vrf); +		if (IS_DEBUG_EVENTS) +			zlog_debug( +				"%s: isis linked to vrf %s vrf_id %u (old id %u)", +				__func__, vrf->name, isis->vrf_id, old_vrf_id); +		if (old_vrf_id != isis->vrf_id) { +			frr_with_privs (&isisd_privs) { +				/* stop zebra redist to us for old vrf */ +				zclient_send_dereg_requests(zclient, +							    old_vrf_id); +				/* start zebra redist to us for new vrf */ +				isis_zebra_vrf_register(isis); +			} +		} +	} + +	return 0; +} + +static int isis_vrf_disable(struct vrf *vrf) +{ +	struct isis *isis; +	vrf_id_t old_vrf_id = VRF_UNKNOWN; + +	if (vrf->vrf_id == VRF_DEFAULT) +		return 0; + +	if (IS_DEBUG_EVENTS) +		zlog_debug("%s: VRF %s id %d disabled.", __func__, vrf->name, +			   vrf->vrf_id); +	isis = isis_lookup_by_vrfname(vrf->name); +	if (isis) { +		old_vrf_id = isis->vrf_id; + +		/* We have instance configured, unlink +		 * from VRF and make it "down". +		 */ +		isis_vrf_unlink(isis, vrf); +		if (IS_DEBUG_EVENTS) +			zlog_debug("%s: isis old_vrf_id %d unlinked", __func__, +				   old_vrf_id); +	} + +	return 0; +} + +void isis_vrf_init(void) +{ +	vrf_init(isis_vrf_new, isis_vrf_enable, isis_vrf_disable, +		 isis_vrf_delete, isis_vrf_enable); +} +  void isis_finish(struct isis *isis)  {  	struct vrf *vrf = NULL; diff --git a/isisd/isisd.h b/isisd/isisd.h index 0c0a1eed10..c26a62dfac 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -73,7 +73,6 @@ struct isis_master {  	struct list *isis;  	/* ISIS thread master. */  	struct thread_master *master; -	/* Various OSPF global configuration. */  	uint8_t options;  };  #define F_ISIS_UNIT_TEST 0x01 @@ -213,15 +212,19 @@ void isis_finish(struct isis *isis);  void isis_master_init(struct thread_master *master);  void isis_vrf_link(struct isis *isis, struct vrf *vrf);  void isis_vrf_unlink(struct isis *isis, struct vrf *vrf); -void isis_global_instance_create(void); +void isis_global_instance_create(const char *vrf_name);  struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id);  struct isis *isis_lookup_by_vrfname(const char *vrfname);  struct isis *isis_lookup_by_sysid(const uint8_t *sysid);  void isis_init(void); -struct isis *isis_new(vrf_id_t vrf_id); +void isis_vrf_init(void); + +struct isis *isis_new(const char *vrf_name);  struct isis_area *isis_area_create(const char *, const char *);  struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id); +struct isis_area *isis_area_lookup_by_vrf(const char *area_tag, +					  const char *vrf_name);  int isis_area_get(struct vty *vty, const char *area_tag);  void isis_area_destroy(struct isis_area *area);  void print_debug(struct vty *, int, int); diff --git a/ldpd/lde.c b/ldpd/lde.c index 734c1ea230..df64f908ea 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -468,6 +468,10 @@ lde_dispatch_parent(struct thread *thread)  			iface = if_lookup_name(ldeconf, kif->ifname);  			if (iface) {  				if_update_info(iface, kif); + +				/* if up see if any labels need to be updated */ +				if (kif->operative) +					lde_route_update(iface, AF_UNSPEC);  				break;  			} @@ -786,7 +790,6 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh)  		kr.remote_label = fnh->remote_label;  		kr.route_type = fnh->route_type;  		kr.route_instance = fnh->route_instance; -  		lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr,  		    sizeof(kr));  		break; @@ -2271,3 +2274,156 @@ lde_check_filter_af(int af, struct ldpd_af_conf *af_conf,  	if (strcmp(af_conf->acl_label_expnull_for, filter_name) == 0)  		lde_change_expnull_for_filter(af);  } + +void lde_route_update(struct iface *iface, int af) +{ +	struct fec	*f; +	struct fec_node	*fn; +	struct fec_nh	*fnh; +	struct lde_nbr  *ln; + +	/* update label of non-connected routes */ +	log_debug("update labels for interface %s", iface->name); +	RB_FOREACH(f, fec_tree, &ft) { +		fn = (struct fec_node *)f; +		if (IS_MPLS_UNRESERVED_LABEL(fn->local_label)) +			continue; + +		switch (af) { +		case AF_INET: +			if (fn->fec.type != FEC_TYPE_IPV4) +				continue; +			break; +		case AF_INET6: +			if (fn->fec.type != FEC_TYPE_IPV6) +				continue; +			break; +		default: +			/* unspecified so process both address families */ +			break; +		} + +		LIST_FOREACH(fnh, &fn->nexthops, entry) { +			/* +			 * If connected leave existing label. If LDP +			 * configured on interface or a static route +			 * may need new label. If no LDP configured +			 * treat fec as a connected route +			 */ +			if (fnh->flags & F_FEC_NH_CONNECTED) +				break; + +			if (fnh->ifindex != iface->ifindex) +				continue; + +			fnh->flags &= ~F_FEC_NH_NO_LDP; +			if (IS_MPLS_RESERVED_LABEL(fn->local_label)) { +				fn->local_label = NO_LABEL; +				fn->local_label = lde_update_label(fn); +				if (fn->local_label != NO_LABEL) +					RB_FOREACH(ln, nbr_tree, &lde_nbrs) +						lde_send_labelmapping( +						    ln, fn, 0); +			} +			break; +		} +	} +	RB_FOREACH(ln, nbr_tree, &lde_nbrs) +		lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, +		    0, NULL, 0); +} + +void lde_route_update_release(struct iface *iface, int af) +{ +	struct lde_nbr	*ln; +	struct fec	*f; +	struct fec_node	*fn; +	struct fec_nh	*fnh; + +	/* update label of interfaces no longer running LDP */ +	log_debug("release all labels for interface %s af %s", iface->name, +	    af == AF_INET ? "ipv4" : "ipv6"); +	RB_FOREACH(f, fec_tree, &ft) { +		fn = (struct fec_node *)f; + +		switch (af) { +		case AF_INET: +			if (fn->fec.type != FEC_TYPE_IPV4) +				continue; +			break; +		case AF_INET6: +			if (fn->fec.type != FEC_TYPE_IPV6) +				continue; +			break; +		default: +			fatalx("lde_route_update_release: unknown af"); +		} + +		if (fn->local_label == NO_LABEL) +			continue; + +		LIST_FOREACH(fnh, &fn->nexthops, entry) { +			/* +			 * If connected leave existing label. If LDP +			 * removed from interface may need new label +			 * and would be treated as a connected route +			 */ +			if (fnh->flags & F_FEC_NH_CONNECTED) +				break; + +			if (fnh->ifindex != iface->ifindex) +				continue; + +			fnh->flags |= F_FEC_NH_NO_LDP; +			RB_FOREACH(ln, nbr_tree, &lde_nbrs) +				lde_send_labelwithdraw(ln, fn, NULL, NULL); +			lde_free_label(fn->local_label); +			fn->local_label = NO_LABEL; +			fn->local_label = lde_update_label(fn); +			if (fn->local_label != NO_LABEL) +				RB_FOREACH(ln, nbr_tree, &lde_nbrs) +					lde_send_labelmapping(ln, fn, 0); +			break; +		} +	} +	RB_FOREACH(ln, nbr_tree, &lde_nbrs) +		lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, +		    0, NULL, 0); +} + +void lde_route_update_release_all(int af) +{ +	struct lde_nbr	*ln; +	struct fec	*f; +	struct fec_node	*fn; +	struct fec_nh	*fnh; + +	/* remove labels from all interfaces as LDP is no longer running for +	 * this address family +	 */ +	log_debug("release all labels for address family %s", +	    af == AF_INET ? "ipv4" : "ipv6"); +	RB_FOREACH(f, fec_tree, &ft) { +		fn = (struct fec_node *)f; +		switch (af) { +		case AF_INET: +			if (fn->fec.type != FEC_TYPE_IPV4) +				continue; +			break; +		case AF_INET6: +			if (fn->fec.type != FEC_TYPE_IPV6) +				continue; +			break; +		default: +			fatalx("lde_route_update_release: unknown af"); +		} + +		RB_FOREACH(ln, nbr_tree, &lde_nbrs) +			lde_send_labelwithdraw(ln, fn, NULL, NULL); + +		LIST_FOREACH(fnh, &fn->nexthops, entry) { +			fnh->flags |= F_FEC_NH_NO_LDP; +			lde_send_delete_klabel(fn, fnh); +		} +	} +} diff --git a/ldpd/lde.h b/ldpd/lde.h index 9e6db3a90b..660aeafb34 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -193,6 +193,9 @@ void		 lde_change_allocate_filter(int);  void		 lde_change_advertise_filter(int);  void		 lde_change_accept_filter(int);  void		 lde_change_expnull_for_filter(int); +void		 lde_route_update(struct iface *, int); +void		 lde_route_update_release(struct iface *, int); +void		 lde_route_update_release_all(int);  struct lde_addr	*lde_address_find(struct lde_nbr *, int,  		    union ldpd_addr *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 11d85b7449..bed276c7b1 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -404,10 +404,15 @@ lde_kernel_update(struct fec *fec)  			 * if LDP configured on interface or a static route  			 * clear flag else treat fec as a connected route  			 */ -			iface = if_lookup(ldeconf,fnh->ifindex); -			if (iface || fnh->route_type == ZEBRA_ROUTE_STATIC) -				fnh->flags &=~F_FEC_NH_NO_LDP; -			else +			if (ldeconf->flags & F_LDPD_ENABLED) { +				iface = if_lookup(ldeconf,fnh->ifindex); +				if (fnh->flags & F_FEC_NH_CONNECTED || +				    iface || +				    fnh->route_type == ZEBRA_ROUTE_STATIC) +					fnh->flags &=~F_FEC_NH_NO_LDP; +				else +					fnh->flags |= F_FEC_NH_NO_LDP; +			} else  				fnh->flags |= F_FEC_NH_NO_LDP;  		} else {  			lde_send_delete_klabel(fn, fnh); @@ -437,6 +442,10 @@ lde_kernel_update(struct fec *fec)  				lde_send_labelmapping(ln, fn, 1);  	} +	/* if no label created yet then don't try to program labeled route */ +	if (fn->local_label == NO_LABEL) +		return; +  	LIST_FOREACH(fnh, &fn->nexthops, entry) {  		lde_send_change_klabel(fn, fnh); @@ -567,7 +576,8 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln, int rcvd_label_mapping)  				fnh->flags &= ~F_FEC_NH_DEFER;  			}  			fnh->remote_label = map->label; -			lde_send_change_klabel(fn, fnh); +			if (fn->local_label != NO_LABEL) +				lde_send_change_klabel(fn, fnh);  			break;  		case FEC_TYPE_PWID:  			pw = (struct l2vpn_pw *) fn->data; diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index fc84c7f76b..53a384fe55 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -616,6 +616,8 @@ DEFPY  (ldp_show_mpls_ldp_binding,  	"Show detailed information\n"  	JSON_STR)  { +	if (!(ldpd_conf->flags & F_LDPD_ENABLED)) +		return CMD_SUCCESS;  	if (!local_label_str)  		local_label = NO_LABEL;  	if (!remote_label_str) diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 927c3a3c03..dca379e4eb 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -1329,6 +1329,7 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)  	int		 reset_nbrs_ipv4 = 0;  	int		 reset_nbrs = 0;  	int		 update_sockets = 0; +	int		 change_ldp_disabled = 0;  	/* update timers */  	if (af_conf->keepalive != xa->keepalive) { @@ -1362,6 +1363,11 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)  	    != (xa->flags & F_LDPD_AF_ALLOCHOSTONLY))  		change_host_label = 1; +	/* disabling LDP for address family */ +	if ((af_conf->flags & F_LDPD_AF_ENABLED) && +	    !(xa->flags & F_LDPD_AF_ENABLED)) +		change_ldp_disabled = 1; +  	af_conf->flags = xa->flags;  	/* update the transport address */ @@ -1409,6 +1415,9 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)  			lde_change_egress_label(af);  		if (change_host_label)  			lde_change_allocate_filter(af); +		if (change_ldp_disabled) +			lde_route_update_release_all(af); +  		break;  	case PROC_LDP_ENGINE:  		if (stop_init_backoff) @@ -1434,13 +1443,22 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)  	struct iface		*iface, *itmp, *xi;  	RB_FOREACH_SAFE(iface, iface_head, &conf->iface_tree, itmp) { -		/* find deleted interfaces */ +		/* find deleted interfaces, which occurs when LDP is removed +		 * for all address families +		 */  		if (if_lookup_name(xconf, iface->name) == NULL) {  			switch (ldpd_process) {  			case PROC_LDP_ENGINE:  				ldpe_if_exit(iface);  				break;  			case PROC_LDE_ENGINE: +				if (iface->ipv4.enabled) +					lde_route_update_release(iface, +					    AF_INET); +				if (iface->ipv6.enabled) +					lde_route_update_release(iface, +					    AF_INET6); +				break;  			case PROC_MAIN:  				break;  			} @@ -1468,6 +1486,29 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)  			continue;  		} +		/* update labels when adding or removing ldp on an +		 * interface +		 */ +		if (ldpd_process == PROC_LDE_ENGINE) { +			/* if we are removing lpd config for an address +			 * family on an interface then advertise routes +			 * learned over this interface as if they were +			 * connected routes +			 */ +			if (iface->ipv4.enabled && !xi->ipv4.enabled) +				lde_route_update_release(iface, AF_INET); +			if (iface->ipv6.enabled && !xi->ipv6.enabled) +				lde_route_update_release(iface, AF_INET6); + +			/* if we are adding lpd config for an address +			 * family on an interface then add proper labels +			 */ +			if (!iface->ipv4.enabled && xi->ipv4.enabled) +				lde_route_update(iface, AF_INET); +			if (!iface->ipv6.enabled && xi->ipv6.enabled) +				lde_route_update(iface, AF_INET6); +		} +  		/* update existing interfaces */  		merge_iface_af(&iface->ipv4, &xi->ipv4);  		merge_iface_af(&iface->ipv6, &xi->ipv6); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 655313bf16..9078e711fb 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -614,10 +614,8 @@ ldpe_dispatch_lde(struct thread *thread)  			map = imsg.data;  			nbr = nbr_find_peerid(imsg.hdr.peerid); -			if (nbr == NULL) { -				log_debug("ldpe_dispatch_lde: cannot find neighbor"); +			if (nbr == NULL)  				break; -			}  			if (nbr->state != NBR_STA_OPER)  				break; @@ -641,10 +639,8 @@ ldpe_dispatch_lde(struct thread *thread)  		case IMSG_REQUEST_ADD_END:  		case IMSG_WITHDRAW_ADD_END:  			nbr = nbr_find_peerid(imsg.hdr.peerid); -			if (nbr == NULL) { -				log_debug("ldpe_dispatch_lde: cannot find neighbor"); +			if (nbr == NULL)  				break; -			}  			if (nbr->state != NBR_STA_OPER)  				break; diff --git a/lib/filter.h b/lib/filter.h index d41f3b65cd..623fb94527 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -32,6 +32,16 @@ extern "C" {  /* Maximum ACL name length */  #define ACL_NAMSIZ                128 +/** Cisco host wildcard mask. */ +#define CISCO_HOST_WILDCARD_MASK  "0.0.0.0" +/** Cisco host wildcard binary mask. */ +#define CISCO_BIN_HOST_WILDCARD_MASK INADDR_ANY + +/** Cisco any wildcard mask. */ +#define CISCO_ANY_WILDCARD_MASK   "255.255.255.255" +/** Cisco binary any wildcard mask. */ +#define CISCO_BIN_ANY_WILDCARD_MASK INADDR_NONE +  /* Filter direction.  */  #define FILTER_IN                 0  #define FILTER_OUT                1 diff --git a/lib/filter_cli.c b/lib/filter_cli.c index 8c7a515dc5..09fc3289ce 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -37,14 +37,8 @@  #define ACCESS_LIST_STR "Access list entry\n"  #define ACCESS_LIST_LEG_STR "IP standard access list\n" -#define ACCESS_LIST_LEG_EXT_STR "IP standard access list (expanded range)\n"  #define ACCESS_LIST_ELEG_STR "IP extended access list\n"  #define ACCESS_LIST_ELEG_EXT_STR "IP extended access list (expanded range)\n" -#define ACCESS_LIST_XLEG_STR                                                   \ -	ACCESS_LIST_LEG_STR                                                    \ -	ACCESS_LIST_LEG_EXT_STR                                                \ -	ACCESS_LIST_ELEG_STR                                                   \ -	ACCESS_LIST_ELEG_EXT_STR  #define ACCESS_LIST_ZEBRA_STR "Access list entry\n"  #define ACCESS_LIST_SEQ_STR                                                    \  	"Sequence number of an entry\n"                                        \ @@ -68,7 +62,6 @@ static int64_t acl_cisco_get_seq(struct access_list *acl, const char *action,  	struct filter f, *fn;  	memset(&f, 0, sizeof(f)); -	memset(&fc, 0, sizeof(fc));  	f.cisco = 1;  	if (strcmp(action, "permit") == 0)  		f.type = FILTER_PERMIT; @@ -110,7 +103,8 @@ static int64_t acl_zebra_get_seq(struct access_list *acl, const char *action,  		f.type = FILTER_DENY;  	fz = &f.u.zfilter; -	fz->prefix = *p; +	if (p->family) +		prefix_copy(&fz->prefix, p);  	fz->exact = exact;  	fn = filter_lookup_zebra(acl, &f); @@ -130,6 +124,7 @@ static void concat_addr_mask_v4(const char *addr, const char *mask, char *dst,  	int plen;  	assert(inet_pton(AF_INET, mask, &ia) == 1); +	ia.s_addr = ~ia.s_addr;  	plen = ip_masklen(ia);  	snprintf(dst, dstlen, "%s/%d", addr, plen);  } @@ -171,17 +166,15 @@ static long acl_get_seq(struct vty *vty, const char *xpath)   */  DEFPY_YANG(  	access_list_std, access_list_std_cmd, -	"access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>", +	"access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",  	ACCESS_LIST_STR  	ACCESS_LIST_LEG_STR -	ACCESS_LIST_LEG_EXT_STR  	ACCESS_LIST_SEQ_STR  	ACCESS_LIST_ACTION_STR  	"A single host address\n"  	"Address to match\n"  	"Address to match\n" -	"Wildcard bits\n" -	"Any source host\n") +	"Wildcard bits\n")  {  	int64_t sseq;  	char ipmask[64]; @@ -193,8 +186,7 @@ DEFPY_YANG(  	 * none given (backward compatibility).  	 */  	snprintf(xpath, sizeof(xpath), -		 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", -		 number_str); +		 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);  	nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);  	if (seq_str == NULL) {  		/* Use XPath to find the next sequence number. */ @@ -222,18 +214,16 @@ DEFPY_YANG(  DEFPY_YANG(  	no_access_list_std, no_access_list_std_cmd, -	"no access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>", +	"no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",  	NO_STR  	ACCESS_LIST_STR  	ACCESS_LIST_LEG_STR -	ACCESS_LIST_LEG_EXT_STR  	ACCESS_LIST_SEQ_STR  	ACCESS_LIST_ACTION_STR  	"A single host address\n"  	"Address to match\n"  	"Address to match\n" -	"Wildcard bits\n" -	"Any source host\n") +	"Wildcard bits\n")  {  	struct access_list *acl;  	struct lyd_node *dnode; @@ -246,15 +236,14 @@ DEFPY_YANG(  		snprintf(  			xpath, sizeof(xpath),  			"/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']", -			number_str, seq_str); +			name, seq_str);  		nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);  		return nb_cli_apply_changes(vty, NULL);  	}  	/* Otherwise, to keep compatibility, we need to figure it out. */  	snprintf(xpath, sizeof(xpath), -		 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", -		 number_str); +		 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);  	/* Access-list must exist before entries. */  	if (yang_dnode_exists(running_config->dnode, xpath) == false) @@ -263,13 +252,9 @@ DEFPY_YANG(  	/* Use access-list data structure to fetch sequence. */  	dnode = yang_dnode_get(running_config->dnode, xpath);  	acl = nb_running_get_entry(dnode, NULL, true); -	if (host_str != NULL) -		sseq = acl_cisco_get_seq(acl, action, host_str, -					 mask_str ? mask_str : "0.0.0.0", NULL, -					 NULL); -	else -		sseq = acl_cisco_get_seq(acl, action, "0.0.0.0", -					 "255.255.255.255", NULL, NULL); +	sseq = acl_cisco_get_seq(acl, action, host_str, +				 mask_str ? mask_str : CISCO_HOST_WILDCARD_MASK, +				 NULL, NULL);  	if (sseq == -1)  		return CMD_WARNING; @@ -282,10 +267,9 @@ DEFPY_YANG(  DEFPY_YANG(  	access_list_ext, access_list_ext_cmd, -	"access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>", +	"access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",  	ACCESS_LIST_STR  	ACCESS_LIST_ELEG_STR -	ACCESS_LIST_ELEG_EXT_STR  	ACCESS_LIST_SEQ_STR  	ACCESS_LIST_ACTION_STR  	"IPv4 address\n" @@ -301,7 +285,7 @@ DEFPY_YANG(  	"Any destination host\n")  {  	int64_t sseq; -	char ipmask[64]; +	char ipmask[64], ipmask_dst[64];  	char xpath[XPATH_MAXLEN];  	char xpath_entry[XPATH_MAXLEN + 128]; @@ -310,8 +294,7 @@ DEFPY_YANG(  	 * none given (backward compatibility).  	 */  	snprintf(xpath, sizeof(xpath), -		 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", -		 number_str); +		 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);  	nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);  	if (seq_str == NULL) {  		/* Use XPath to find the next sequence number. */ @@ -337,12 +320,12 @@ DEFPY_YANG(  	if (dst_str != NULL && dst_mask_str == NULL) {  		nb_cli_enqueue_change(vty, "./destination-host", NB_OP_MODIFY, -				      src_str); +				      dst_str);  	} else if (dst_str != NULL && dst_mask_str != NULL) { -		concat_addr_mask_v4(dst_str, dst_mask_str, ipmask, -				    sizeof(ipmask)); +		concat_addr_mask_v4(dst_str, dst_mask_str, ipmask_dst, +				    sizeof(ipmask_dst));  		nb_cli_enqueue_change(vty, "./destination-network", -				      NB_OP_MODIFY, ipmask); +				      NB_OP_MODIFY, ipmask_dst);  	} else {  		nb_cli_enqueue_change(vty, "./destination-any", NB_OP_CREATE,  				      NULL); @@ -353,11 +336,10 @@ DEFPY_YANG(  DEFPY_YANG(  	no_access_list_ext, no_access_list_ext_cmd, -	"no access-list <(100-199)|(2000-2699)>$number [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>", +	"no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",  	NO_STR  	ACCESS_LIST_STR  	ACCESS_LIST_ELEG_STR -	ACCESS_LIST_ELEG_EXT_STR  	ACCESS_LIST_SEQ_STR  	ACCESS_LIST_ACTION_STR  	"Any Internet Protocol\n" @@ -383,15 +365,14 @@ DEFPY_YANG(  		snprintfrr(  			xpath, sizeof(xpath),  			"/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']", -			number_str, seq_str); +			name, seq_str);  		nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);  		return nb_cli_apply_changes(vty, NULL);  	}  	/* Otherwise, to keep compatibility, we need to figure it out. */  	snprintf(xpath, sizeof(xpath), -		 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", -		 number_str); +		 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name);  	/* Access-list must exist before entries. */  	if (yang_dnode_exists(running_config->dnode, xpath) == false) @@ -404,24 +385,28 @@ DEFPY_YANG(  		if (dst_str != NULL)  			sseq = acl_cisco_get_seq(  				acl, action, src_str, -				src_mask_str ? src_mask_str : "0.0.0.0", +				src_mask_str ? src_mask_str +					     : CISCO_HOST_WILDCARD_MASK,  				dst_str, -				dst_mask_str ? dst_mask_str : "0.0.0.0"); +				dst_mask_str ? dst_mask_str +					     : CISCO_HOST_WILDCARD_MASK);  		else -			sseq = acl_cisco_get_seq(acl, action, src_str, -						 src_mask_str ? src_mask_str -							      : "0.0.0.0", -						 "0.0.0.0", "255.255.255.255"); +			sseq = acl_cisco_get_seq( +				acl, action, src_str, +				src_mask_str ? src_mask_str +					     : CISCO_HOST_WILDCARD_MASK, +				"0.0.0.0", CISCO_ANY_WILDCARD_MASK);  	} else {  		if (dst_str != NULL) -			sseq = acl_cisco_get_seq(acl, action, "0.0.0.0", -						 "255.255.255.255", dst_str, -						 dst_mask_str ? dst_mask_str -							      : "0.0.0.0"); +			sseq = acl_cisco_get_seq( +				acl, action, "0.0.0.0", CISCO_ANY_WILDCARD_MASK, +				dst_str, +				dst_mask_str ? dst_mask_str +					     : CISCO_HOST_WILDCARD_MASK);  		else -			sseq = acl_cisco_get_seq(acl, action, "0.0.0.0", -						 "255.255.255.255", "0.0.0.0", -						 "255.255.255.255"); +			sseq = acl_cisco_get_seq( +				acl, action, "0.0.0.0", CISCO_ANY_WILDCARD_MASK, +				"0.0.0.0", CISCO_ANY_WILDCARD_MASK);  	}  	if (sseq == -1)  		return CMD_WARNING; @@ -522,7 +507,7 @@ DEFPY_YANG(  	/* Use access-list data structure to fetch sequence. */  	dnode = yang_dnode_get(running_config->dnode, xpath);  	acl = nb_running_get_entry(dnode, NULL, true); -	if (prefix == NULL) { +	if (prefix_str == NULL) {  		memset(&pany, 0, sizeof(pany));  		pany.family = AF_INET;  		sseq = acl_zebra_get_seq(acl, action, &pany, exact); diff --git a/lib/filter_nb.c b/lib/filter_nb.c index 91691d2f1d..8838a48abd 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -29,6 +29,7 @@  #include "lib/filter.h"  #include "lib/plist.h"  #include "lib/plist_int.h" +#include "lib/routemap.h"  /* Helper function. */  static in_addr_t @@ -40,6 +41,22 @@ ipv4_network_addr(in_addr_t hostaddr, int masklen)  	return hostaddr & mask.s_addr;  } +static void acl_notify_route_map(struct access_list *acl, int route_map_event) +{ +	switch (route_map_event) { +	case RMAP_EVENT_FILTER_ADDED: +		if (acl->master->add_hook) +			(*acl->master->add_hook)(acl); +		break; +	case RMAP_EVENT_FILTER_DELETED: +		if (acl->master->delete_hook) +			(*acl->master->delete_hook)(acl); +		break; +	} + +	route_map_notify_dependencies(acl->name, route_map_event); +} +  static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args)  {  	int type = yang_dnode_get_enum(args->dnode, "../../type"); @@ -112,6 +129,19 @@ static void prefix_list_entry_set_empty(struct prefix_list_entry *ple)  	ple->le = 0;  } +/** + * Unsets the cisco style rule for addresses so it becomes disabled (the + * equivalent of setting: `0.0.0.0/32`). + * + * \param addr address part. + * \param mask mask part. + */ +static void cisco_unset_addr_mask(struct in_addr *addr, struct in_addr *mask) +{ +	addr->s_addr = INADDR_ANY; +	mask->s_addr = CISCO_BIN_HOST_WILDCARD_MASK; +} +  /*   * XPath: /frr-filter:lib/access-list   */ @@ -255,6 +285,8 @@ lib_access_list_entry_action_modify(struct nb_cb_modify_args *args)  	else  		f->type = FILTER_DENY; +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); +  	return NB_OK;  } @@ -275,6 +307,8 @@ lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)  	fz = &f->u.zfilter;  	yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL); +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); +  	return NB_OK;  } @@ -291,6 +325,8 @@ lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)  	fz = &f->u.zfilter;  	memset(&fz->prefix, 0, sizeof(fz->prefix)); +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); +  	return NB_OK;  } @@ -310,6 +346,8 @@ lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)  	fz = &f->u.zfilter;  	fz->exact = yang_dnode_get_bool(args->dnode, NULL); +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); +  	return NB_OK;  } @@ -326,6 +364,8 @@ lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)  	fz = &f->u.zfilter;  	fz->exact = 0; +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); +  	return NB_OK;  } @@ -345,7 +385,9 @@ lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)  	f->cisco = 1;  	fc = &f->u.cfilter;  	yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL); -	fc->addr_mask.s_addr = INADDR_ANY; +	fc->addr_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK; + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);  	return NB_OK;  } @@ -361,8 +403,9 @@ lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args)  	f = nb_running_get_entry(args->dnode, NULL, true);  	fc = &f->u.cfilter; -	fc->addr.s_addr = INADDR_ANY; -	fc->addr_mask.s_addr = INADDR_NONE; +	cisco_unset_addr_mask(&fc->addr, &fc->addr_mask); + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);  	return NB_OK;  } @@ -386,6 +429,9 @@ lib_access_list_entry_network_modify(struct nb_cb_modify_args *args)  	yang_dnode_get_prefix(&p, args->dnode, NULL);  	fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);  	masklen2ip(p.prefixlen, &fc->addr_mask); +	fc->addr_mask.s_addr = ~fc->addr_mask.s_addr; + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);  	return NB_OK;  } @@ -401,8 +447,9 @@ lib_access_list_entry_network_destroy(struct nb_cb_destroy_args *args)  	f = nb_running_get_entry(args->dnode, NULL, true);  	fc = &f->u.cfilter; -	fc->addr.s_addr = INADDR_ANY; -	fc->addr_mask.s_addr = INADDR_NONE; +	cisco_unset_addr_mask(&fc->addr, &fc->addr_mask); + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);  	return NB_OK;  } @@ -423,7 +470,9 @@ lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)  	f->cisco = 1;  	fc = &f->u.cfilter;  	fc->addr.s_addr = INADDR_ANY; -	fc->addr_mask.s_addr = INADDR_NONE; +	fc->addr_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK; + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);  	return NB_OK;  } @@ -439,8 +488,9 @@ lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args)  	f = nb_running_get_entry(args->dnode, NULL, true);  	fc = &f->u.cfilter; -	fc->addr.s_addr = INADDR_ANY; -	fc->addr_mask.s_addr = INADDR_NONE; +	cisco_unset_addr_mask(&fc->addr, &fc->addr_mask); + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);  	return NB_OK;  } @@ -461,7 +511,9 @@ static int lib_access_list_entry_destination_host_modify(  	fc = &f->u.cfilter;  	fc->extended = 1;  	yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL); -	fc->mask_mask.s_addr = INADDR_ANY; +	fc->mask_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK; + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);  	return NB_OK;  } @@ -478,8 +530,9 @@ static int lib_access_list_entry_destination_host_destroy(  	f = nb_running_get_entry(args->dnode, NULL, true);  	fc = &f->u.cfilter;  	fc->extended = 0; -	fc->mask.s_addr = INADDR_ANY; -	fc->mask_mask.s_addr = INADDR_NONE; +	cisco_unset_addr_mask(&fc->mask, &fc->mask_mask); + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);  	return NB_OK;  } @@ -503,6 +556,9 @@ static int lib_access_list_entry_destination_network_modify(  	yang_dnode_get_prefix(&p, args->dnode, NULL);  	fc->mask.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);  	masklen2ip(p.prefixlen, &fc->mask_mask); +	fc->mask_mask.s_addr = ~fc->mask_mask.s_addr; + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);  	return NB_OK;  } @@ -519,8 +575,9 @@ static int lib_access_list_entry_destination_network_destroy(  	f = nb_running_get_entry(args->dnode, NULL, true);  	fc = &f->u.cfilter;  	fc->extended = 0; -	fc->mask.s_addr = INADDR_ANY; -	fc->mask_mask.s_addr = INADDR_NONE; +	cisco_unset_addr_mask(&fc->mask, &fc->mask_mask); + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);  	return NB_OK;  } @@ -541,7 +598,9 @@ static int lib_access_list_entry_destination_any_create(  	fc = &f->u.cfilter;  	fc->extended = 1;  	fc->mask.s_addr = INADDR_ANY; -	fc->mask_mask.s_addr = INADDR_NONE; +	fc->mask_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK; + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);  	return NB_OK;  } @@ -558,8 +617,9 @@ static int lib_access_list_entry_destination_any_destroy(  	f = nb_running_get_entry(args->dnode, NULL, true);  	fc = &f->u.cfilter;  	fc->extended = 0; -	fc->mask.s_addr = INADDR_ANY; -	fc->mask_mask.s_addr = INADDR_NONE; +	cisco_unset_addr_mask(&fc->mask, &fc->mask_mask); + +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);  	return NB_OK;  } @@ -594,6 +654,8 @@ static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)  		break;  	} +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED); +  	return NB_OK;  } @@ -609,6 +671,8 @@ static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)  	fz = &f->u.zfilter;  	fz->prefix.family = 0; +	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED); +  	return NB_OK;  } diff --git a/lib/hash.c b/lib/hash.c index 7f8a237047..85982774ac 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -77,9 +77,20 @@ void *hash_alloc_intern(void *arg)  	return arg;  } +/* + * ssq = ssq + (new^2 - old^2) + *     = ssq + ((new + old) * (new - old)) + */  #define hash_update_ssq(hz, old, new)                                          \ -	atomic_fetch_add_explicit(&hz->stats.ssq, (new + old) * (new - old),   \ -				  memory_order_relaxed); +	do {                                                                   \ +		int _adjust = (new + old) * (new - old);                       \ +		if (_adjust < 0)                                               \ +			atomic_fetch_sub_explicit(&hz->stats.ssq, -_adjust,    \ +						  memory_order_relaxed);       \ +		else                                                           \ +			atomic_fetch_add_explicit(&hz->stats.ssq, _adjust,     \ +						  memory_order_relaxed);       \ +	} while (0)  /* Expand hash if the chain length exceeds the threshold. */  static void hash_expand(struct hash *hash) diff --git a/lib/mpls.h b/lib/mpls.h index 8922a36664..74bd7aae3e 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -72,8 +72,7 @@ extern "C" {  /* Maximum # labels that can be pushed. */  #define MPLS_MAX_LABELS                    16 -#define IS_MPLS_RESERVED_LABEL(label)                                          \ -	(label >= MPLS_LABEL_RESERVED_MIN && label <= MPLS_LABEL_RESERVED_MAX) +#define IS_MPLS_RESERVED_LABEL(label) (label <= MPLS_LABEL_RESERVED_MAX)  #define IS_MPLS_UNRESERVED_LABEL(label)                                        \  	(label >= MPLS_LABEL_UNRESERVED_MIN                                    \ diff --git a/lib/privs.c b/lib/privs.c index 5c7e1240e2..dc43b7279d 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -1020,11 +1020,11 @@ void zprivs_get_ids(struct zprivs_ids_t *ids)  	ids->uid_priv = getuid();  	(zprivs_state.zuid) ? (ids->uid_normal = zprivs_state.zuid) -			    : (ids->uid_normal = -1); +			    : (ids->uid_normal = (uid_t)-1);  	(zprivs_state.zgid) ? (ids->gid_normal = zprivs_state.zgid) -			    : (ids->gid_normal = -1); +			    : (ids->gid_normal = (uid_t)-1);  	(zprivs_state.vtygrp) ? (ids->gid_vty = zprivs_state.vtygrp) -			      : (ids->gid_vty = -1); +			      : (ids->gid_vty = (uid_t)-1);  	return;  } diff --git a/lib/stream.c b/lib/stream.c index 6e62e11380..dc207c16a4 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -268,6 +268,30 @@ bool stream_forward_getp2(struct stream *s, size_t size)  	return true;  } +void stream_rewind_getp(struct stream *s, size_t size) +{ +	STREAM_VERIFY_SANE(s); + +	if (size > s->getp || !GETP_VALID(s, s->getp - size)) { +		STREAM_BOUND_WARN(s, "rewind getp"); +		return; +	} + +	s->getp -= size; +} + +bool stream_rewind_getp2(struct stream *s, size_t size) +{ +	STREAM_VERIFY_SANE(s); + +	if (size > s->getp || !GETP_VALID(s, s->getp - size)) +		return false; + +	s->getp -= size; + +	return true; +} +  void stream_forward_endp(struct stream *s, size_t size)  {  	STREAM_VERIFY_SANE(s); diff --git a/lib/stream.h b/lib/stream.h index f2c16b3486..23f85d809b 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -160,7 +160,6 @@ extern size_t stream_resize_inplace(struct stream **sptr, size_t newsize);  extern size_t stream_get_getp(const struct stream *s);  extern size_t stream_get_endp(const struct stream *s);  extern size_t stream_get_size(const struct stream *s); -extern uint8_t *stream_get_data(struct stream *s);  /**   * Create a new stream structure; copy offset bytes from s1 to the new @@ -174,6 +173,8 @@ extern void stream_set_getp(struct stream *, size_t);  extern void stream_set_endp(struct stream *, size_t);  extern void stream_forward_getp(struct stream *, size_t);  extern bool stream_forward_getp2(struct stream *, size_t); +extern void stream_rewind_getp(struct stream *s, size_t size); +extern bool stream_rewind_getp2(struct stream *s, size_t size);  extern void stream_forward_endp(struct stream *, size_t);  extern bool stream_forward_endp2(struct stream *, size_t); @@ -461,6 +462,12 @@ static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)  			goto stream_failure;                                   \  	} while (0) +#define STREAM_REWIND_GETP(STR, SIZE)                                          \ +	do {                                                                   \ +		if (!stream_rewind_getp2((STR), (SIZE)))                       \ +			goto stream_failure;                                   \ +	} while (0) +  #define STREAM_FORWARD_ENDP(STR, SIZE)                                         \  	do {                                                                   \  		if (!stream_forward_endp2((STR), (SIZE)))                      \ diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index b339790492..6fe3a289ce 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -72,7 +72,7 @@ static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route *route,  	struct ospf6_interface *oi;  	oi = ospf6_interface_lookup_by_ifindex( -		ospf6_route_get_first_nh_index(route)); +		ospf6_route_get_first_nh_index(route), area->ospf6->vrf_id);  	if (oi && oi->area && oi->area == area)  		return 1;  	else diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 5562529ea8..71ca5afcd2 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -47,8 +47,8 @@  #include "ospf6_flood.h"  #include "ospf6d.h" -static void ospf6_asbr_redistribute_set(int type); -static void ospf6_asbr_redistribute_unset(int type); +static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id); +static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id);  unsigned char conf_debug_ospf6_asbr = 0; @@ -881,8 +881,8 @@ static int ospf6_asbr_routemap_update_timer(struct thread *thread)  				   __func__, ospf6->rmap[arg_type].name,  				   ZROUTE_NAME(arg_type)); -		ospf6_zebra_no_redistribute(arg_type); -		ospf6_zebra_redistribute(arg_type); +		ospf6_zebra_no_redistribute(arg_type, ospf6->vrf_id); +		ospf6_zebra_redistribute(arg_type, ospf6->vrf_id);  	}  	XFREE(MTYPE_OSPF6_DIST_ARGS, arg); @@ -948,9 +948,11 @@ static void ospf6_asbr_routemap_update(const char *mapname)  							"%s: route-map %s deleted, reset redist %s",  							__func__, mapname,  							ZROUTE_NAME(type)); -					ospf6_asbr_redistribute_unset(type); +					ospf6_asbr_redistribute_unset( +						type, ospf6->vrf_id);  					ospf6_asbr_routemap_set(type, mapname); -					ospf6_asbr_redistribute_set(type); +					ospf6_asbr_redistribute_set( +						type, ospf6->vrf_id);  				}  			}  		} else @@ -977,17 +979,17 @@ int ospf6_asbr_is_asbr(struct ospf6 *o)  	return o->external_table->count;  } -static void ospf6_asbr_redistribute_set(int type) +static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id)  { -	ospf6_zebra_redistribute(type); +	ospf6_zebra_redistribute(type, vrf_id);  } -static void ospf6_asbr_redistribute_unset(int type) +static void ospf6_asbr_redistribute_unset(int type, vrf_id_t vrf_id)  {  	struct ospf6_route *route;  	struct ospf6_external_info *info; -	ospf6_zebra_no_redistribute(type); +	ospf6_zebra_no_redistribute(type, vrf_id);  	for (route = ospf6_route_head(ospf6->external_table); route;  	     route = ospf6_route_next(route)) { @@ -1031,7 +1033,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,  	struct listnode *lnode, *lnnode;  	struct ospf6_area *oa; -	if (!ospf6_zebra_is_redistribute(type)) +	if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))  		return;  	memset(&troute, 0, sizeof(troute)); @@ -1243,13 +1245,15 @@ DEFUN (ospf6_redistribute,  {  	int type; +	OSPF6_CMD_CHECK_RUNNING(); +  	char *proto = argv[argc - 1]->text;  	type = proto_redistnum(AFI_IP6, proto);  	if (type < 0)  		return CMD_WARNING_CONFIG_FAILED; -	ospf6_asbr_redistribute_unset(type); -	ospf6_asbr_redistribute_set(type); +	ospf6_asbr_redistribute_unset(type, ospf6->vrf_id); +	ospf6_asbr_redistribute_set(type, ospf6->vrf_id);  	return CMD_SUCCESS;  } @@ -1265,14 +1269,16 @@ DEFUN (ospf6_redistribute_routemap,  	int idx_word = 3;  	int type; +	OSPF6_CMD_CHECK_RUNNING(); +  	char *proto = argv[idx_protocol]->text;  	type = proto_redistnum(AFI_IP6, proto);  	if (type < 0)  		return CMD_WARNING_CONFIG_FAILED; -	ospf6_asbr_redistribute_unset(type); +	ospf6_asbr_redistribute_unset(type, ospf6->vrf_id);  	ospf6_asbr_routemap_set(type, argv[idx_word]->arg); -	ospf6_asbr_redistribute_set(type); +	ospf6_asbr_redistribute_set(type, ospf6->vrf_id);  	return CMD_SUCCESS;  } @@ -1288,12 +1294,14 @@ DEFUN (no_ospf6_redistribute,  	int idx_protocol = 2;  	int type; +	OSPF6_CMD_CHECK_RUNNING(); +  	char *proto = argv[idx_protocol]->text;  	type = proto_redistnum(AFI_IP6, proto);  	if (type < 0)  		return CMD_WARNING_CONFIG_FAILED; -	ospf6_asbr_redistribute_unset(type); +	ospf6_asbr_redistribute_unset(type, ospf6->vrf_id);  	return CMD_SUCCESS;  } @@ -1305,7 +1313,7 @@ int ospf6_redistribute_config_write(struct vty *vty)  	for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {  		if (type == ZEBRA_ROUTE_OSPF6)  			continue; -		if (!ospf6_zebra_is_redistribute(type)) +		if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))  			continue;  		if (ospf6->rmap[type].name) @@ -1340,7 +1348,7 @@ static void ospf6_redistribute_show_config(struct vty *vty)  	for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {  		if (type == ZEBRA_ROUTE_OSPF6)  			continue; -		if (!ospf6_zebra_is_redistribute(type)) +		if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))  			continue;  		if (ospf6->rmap[type].name) @@ -1408,7 +1416,7 @@ ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,  	if (type == RMAP_OSPF6) {  		ei = ((struct ospf6_route *)object)->route_option; -		ifp = if_lookup_by_name((char *)rule, VRF_DEFAULT); +		ifp = if_lookup_by_name_all_vrf((char *)rule);  		if (ifp != NULL && ei->ifindex == ifp->ifindex)  			return RMAP_MATCH; @@ -1880,15 +1888,15 @@ void ospf6_asbr_init(void)  	install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd);  } -void ospf6_asbr_redistribute_reset(void) +void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id)  {  	int type;  	for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {  		if (type == ZEBRA_ROUTE_OSPF6)  			continue; -		if (ospf6_zebra_is_redistribute(type)) -			ospf6_asbr_redistribute_unset(type); +		if (ospf6_zebra_is_redistribute(type, vrf_id)) +			ospf6_asbr_redistribute_unset(type, vrf_id);  	}  } diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index 9890ef0619..41b1ac70e9 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -88,7 +88,7 @@ extern void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,  extern int ospf6_redistribute_config_write(struct vty *vty);  extern void ospf6_asbr_init(void); -extern void ospf6_asbr_redistribute_reset(void); +extern void ospf6_asbr_redistribute_reset(vrf_id_t vrf_id);  extern void ospf6_asbr_terminate(void);  extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *); diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c index 916e59baf0..1b58cd14f6 100644 --- a/ospf6d/ospf6_bfd.c +++ b/ospf6d/ospf6_bfd.c @@ -89,8 +89,8 @@ void ospf6_bfd_reg_dereg_nbr(struct ospf6_neighbor *on, int command)  	cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);  	bfd_peer_sendmsg(zclient, bfd_info, AF_INET6, &on->linklocal_addr, -			 on->ospf6_if->linklocal_addr, ifp->name, 0, 0, -			 cbit, command, 0, VRF_DEFAULT); +			 on->ospf6_if->linklocal_addr, ifp->name, 0, 0, cbit, +			 command, 0, ifp->vrf_id);  	if (command == ZEBRA_BFD_DEST_DEREGISTER)  		bfd_info_free((struct bfd_info **)&on->bfd_info); @@ -143,7 +143,7 @@ static void ospf6_bfd_reg_dereg_all_nbr(struct ospf6_interface *oi, int command)   */  static int ospf6_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)  { -	struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); +	struct vrf *vrf = vrf_lookup_by_id(vrf_id);  	struct listnode *node;  	struct interface *ifp;  	struct ospf6_interface *oi; diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index d10329a93b..fabcc426ea 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -56,12 +56,13 @@ const char *const ospf6_interface_state_str[] = {  	"None",    "Down", "Loopback", "Waiting", "PointToPoint",  	"DROther", "BDR",  "DR",       NULL}; -struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t ifindex) +struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t ifindex, +							  vrf_id_t vrf_id)  {  	struct ospf6_interface *oi;  	struct interface *ifp; -	ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); +	ifp = if_lookup_by_index(ifindex, vrf_id);  	if (ifp == NULL)  		return (struct ospf6_interface *)NULL; @@ -1022,7 +1023,7 @@ DEFUN (show_ipv6_ospf6_interface,  	return CMD_SUCCESS;  } -static int ospf6_interface_show_traffic(struct vty *vty, uint32_t vrf_id, +static int ospf6_interface_show_traffic(struct vty *vty,  					struct interface *intf_ifp,  					int display_once)  { @@ -1030,7 +1031,10 @@ static int ospf6_interface_show_traffic(struct vty *vty, uint32_t vrf_id,  	struct vrf *vrf = NULL;  	struct ospf6_interface *oi = NULL; -	vrf = vrf_lookup_by_id(vrf_id); +	if (intf_ifp) +		vrf = vrf_lookup_by_id(intf_ifp->vrf_id); +	else +		vrf = vrf_lookup_by_id(VRF_DEFAULT);  	if (!display_once) {  		vty_out(vty, "\n"); @@ -1105,7 +1109,7 @@ DEFUN (show_ipv6_ospf6_interface_traffic,  		}  	} -	ospf6_interface_show_traffic(vty, VRF_DEFAULT, ifp, display_once); +	ospf6_interface_show_traffic(vty, ifp, display_once);  	return CMD_SUCCESS; diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 6cbfe04c44..dd7f4d1b1e 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -170,7 +170,8 @@ extern const char *const ospf6_interface_state_str[];  /* Function Prototypes */ -extern struct ospf6_interface *ospf6_interface_lookup_by_ifindex(ifindex_t); +extern struct ospf6_interface * +ospf6_interface_lookup_by_ifindex(ifindex_t, vrf_id_t vrf_id);  extern struct ospf6_interface *ospf6_interface_create(struct interface *);  extern void ospf6_interface_delete(struct ospf6_interface *); diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index ef5d1d0583..6eda9f750c 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1569,8 +1569,8 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,  				if (intra_prefix_lsa->ref_adv_router  				     == oa->ospf6->router_id) {  					ifp = if_lookup_prefix( -							&old_route->prefix, -							VRF_DEFAULT); +						&old_route->prefix, +						oa->ospf6->vrf_id);  					if (ifp)  						ospf6_route_add_nexthop(  								old_route, @@ -1714,7 +1714,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa)  		memcpy(&route->path.ls_prefix, &ls_prefix,  		       sizeof(struct prefix));  		if (direct_connect) { -			ifp = if_lookup_prefix(&route->prefix, VRF_DEFAULT); +			ifp = if_lookup_prefix(&route->prefix, +					       oa->ospf6->vrf_id);  			if (ifp)  				ospf6_route_add_nexthop(route, ifp->ifindex,  							NULL); diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 8ae5fdcf06..182faf0038 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -79,15 +79,17 @@ struct thread_master *master;  static void __attribute__((noreturn)) ospf6_exit(int status)  { -	struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); +	struct vrf *vrf;  	struct interface *ifp;  	frr_early_fini();  	if (ospf6) { +		vrf = vrf_lookup_by_id(ospf6->vrf_id);  		ospf6_delete(ospf6);  		ospf6 = NULL; -	} +	} else +		vrf = vrf_lookup_by_id(VRF_DEFAULT);  	bfd_gbl_exit(); diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index f891f548ae..4830b38a66 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -1554,7 +1554,7 @@ int ospf6_receive(struct thread *thread)  		return 0;  	} -	oi = ospf6_interface_lookup_by_ifindex(ifindex); +	oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);  	if (oi == NULL || oi->area == NULL  	    || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {  		if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 723746c471..a443e4c3ba 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -307,14 +307,14 @@ void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,  				inet_ntop(AF_INET6, &nh->address, buf,  					  sizeof(buf));  				ifname = ifindex2ifname(nh->ifindex, -							VRF_DEFAULT); +							ospf6->vrf_id);  				zlog_debug("  nexthop: %s%%%.*s(%d)", buf,  					   IFNAMSIZ, ifname, nh->ifindex);  			}  			if (i >= entries)  				return; -			nexthops[i].vrf_id = VRF_DEFAULT; +			nexthops[i].vrf_id = ospf6->vrf_id;  			nexthops[i].ifindex = nh->ifindex;  			if (!IN6_IS_ADDR_UNSPECIFIED(&nh->address)) {  				nexthops[i].gate.ipv6 = nh->address; @@ -1042,6 +1042,11 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route)  	struct listnode *node;  	struct ospf6_nexthop *nh; +	if (ospf6 == NULL) { +		vty_out(vty, "OSPFv3 is not running\n"); +		return; +	} +  	monotime(&now);  	timersub(&now, &route->changed, &res);  	timerstring(&res, duration, sizeof(duration)); @@ -1060,7 +1065,7 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route)  	for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {  		/* nexthop */  		inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop)); -		ifname = ifindex2ifname(nh->ifindex, VRF_DEFAULT); +		ifname = ifindex2ifname(nh->ifindex, ospf6->vrf_id);  		if (!i) {  			vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n", @@ -1086,6 +1091,11 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route)  	struct listnode *node;  	struct ospf6_nexthop *nh; +	if (ospf6 == NULL) { +		vty_out(vty, "OSPFv3 is not running\n"); +		return; +	} +  	monotime(&now);  	/* destination */ @@ -1160,7 +1170,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route)  	for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {  		/* nexthop */  		inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop)); -		ifname = ifindex2ifname(nh->ifindex, VRF_DEFAULT); +		ifname = ifindex2ifname(nh->ifindex, ospf6->vrf_id);  		vty_out(vty, "  %s %.*s\n", nexthop, IFNAMSIZ, ifname);  	}  	vty_out(vty, "\n"); diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 9a1141f631..57cc055296 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -837,7 +837,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,  				  int exact, size_t *var_len,  				  WriteMethod **write_method)  { -	struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); +	struct vrf *vrf;  	struct ospf6_lsa *lsa = NULL;  	ifindex_t ifindex;  	uint32_t area_id, id, instid, adv_router; @@ -861,6 +861,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,  	if (ospf6 == NULL)  		return NULL; +	vrf = vrf_lookup_by_id(ospf6->vrf_id);  	/* Get variable length. */  	offset = name + v->namelen;  	offsetlen = *length - v->namelen; @@ -926,7 +927,8 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,  				return NULL;  			lsa = ospf6_lsdb_lookup(type, id, adv_router, oa->lsdb);  		} else if (v->magic & OSPFv3WWLINKTABLE) { -			oi = ospf6_interface_lookup_by_ifindex(ifindex); +			oi = ospf6_interface_lookup_by_ifindex(ifindex, +							       ospf6->vrf_id);  			if (!oi || oi->instance_id != instid)  				return NULL;  			lsa = ospf6_lsdb_lookup(type, id, adv_router, oi->lsdb); @@ -963,7 +965,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length,  				if (!iif->ifindex)  					continue;  				oi = ospf6_interface_lookup_by_ifindex( -					iif->ifindex); +					iif->ifindex, iif->vrf_id);  				if (!oi)  					continue;  				if (iif->ifindex < ifindex) @@ -1038,7 +1040,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,  			      int exact, size_t *var_len,  			      WriteMethod **write_method)  { -	struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); +	struct vrf *vrf;  	ifindex_t ifindex = 0;  	unsigned int instid = 0;  	struct ospf6_interface *oi = NULL; @@ -1058,6 +1060,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,  	if (ospf6 == NULL)  		return NULL; +	vrf = vrf_lookup_by_id(ospf6->vrf_id);  	/* Get variable length. */  	offset = name + v->namelen;  	offsetlen = *length - v->namelen; @@ -1080,7 +1083,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,  	// offsetlen -= len;  	if (exact) { -		oi = ospf6_interface_lookup_by_ifindex(ifindex); +		oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);  		if (!oi || oi->instance_id != instid)  			return NULL;  	} else { @@ -1095,7 +1098,8 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length,  		for (ALL_LIST_ELEMENTS_RO(ifslist, i, iif)) {  			if (!iif->ifindex)  				continue; -			oi = ospf6_interface_lookup_by_ifindex(iif->ifindex); +			oi = ospf6_interface_lookup_by_ifindex(iif->ifindex, +							       iif->vrf_id);  			if (!oi)  				continue;  			if (iif->ifindex > ifindex @@ -1191,7 +1195,7 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,  			       int exact, size_t *var_len,  			       WriteMethod **write_method)  { -	struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); +	struct vrf *vrf;  	ifindex_t ifindex = 0;  	unsigned int instid, rtrid;  	struct ospf6_interface *oi = NULL; @@ -1212,6 +1216,7 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,  	if (ospf6 == NULL)  		return NULL; +	vrf = vrf_lookup_by_id(ospf6->vrf_id);  	/* Get variable length. */  	offset = name + v->namelen;  	offsetlen = *length - v->namelen; @@ -1241,7 +1246,7 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,  	// offsetlen -= len;  	if (exact) { -		oi = ospf6_interface_lookup_by_ifindex(ifindex); +		oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);  		if (!oi || oi->instance_id != instid)  			return NULL;  		on = ospf6_neighbor_lookup(rtrid, oi); @@ -1257,7 +1262,8 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length,  		for (ALL_LIST_ELEMENTS_RO(ifslist, i, iif)) {  			if (!iif->ifindex)  				continue; -			oi = ospf6_interface_lookup_by_ifindex(iif->ifindex); +			oi = ospf6_interface_lookup_by_ifindex(iif->ifindex, +							       iif->vrf_id);  			if (!oi)  				continue;  			for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) { diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index e75c132956..e5eb8d74eb 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -278,7 +278,7 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,  		return;  	} -	oi = ospf6_interface_lookup_by_ifindex(ifindex); +	oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);  	if (oi == NULL) {  		if (IS_OSPF6_DEBUG_SPF(PROCESS))  			zlog_debug("Can't find interface in SPF: ifindex %d", diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 50687a7290..6f23051dc3 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -232,7 +232,7 @@ static void ospf6_disable(struct ospf6 *o)  			ospf6_area_disable(oa);  		/* XXX: This also changes persistent settings */ -		ospf6_asbr_redistribute_reset(); +		ospf6_asbr_redistribute_reset(o->vrf_id);  		ospf6_lsdb_remove_all(o->lsdb);  		ospf6_route_remove_all(o->route_table); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 2773a666a3..62e0e149b8 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -75,25 +75,25 @@ static int ospf6_router_id_update_zebra(ZAPI_CALLBACK_ARGS)  }  /* redistribute function */ -void ospf6_zebra_redistribute(int type) +void ospf6_zebra_redistribute(int type, vrf_id_t vrf_id)  { -	if (vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT)) +	if (vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id))  		return; -	vrf_bitmap_set(zclient->redist[AFI_IP6][type], VRF_DEFAULT); +	vrf_bitmap_set(zclient->redist[AFI_IP6][type], vrf_id);  	if (zclient->sock > 0)  		zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, -					AFI_IP6, type, 0, VRF_DEFAULT); +					AFI_IP6, type, 0, vrf_id);  } -void ospf6_zebra_no_redistribute(int type) +void ospf6_zebra_no_redistribute(int type, vrf_id_t vrf_id)  { -	if (!vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT)) +	if (!vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id))  		return; -	vrf_bitmap_unset(zclient->redist[AFI_IP6][type], VRF_DEFAULT); +	vrf_bitmap_unset(zclient->redist[AFI_IP6][type], vrf_id);  	if (zclient->sock > 0)  		zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, -					AFI_IP6, type, 0, VRF_DEFAULT); +					AFI_IP6, type, 0, vrf_id);  }  static int ospf6_zebra_if_address_update_add(ZAPI_CALLBACK_ARGS) @@ -279,7 +279,7 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request)  	dest = &request->prefix;  	memset(&api, 0, sizeof(api)); -	api.vrf_id = VRF_DEFAULT; +	api.vrf_id = ospf6->vrf_id;  	api.type = ZEBRA_ROUTE_OSPF6;  	api.safi = SAFI_UNICAST;  	api.prefix = *dest; @@ -330,7 +330,7 @@ void ospf6_zebra_add_discard(struct ospf6_route *request)  	if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {  		memset(&api, 0, sizeof(api)); -		api.vrf_id = VRF_DEFAULT; +		api.vrf_id = ospf6->vrf_id;  		api.type = ZEBRA_ROUTE_OSPF6;  		api.safi = SAFI_UNICAST;  		api.prefix = *dest; @@ -363,7 +363,7 @@ void ospf6_zebra_delete_discard(struct ospf6_route *request)  	if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {  		memset(&api, 0, sizeof(api)); -		api.vrf_id = VRF_DEFAULT; +		api.vrf_id = ospf6->vrf_id;  		api.type = ZEBRA_ROUTE_OSPF6;  		api.safi = SAFI_UNICAST;  		api.prefix = *dest; diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h index e2f778fa72..d23268303a 100644 --- a/ospf6d/ospf6_zebra.h +++ b/ospf6d/ospf6_zebra.h @@ -45,10 +45,10 @@ extern struct zclient *zclient;  extern void ospf6_zebra_route_update_add(struct ospf6_route *request);  extern void ospf6_zebra_route_update_remove(struct ospf6_route *request); -extern void ospf6_zebra_redistribute(int); -extern void ospf6_zebra_no_redistribute(int); -#define ospf6_zebra_is_redistribute(type)                                      \ -	vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT) +extern void ospf6_zebra_redistribute(int, vrf_id_t vrf_id); +extern void ospf6_zebra_no_redistribute(int, vrf_id_t vrf_id); +#define ospf6_zebra_is_redistribute(type, vrf_id)                              \ +	vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id)  extern void ospf6_zebra_init(struct thread_master *);  extern void ospf6_zebra_add_discard(struct ospf6_route *request);  extern void ospf6_zebra_delete_discard(struct ospf6_route *request); diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 3dbc476172..f6c0504999 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -1802,6 +1802,7 @@ static int ospf_abr_task_timer(struct thread *thread)  	ospf_abr_task(ospf);  	ospf_abr_nssa_task(ospf); /* if nssa-abr, then scan Type-7 LSDB */ +	ospf_asbr_nssa_redist_task(ospf);  	return 0;  } diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 1480b0e391..8fb6402c7e 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -275,6 +275,30 @@ void ospf_asbr_status_update(struct ospf *ospf, uint8_t status)  	ospf_router_lsa_update(ospf);  } +/* If there's redistribution configured, we need to refresh external + * LSAs in order to install Type-7 and flood to all NSSA Areas + */ +void ospf_asbr_nssa_redist_task(struct ospf *ospf) +{ +	int type; + +	for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { +		struct list *red_list; +		struct listnode *node; +		struct ospf_redist *red; + +		red_list = ospf->redist[type]; +		if (!red_list) +			continue; + +		for (ALL_LIST_ELEMENTS_RO(red_list, node, red)) +			ospf_external_lsa_refresh_type( +				ospf, type, red->instance, LSA_REFRESH_FORCE); +	} + +	ospf_external_lsa_refresh_default(ospf); +} +  void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type,  				unsigned short instance)  { diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index 1bcc32e3d8..ede6c47906 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -72,6 +72,7 @@ extern struct external_info *ospf_external_info_lookup(struct ospf *, uint8_t,  						       unsigned short,  						       struct prefix_ipv4 *);  extern void ospf_asbr_status_update(struct ospf *, uint8_t); +extern void ospf_asbr_nssa_redist_task(struct ospf *ospf);  extern void ospf_redistribute_withdraw(struct ospf *, uint8_t, unsigned short);  extern void ospf_asbr_check(void); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index eb125394b8..8cf8430247 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1353,11 +1353,18 @@ static int ospf_distribute_list_update_timer(struct thread *thread)  						default_refresh = 1;  					else if (  						(lsa = ospf_external_info_find_lsa( -							 ospf, &ei->p))) -						ospf_external_lsa_refresh( -							ospf, lsa, ei, -							LSA_REFRESH_IF_CHANGED); -					else +							 ospf, &ei->p))) { +						if (!CHECK_FLAG( +							    lsa->flags, +							    OSPF_LSA_IN_MAXAGE)) +							ospf_external_lsa_refresh( +								ospf, lsa, ei, +								LSA_REFRESH_IF_CHANGED); +						else +							ospf_external_lsa_refresh( +								ospf, lsa, ei, +								LSA_REFRESH_FORCE); +					} else  						ospf_external_lsa_originate(  							ospf, ei);  				} diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index cce97b5dfb..058881cbfc 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -785,8 +785,13 @@ void pbr_map_check_vrf_nh_group_change(const char *nh_group,  			if (pbrms->nhgrp_name)  				continue; -			if (pbrms->nhg -			    && strcmp(nh_group, pbrms->internal_nhg_name)) +			if (pbrms->nhg == NULL) +				continue; + +			if (strcmp(nh_group, pbrms->internal_nhg_name)) +				continue; + +			if (pbrms->nhg->nexthop == NULL)  				continue;  			if (pbrms->nhg->nexthop->vrf_id != old_vrf_id) @@ -810,8 +815,13 @@ void pbr_map_check_interface_nh_group_change(const char *nh_group,  			if (pbrms->nhgrp_name)  				continue; -			if (pbrms->nhg -			    && strcmp(nh_group, pbrms->internal_nhg_name)) +			if (pbrms->nhg == NULL) +				continue; + +			if (strcmp(nh_group, pbrms->internal_nhg_name)) +				continue; + +			if (pbrms->nhg->nexthop == NULL)  				continue;  			if (pbrms->nhg->nexthop->ifindex != oldifindex) diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index e615818a10..3fb3759049 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -708,14 +708,14 @@ struct pbr_nht_individual {  	struct pbr_nexthop_cache *pnhc;  	vrf_id_t old_vrf_id; -	uint32_t valid; +	bool valid;  	bool nhr_matched;  };  static bool  pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc, -				     const struct pbr_nht_individual *pnhi) +				     struct pbr_nht_individual *pnhi)  {  	bool is_valid = pnhc->valid; @@ -736,6 +736,7 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,  		break;  	} +	pnhi->nhr_matched = true;  	if (!pnhi->nhr->nexthop_num) {  		is_valid = false;  		goto done; @@ -767,8 +768,9 @@ done:  	return pnhc->valid;  } -static bool pbr_nht_individual_nexthop_interface_update( -	struct pbr_nexthop_cache *pnhc, const struct pbr_nht_individual *pnhi) +static bool +pbr_nht_individual_nexthop_interface_update(struct pbr_nexthop_cache *pnhc, +					    struct pbr_nht_individual *pnhi)  {  	bool is_valid = pnhc->valid; @@ -779,6 +781,7 @@ static bool pbr_nht_individual_nexthop_interface_update(  	    != pnhi->ifp->ifindex) /* Un-related interface */  		goto done; +	pnhi->nhr_matched = true;  	is_valid = !!if_is_up(pnhi->ifp);  done: @@ -793,9 +796,8 @@ done:   * If the update is un-related, the subroutines shoud just return their cached   * valid state.   */ -static void -pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc, -				  const struct pbr_nht_individual *pnhi) +static void pbr_nht_individual_nexthop_update(struct pbr_nexthop_cache *pnhc, +					      struct pbr_nht_individual *pnhi)  {  	assert(pnhi->nhr || pnhi->ifp); /* Either nexthop or interface update */ @@ -837,7 +839,7 @@ static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b,  	       pnhc->valid);  	if (pnhc->valid) -		pnhi->valid += 1; +		pnhi->valid = true;  }  static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket *b, @@ -869,10 +871,14 @@ static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data)  	old_valid = pnhgc->valid;  	pnhi.nhr = (struct zapi_route *)data; -	pnhi.valid = 0; +	pnhi.valid = false; +	pnhi.nhr_matched = false;  	hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_update_lookup,  		     &pnhi); +	if (!pnhi.nhr_matched) +		return; +  	/*  	 * If any of the specified nexthops are valid we are valid  	 */ @@ -1085,7 +1091,7 @@ pbr_nht_individual_nexthop_interface_update_lookup(struct hash_bucket *b,  	       old_valid, pnhc->valid);  	if (pnhc->valid) -		pnhi->valid += 1; +		pnhi->valid = true;  }  static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b, @@ -1098,14 +1104,14 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,  	old_valid = pnhgc->valid;  	pnhi.ifp = data; -	pnhi.valid = 0; +	pnhi.valid = false;  	hash_iterate(pnhgc->nhh,  		     pbr_nht_individual_nexthop_interface_update_lookup, &pnhi);  	/*  	 * If any of the specified nexthops are valid we are valid  	 */ -	pnhgc->valid = !!pnhi.valid; +	pnhgc->valid = pnhi.valid;  	if (old_valid != pnhgc->valid)  		pbr_map_check_nh_group_change(pnhgc->name); diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h index bcd770c2cf..6346795215 100644 --- a/pbrd/pbr_nht.h +++ b/pbrd/pbr_nht.h @@ -55,6 +55,7 @@ struct pbr_nexthop_cache {  	bool looked_at;  	bool valid; +	bool nhr_matched;  };  extern void pbr_nht_write_table_range(struct vty *vty); diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 929214a142..bd0d5b27f4 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -170,7 +170,7 @@ BuildRequires:  make  BuildRequires:  ncurses-devel  BuildRequires:  readline-devel  BuildRequires:  texinfo -BuildRequires:  libyang-devel >= 0.16.74 +BuildRequires:  libyang-devel >= 1.0.184  %if 0%{?rhel} && 0%{?rhel} < 7  #python27-devel is available from ius community repo for RedHat/CentOS 6  BuildRequires:  python27-devel diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index dae906b956..73bb531dc0 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -291,7 +291,7 @@ int main(int argc, char **argv)  	/* IS-IS inits. */  	yang_module_load("frr-isisd"); -	isis = isis_new(VRF_DEFAULT); +	isis = isis_new(VRF_DEFAULT_NAME);  	listnode_add(im->isis, isis);  	SET_FLAG(im->options, F_ISIS_UNIT_TEST);  	debug_spf_events |= DEBUG_SPF_EVENTS; diff --git a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf index c0896353ae..4798d17c40 100644 --- a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf +++ b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf @@ -1,5 +1,7 @@  interface r1-eth1   ip ospf area 0 + ip ospf hello-interval 2 + ip ospf dead-interval 10   ip ospf bfd  !  router ospf diff --git a/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf index f16844401e..d8fce344a8 100644 --- a/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf +++ b/tests/topotests/bfd-profiles-topo1/r6/ospfd.conf @@ -1,5 +1,7 @@  interface r6-eth0   ip ospf area 0 + ip ospf hello-interval 2 + ip ospf dead-interval 10   ip ospf bfd  !  router ospf diff --git a/tests/topotests/bfd-topo2/r2/ospf6d.conf b/tests/topotests/bfd-topo2/r2/ospf6d.conf index f1cdb50285..48a729ce19 100644 --- a/tests/topotests/bfd-topo2/r2/ospf6d.conf +++ b/tests/topotests/bfd-topo2/r2/ospf6d.conf @@ -1,5 +1,7 @@  interface r2-eth2   ipv6 ospf6 bfd + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10  !  router ospf6   ospf6 router-id 10.254.254.2 diff --git a/tests/topotests/bfd-topo2/r2/ospfd.conf b/tests/topotests/bfd-topo2/r2/ospfd.conf index 8e0c45980d..c786f1fe43 100644 --- a/tests/topotests/bfd-topo2/r2/ospfd.conf +++ b/tests/topotests/bfd-topo2/r2/ospfd.conf @@ -1,5 +1,7 @@  interface r2-eth1   ip ospf area 0.0.0.1 + ip ospf hello-interval 2 + ip ospf dead-interval 10   ip ospf bfd  !  router ospf diff --git a/tests/topotests/bfd-topo2/r3/ospfd.conf b/tests/topotests/bfd-topo2/r3/ospfd.conf index cf2a1bdf76..932ab4da63 100644 --- a/tests/topotests/bfd-topo2/r3/ospfd.conf +++ b/tests/topotests/bfd-topo2/r3/ospfd.conf @@ -1,5 +1,7 @@  interface r3-eth0   ip ospf area 0.0.0.1 + ip ospf hello-interval 2 + ip ospf dead-interval 10   ip ospf bfd  !  router ospf diff --git a/tests/topotests/bfd-topo2/r4/ospf6d.conf b/tests/topotests/bfd-topo2/r4/ospf6d.conf index 756597d6f8..57f7f6c079 100644 --- a/tests/topotests/bfd-topo2/r4/ospf6d.conf +++ b/tests/topotests/bfd-topo2/r4/ospf6d.conf @@ -1,5 +1,7 @@  interface r4-eth0   ipv6 ospf6 bfd + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10  !  router ospf6   ospf6 router-id 10.254.254.4 diff --git a/tests/topotests/bgp-auth/R1/bgpd.conf b/tests/topotests/bgp-auth/R1/bgpd.conf new file mode 100644 index 0000000000..1cb26c6537 --- /dev/null +++ b/tests/topotests/bgp-auth/R1/bgpd.conf @@ -0,0 +1,18 @@ +router bgp 65001 + timers bgp 3 9 + bgp router-id 1.1.1.1 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 password hello1 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 timers connect 10 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 password hello2 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + address-family ipv4 unicast +  neighbor 2.2.2.2 activate +  neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf new file mode 100644 index 0000000000..aab35073cf --- /dev/null +++ b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf.conf @@ -0,0 +1,40 @@ +log file /tmp/topotests/test_bgp_auth/R1/bgpd.log debugging +debug bgp neighbor-events + +router bgp 65001 vrf blue + timers bgp 3 9 + bgp router-id 1.1.1.1 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo1 + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 password blue1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo1 + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password blue2 + address-family ipv4 unicast +  neighbor 2.2.2.2 activate +  neighbor 3.3.3.3 activate + +router bgp 65001 vrf red + timers bgp 3 9 + bgp router-id 1.1.1.1 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo2 + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 password red1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo2 + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password red2 + address-family ipv4 unicast +  neighbor 2.2.2.2 activate +  neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf new file mode 100644 index 0000000000..7e15720c7e --- /dev/null +++ b/tests/topotests/bgp-auth/R1/bgpd_multi_vrf_prefix.conf @@ -0,0 +1,37 @@ +router bgp 65001 vrf blue + timers bgp 3 9 + bgp router-id 1.1.1.1 + neighbor TWO_GROUP_blue peer-group + neighbor TWO_GROUP_blue remote-as 65002 + neighbor TWO_GROUP_blue update-source 1.1.1.1 + neighbor TWO_GROUP_blue ebgp-multihop 3 + neighbor TWO_GROUP_blue password blue1 + neighbor THREE_GROUP_blue peer-group + neighbor THREE_GROUP_blue remote-as 65003 + neighbor THREE_GROUP_blue update-source 1.1.1.1 + neighbor THREE_GROUP_blue ebgp-multihop 3 + neighbor THREE_GROUP_blue password blue2 + bgp listen range 2.2.2.0/24 peer-group TWO_GROUP_blue  + bgp listen range 3.3.3.0/24 peer-group THREE_GROUP_blue + address-family ipv4 unicast + neighbor TWO_GROUP_blue maximum-prefix 4294967295 + neighbor THREE_GROUP_blue maximum-prefix 4294967295 + +router bgp 65001 vrf red + timers bgp 3 9 + bgp router-id 1.1.1.1 + neighbor TWO_GROUP_red peer-group + neighbor TWO_GROUP_red remote-as 65002 + neighbor TWO_GROUP_red update-source 1.1.1.1 + neighbor TWO_GROUP_red ebgp-multihop 3 + neighbor TWO_GROUP_red password red1 + neighbor THREE_GROUP_red peer-group + neighbor THREE_GROUP_red remote-as 65003 + neighbor THREE_GROUP_red update-source 1.1.1.1 + neighbor THREE_GROUP_red ebgp-multihop 3 + neighbor THREE_GROUP_red password red2 + bgp listen range 2.2.2.0/24 peer-group TWO_GROUP_red + bgp listen range 3.3.3.0/24 peer-group THREE_GROUP_red + address-family ipv4 unicast + neighbor TWO_GROUP_red maximum-prefix 4294967295 + neighbor THREE_GROUP_red maximum-prefix 4294967295 diff --git a/tests/topotests/bgp-auth/R1/bgpd_prefix.conf b/tests/topotests/bgp-auth/R1/bgpd_prefix.conf new file mode 100644 index 0000000000..9200b0501d --- /dev/null +++ b/tests/topotests/bgp-auth/R1/bgpd_prefix.conf @@ -0,0 +1,18 @@ +router bgp 65001 + timers bgp 3 9 + bgp router-id 1.1.1.1 + neighbor TWO_GROUP peer-group + neighbor TWO_GROUP remote-as 65002 + neighbor TWO_GROUP update-source 1.1.1.1 + neighbor TWO_GROUP ebgp-multihop 3 + neighbor TWO_GROUP password hello1 + neighbor THREE_GROUP peer-group + neighbor THREE_GROUP remote-as 65003 + neighbor THREE_GROUP update-source 1.1.1.1 + neighbor THREE_GROUP ebgp-multihop 3 + neighbor THREE_GROUP password hello2 + bgp listen range 2.2.2.0/24 peer-group TWO_GROUP  + bgp listen range 3.3.3.0/24 peer-group THREE_GROUP  + address-family ipv4 unicast + neighbor TWO_GROUP maximum-prefix 4294967295 + neighbor THREE_GROUP maximum-prefix 4294967295 diff --git a/tests/topotests/bgp-auth/R1/bgpd_vrf.conf b/tests/topotests/bgp-auth/R1/bgpd_vrf.conf new file mode 100644 index 0000000000..73aa8c1a03 --- /dev/null +++ b/tests/topotests/bgp-auth/R1/bgpd_vrf.conf @@ -0,0 +1,21 @@ +log file /tmp/topotests/test_bgp_auth/R1/bgpd.log debugging +debug bgp neighbor-events + +router bgp 65001 vrf blue + timers bgp 3 9 + bgp router-id 1.1.1.1 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo1 + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 password hello1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo1 + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password hello2 + address-family ipv4 unicast +  neighbor 2.2.2.2 activate +  neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf b/tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf new file mode 100644 index 0000000000..d68951b406 --- /dev/null +++ b/tests/topotests/bgp-auth/R1/bgpd_vrf_prefix.conf @@ -0,0 +1,18 @@ +router bgp 65001 vrf blue + timers bgp 3 9 + bgp router-id 1.1.1.1 + neighbor TWO_GROUP_blue peer-group + neighbor TWO_GROUP_blue remote-as 65002 + neighbor TWO_GROUP_blue update-source 1.1.1.1 + neighbor TWO_GROUP_blue ebgp-multihop 3 + neighbor TWO_GROUP_blue password hello1 + neighbor THREE_GROUP_blue peer-group + neighbor THREE_GROUP_blue remote-as 65003 + neighbor THREE_GROUP_blue update-source 1.1.1.1 + neighbor THREE_GROUP_blue ebgp-multihop 3 + neighbor THREE_GROUP_blue password hello2 + bgp listen range 2.2.2.0/24 peer-group TWO_GROUP_blue + bgp listen range 3.3.3.0/24 peer-group THREE_GROUP_blue  + address-family ipv4 unicast + neighbor TWO_GROUP_blue maximum-prefix 4294967295 + neighbor THREE_GROUP_blue maximum-prefix 4294967295 diff --git a/tests/topotests/bgp-auth/R1/ospfd.conf b/tests/topotests/bgp-auth/R1/ospfd.conf new file mode 100644 index 0000000000..79eb0e33da --- /dev/null +++ b/tests/topotests/bgp-auth/R1/ospfd.conf @@ -0,0 +1,4 @@ +router ospf + network 10.10.0.0/16 area 0 + network 10.20.0.0/16 area 0 + network 1.1.1.1/32 area 0 diff --git a/tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf b/tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf new file mode 100644 index 0000000000..e2a28000b8 --- /dev/null +++ b/tests/topotests/bgp-auth/R1/ospfd_multi_vrf.conf @@ -0,0 +1,9 @@ +router ospf vrf blue + network 10.10.0.0/16 area 0 + network 10.20.0.0/16 area 0 + network 1.1.1.1/32 area 0 + +router ospf vrf red + network 10.10.0.0/16 area 0 + network 10.20.0.0/16 area 0 + network 1.1.1.1/32 area 0 diff --git a/tests/topotests/bgp-auth/R1/ospfd_vrf.conf b/tests/topotests/bgp-auth/R1/ospfd_vrf.conf new file mode 100644 index 0000000000..0b7fbae8c4 --- /dev/null +++ b/tests/topotests/bgp-auth/R1/ospfd_vrf.conf @@ -0,0 +1,4 @@ +router ospf vrf blue + network 10.10.0.0/16 area 0 + network 10.20.0.0/16 area 0 + network 1.1.1.1/32 area 0 diff --git a/tests/topotests/bgp-auth/R1/zebra.conf b/tests/topotests/bgp-auth/R1/zebra.conf new file mode 100644 index 0000000000..d39915335a --- /dev/null +++ b/tests/topotests/bgp-auth/R1/zebra.conf @@ -0,0 +1,21 @@ +log file zebra.log +! +interface lo + ip address 1.1.1.1/32 +interface lo1 vrf blue + ip address 1.1.1.1/32 +interface lo2 vrf red + ip address 1.1.1.1/32 +interface R1-eth0 + ip address 10.10.0.1/24 +interface R1-eth1 + ip address 10.20.0.1/24 +interface R1-eth2 vrf blue + ip address 10.10.0.1/24 +interface R1-eth3 vrf blue + ip address 10.20.0.1/24 +interface R1-eth4 vrf red + ip address 10.10.0.1/24 +interface R1-eth5 vrf red + ip address 10.20.0.1/24 +!
\ No newline at end of file diff --git a/tests/topotests/bgp-auth/R2/bgpd.conf b/tests/topotests/bgp-auth/R2/bgpd.conf new file mode 100644 index 0000000000..fa2a570ef9 --- /dev/null +++ b/tests/topotests/bgp-auth/R2/bgpd.conf @@ -0,0 +1,18 @@ +router bgp 65002 + timers bgp 3 9 + bgp router-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password hello1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password hello3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf new file mode 100644 index 0000000000..d5f70edf68 --- /dev/null +++ b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf.conf @@ -0,0 +1,37 @@ +router bgp 65002 vrf blue + timers bgp 3 9 + bgp router-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo1 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password blue1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo1 + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password blue3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 3.3.3.3 activate + +router bgp 65002 vrf red + timers bgp 3 9 + bgp router-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo2 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password red1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo2 + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password red3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf new file mode 100644 index 0000000000..d5f70edf68 --- /dev/null +++ b/tests/topotests/bgp-auth/R2/bgpd_multi_vrf_prefix.conf @@ -0,0 +1,37 @@ +router bgp 65002 vrf blue + timers bgp 3 9 + bgp router-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo1 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password blue1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo1 + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password blue3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 3.3.3.3 activate + +router bgp 65002 vrf red + timers bgp 3 9 + bgp router-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo2 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password red1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo2 + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password red3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp-auth/R2/bgpd_prefix.conf b/tests/topotests/bgp-auth/R2/bgpd_prefix.conf new file mode 100644 index 0000000000..fa2a570ef9 --- /dev/null +++ b/tests/topotests/bgp-auth/R2/bgpd_prefix.conf @@ -0,0 +1,18 @@ +router bgp 65002 + timers bgp 3 9 + bgp router-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password hello1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password hello3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp-auth/R2/bgpd_vrf.conf b/tests/topotests/bgp-auth/R2/bgpd_vrf.conf new file mode 100644 index 0000000000..d1f3847420 --- /dev/null +++ b/tests/topotests/bgp-auth/R2/bgpd_vrf.conf @@ -0,0 +1,18 @@ +router bgp 65002 vrf blue + timers bgp 3 9 + bgp router-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo1 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password hello1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo1 + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password hello3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf b/tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf new file mode 100644 index 0000000000..d1f3847420 --- /dev/null +++ b/tests/topotests/bgp-auth/R2/bgpd_vrf_prefix.conf @@ -0,0 +1,18 @@ +router bgp 65002 vrf blue + timers bgp 3 9 + bgp router-id 2.2.2.2 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo1 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password hello1 + neighbor 3.3.3.3 remote-as 65003 + neighbor 3.3.3.3 update-source lo1 + neighbor 3.3.3.3 ebgp-multihop 3 + neighbor 3.3.3.3 timers 3 10 + neighbor 3.3.3.3 timers connect 10 + neighbor 3.3.3.3 password hello3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp-auth/R2/ospfd.conf b/tests/topotests/bgp-auth/R2/ospfd.conf new file mode 100644 index 0000000000..028b546a0c --- /dev/null +++ b/tests/topotests/bgp-auth/R2/ospfd.conf @@ -0,0 +1,4 @@ +router ospf + network 10.10.0.0/16 area 0 + network 10.30.0.0/16 area 0 + network 2.2.2.2/32 area 0 diff --git a/tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf b/tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf new file mode 100644 index 0000000000..a05dfb8e41 --- /dev/null +++ b/tests/topotests/bgp-auth/R2/ospfd_multi_vrf.conf @@ -0,0 +1,9 @@ +router ospf vrf blue + network 10.10.0.0/16 area 0 + network 10.30.0.0/16 area 0 + network 2.2.2.2/32 area 0 + +router ospf vrf red + network 10.10.0.0/16 area 0 + network 10.30.0.0/16 area 0 + network 2.2.2.2/32 area 0 diff --git a/tests/topotests/bgp-auth/R2/ospfd_vrf.conf b/tests/topotests/bgp-auth/R2/ospfd_vrf.conf new file mode 100644 index 0000000000..b198d352e2 --- /dev/null +++ b/tests/topotests/bgp-auth/R2/ospfd_vrf.conf @@ -0,0 +1,4 @@ +router ospf vrf blue + network 10.10.0.0/16 area 0 + network 10.30.0.0/16 area 0 + network 2.2.2.2/32 area 0 diff --git a/tests/topotests/bgp-auth/R2/zebra.conf b/tests/topotests/bgp-auth/R2/zebra.conf new file mode 100644 index 0000000000..fece68472a --- /dev/null +++ b/tests/topotests/bgp-auth/R2/zebra.conf @@ -0,0 +1,21 @@ +log file zebra.log +! +interface lo + ip address 2.2.2.2/32 +interface lo1 vrf blue + ip address 2.2.2.2/32 +interface lo2 vrf red + ip address 2.2.2.2/32 +interface R2-eth0 + ip address 10.10.0.2/24 +interface R2-eth1 + ip address 10.30.0.2/24 +interface R2-eth2 vrf blue + ip address 10.10.0.2/24 +interface R2-eth3 vrf blue + ip address 10.30.0.2/24 +interface R2-eth4 vrf red + ip address 10.10.0.2/24 +interface R2-eth5 vrf red + ip address 10.30.0.2/24 +!
\ No newline at end of file diff --git a/tests/topotests/bgp-auth/R3/bgpd.conf b/tests/topotests/bgp-auth/R3/bgpd.conf new file mode 100644 index 0000000000..deccfd418b --- /dev/null +++ b/tests/topotests/bgp-auth/R3/bgpd.conf @@ -0,0 +1,18 @@ +router bgp 65003 + timers bgp 3 9 + bgp router-id 3.3.3.3 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password hello2 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 password hello3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 2.2.2.2 activate diff --git a/tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf new file mode 100644 index 0000000000..fe3e64d8d5 --- /dev/null +++ b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf.conf @@ -0,0 +1,37 @@ +router bgp 65003 vrf blue + timers bgp 3 9 + bgp router-id 3.3.3.3 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo1 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password blue2 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo1 + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 password blue3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 2.2.2.2 activate + +router bgp 65003 vrf red + timers bgp 3 9 + bgp router-id 3.3.3.3 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo2 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password red2 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo2 + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 password red3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 2.2.2.2 activate diff --git a/tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf new file mode 100644 index 0000000000..fe3e64d8d5 --- /dev/null +++ b/tests/topotests/bgp-auth/R3/bgpd_multi_vrf_prefix.conf @@ -0,0 +1,37 @@ +router bgp 65003 vrf blue + timers bgp 3 9 + bgp router-id 3.3.3.3 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo1 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password blue2 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo1 + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 password blue3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 2.2.2.2 activate + +router bgp 65003 vrf red + timers bgp 3 9 + bgp router-id 3.3.3.3 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo2 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password red2 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo2 + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 password red3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 2.2.2.2 activate diff --git a/tests/topotests/bgp-auth/R3/bgpd_prefix.conf b/tests/topotests/bgp-auth/R3/bgpd_prefix.conf new file mode 100644 index 0000000000..deccfd418b --- /dev/null +++ b/tests/topotests/bgp-auth/R3/bgpd_prefix.conf @@ -0,0 +1,18 @@ +router bgp 65003 + timers bgp 3 9 + bgp router-id 3.3.3.3 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password hello2 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 password hello3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 2.2.2.2 activate diff --git a/tests/topotests/bgp-auth/R3/bgpd_vrf.conf b/tests/topotests/bgp-auth/R3/bgpd_vrf.conf new file mode 100644 index 0000000000..c109aa801b --- /dev/null +++ b/tests/topotests/bgp-auth/R3/bgpd_vrf.conf @@ -0,0 +1,18 @@ +router bgp 65003 vrf blue + timers bgp 3 9 + bgp router-id 3.3.3.3 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo1 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password hello2 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo1 + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 password hello3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 2.2.2.2 activate diff --git a/tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf b/tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf new file mode 100644 index 0000000000..c109aa801b --- /dev/null +++ b/tests/topotests/bgp-auth/R3/bgpd_vrf_prefix.conf @@ -0,0 +1,18 @@ +router bgp 65003 vrf blue + timers bgp 3 9 + bgp router-id 3.3.3.3 + neighbor 1.1.1.1 remote-as 65001 + neighbor 1.1.1.1 update-source lo1 + neighbor 1.1.1.1 ebgp-multihop 3 + neighbor 1.1.1.1 timers 3 10 + neighbor 1.1.1.1 timers connect 10 + neighbor 1.1.1.1 password hello2 + neighbor 2.2.2.2 remote-as 65002 + neighbor 2.2.2.2 update-source lo1 + neighbor 2.2.2.2 ebgp-multihop 3 + neighbor 2.2.2.2 timers connect 10 + neighbor 2.2.2.2 timers 3 10 + neighbor 2.2.2.2 password hello3 + address-family ipv4 unicast +  neighbor 1.1.1.1 activate +  neighbor 2.2.2.2 activate diff --git a/tests/topotests/bgp-auth/R3/ospfd.conf b/tests/topotests/bgp-auth/R3/ospfd.conf new file mode 100644 index 0000000000..0f0a2e926a --- /dev/null +++ b/tests/topotests/bgp-auth/R3/ospfd.conf @@ -0,0 +1,4 @@ +router ospf + network 10.20.0.0/16 area 0 + network 10.30.0.0/16 area 0 + network 3.3.3.3/32 area 0 diff --git a/tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf b/tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf new file mode 100644 index 0000000000..f32d2a8423 --- /dev/null +++ b/tests/topotests/bgp-auth/R3/ospfd_multi_vrf.conf @@ -0,0 +1,9 @@ +router ospf vrf blue + network 10.20.0.0/16 area 0 + network 10.30.0.0/16 area 0 + network 3.3.3.3/32 area 0 +! +router ospf vrf red + network 10.20.0.0/16 area 0 + network 10.30.0.0/16 area 0 + network 3.3.3.3/32 area 0 diff --git a/tests/topotests/bgp-auth/R3/ospfd_vrf.conf b/tests/topotests/bgp-auth/R3/ospfd_vrf.conf new file mode 100644 index 0000000000..6465b635aa --- /dev/null +++ b/tests/topotests/bgp-auth/R3/ospfd_vrf.conf @@ -0,0 +1,4 @@ +router ospf vrf blue + network 10.20.0.0/16 area 0 + network 10.30.0.0/16 area 0 + network 3.3.3.3/32 area 0 diff --git a/tests/topotests/bgp-auth/R3/zebra.conf b/tests/topotests/bgp-auth/R3/zebra.conf new file mode 100644 index 0000000000..0fe3acdfd0 --- /dev/null +++ b/tests/topotests/bgp-auth/R3/zebra.conf @@ -0,0 +1,21 @@ +log file zebra.log +! +interface lo + ip address 3.3.3.3/32 +interface lo1 vrf blue + ip address 3.3.3.3/32 +interface lo2 vrf red + ip address 3.3.3.3/32 +interface R3-eth0 + ip address 10.20.0.3/24 +interface R3-eth1 + ip address 10.30.0.3/24 +interface R3-eth2 vrf blue + ip address 10.20.0.3/24 +interface R3-eth3 vrf blue + ip address 10.30.0.3/24 +interface R3-eth4 vrf red + ip address 10.20.0.3/24 +interface R3-eth5 vrf red + ip address 10.30.0.3/24 +!
\ No newline at end of file diff --git a/tests/topotests/bgp-auth/test_bgp_auth.py b/tests/topotests/bgp-auth/test_bgp_auth.py new file mode 100755 index 0000000000..6198997b86 --- /dev/null +++ b/tests/topotests/bgp-auth/test_bgp_auth.py @@ -0,0 +1,747 @@ +#!/usr/bin/env python + +# +# test_bgp_auth.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 by Volta Networks +# +# 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. +# + +""" +test_bgp_auth.py: Test BGP Md5 Authentication + +                             +------+ +                    +--------|      |--------+ +                    | +------|  R1  |------+ | +                    | | -----|      |----+ | | +                    | | |    +------+    | | | +                    | | |                | | | +                   +------+            +------+ +                   |      |------------|      | +                   |  R2  |------------|  R3  | +                   |      |------------|      | +                   +------+            +------+ + + +setup is 3 routers with 3 links between each each link in a different vrf +Default, blue and red respectively +Tests check various fiddling with passwords and checking that the peer +establishment is as expected and passwords are not leaked across sockets  +for bgp instances +""" + +import os +import sys +import json +import platform +from functools import partial +import pytest +from time import sleep + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +from lib.common_config import apply_raw_config + +ERROR_LIST = ["Malformed", "Failure", "Unknown", "Incomplete"] + + +class InvalidCLIError(Exception): +    """Raise when the CLI command is wrong""" + +    pass + + +class TemplateTopo(Topo): +    "Test topology builder" + +    def build(self, *_args, **_opts): +        "Build function" +        tgen = get_topogen(self) + +        # This function only purpose is to define allocation and relationship +        # between routers, switches and hosts. +        # +        # +        # Create routers +        tgen.add_router("R1") +        tgen.add_router("R2") +        tgen.add_router("R3") + +        # R1-R2 1 +        switch = tgen.add_switch("s1") +        switch.add_link(tgen.gears["R1"]) +        switch.add_link(tgen.gears["R2"]) + +        # R1-R3 1 +        switch = tgen.add_switch("s2") +        switch.add_link(tgen.gears["R1"]) +        switch.add_link(tgen.gears["R3"]) + +        # R2-R3 1 +        switch = tgen.add_switch("s3") +        switch.add_link(tgen.gears["R2"]) +        switch.add_link(tgen.gears["R3"]) + +        # R1-R2 2 +        switch = tgen.add_switch("s4") +        switch.add_link(tgen.gears["R1"]) +        switch.add_link(tgen.gears["R2"]) + +        # R1-R3 2 +        switch = tgen.add_switch("s5") +        switch.add_link(tgen.gears["R1"]) +        switch.add_link(tgen.gears["R3"]) + +        # R2-R3 2 +        switch = tgen.add_switch("s6") +        switch.add_link(tgen.gears["R2"]) +        switch.add_link(tgen.gears["R3"]) + +        # R1-R2 3 +        switch = tgen.add_switch("s7") +        switch.add_link(tgen.gears["R1"]) +        switch.add_link(tgen.gears["R2"]) + +        # R1-R3 2 +        switch = tgen.add_switch("s8") +        switch.add_link(tgen.gears["R1"]) +        switch.add_link(tgen.gears["R3"]) + +        # R2-R3 2 +        switch = tgen.add_switch("s9") +        switch.add_link(tgen.gears["R2"]) +        switch.add_link(tgen.gears["R3"]) + + +def setup_module(mod): +    "Sets up the pytest environment" +    # This function initiates the topology build with Topogen... +    tgen = Topogen(TemplateTopo, mod.__name__) +    # ... and here it calls Mininet initialization functions. +    tgen.start_topology() + +    r1 = tgen.gears["R1"] +    r2 = tgen.gears["R2"] +    r3 = tgen.gears["R3"] + +    # blue vrf +    r1.run("ip link add blue type vrf table 1001") +    r1.run("ip link set up dev blue") +    r2.run("ip link add blue type vrf table 1001") +    r2.run("ip link set up dev blue") +    r3.run("ip link add blue type vrf table 1001") +    r3.run("ip link set up dev blue") + +    r1.run("ip link add lo1 type dummy") +    r1.run("ip link set lo1 master blue") +    r1.run("ip link set up dev lo1") +    r2.run("ip link add lo1 type dummy") +    r2.run("ip link set up dev lo1") +    r2.run("ip link set lo1 master blue") +    r3.run("ip link add lo1 type dummy") +    r3.run("ip link set up dev lo1") +    r3.run("ip link set lo1 master blue") + +    r1.run("ip link set R1-eth2 master blue") +    r1.run("ip link set R1-eth3 master blue") +    r2.run("ip link set R2-eth2 master blue") +    r2.run("ip link set R2-eth3 master blue") +    r3.run("ip link set R3-eth2 master blue") +    r3.run("ip link set R3-eth3 master blue") + +    r1.run("ip link set up dev  R1-eth2") +    r1.run("ip link set up dev  R1-eth3") +    r2.run("ip link set up dev  R2-eth2") +    r2.run("ip link set up dev  R2-eth3") +    r3.run("ip link set up dev  R3-eth2") +    r3.run("ip link set up dev  R3-eth3") + +    # red vrf +    r1.run("ip link add red type vrf table 1002") +    r1.run("ip link set up dev red") +    r2.run("ip link add red type vrf table 1002") +    r2.run("ip link set up dev red") +    r3.run("ip link add red type vrf table 1002") +    r3.run("ip link set up dev red") + +    r1.run("ip link add lo2 type dummy") +    r1.run("ip link set lo2 master red") +    r1.run("ip link set up dev lo2") +    r2.run("ip link add lo2 type dummy") +    r2.run("ip link set up dev lo2") +    r2.run("ip link set lo2 master red") +    r3.run("ip link add lo2 type dummy") +    r3.run("ip link set up dev lo2") +    r3.run("ip link set lo2 master red") + +    r1.run("ip link set R1-eth4 master red") +    r1.run("ip link set R1-eth5 master red") +    r2.run("ip link set R2-eth4 master red") +    r2.run("ip link set R2-eth5 master red") +    r3.run("ip link set R3-eth4 master red") +    r3.run("ip link set R3-eth5 master red") + +    r1.run("ip link set up dev  R1-eth4") +    r1.run("ip link set up dev  R1-eth5") +    r2.run("ip link set up dev  R2-eth4") +    r2.run("ip link set up dev  R2-eth5") +    r3.run("ip link set up dev  R3-eth4") +    r3.run("ip link set up dev  R3-eth5") + +    # This is a sample of configuration loading. +    router_list = tgen.routers() + +    # For all registred routers, load the zebra configuration file +    for rname, router in router_list.iteritems(): +        router.load_config( +            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) +        ) +        router.load_config( +            TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) +        ) +        router.load_config( +            TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) +        ) + +    # After loading the configurations, this function loads configured daemons. +    tgen.start_router() + + +def teardown_module(mod): +    "Teardown the pytest environment" +    tgen = get_topogen() + +    # This function tears down the whole topology. +    tgen.stop_topology() + + +def vrf_str(vrf): +    if vrf == "": +        vrf_str = "" +    else: +        vrf_str = "vrf {}".format(vrf) + +    return vrf_str + + +def peer_name(rtr, prefix, vrf): +    "generate VRF string for CLI" +    if vrf == "": +        vrf_str = "" +    else: +        vrf_str = "_" + vrf + +    if prefix == "yes": +        if rtr == "R2": +            return "TWO_GROUP" + vrf_str +        else: +            return "THREE_GROUP" + vrf_str +    else: +        if rtr == "R2": +            return "2.2.2.2" +        else: +            return "3.3.3.3" + + +def print_diag(vrf): +    "print failure disagnostics" +     +    tgen = get_topogen() +    router_list = tgen.routers() +    for rname, router in router_list.iteritems(): +        print(rname + ":") +        print(router.vtysh_cmd("show run")) +        print(router.vtysh_cmd("show ip route {}".format(vrf_str(vrf)))) +        print(router.vtysh_cmd("show bgp {} neighbor".format(vrf_str(vrf)))) + + +def configure(conf_file): +    "configure from a file" + +    tgen = get_topogen() +    router_list = tgen.routers() +    for rname, router in router_list.iteritems(): +        with open( +            os.path.join(CWD, "{}/{}").format(router.name, conf_file), "r+" +        ) as cfg: +            new_config = cfg.read() + +            output = router.vtysh_multicmd(new_config, pretty_output=False) +            for out_err in ERROR_LIST: +                if out_err.lower() in output.lower(): +                    raise InvalidCLIError("%s" % output) + + +def clear_bgp(vrf=""): +    " clear bgp configuration for a vrf" + +    tgen = get_topogen() +    r1 = tgen.gears["R1"] +    r2 = tgen.gears["R2"] +    r3 = tgen.gears["R3"] + +    router_list = tgen.routers() +    if vrf == "": +        r1.vtysh_cmd("conf t\nno router bgp 65001") +        r2.vtysh_cmd("conf t\nno router bgp 65002") +        r2.vtysh_cmd("conf t\nno router bgp 65003") +    else: +        r1.vtysh_cmd("conf t\nno router bgp 65001 vrf {}".format(vrf)) +        r2.vtysh_cmd("conf t\nno router bgp 65002 vrf {}".format(vrf)) +        r3.vtysh_cmd("conf t\nno router bgp 65003 vrf {}".format(vrf)) + + +def clear_ospf(vrf=""): +    "clear ospf configuration for a vrf" + +    tgen = get_topogen() +    router_list = tgen.routers() +    for rname, router in router_list.iteritems(): +        if vrf == "": +            router.vtysh_cmd("conf t\nno router ospf") +        else: +            router.vtysh_cmd("conf t\nno router ospf vrf {}".format(vrf)) + + +def check_neigh_state(router, peer, state, vrf=""): +    "check BGP neighbor state on a router" +     +    count = 0 +    matched = False +    neigh_output = "" +    while count < 125: +        if vrf == "": +            neigh_output = router.vtysh_cmd("show bgp neighbors {} json".format(peer)) +        else: +            neigh_output = router.vtysh_cmd( +                "show bgp vrf {} neighbors {} json".format(vrf, peer) +            ) +        neigh_output_json = json.loads(neigh_output) +        if neigh_output_json[peer]["bgpState"] == state: +            matched = True +            break +        count += 1 +        sleep(1) + +    assertmsg = "{} could not peer {} state expected {} got {} ".format( +        router.name, peer, state, neigh_output_json[peer]["bgpState"] +    ) +    if matched != True: +        print_diag(vrf) +    assert matched == True, assertmsg + + +def check_all_peers_established(vrf=""): +    "standard check for extablished peers per vrf" + +    tgen = get_topogen() +    r1 = tgen.gears["R1"] +    r2 = tgen.gears["R2"] +    r3 = tgen.gears["R3"] +    # do r1 last as he might be the dynamic one +    check_neigh_state(r2, "1.1.1.1", "Established", vrf) +    check_neigh_state(r2, "3.3.3.3", "Established", vrf) +    check_neigh_state(r3, "1.1.1.1", "Established", vrf) +    check_neigh_state(r3, "2.2.2.2", "Established", vrf) +    check_neigh_state(r1, "2.2.2.2", "Established", vrf) +    check_neigh_state(r1, "3.3.3.3", "Established", vrf) + + +def check_vrf_peer_remove_passwords(vrf="", prefix="no"): +    "selectively remove passwords checking state" + +    tgen = get_topogen() +    r1 = tgen.gears["R1"] +    r2 = tgen.gears["R2"] +    r3 = tgen.gears["R3"] + +    r1.vtysh_cmd( +        "conf t\nrouter bgp 65001 {}\nno neighbor {} password".format( +            vrf_str(vrf), peer_name("R2", prefix, vrf) +        ) +    ) + +    check_neigh_state(r2, "1.1.1.1", "Connect", vrf) +    check_neigh_state(r2, "3.3.3.3", "Established", vrf) +    check_neigh_state(r3, "1.1.1.1", "Established", vrf) +    check_neigh_state(r3, "2.2.2.2", "Established", vrf) +    # don't check dynamic downed peers - they are removed +    if prefix == "no": +        check_neigh_state(r1, "2.2.2.2", "Connect", vrf) +    check_neigh_state(r1, "3.3.3.3", "Established", vrf) + +    r2.vtysh_cmd( +        "conf t\nrouter bgp 65002 {}\nno neighbor 1.1.1.1 password".format(vrf_str(vrf)) +    ) +    check_all_peers_established(vrf) + +    r1.vtysh_cmd( +        "conf t\nrouter bgp 65001 {}\nno neighbor {} password".format( +            vrf_str(vrf), peer_name("R3", prefix, vrf) +        ) +    ) +    check_neigh_state(r2, "1.1.1.1", "Established", vrf) +    check_neigh_state(r2, "3.3.3.3", "Established", vrf) +    check_neigh_state(r3, "1.1.1.1", "Connect", vrf) +    check_neigh_state(r3, "2.2.2.2", "Established", vrf) +    check_neigh_state(r1, "2.2.2.2", "Established", vrf) +    # don't check dynamic downed peers - they are removed +    if prefix == "no": +        check_neigh_state(r1, "3.3.3.3", "Connect", vrf) + +    r3.vtysh_cmd( +        "conf t\nrouter bgp 65003 {}\nno neighbor 1.1.1.1 password".format(vrf_str(vrf)) +    ) +    check_all_peers_established(vrf) + +    r2.vtysh_cmd( +        "conf t\nrouter bgp 65002 {}\nno neighbor 3.3.3.3 password".format(vrf_str(vrf)) +    ) +    check_neigh_state(r2, "1.1.1.1", "Established", vrf) +    check_neigh_state(r2, "3.3.3.3", "Connect", vrf) +    check_neigh_state(r3, "1.1.1.1", "Established", vrf) +    check_neigh_state(r3, "2.2.2.2", "Connect", vrf) +    check_neigh_state(r1, "2.2.2.2", "Established", vrf) +    check_neigh_state(r1, "3.3.3.3", "Established", vrf) + +    r3.vtysh_cmd( +        "conf t\nrouter bgp 65003 {}\nno neighbor 2.2.2.2 password".format(vrf_str(vrf)) +    ) +    check_all_peers_established(vrf) + + +def check_vrf_peer_change_passwords(vrf="", prefix="no"): +    "selectively change passwords checking state" + +    tgen = get_topogen() +    r1 = tgen.gears["R1"] +    r2 = tgen.gears["R2"] +    r3 = tgen.gears["R3"] +    check_all_peers_established(vrf) + +    r1.vtysh_cmd( +        "conf t\nrouter bgp 65001 {}\nneighbor {} password change1".format( +            vrf_str(vrf), peer_name("R2", prefix, vrf) +        ) +    ) +    check_neigh_state(r2, "1.1.1.1", "Connect", vrf) +    check_neigh_state(r2, "3.3.3.3", "Established", vrf) +    check_neigh_state(r3, "1.1.1.1", "Established", vrf) +    check_neigh_state(r3, "2.2.2.2", "Established", vrf) +    # don't check dynamic downed peers - they are removed +    if prefix == "no": +        check_neigh_state(r1, "2.2.2.2", "Connect", vrf) +    check_neigh_state(r1, "3.3.3.3", "Established", vrf) + +    r2.vtysh_cmd( +        "conf t\nrouter bgp 65002 {}\nneighbor 1.1.1.1 password change1".format( +            vrf_str(vrf) +        ) +    ) +    check_all_peers_established(vrf) + +    r1.vtysh_cmd( +        "conf t\nrouter bgp 65001 {}\nneighbor {} password change2".format( +            vrf_str(vrf), peer_name("R3", prefix, vrf) +        ) +    ) +    check_neigh_state(r2, "1.1.1.1", "Established", vrf) +    check_neigh_state(r2, "3.3.3.3", "Established", vrf) +    check_neigh_state(r3, "1.1.1.1", "Connect", vrf) +    check_neigh_state(r3, "2.2.2.2", "Established", vrf) +    check_neigh_state(r1, "2.2.2.2", "Established", vrf) +    # don't check dynamic downed peers - they are removed +    if prefix == "no": +        check_neigh_state(r1, "3.3.3.3", "Connect", vrf) + +    r3.vtysh_cmd( +        "conf t\nrouter bgp 65003 {}\nneighbor 1.1.1.1 password change2".format( +            vrf_str(vrf) +        ) +    ) +    check_all_peers_established(vrf) + +    r2.vtysh_cmd( +        "conf t\nrouter bgp 65002 {}\nneighbor 3.3.3.3 password change3".format( +            vrf_str(vrf) +        ) +    ) +    check_neigh_state(r2, "1.1.1.1", "Established", vrf) +    check_neigh_state(r2, "3.3.3.3", "Connect", vrf) +    check_neigh_state(r3, "1.1.1.1", "Established", vrf) +    check_neigh_state(r3, "2.2.2.2", "Connect", vrf) +    check_neigh_state(r1, "2.2.2.2", "Established", vrf) +    check_neigh_state(r1, "3.3.3.3", "Established", vrf) + +    r3.vtysh_cmd( +        "conf t\nrouter bgp 65003 {}\nneighbor 2.2.2.2 password change3".format( +            vrf_str(vrf) +        ) +    ) +    check_all_peers_established(vrf) + + +def test_default_peer_established(): +    "default vrf 3 peers same password" + +    check_all_peers_established() +    clear_bgp() +    # tgen.mininet_cli() + + +def test_default_peer_remove_passwords(): +    "selectively remove passwords checking state" + +    configure("bgpd.conf") +    check_vrf_peer_remove_passwords() +    clear_bgp() + + +def test_default_peer_change_passwords(): +    "selectively change passwords checking state" + +    configure("bgpd.conf") +    check_vrf_peer_change_passwords() +    clear_bgp() + + +def test_default_prefix_peer_established(): +    "default vrf 3 peers same password with prefix config" + +    # only supported in kernel > 5.3 +    if topotest.version_cmp(platform.release(), "5.3") < 0: +        return + +    configure("bgpd_prefix.conf") +    check_all_peers_established() +    clear_bgp() +    # tgen.mininet_cli() + + +def test_prefix_peer_remove_passwords(): +    "selectively remove passwords checking state with prefix config" + +    # only supported in kernel > 5.3 +    if topotest.version_cmp(platform.release(), "5.3") < 0: +        return +    configure("bgpd_prefix.conf") +    check_vrf_peer_remove_passwords(prefix="yes") +    clear_bgp() + + +def test_prefix_peer_change_passwords(): +    "selecively change passwords checkig state with prefix config" + +    # only supported in kernel > 5.3 +    if topotest.version_cmp(platform.release(), "5.3") < 0: +        return +    configure("bgpd_prefix.conf") +    check_vrf_peer_change_passwords(prefix="yes") +    clear_bgp() +    clear_ospf() + + +def test_vrf_peer_established(): +    "default vrf 3 peers same password with VRF config" + +    # clean routers and load vrf config +    configure("bgpd_vrf.conf") +    configure("ospfd_vrf.conf") + +    check_all_peers_established("blue") +    clear_bgp("blue") +    # tgen.mininet_cli() + + +def test_vrf_peer_remove_passwords(): +    "selectively remove passwords checking state with VRF config" + +    configure("bgpd_vrf.conf") +    check_vrf_peer_remove_passwords(vrf="blue") +    clear_bgp("blue") + + +def test_vrf_peer_change_passwords(): +    "selectively change passwords checking state with VRF config" + +    configure("bgpd_vrf.conf") +    check_vrf_peer_change_passwords(vrf="blue") +    clear_bgp("blue") + + +def test_vrf_prefix_peer_established(): +    "default vrf 3 peers same password with VRF prefix config" + +    # only supported in kernel > 5.3 +    if topotest.version_cmp(platform.release(), "5.3") < 0: +        clear_bgp("blue") +        return + +    configure("bgpd_vrf_prefix.conf") +    check_all_peers_established("blue") +    clear_bgp("blue") + + +def test_vrf_prefix_peer_remove_passwords(): +    "selectively remove passwords checking state with VRF prefix config" + +    # only supported in kernel > 5.3 +    if topotest.version_cmp(platform.release(), "5.3") < 0: +        return + +    configure("bgpd_vrf_prefix.conf") +    check_vrf_peer_remove_passwords(vrf="blue", prefix="yes") +    clear_bgp("blue") + + +def test_vrf_prefix_peer_change_passwords(): +    "selectively change passwords checking state with VRF prefix config" + +    tgen = get_topogen() +    r1 = tgen.gears["R1"] +    r2 = tgen.gears["R2"] +    r3 = tgen.gears["R3"] + +    # only supported in kernel > 5.3 +    if topotest.version_cmp(platform.release(), "5.3") < 0: +        clear_ospf("blue") +        return + +    configure("bgpd_vrf_prefix.conf") +    check_vrf_peer_change_passwords(vrf="blue", prefix="yes") +    clear_bgp("blue") +    clear_ospf("blue") + + +def test_multiple_vrf_peer_established(): +    "default vrf 3 peers same password with multiple VRFs" + +    configure("bgpd_multi_vrf.conf") +    configure("ospfd_multi_vrf.conf") +    check_all_peers_established("blue") +    check_all_peers_established("red") +    clear_bgp("blue") +    clear_bgp("red") +    # tgen.mininet_cli() + + +def test_multiple_vrf_peer_remove_passwords(): +    "selectively remove passwords checking state with multiple VRFs" + +    configure("bgpd_multi_vrf.conf") +    check_vrf_peer_remove_passwords("blue") +    check_all_peers_established("red") +    check_vrf_peer_remove_passwords("red") +    check_all_peers_established("blue") +    clear_bgp("blue") +    clear_bgp("red") +    # tgen.mininet_cli() + + +def test_multiple_vrf_peer_change_passwords(): +    "selectively change passwords checking state with multiple VRFs" + +    configure("bgpd_multi_vrf.conf") +    check_vrf_peer_change_passwords("blue") +    check_all_peers_established("red") +    check_vrf_peer_change_passwords("red") +    check_all_peers_established("blue") +    clear_bgp("blue") +    clear_bgp("red") +    # tgen.mininet_cli() + + +def test_multiple_vrf_prefix_peer_established(): +    "default vrf 3 peers same password with multilpe VRFs and prefix config" + +    # only supported in kernel > 5.3 +    if topotest.version_cmp(platform.release(), "5.3") < 0: +        return + +    configure("bgpd_multi_vrf.conf") +    configure("ospfd_multi_vrf.conf") +    check_all_peers_established("blue") +    check_all_peers_established("red") +    clear_bgp("blue") +    clear_bgp("red") +    # tgen.mininet_cli() + + +def test_multiple_vrf_prefix_peer_remove_passwords(): +    "selectively remove passwords checking state with multiple vrfs and prefix config" + +    # only supported in kernel > 5.3 +    if topotest.version_cmp(platform.release(), "5.3") < 0: +        return + +    configure("bgpd_multi_vrf_prefix.conf") +    tgen = get_topogen() +    check_vrf_peer_remove_passwords(vrf="blue", prefix="yes") +    check_all_peers_established("red") +    check_vrf_peer_remove_passwords(vrf="red", prefix="yes") +    check_all_peers_established("blue") +    clear_bgp("blue") +    clear_bgp("red") +    # tgen.mininet_cli() + + +def test_multiple_vrf_prefix_peer_change_passwords(): +    "selectively change passwords checking state with multiple vrfs and prefix config" + +    # only supported in kernel > 5.3 +    if topotest.version_cmp(platform.release(), "5.3") < 0: +        clear_bgp("blue") +        clear_bgp("red") +        clear_ospf("blue") +        clear_ospf("red") +        return + +    configure("bgpd_multi_vrf_prefix.conf") +    check_vrf_peer_change_passwords(vrf="blue", prefix="yes") +    check_all_peers_established("red") +    check_vrf_peer_change_passwords(vrf="red", prefix="yes") +    check_all_peers_established("blue") +    clear_bgp("blue") +    clear_bgp("red") +    clear_ospf("blue") +    clear_ospf("red") +    # tgen.mininet_cli() + + +def test_memory_leak(): +    "Run the memory leak test and report results." +    tgen = get_topogen() +    if not tgen.is_memleak_enabled(): +        pytest.skip("Memory leak test/report is disabled") + +    tgen.report_memory_leaks() + + +if __name__ == "__main__": +    args = ["-s"] + sys.argv[1:] +    sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/P1/ospfd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/P1/ospfd.conf index 772675ddff..2db7edb806 100644 --- a/tests/topotests/bgp-evpn-vxlan_topo1/P1/ospfd.conf +++ b/tests/topotests/bgp-evpn-vxlan_topo1/P1/ospfd.conf @@ -2,3 +2,12 @@  router ospf   network 10.20.0.0/16 area 0   network 10.20.20.20/32 area 0 +! +int P1-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int P1-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/bgpd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/bgpd.conf index d337201f71..c7a76a98ed 100644 --- a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/bgpd.conf +++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/bgpd.conf @@ -4,6 +4,7 @@ router bgp 65000   no bgp default ipv4-unicast   neighbor 10.30.30.30 remote-as 65000   neighbor 10.30.30.30 update-source lo + neighbor 10.30.30.30 timers 3 10   address-family l2vpn evpn    neighbor 10.30.30.30 activate    advertise-all-vni diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/ospfd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/ospfd.conf index 31c7fc4188..f1c2b42dc1 100644 --- a/tests/topotests/bgp-evpn-vxlan_topo1/PE1/ospfd.conf +++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE1/ospfd.conf @@ -2,3 +2,8 @@  router ospf   network 10.20.0.0/16 area 0   network 10.10.10.10/32 area 0 +! +int PE1-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/bgpd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/bgpd.conf index d99e33fc06..0a24158bb8 100644 --- a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/bgpd.conf +++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/bgpd.conf @@ -4,6 +4,7 @@ router bgp 65000   no bgp default ipv4-unicast   neighbor 10.10.10.10 remote-as 65000   neighbor 10.10.10.10 update-source lo + neighbor 10.10.10.10 timers 3 10   !   address-family l2vpn evpn    neighbor 10.10.10.10 activate diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/ospfd.conf b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/ospfd.conf index c1a8308db5..065c993303 100644 --- a/tests/topotests/bgp-evpn-vxlan_topo1/PE2/ospfd.conf +++ b/tests/topotests/bgp-evpn-vxlan_topo1/PE2/ospfd.conf @@ -2,3 +2,8 @@  router ospf   network 10.20.0.0/16 area 0   network 10.30.30.30/32 area 0 +! +int PE2-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_features/r1/bgpd.conf b/tests/topotests/bgp_features/r1/bgpd.conf index 48b71fc91a..7aea2dc161 100644 --- a/tests/topotests/bgp_features/r1/bgpd.conf +++ b/tests/topotests/bgp_features/r1/bgpd.conf @@ -3,14 +3,18 @@ hostname r1  log file bgpd.log  !  router bgp 65000 + timers bgp 3 10 + coalesce-time 0   bgp router-id 192.168.0.1   bgp log-neighbor-changes   no bgp ebgp-requires-policy   neighbor 192.168.0.2 remote-as 65000   neighbor 192.168.0.2 description Router R2 (iBGP)   neighbor 192.168.0.2 update-source lo + neighbor 192.168.0.2 timers connect 5   neighbor 192.168.101.2 remote-as 65100   neighbor 192.168.101.2 description Router R4 (eBGP AS 65100) + neighbor 192.168.101.2 timers connect 5   !   address-family ipv4 unicast    network 192.168.0.0/24 diff --git a/tests/topotests/bgp_features/r1/ospfd.conf b/tests/topotests/bgp_features/r1/ospfd.conf index 952abdec59..8f1711db7b 100644 --- a/tests/topotests/bgp_features/r1/ospfd.conf +++ b/tests/topotests/bgp_features/r1/ospfd.conf @@ -7,6 +7,17 @@ router ospf   ospf router-id 192.168.0.1   log-adjacency-changes   network 192.168.0.0/20 area 0.0.0.0 + timers throttle spf 0 0 0 + timers lsa min-arrival 10 + timers throttle lsa all 0 + refresh timer 10  !  line vty +interface r1-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +interface r1-eth2 + ip ospf hello-interval 2 + ip ospf dead-interval 10  ! diff --git a/tests/topotests/bgp_features/r2/bgpd.conf b/tests/topotests/bgp_features/r2/bgpd.conf index 775733d1d3..3daf9842ce 100644 --- a/tests/topotests/bgp_features/r2/bgpd.conf +++ b/tests/topotests/bgp_features/r2/bgpd.conf @@ -4,13 +4,17 @@ log file bgpd.log  !  router bgp 65000   bgp router-id 192.168.0.2 + timers bgp 3 10 + coalesce-time 0   bgp log-neighbor-changes   no bgp ebgp-requires-policy   neighbor 192.168.0.1 remote-as 65000   neighbor 192.168.0.1 description Router R1 (iBGP)   neighbor 192.168.0.1 update-source lo + neighbor 192.168.0.1 timers connect 5   neighbor 192.168.201.2 remote-as 65200   neighbor 192.168.201.2 description Router R5 (eBGP AS 65200) + neighbor 192.168.201.2 timers connect 5   !   address-family ipv4 unicast    network 192.168.0.0/24 diff --git a/tests/topotests/bgp_features/r2/ospfd.conf b/tests/topotests/bgp_features/r2/ospfd.conf index c9ebfe506e..2174fddb11 100644 --- a/tests/topotests/bgp_features/r2/ospfd.conf +++ b/tests/topotests/bgp_features/r2/ospfd.conf @@ -7,6 +7,17 @@ router ospf   ospf router-id 192.168.0.2   log-adjacency-changes   network 192.168.0.0/20 area 0.0.0.0 + timers throttle spf 0 0 0 + timers lsa min-arrival 10 + timers throttle lsa all 0 + refresh timer 10 +! +int r2-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +int r2-eth2 + ip ospf hello-interval 2 + ip ospf dead-interval 10  !  line vty  ! diff --git a/tests/topotests/bgp_features/r3/ospfd.conf b/tests/topotests/bgp_features/r3/ospfd.conf index a8d66f1ed3..795344fbe6 100644 --- a/tests/topotests/bgp_features/r3/ospfd.conf +++ b/tests/topotests/bgp_features/r3/ospfd.conf @@ -7,6 +7,17 @@ router ospf   ospf router-id 192.168.0.3   log-adjacency-changes   network 192.168.0.0/20 area 0.0.0.0 + timers throttle spf 0 0 0 + timers lsa min-arrival 10 + timers throttle lsa all 0 + refresh timer 10 +! +int r3-eth1 +  ip ospf hello-interval 2 +  ip ospf dead-interval 10 +int r3-eth2 +  ip ospf hello-interval 2 +  ip ospf dead-interval 10  !  line vty  ! diff --git a/tests/topotests/bgp_features/r4/bgpd.conf b/tests/topotests/bgp_features/r4/bgpd.conf index 83b452b86d..fe1a4d4ffe 100644 --- a/tests/topotests/bgp_features/r4/bgpd.conf +++ b/tests/topotests/bgp_features/r4/bgpd.conf @@ -4,10 +4,13 @@ log file bgpd.log  !  router bgp 65100   bgp router-id 192.168.100.1 + timers bgp 3 10 + coalesce-time 0   bgp log-neighbor-changes   no bgp ebgp-requires-policy   neighbor 192.168.101.1 remote-as 65000   neighbor 192.168.101.1 description Router R1 (eBGP AS 65000) + neighbor 192.168.101.1 timers connect 5   !   address-family ipv4 unicast    network 192.168.100.0/24 diff --git a/tests/topotests/bgp_features/r5/bgpd.conf b/tests/topotests/bgp_features/r5/bgpd.conf index a6a42a007c..8504213b41 100644 --- a/tests/topotests/bgp_features/r5/bgpd.conf +++ b/tests/topotests/bgp_features/r5/bgpd.conf @@ -4,10 +4,13 @@ log file bgpd.log  !  router bgp 65200   bgp router-id 192.168.200.1 + timers bgp 3 10 + coalesce-time 0   bgp log-neighbor-changes   no bgp ebgp-requires-policy   neighbor 192.168.201.1 remote-as 65000   neighbor 192.168.201.1 description Router R2 (eBGP AS 65000) + neighbor 192.168.201.1 timers connect 5   !   address-family ipv4 unicast    network 192.168.200.0/24 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf index 2712e54f12..8b885341eb 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce1/bgpd.conf @@ -10,6 +10,7 @@ router bgp 5226     no bgp ebgp-requires-policy     neighbor 192.168.1.1 remote-as 5226     neighbor 192.168.1.1 update-source 192.168.1.2 +   neighbor 192.168.1.1 timers 3 10     address-family ipv4 unicast       network 5.1.0.0/24 route-map rm-nh       network 5.1.1.0/24 route-map rm-nh diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf index 69305512cb..2accaae163 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce2/bgpd.conf @@ -10,6 +10,7 @@ router bgp 5226     no bgp ebgp-requires-policy     neighbor 192.168.1.1 remote-as 5226     neighbor 192.168.1.1 update-source 192.168.1.2 +   neighbor 192.168.1.1 timers 3 10     address-family ipv4 unicast       network 5.1.0.0/24 route-map rm-nh       network 5.1.1.0/24 route-map rm-nh diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf index 3ad95c3612..42eff1b9b1 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/ce3/bgpd.conf @@ -10,6 +10,7 @@ router bgp 5226     no bgp ebgp-requires-policy     neighbor 192.168.1.1 remote-as 5226     neighbor 192.168.1.1 update-source 192.168.1.2 +   neighbor 192.168.1.1 timers 3 10     address-family ipv4 unicast       network 5.1.2.0/24 route-map rm-nh       network 5.1.3.0/24 route-map rm-nh diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf index 502c4c8b2f..a564da9411 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/bgpd.conf @@ -11,8 +11,10 @@ router bgp 5226     neighbor 192.168.1.2 remote-as 5226     neighbor 192.168.1.2 update-source 192.168.1.1     neighbor 192.168.1.2 route-reflector-client +   neighbor 192.168.1.2 timers 3 10     neighbor 2.2.2.2 remote-as 5226     neighbor 2.2.2.2 update-source 1.1.1.1 +   neighbor 2.2.2.2 timers 3 10  !     address-family ipv4 unicast       redistribute vnc-direct diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf index c5097e214f..460a8fb016 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ospfd.conf @@ -6,3 +6,7 @@ router ospf   network 0.0.0.0/4 area 0   redistribute static  ! +int r1-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf index 95890f25b9..3167306700 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/bgpd.conf @@ -10,10 +10,13 @@ router bgp 5226     no bgp ebgp-requires-policy     neighbor 1.1.1.1 remote-as 5226     neighbor 1.1.1.1 update-source 2.2.2.2 +   neighbor 1.1.1.1 timers 3 10     neighbor 3.3.3.3 remote-as 5226     neighbor 3.3.3.3 update-source 2.2.2.2 +   neighbor 3.3.3.3 timers 3 10     neighbor 4.4.4.4 remote-as 5226     neighbor 4.4.4.4 update-source 2.2.2.2 +   neighbor 4.4.4.4 timers 3 10     address-family ipv4 unicast       no neighbor 1.1.1.1 activate       no neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf index 8678813665..dbed6189c8 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ospfd.conf @@ -5,3 +5,15 @@ router ospf   router-id 2.2.2.2   network 0.0.0.0/0 area 0  ! +int r2-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth2 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf index 2f7de073c3..445da08248 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/bgpd.conf @@ -11,8 +11,10 @@ router bgp 5226     neighbor 192.168.1.2 remote-as 5226     neighbor 192.168.1.2 update-source 192.168.1.2     neighbor 192.168.1.2 route-reflector-client +   neighbor 192.168.1.2 timers 3 10     neighbor 2.2.2.2 remote-as 5226     neighbor 2.2.2.2 update-source 3.3.3.3 +   neighbor 2.2.2.2 timers 3 10  !     address-family ipv4 unicast       redistribute vnc-direct diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf index c7c358f9dc..0e64ed6fc5 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ospfd.conf @@ -7,3 +7,11 @@ router ospf   network 0.0.0.0/4 area 0   redistribute static  ! +int r3-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r3-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf index 720d06dbf1..1941352450 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/bgpd.conf @@ -11,8 +11,10 @@ router bgp 5226     neighbor 192.168.1.2 remote-as 5226     neighbor 192.168.1.2 update-source 192.168.1.1     neighbor 192.168.1.2 route-reflector-client +   neighbor 192.168.1.2 timers 3 10     neighbor 2.2.2.2 remote-as 5226     neighbor 2.2.2.2 update-source 4.4.4.4 +   neighbor 2.2.2.2 timers 3 10  !     address-family ipv4 unicast       redistribute vnc-direct diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf index 83d09c09a4..89e37df479 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ospfd.conf @@ -6,3 +6,7 @@ router ospf   network 0.0.0.0/4 area 0   redistribute static  ! +int r4-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf index b81cd33c4f..6e6b9edde2 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce1/bgpd.conf @@ -12,6 +12,7 @@ router bgp 5227     no bgp ebgp-requires-policy     neighbor 192.168.1.1 remote-as 5227     neighbor 192.168.1.1 update-source 192.168.1.2 +   neighbor 192.168.1.1 timers 3 10     address-family ipv4 unicast       network 99.0.0.1/32       network 5.1.0.0/24 route-map rm-nh diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf index f18e5b852e..618acabd9f 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce2/bgpd.conf @@ -12,6 +12,7 @@ router bgp 5227     no bgp ebgp-requires-policy     neighbor 192.168.1.1 remote-as 5227     neighbor 192.168.1.1 update-source 192.168.1.2 +   neighbor 192.168.1.1 timers 3 10     address-family ipv4 unicast       network 99.0.0.2/32       network 5.1.0.0/24 route-map rm-nh diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf index 54a0933588..85c5973e6f 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce3/bgpd.conf @@ -12,6 +12,7 @@ router bgp 5227     no bgp ebgp-requires-policy     neighbor 192.168.1.1 remote-as 5227     neighbor 192.168.1.1 update-source 192.168.1.2 +   neighbor 192.168.1.1 timers 3 10     address-family ipv4 unicast       network 99.0.0.3/32       network 5.1.2.0/24 route-map rm-nh diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf index 5289628480..6a5075a000 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/ce4/bgpd.conf @@ -12,6 +12,7 @@ router bgp 5228 vrf ce4-cust2     no bgp ebgp-requires-policy     neighbor 192.168.2.1 remote-as 5228     neighbor 192.168.2.1 update-source 192.168.2.2 +   neighbor 192.168.2.1 timers 3 10     address-family ipv4 unicast       network 99.0.0.4/32       network 5.4.2.0/24 route-map rm-nh diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf index 5da53ae1e7..8d42cfc0d8 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf @@ -18,6 +18,7 @@ router bgp 5226     no bgp ebgp-requires-policy     neighbor 2.2.2.2 remote-as 5226     neighbor 2.2.2.2 update-source 1.1.1.1 +   neighbor 2.2.2.2 timers 3 10     address-family ipv4 unicast       no neighbor 2.2.2.2 activate @@ -35,6 +36,7 @@ router bgp 5227 vrf r1-cust1     neighbor 192.168.1.2 remote-as 5227     neighbor 192.168.1.2 update-source 192.168.1.1 +   neighbor 192.168.1.2 timers 3 10     address-family ipv4 unicast       neighbor 192.168.1.2 activate diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf index c5097e214f..460a8fb016 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ospfd.conf @@ -6,3 +6,7 @@ router ospf   network 0.0.0.0/4 area 0   redistribute static  ! +int r1-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf index e4a6b8e32c..7b42b770b5 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/bgpd.conf @@ -12,10 +12,13 @@ router bgp 5226     no bgp ebgp-requires-policy     neighbor 1.1.1.1 remote-as 5226     neighbor 1.1.1.1 update-source 2.2.2.2 +   neighbor 1.1.1.1 timers 3 10     neighbor 3.3.3.3 remote-as 5226     neighbor 3.3.3.3 update-source 2.2.2.2 +   neighbor 3.3.3.3 timers 3 10     neighbor 4.4.4.4 remote-as 5226     neighbor 4.4.4.4 update-source 2.2.2.2 +   neighbor 4.4.4.4 timers 3 10     address-family ipv4 unicast       no neighbor 1.1.1.1 activate       no neighbor 3.3.3.3 activate diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf index 8678813665..dbed6189c8 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ospfd.conf @@ -5,3 +5,15 @@ router ospf   router-id 2.2.2.2   network 0.0.0.0/0 area 0  ! +int r2-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth2 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf index a861469c7a..6c9640eea0 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/bgpd.conf @@ -13,6 +13,7 @@ router bgp 5226     no bgp ebgp-requires-policy     neighbor 2.2.2.2 remote-as 5226     neighbor 2.2.2.2 update-source 3.3.3.3 +   neighbor 2.2.2.2 timers 3 10     address-family ipv4 unicast       no neighbor 2.2.2.2 activate @@ -29,6 +30,7 @@ router bgp 5227 vrf r3-cust1     neighbor 192.168.1.2 remote-as 5227     neighbor 192.168.1.2 update-source 192.168.1.1 +   neighbor 192.168.1.2 timers 3 10     address-family ipv4 unicast       neighbor 192.168.1.2 activate diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf index c7c358f9dc..0e64ed6fc5 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ospfd.conf @@ -7,3 +7,11 @@ router ospf   network 0.0.0.0/4 area 0   redistribute static  ! +int r3-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r3-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf index 480f95954e..ca9e627172 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/bgpd.conf @@ -16,6 +16,7 @@ router bgp 5226     no bgp ebgp-requires-policy     neighbor 2.2.2.2 remote-as 5226     neighbor 2.2.2.2 update-source 4.4.4.4 +   neighbor 2.2.2.2 timers 3 10     address-family ipv4 unicast       no neighbor 2.2.2.2 activate @@ -32,6 +33,7 @@ router bgp 5227 vrf r4-cust1     neighbor 192.168.1.2 remote-as 5227     neighbor 192.168.1.2 update-source 192.168.1.1 +   neighbor 192.168.1.2 timers 3 10     address-family ipv4 unicast       neighbor 192.168.1.2 activate @@ -52,6 +54,7 @@ router bgp 5228 vrf r4-cust2     neighbor 192.168.2.2 remote-as 5228     neighbor 192.168.2.2 update-source 192.168.2.1 +   neighbor 192.168.2.2 timers 3 10     address-family ipv4 unicast       neighbor 192.168.2.2 activate diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf index 83d09c09a4..89e37df479 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ospfd.conf @@ -6,3 +6,7 @@ router ospf   network 0.0.0.0/4 area 0   redistribute static  ! +int r4-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf index c5097e214f..460a8fb016 100644 --- a/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf +++ b/tests/topotests/bgp_rfapi_basic_sanity/r1/ospfd.conf @@ -6,3 +6,7 @@ router ospf   network 0.0.0.0/4 area 0   redistribute static  ! +int r1-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf index 8678813665..dbed6189c8 100644 --- a/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf +++ b/tests/topotests/bgp_rfapi_basic_sanity/r2/ospfd.conf @@ -5,3 +5,15 @@ router ospf   router-id 2.2.2.2   network 0.0.0.0/0 area 0  ! +int r2-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth2 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf index c7c358f9dc..0e64ed6fc5 100644 --- a/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf +++ b/tests/topotests/bgp_rfapi_basic_sanity/r3/ospfd.conf @@ -7,3 +7,11 @@ router ospf   network 0.0.0.0/4 area 0   redistribute static  ! +int r3-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r3-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf index 83d09c09a4..89e37df479 100644 --- a/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf +++ b/tests/topotests/bgp_rfapi_basic_sanity/r4/ospfd.conf @@ -6,3 +6,7 @@ router ospf   network 0.0.0.0/4 area 0   redistribute static  ! +int r4-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/bgp_update_delay/__init__.py b/tests/topotests/bgp_update_delay/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_update_delay/__init__.py diff --git a/tests/topotests/bgp_update_delay/r1/bgpd.conf b/tests/topotests/bgp_update_delay/r1/bgpd.conf new file mode 100644 index 0000000000..8ebb509d6d --- /dev/null +++ b/tests/topotests/bgp_update_delay/r1/bgpd.conf @@ -0,0 +1,10 @@ +! exit1 +router bgp 65001 +  no bgp ebgp-requires-policy +  neighbor 192.168.255.1 remote-as 65002 +  neighbor 192.168.255.1 timers connect 10 +  address-family ipv4 unicast +    redistribute connected +  exit-address-family +  ! +! diff --git a/tests/topotests/bgp_update_delay/r1/zebra.conf b/tests/topotests/bgp_update_delay/r1/zebra.conf new file mode 100644 index 0000000000..9904bb4e16 --- /dev/null +++ b/tests/topotests/bgp_update_delay/r1/zebra.conf @@ -0,0 +1,9 @@ +! exit1 +interface lo + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_update_delay/r2/bgpd.conf b/tests/topotests/bgp_update_delay/r2/bgpd.conf new file mode 100644 index 0000000000..438f9950a5 --- /dev/null +++ b/tests/topotests/bgp_update_delay/r2/bgpd.conf @@ -0,0 +1,18 @@ +! spine +router bgp 65002 +  no bgp ebgp-requires-policy +  timers bgp 3 9 +  neighbor 192.168.255.2 remote-as 65001 +  neighbor 192.168.254.2 remote-as 65003 +  neighbor 192.168.253.2 remote-as 65004 +  neighbor 192.168.255.2 timers connect 10 +  neighbor 192.168.254.2 timers connect 10 +  neighbor 192.168.253.2 timers connect 10 +! + router bgp 65002 vrf vrf1 +  no bgp ebgp-requires-policy +  timers bgp 3 9 +  neighbor 192.168.252.2 remote-as 65005 +  neighbor 192.168.252.2 timers connect 10 +  ! +! diff --git a/tests/topotests/bgp_update_delay/r2/zebra.conf b/tests/topotests/bgp_update_delay/r2/zebra.conf new file mode 100644 index 0000000000..420f00d974 --- /dev/null +++ b/tests/topotests/bgp_update_delay/r2/zebra.conf @@ -0,0 +1,20 @@ +! spine +interface r2-eth0 + ip address 192.168.255.1/30 +! +interface r2-eth1 + ip address 192.168.254.1/30 +! +interface r2-eth2 + ip address 192.168.253.1/30 +! +interface r2-eth3 + ip address 192.168.252.1/30 + vrf vrf1 +! +auto vrf1 +iface vrf1 +  vrf-table auto +! +ip forwarding +! diff --git a/tests/topotests/bgp_update_delay/r3/bgpd.conf b/tests/topotests/bgp_update_delay/r3/bgpd.conf new file mode 100644 index 0000000000..53e51788f7 --- /dev/null +++ b/tests/topotests/bgp_update_delay/r3/bgpd.conf @@ -0,0 +1,10 @@ +! exit2 +router bgp 65003 +  no bgp ebgp-requires-policy +  timers bgp 3 9 +  neighbor 192.168.254.1 remote-as 65002 +  neighbor 192.168.254.1 timers connect 10 +  address-family ipv4 unicast +    redistribute connected +  ! +! diff --git a/tests/topotests/bgp_update_delay/r3/zebra.conf b/tests/topotests/bgp_update_delay/r3/zebra.conf new file mode 100644 index 0000000000..f490d97afe --- /dev/null +++ b/tests/topotests/bgp_update_delay/r3/zebra.conf @@ -0,0 +1,9 @@ +! exit2 +interface lo + ip address 172.16.254.254/32 +! +interface r3-eth0 + ip address 192.168.254.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_update_delay/r4/bgpd.conf b/tests/topotests/bgp_update_delay/r4/bgpd.conf new file mode 100644 index 0000000000..34cb429c0a --- /dev/null +++ b/tests/topotests/bgp_update_delay/r4/bgpd.conf @@ -0,0 +1,11 @@ +! exit2 +router bgp 65004 +  no bgp ebgp-requires-policy +  timers bgp 3 9 +  neighbor 192.168.253.1 remote-as 65002 +  neighbor 192.168.253.1 timers connect 10 +  address-family ipv4 unicast +    redistribute connected +  exit-address-family +  ! +! diff --git a/tests/topotests/bgp_update_delay/r4/zebra.conf b/tests/topotests/bgp_update_delay/r4/zebra.conf new file mode 100644 index 0000000000..baba04c160 --- /dev/null +++ b/tests/topotests/bgp_update_delay/r4/zebra.conf @@ -0,0 +1,9 @@ +! exit2 +interface lo + ip address 172.16.253.254/32 +! +interface r4-eth0 + ip address 192.168.253.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_update_delay/r5/bgpd.conf b/tests/topotests/bgp_update_delay/r5/bgpd.conf new file mode 100644 index 0000000000..66ecc703cd --- /dev/null +++ b/tests/topotests/bgp_update_delay/r5/bgpd.conf @@ -0,0 +1,11 @@ +! exit1 +router bgp 65005 +  no bgp ebgp-requires-policy +  timers bgp 3 9 +  neighbor 192.168.252.1 remote-as 65002 +  neighbor 192.168.252.1 timers connect 10 +  address-family ipv4 unicast +    redistribute connected +  exit-address-family +  ! +! diff --git a/tests/topotests/bgp_update_delay/r5/zebra.conf b/tests/topotests/bgp_update_delay/r5/zebra.conf new file mode 100644 index 0000000000..8adf6f89e0 --- /dev/null +++ b/tests/topotests/bgp_update_delay/r5/zebra.conf @@ -0,0 +1,9 @@ +! exit1 +interface lo + ip address 172.16.252.254/32 +! +interface r1-eth0 + ip address 192.168.252.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py new file mode 100755 index 0000000000..9d2818b965 --- /dev/null +++ b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python + +# +# test_bgp_update_delay.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Don Slice <dslice@nvidia.com> +# +# 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. +# + +""" +Test the ability to define update-delay to delay bestpath, rib install +and advertisement to peers when frr is started, restarted or "clear ip +bgp *" is performed. Test both the vrf-specific and global configuration +and operation. + +r1 +| +r2----r3 +| \ +|  \ +r5  r4 + + +r2 is UUT and peers with r1, r3, and r4 in default bgp instance. +r2 peers with r5 in vrf vrf1. + +Check r2 initial convergence in default table +Define update-delay with max-delay in the default bgp instance on r2 +Shutdown peering on r1 toward r2 so that delay timers can be exercised +Clear bgp neighbors on r2 and then check for the 'in progress' indicator +Check that r2 only installs route learned from r4 after the max-delay timer expires +Define update-delay with max-delay and estabish-wait and check json output showing set +Clear neighbors on r2 and check that r3 installs route from r4 after establish-wait time +Remove update-delay timer on r2 to verify that it goes back to normal behavior +Clear neighbors on r2 and check that route install time on r2 does not delay +Define global bgp update-delay with max-delay and establish-wait on r2 +Check that r2 default instance and vrf1 have the max-delay and establish set +Clear neighbors on r2 and check route-install time is after the establish-wait timer + +Note that the keepalive/hold times were changed to 3/9 and the connect retry timer +to 10 to improve the odds the convergence timing in this test case is useful in the +event of packet loss. +""" + +import os +import sys +import json +import time +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.topolog import logger +from mininet.topo import Topo + + +class TemplateTopo(Topo): +    def build(self, *_args, **_opts): +        tgen = get_topogen(self) + +        for routern in range(1, 6): +            tgen.add_router("r{}".format(routern)) + +        switch = tgen.add_switch("s1") +        switch.add_link(tgen.gears["r1"]) +        switch.add_link(tgen.gears["r2"]) + +        switch = tgen.add_switch("s2") +        switch.add_link(tgen.gears["r2"]) +        switch.add_link(tgen.gears["r3"]) + +        switch = tgen.add_switch("s3") +        switch.add_link(tgen.gears["r2"]) +        switch.add_link(tgen.gears["r4"]) + +        switch = tgen.add_switch("s4") +        switch.add_link(tgen.gears["r2"]) +        switch.add_link(tgen.gears["r5"]) + + +def setup_module(mod): +    tgen = Topogen(TemplateTopo, mod.__name__) +    tgen.start_topology() + +    router_list = tgen.routers() + +    for i, (rname, router) in enumerate(router_list.iteritems(), 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)) +        ) + +    tgen.start_router() + + +def teardown_module(mod): +    tgen = get_topogen() +    tgen.stop_topology() + + +def test_bgp_update_delay(): +    tgen = get_topogen() + +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    router1 = tgen.gears["r1"] +    router2 = tgen.gears["r2"] +    router3 = tgen.gears["r3"] + +    # initial convergence without update-delay defined +    def _bgp_converge(router): +        output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json")) +        expected = { +            "192.168.255.2": { +                "bgpState": "Established", +                "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}}, +            } +        } +        return topotest.json_cmp(output, expected) + +    def _bgp_check_update_delay(router): +        output = json.loads(router.vtysh_cmd("show ip bgp sum json")) +        expected = {"ipv4Unicast": {"updateDelayLimit": 20}} + +        return topotest.json_cmp(output, expected) + +    def _bgp_check_update_delay_in_progress(router): +        output = json.loads(router.vtysh_cmd("show ip bgp sum json")) +        expected = {"ipv4Unicast": {"updateDelayInProgress":True}} + +        return topotest.json_cmp(output, expected) + +    def _bgp_check_route_install(router): +        output = json.loads(router.vtysh_cmd("show ip route 172.16.253.254/32 json")) +        expected = {"172.16.253.254/32": [ {"protocol": "bgp"}]} + +        return topotest.json_cmp(output, expected) + +    def _bgp_check_update_delay_and_wait(router): +        output = json.loads(router.vtysh_cmd("show ip bgp sum json")) +        expected = { +                "ipv4Unicast": { +                    "updateDelayLimit": 20, +                    "updateDelayEstablishWait": 10}} + +        return topotest.json_cmp(output, expected) + +    def _bgp_check_update_delay(router): +        output = json.loads(router.vtysh_cmd("show ip bgp sum json")) +        expected = {"ipv4Unicast": {"updateDelayLimit": 20}} + +        return topotest.json_cmp(output, expected) + +    def _bgp_check_vrf_update_delay_and_wait(router): +        output = json.loads(router.vtysh_cmd("show ip bgp vrf vrf1 sum json")) +        expected = { +                "ipv4Unicast": { +                    "updateDelayLimit": 20, +                    "updateDelayEstablishWait": 10}} + + +        return topotest.json_cmp(output, expected) + + +    # Check r2 initial convergence in default table +    test_func = functools.partial(_bgp_converge, router2) +    success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + +    assert result is None, 'Failed bgp convergence in "{}"'.format(router2) + +    # Define update-delay with max-delay in the default bgp instance on r2 +    router2.vtysh_cmd( +        """ +          configure terminal +            router bgp 65002 +              update-delay 20 +        """ +        ) + +    # Shutdown peering on r1 toward r2 so that delay timers can be exercised +    router1.vtysh_cmd( +        """ +          configure terminal +            router bgp 65001 +              neighbor 192.168.255.1 shut +        """ +        ) + +    # Clear bgp neighbors on r2 and then check for the 'in progress' indicator +    router2.vtysh_cmd("""clear ip bgp *""") + +    test_func = functools.partial(_bgp_check_update_delay_in_progress, router2) +    success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + +    assert result is None, 'Failed to set update-delay max-delay timer "{}"'.format(router2) + +    # Check that r2 only installs route learned from r4 after the max-delay timer expires +    test_func = functools.partial(_bgp_check_route_install, router2) +    success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + +    assert result is None, 'Failed to install route after update-delay "{}"'.format(router2) + +    # Define update-delay with max-delay and estabish-wait and check json output showing set +    router2.vtysh_cmd( +        """ +          configure terminal +            router bgp 65002 +              update-delay 20 10 +        """ +        ) + +    test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) +    success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + +    assert result is None, 'Failed to set max-delay and establish-weight timers in "{}"'.format(router2) + +    # Define update-delay with max-delay and estabish-wait and check json output showing set +    router2.vtysh_cmd("""clear ip bgp *""") + +    test_func = functools.partial(_bgp_check_route_install, router3) +    success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + +    assert result is None, 'Failed to installed advertised route after establish-wait timer espired "{}"'.format(router2) + +    # Remove update-delay timer on r2 to verify that it goes back to normal behavior +    router2.vtysh_cmd( +        """ +          configure terminal +            router bgp 65002 +              no update-delay +        """ +        ) + +    # Clear neighbors on r2 and check that route install time on r2 does not delay +    router2.vtysh_cmd("""clear ip bgp *""") + +    test_func = functools.partial(_bgp_check_route_install, router2) +    success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + +    assert result is None, 'Failed to remove update-delay delay timing "{}"'.format(router2) + +    # Define global bgp update-delay with max-delay and establish-wait on r2 +    router2.vtysh_cmd( +        """ +          configure terminal +            bgp update-delay 20 10 +        """ +        ) + +    # Check that r2 default instance and vrf1 have the max-delay and establish set +    test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) +    success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + +    assert result is None, 'Failed to set update-delay in default instance "{}"'.format(router2) + +    test_func = functools.partial(_bgp_check_vrf_update_delay_and_wait, router2) +    success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + +    assert result is None, 'Failed to set update-delay in vrf1 "{}"'.format(router2) + +    # Clear neighbors on r2 and check route-install time is after the establish-wait timer +    router2.vtysh_cmd("""clear ip bgp *""") + +    test_func = functools.partial(_bgp_check_route_install, router3) +    success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + +    assert result is None, 'Failed to installed advertised route after establish-wait timer espired "{}"'.format(router2) + + +if __name__ == "__main__": +    args = ["-s"] + sys.argv[1:] +    sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json new file mode 100644 index 0000000000..b1d7d09db8 --- /dev/null +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json @@ -0,0 +1,563 @@ +{ +    "address_types": ["ipv4","ipv6"], +    "ipv4base": "10.0.0.0", +    "ipv4mask": 30, +    "ipv6base": "fd00::", +    "ipv6mask": 64, +    "link_ip_start": { +        "ipv4": "10.0.0.0", +        "v4mask": 30, +        "ipv6": "fd00::", +        "v6mask": 64 +    }, +    "lo_prefix": { +        "ipv4": "1.0.", +        "v4mask": 32, +        "ipv6": "2001:db8:f::", +        "v6mask": 128 +    }, +    "routers": { +        "r1": { +            "links": { +                "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"}, +                "r3-link1": {"ipv4": "auto", "ipv6": "auto"}, +                "r4-link1": {"ipv4": "auto", "ipv6": "auto"} +            }, +            "vrfs":[ +                { +                    "name": "ISR", +                    "id": "1" +                } +            ], +            "bgp": +            [ +                { +                    "local_as": "100", +                    "vrf": "ISR", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "next_hop_self": true +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "next_hop_self": true, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ], +            "static_routes":[ +                { +                    "network": ["11.11.11.1/32", "11.11.11.11/32"], +                    "next_hop":"Null0", +                    "vrf": "ISR" +                }, +                { +                    "network": ["11:11::1/128", "11:11::11/128"], +                    "next_hop":"Null0", +                    "vrf": "ISR" +                }, +                { +                    "network": ["10.10.10.10/32", "10.10.10.100/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["10:10::10/128", "10:10::100/128"], +                    "next_hop":"Null0" +                } +            ], +            "route_maps": { +                "rmap_global": [{ +                    "action": "permit", +                    "set": { +                        "ipv6": { +                            "nexthop": "prefer-global" +                        } +                    } +                }] +            } +        }, +        "r2": { +            "links": { +                "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"}, +                "r3-link1": {"ipv4": "auto", "ipv6": "auto"}, +                "r4-link1": {"ipv4": "auto", "ipv6": "auto"} +            }, +            "vrfs":[ +                { +                    "name": "ISR", +                    "id": "1" +                } +            ], +            "bgp": +            [ +                { +                    "local_as": "100", +                    "vrf": "ISR", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "next_hop_self": true +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "next_hop_self": true, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ], +            "static_routes":[ +                { +                    "network": ["22.22.22.2/32", "22.22.22.22/32"], +                    "next_hop":"Null0", +                    "vrf": "ISR" +                }, +                { +                    "network": ["22:22::2/128", "22:22::22/128"], +                    "next_hop":"Null0", +                    "vrf": "ISR" +                }, +                { +                    "network": ["20.20.20.20/32", "20.20.20.200/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["20:20::20/128", "20:20::200/128"], +                    "next_hop":"Null0" +                } +            ], +            "route_maps": { +                "rmap_global": [{ +                    "action": "permit", +                    "set": { +                        "ipv6": { +                            "nexthop": "prefer-global" +                        } +                    } +                }] +            } +        }, +        "r3": { +            "links": { +                "r1-link1": {"ipv4": "auto", "ipv6": "auto"}, +                "r2-link1": {"ipv4": "auto", "ipv6": "auto"} +            }, +            "bgp": +            [ +                { +                    "local_as": "300", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "300", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ], +            "static_routes":[ +                { +                    "network": ["30.30.30.3/32", "30.30.30.30/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["30:30::3/128", "30:30::30/128"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["50.50.50.5/32", "50.50.50.50/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["50:50::5/128", "50:50::50/128"], +                    "next_hop":"Null0" +                } +            ], +            "route_maps": { +                "rmap_global": [{ +                    "action": "permit", +                    "set": { +                        "ipv6": { +                            "nexthop": "prefer-global" +                        } +                    } +                }] +            } +        }, +        "r4": { +            "links": { +                "r1-link1": {"ipv4": "auto", "ipv6": "auto"}, +                "r2-link1": {"ipv4": "auto", "ipv6": "auto"} +            }, +            "bgp": +            [ +                { +                    "local_as": "400", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "400", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ], +            "static_routes":[ +                { +                    "network": ["40.40.40.4/32", "40.40.40.40/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["40:40::4/128", "40:40::40/128"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["50.50.50.5/32", "50.50.50.50/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["50:50::5/128", "50:50::50/128"], +                    "next_hop":"Null0" +                } +            ], +            "route_maps": { +                "rmap_global": [{ +                    "action": "permit", +                    "set": { +                        "ipv6": { +                            "nexthop": "prefer-global" +                        } +                    } +                }] +            } +        } +    } +} diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json new file mode 100644 index 0000000000..b1d7d09db8 --- /dev/null +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json @@ -0,0 +1,563 @@ +{ +    "address_types": ["ipv4","ipv6"], +    "ipv4base": "10.0.0.0", +    "ipv4mask": 30, +    "ipv6base": "fd00::", +    "ipv6mask": 64, +    "link_ip_start": { +        "ipv4": "10.0.0.0", +        "v4mask": 30, +        "ipv6": "fd00::", +        "v6mask": 64 +    }, +    "lo_prefix": { +        "ipv4": "1.0.", +        "v4mask": 32, +        "ipv6": "2001:db8:f::", +        "v6mask": 128 +    }, +    "routers": { +        "r1": { +            "links": { +                "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"}, +                "r3-link1": {"ipv4": "auto", "ipv6": "auto"}, +                "r4-link1": {"ipv4": "auto", "ipv6": "auto"} +            }, +            "vrfs":[ +                { +                    "name": "ISR", +                    "id": "1" +                } +            ], +            "bgp": +            [ +                { +                    "local_as": "100", +                    "vrf": "ISR", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "next_hop_self": true +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "next_hop_self": true, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ], +            "static_routes":[ +                { +                    "network": ["11.11.11.1/32", "11.11.11.11/32"], +                    "next_hop":"Null0", +                    "vrf": "ISR" +                }, +                { +                    "network": ["11:11::1/128", "11:11::11/128"], +                    "next_hop":"Null0", +                    "vrf": "ISR" +                }, +                { +                    "network": ["10.10.10.10/32", "10.10.10.100/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["10:10::10/128", "10:10::100/128"], +                    "next_hop":"Null0" +                } +            ], +            "route_maps": { +                "rmap_global": [{ +                    "action": "permit", +                    "set": { +                        "ipv6": { +                            "nexthop": "prefer-global" +                        } +                    } +                }] +            } +        }, +        "r2": { +            "links": { +                "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"}, +                "r3-link1": {"ipv4": "auto", "ipv6": "auto"}, +                "r4-link1": {"ipv4": "auto", "ipv6": "auto"} +            }, +            "vrfs":[ +                { +                    "name": "ISR", +                    "id": "1" +                } +            ], +            "bgp": +            [ +                { +                    "local_as": "100", +                    "vrf": "ISR", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "next_hop_self": true +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "next_hop_self": true, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ], +            "static_routes":[ +                { +                    "network": ["22.22.22.2/32", "22.22.22.22/32"], +                    "next_hop":"Null0", +                    "vrf": "ISR" +                }, +                { +                    "network": ["22:22::2/128", "22:22::22/128"], +                    "next_hop":"Null0", +                    "vrf": "ISR" +                }, +                { +                    "network": ["20.20.20.20/32", "20.20.20.200/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["20:20::20/128", "20:20::200/128"], +                    "next_hop":"Null0" +                } +            ], +            "route_maps": { +                "rmap_global": [{ +                    "action": "permit", +                    "set": { +                        "ipv6": { +                            "nexthop": "prefer-global" +                        } +                    } +                }] +            } +        }, +        "r3": { +            "links": { +                "r1-link1": {"ipv4": "auto", "ipv6": "auto"}, +                "r2-link1": {"ipv4": "auto", "ipv6": "auto"} +            }, +            "bgp": +            [ +                { +                    "local_as": "300", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "300", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ], +            "static_routes":[ +                { +                    "network": ["30.30.30.3/32", "30.30.30.30/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["30:30::3/128", "30:30::30/128"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["50.50.50.5/32", "50.50.50.50/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["50:50::5/128", "50:50::50/128"], +                    "next_hop":"Null0" +                } +            ], +            "route_maps": { +                "rmap_global": [{ +                    "action": "permit", +                    "set": { +                        "ipv6": { +                            "nexthop": "prefer-global" +                        } +                    } +                }] +            } +        }, +        "r4": { +            "links": { +                "r1-link1": {"ipv4": "auto", "ipv6": "auto"}, +                "r2-link1": {"ipv4": "auto", "ipv6": "auto"} +            }, +            "bgp": +            [ +                { +                    "local_as": "400", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "400", +                    "address_family": { +                        "ipv4": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3 +                                            } +                                        } +                                    } +                                } +                            } +                        }, +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "keepalivetimer": 1, +                                                "holddowntimer": 3, +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in" +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ], +            "static_routes":[ +                { +                    "network": ["40.40.40.4/32", "40.40.40.40/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["40:40::4/128", "40:40::40/128"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["50.50.50.5/32", "50.50.50.50/32"], +                    "next_hop":"Null0" +                }, +                { +                    "network": ["50:50::5/128", "50:50::50/128"], +                    "next_hop":"Null0" +                } +            ], +            "route_maps": { +                "rmap_global": [{ +                    "action": "permit", +                    "set": { +                        "ipv6": { +                            "nexthop": "prefer-global" +                        } +                    } +                }] +            } +        } +    } +} diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py new file mode 100755 index 0000000000..1947548b3e --- /dev/null +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py @@ -0,0 +1,1848 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# 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 VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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. +# + +""" +Following tests are covered to test BGP Multi-VRF Dynamic Route Leaking: + +1. Verify that dynamically imported routes are further advertised +    to iBGP peers(peer in cluster). +2. Verify matching a prefix based on community attribute and +    importing it by stripping off this value +3. Verify the route-map operation along with dynamic import command. +4. Verifying the JSON outputs for all supported commands +""" + +import os +import sys +import json +import time +import pytest +import platform + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) +sys.path.append(os.path.join(CWD, '../lib/')) + +# Required to instantiate the topology builder class. + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topotest import version_cmp +from mininet.topo import Topo + +from lib.common_config import ( +    start_topology, write_test_header, check_address_types, +    write_test_footer, reset_config_on_routers, +    verify_rib, step, create_route_maps, +    shutdown_bringup_interface, create_static_routes, +    create_prefix_lists, create_bgp_community_lists, +    create_interface_in_kernel, +    check_router_status, verify_cli_json, +    get_frr_ipv6_linklocal, verify_fib_routes +) + +from lib.topolog import logger +from lib.bgp import ( +    verify_bgp_convergence, create_router_bgp, +    clear_bgp, verify_bgp_community, verify_bgp_rib +) +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology creation +jsonFile = "{}/bgp_vrf_dynamic_route_leak_topo1.json".format(CWD) +try: +    with open(jsonFile, "r") as topoJson: +        topo = json.load(topoJson) +except IOError: +    assert False, "Could not read file {}".format(jsonFile) + +# Global variables +NETWORK1_1 = {"ipv4": "11.11.11.1/32", "ipv6": "11:11::1/128"} +NETWORK1_2 = {"ipv4": "11.11.11.11/32", "ipv6": "11:11::11/128"} +NETWORK1_3 = {"ipv4": "10.10.10.10/32", "ipv6": "10:10::10/128"} +NETWORK1_4 = {"ipv4": "10.10.10.100/32", "ipv6": "10:10::100/128"} + +NETWORK2_1 = {"ipv4": "22.22.22.2/32", "ipv6": "22:22::2/128"} +NETWORK2_2 = {"ipv4": "22.22.22.22/32", "ipv6": "22:22::22/128"} +NETWORK2_3 = {"ipv4": "20.20.20.20/32", "ipv6": "20:20::20/128"} +NETWORK2_4 = {"ipv4": "20.20.20.200/32", "ipv6": "20:20::200/128"} + +NETWORK3_1 = {"ipv4": "30.30.30.3/32", "ipv6": "30:30::3/128"} +NETWORK3_2 = {"ipv4": "30.30.30.30/32", "ipv6": "30:30::30/128"} +NETWORK3_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"} +NETWORK3_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"} + +NETWORK4_1 = {"ipv4": "40.40.40.4/32", "ipv6": "40:40::4/128"} +NETWORK4_2 = {"ipv4": "40.40.40.40/32", "ipv6": "40:40::40/128"} +NETWORK4_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"} +NETWORK4_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"} + +NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} +LOOPBACK_1 = {"ipv4": "10.0.0.7/24", "ipv6": "fd00:0:0:1::7/64", +              "ipv4_mask": "255.255.255.0", "ipv6_mask": None} +LOOPBACK_2 = {"ipv4": "10.0.0.16/24", "ipv6": "fd00:0:0:3::5/64", +              "ipv4_mask": "255.255.255.0", "ipv6_mask": None} +PREFERRED_NEXT_HOP = "global" + + +class CreateTopo(Topo): +    """ +    Test BasicTopo - topology 1 + +    * `Topo`: Topology object +    """ + +    def build(self, *_args, **_opts): +        """Build function""" +        tgen = get_topogen(self) + +        # Building topology from json file +        build_topo_from_json(tgen, topo) + + +def setup_module(mod): +    """ +    Sets up the pytest environment + +    * `mod`: module name +    """ + +    global topo +    testsuite_run_time = time.asctime(time.localtime(time.time())) +    logger.info("Testsuite start time: {}".format(testsuite_run_time)) +    logger.info("=" * 40) + +    logger.info("Running setup_module to create topology") + +    # This function initiates the topology build with Topogen... +    tgen = Topogen(CreateTopo, mod.__name__) +    # ... and here it calls Mininet initialization functions. + +    # Starting topology, create tmp files which are loaded to routers +    #  to start deamons and then start routers +    start_topology(tgen) + +    # Run these tests for kernel version 4.19 or above +    if version_cmp(platform.release(), '4.19') < 0: +        error_msg = ('BGP vrf dynamic route leak tests will not run ' +            '(have kernel "{}", but it requires >= 4.19)'.\ +            format(platform.release())) +        pytest.skip(error_msg) + +    # Creating configuration from JSON +    build_config_from_json(tgen, topo) + +    global BGP_CONVERGENCE +    global ADDR_TYPES +    ADDR_TYPES = check_address_types() + +    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) +    assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}". \ +        format(BGP_CONVERGENCE) + +    logger.info("Running setup_module() done") + + +def teardown_module(): +    """Teardown the pytest environment""" + +    logger.info("Running teardown_module to delete topology") + +    tgen = get_topogen() + +    # Stop toplogy and Remove tmp files +    tgen.stop_topology() + +    logger.info("Testsuite end time: {}". +                format(time.asctime(time.localtime(time.time())))) +    logger.info("=" * 40) + +##################################################### +# +#   Local APIs +# +##################################################### + +def disable_route_map_to_prefer_global_next_hop(tgen, topo): +    """ +    This API is to remove prefer global route-map applied on neighbors + +    Parameter: +    ---------- +    * `tgen` : Topogen object +    * `topo` : Input JSON data + +    Returns: +    -------- +    True/errormsg + +    """ + +    logger.info("Remove prefer-global rmap applied on neighbors") +    input_dict = { +        "r1": { +            "bgp": +            [ +                { +                    "local_as": "100", +                    "vrf": "ISR", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r1-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ] +        }, +        "r2": { +            "bgp": +            [ +                { +                    "local_as": "100", +                    "vrf": "ISR", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r3": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "100", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r4": { +                                        "dest_link": { +                                            "r2-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ] +        }, +        "r3": { +            "bgp": +            [ +                { +                    "local_as": "300", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "300", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r3-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ] +        }, +        "r4": { +            "bgp": +            [ +                { +                    "local_as": "400", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r1": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                }, +                { +                    "local_as": "400", +                    "address_family": { +                        "ipv6": { +                            "unicast": { +                                "neighbor": { +                                    "r2": { +                                        "dest_link": { +                                            "r4-link1": { +                                                "route_maps": [{ +                                                    "name": "rmap_global", +                                                    "direction": "in", +                                                    "delete": True +                                                }] +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                } +            ] +        } +    } + +    result = create_router_bgp(tgen, topo, input_dict) +    assert result is True, "Testcase {} :Failed \n Error: {}". \ +        format(tc_name, result) + +    return True + + +##################################################### +# +#   Testcases +# +##################################################### + +def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request): +    """ +    TC5_FUNC_5: +    1.5.5. Verify that dynamically imported routes are further advertised +    to iBGP peers(peer in cluster). +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) +    build_config_from_json(tgen, topo) + +    if tgen.routers_have_failure(): +        check_router_status(tgen) + +    for addr_type in ADDR_TYPES: + +        step("Redistribute configured static routes into BGP process" +                " on R1 and R3/R4") + +        input_dict_1={} +        DUT = ["r1", "r3", "r4"] +        VRFS = ["default", "default", "default"] +        AS_NUM = [100, 300, 400] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_1.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "redistribute": [{ +                                    "redist_type": "static" +                                }] +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_1) +        assert result is True, "Testcase {} :Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify that R1 receives BGP routes from R3 and R4 in " +             "vrf default.") + +        input_routes_r3 = { +            "r3": { +                "static_routes": [{ +                    "network": [ +                        NETWORK3_1[addr_type], \ +                        NETWORK3_2[addr_type], \ +                        NETWORK3_3[addr_type], \ +                        NETWORK3_4[addr_type] +                    ] +                }] +            } +        } + +        input_routes_r4 = { +            "r4": { +                "static_routes": [{ +                    "network": [ +                        NETWORK4_1[addr_type], \ +                        NETWORK4_2[addr_type], \ +                        NETWORK4_3[addr_type], \ +                        NETWORK4_4[addr_type] +                    ] +                }] +            } +        } + +        DUT = ["r1", "r2"] +        INPUT_DICT = [input_routes_r3, input_routes_r4] + +        for dut, routes in zip(DUT, INPUT_DICT): +            result = verify_bgp_rib(tgen, addr_type, dut, routes) +            assert result is True, \ +                "Testcase {} : Failed \n Error {}". \ +                    format(tc_name, result) + +            result = verify_fib_routes(tgen, addr_type, dut, routes) +            assert result is True, \ +                "Testcase {} : Failed \n Error {}". \ +                    format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Import from default vrf into vrf ISR on R1") + +        input_dict_isr={} +        DUT = ["r1", "r2"] +        VRFS = ["ISR", "ISR"] +        AS_NUM = [100, 100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_isr.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "default" +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify that default vrf's imported routes are installed " +             "in RIB/FIB of vrf ISR on R1:") + +        input_routes_r3 = { +            "r3": { +                "static_routes": [{ +                    "network": [ +                        NETWORK3_1[addr_type], \ +                        NETWORK3_2[addr_type], \ +                        NETWORK3_3[addr_type], \ +                        NETWORK3_4[addr_type] +                    ], +                    "vrf": "ISR" +                }] +            } +        } + +        input_routes_r4 = { +            "r4": { +                "static_routes": [{ +                    "network": [ +                        NETWORK4_1[addr_type], \ +                        NETWORK4_2[addr_type], \ +                        NETWORK4_3[addr_type], \ +                        NETWORK4_4[addr_type] +                    ], +                    "vrf": "ISR" +                }] +            } +        } + +        INPUT_DICT_VRF = [input_routes_r3, input_routes_r4] + +        for routes in INPUT_DICT_VRF: +            result = verify_bgp_rib(tgen, addr_type, "r1", routes) +            assert result is True, \ +                "Testcase {} : Failed \n Error {}". \ +                    format(tc_name, result) + +            result =  verify_fib_routes(tgen, addr_type, "r1", routes) +            assert result is True, \ +                "Testcase {} : Failed \n Error {}". \ +                    format(tc_name, result) + +    intf_r2_r1 = topo["routers"]["r2"]["links"]["r1-link1"] +    for addr_type in ADDR_TYPES: + +        step("Create a loopback10 interface on R1 with below IP address and " +            "associate with vrf ISR:") + +        create_interface_in_kernel(tgen, "r1", "loopback2", +                                   LOOPBACK_2[addr_type], +                                   "ISR", +                                   LOOPBACK_2["{}_mask".\ +                                   format(addr_type)]) + +    for addr_type in ADDR_TYPES: + +        step("On router R1 Change the next-hop of static routes in vrf " +                "ISR to LOOPBACK_1") + +        input_routes_r1= { +            "r1": { +                "static_routes":[ +                    { +                        "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]], +                        "next_hop":"Null0", +                        "delete": True +                    } +                ] +            } +        } + +        result = create_static_routes(tgen, input_routes_r1) +        assert result is True, "Testcase {} :Failed \n Error: {}". \ +            format(tc_name, result) + +        input_routes_r1= { +            "r1": { +                "static_routes":[ +                    { +                        "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]], +                        "next_hop": (intf_r2_r1[addr_type]).split("/")[0] +                    } +                ] +            } +        } + +        result = create_static_routes(tgen, input_routes_r1) +        assert result is True, "Testcase {} :Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify that, though R1 originating BGP routes with next-hop" +            " 24.1.1.2/24::1:2, which is local to R2(but in default vrf)" +            ", R2 must receives and install all routes from R1 in vrf ISR.") +        step("Verify on R2, that it now rejects 10.10.10.x routes originated " +            "from R1. As next-hop IP is local to R2's vrf ISR.") + +        input_routes_r1= { +            "r1": { +                "static_routes":[ +                    { +                        "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]], +                        "vrf": "ISR" +                    } +                ] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                                expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Routes are still present \n Error {}". \ +                format(tc_name, result)) + +    write_test_footer(tc_name) + + +def test_dynamic_imported_matching_prefix_based_on_community_list_p0(request): +    """ +    TC7_FUNC_7: +    1.5.7. Verify matching a prefix based on community attribute and +    importing it by stripping off this value +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) +    build_config_from_json(tgen, topo) + +    if tgen.routers_have_failure(): +        check_router_status(tgen) + +    for addr_type in ADDR_TYPES: + +        step("Configure route-map to set community attribute for a specific" +            "prefix on R1 in vrf ISR") + +        input_dict_pf = { +            "r1": { +                "prefix_lists": { +                    addr_type: { +                        "pflist_ABC_{}".format(addr_type): [{ +                            "seqid": 10, +                            "network": NETWORK1_1[addr_type], +                            "action": "permit" +                        }] +                    } +                } +            } +        } +        result = create_prefix_lists(tgen, input_dict_pf) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +    input_dict_cl = { +        "r1": { +            "bgp_community_lists": [ +            { +                "community_type": "expanded", +                "action": "permit", +                "name": "COMM", +                "value": "100:100" +                } +            ] +        } +    } +    result = create_bgp_community_lists(tgen, input_dict_cl) +    assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +        tc_name, result) + +    for addr_type in ADDR_TYPES: +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_XYZ_{}".format(addr_type): [{ +                        "action": "permit", +                        "match": { +                            addr_type: { +                                "prefix_lists": +                                    "pflist_ABC_{}".format(addr_type) +                            } +                        }, +                        "set": { +                            "community": {"num": "100:100"} +                        } +                    }] +                } +            } +        } +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Apply this route-map on R1 to vrf ISR while redistributing the" +            " prefixes into BGP") + +        input_dict_1={} +        DUT = ["r1"] +        VRFS = ["ISR"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_1.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "redistribute": [{ +                                    "redist_type": "static", +                                        "attribute": { +                                            "route-map" : "rmap_XYZ_{}".\ +                                                format(addr_type) +                                        } +                                    } +                                ] +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_1) +        assert result is True, "Testcase {} :Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Configure another route-map for filtering the prefixes based on" +            " community attribute while importing into default vrf") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_IMP_{}".format(addr_type): [{ +                        "action": "permit", +                        "match": { +                            "community_list": {"id": "COMM"} +                        }, +                        "set": { +                            "community": {"num": "none"} +                        } +                    }] +                } +            } +        } +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Apply the route-map while Importing vrf ISR's prefixes into " +            "default vrf on router R1:") + +        input_dict_isr={} +        DUT = ["r1"] +        VRFS = ["default"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_isr.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "ISR" +                                } +                            } +                        } +                    } +                }) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "route-map rmap_IMP_{}".format(addr_type) +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify on R1 that only prefixes with community value 100:100" +            "in vrf ISR are imported to vrf default. While importing, the" +            " community value has been stripped off:") + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +        input_dict_comm = { +            "community": "100:100" +        } + +        result = verify_bgp_community(tgen, addr_type, dut, [NETWORK1_1[addr_type]], +                                      input_dict_comm, expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Error: Commnunity is not stipped off, {}".format( +            tc_name, result)) + +    for addr_type in ADDR_TYPES: + +        step("Remove/re-add route-map XYZ from redistribution.") + +        input_dict_1={} +        DUT = ["r1"] +        VRFS = ["ISR"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_1.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "redistribute": [{ +                                    "redist_type": "static", +                                    "attribute": { +                                        "route-map" : "rmap_XYZ_{}".\ +                                            format(addr_type) +                                    }, +                                    "delete": True +                                }] +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_1) +        assert result is True, "Testcase {} :Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify that all the routes disappear from vrf default when " +            "route-map is removed from redistribution, and appear again " +            "when route-map is re-added to redistribution in vrf ISR.") + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                                expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Error : Routes are still present \n {}".\ +                format(tc_name, result)) + +    for addr_type in ADDR_TYPES: + +        input_dict_1={} +        DUT = ["r1"] +        VRFS = ["ISR"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_1.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "redistribute": [{ +                                    "redist_type": "static", +                                    "attribute": { +                                        "route-map" : "rmap_XYZ_{}".\ +                                            format(addr_type) +                                    } +                                }] +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_1) +        assert result is True, "Testcase {} :Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Remove/re-add route-map IMP form import statement.") + +        input_dict_isr={} +        DUT = ["r1"] +        VRFS = ["default"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_isr.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "ISR" +                                } +                            } +                        } +                    } +                }) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "route-map rmap_IMP_{}".format(addr_type), +                                    "delete": True +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify that when route-map IMP is removed all the prefixes of" +            " vrf ISR are imported to vrf default. However when route-map " +            "IMP is re-added only 11.11.11.1 and 11:11::1 (with community " +            "value) are imported.") + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        input_dict_isr={} +        DUT = ["r1"] +        VRFS = ["default"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_isr.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "ISR" +                                } +                            } +                        } +                    } +                }) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "route-map rmap_IMP_{}".format(addr_type) +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Delete/Re-add prefix-list ABC.") + +        input_dict_pf = { +            "r1": { +                "prefix_lists": { +                    addr_type: { +                        "pflist_ABC_{}".format(addr_type): [{ +                            "seqid": 10, +                            "network": NETWORK1_1[addr_type], +                            "action": "permit", +                            "delete": True +                        }] +                    } +                } +            } +        } +        result = create_prefix_lists(tgen, input_dict_pf) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                                expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Error : Routes are still present \n {}".\ +                format(tc_name, result)) + +        input_dict_pf["r1"]["prefix_lists"][addr_type]["pflist_ABC_{}".\ +            format(addr_type)][0]["delete"]=False + +        result = create_prefix_lists(tgen, input_dict_pf) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +        step("Delete/Re-add community-list COMM.") + +        input_dict_cl = { +            "r1": { +                "bgp_community_lists": [ +                { +                    "community_type": "expanded", +                    "action": "permit", +                    "name": "COMM", +                    "value": "100:100", +                    "delete": True +                    } +                ] +            } +        } +        result = create_bgp_community_lists(tgen, input_dict_cl) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                                expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Error : Routes are still present \n {}".\ +                format(tc_name, result)) + +        input_dict_cl["r1"]["bgp_community_lists"][0]["delete"]=False + +        result = create_bgp_community_lists(tgen, input_dict_cl) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +        step("Delete/Re-add route-map XYZ.") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_XYZ_{}".format(addr_type): [{ +                        "action": "permit", +                        "match": { +                            addr_type: { +                                "prefix_lists": +                                    "pflist_ABC_{}".format(addr_type) +                            } +                        }, +                        "set": { +                            "community": {"num": "100:100"} +                        }, +                        "delete": True +                    }] +                } +            } +        } +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                                expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Error : Routes are still present \n {}".\ +                format(tc_name, result)) + +        input_dict_rm["r1"]["route_maps"]["rmap_XYZ_{}".format(addr_type)][0]["delete"]=False + +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +        step("Delete/Re-add route-map IMP.") + +        input_dict_rm2 = { +            "r1": { +                "route_maps": { +                    "rmap_IMP_{}".format(addr_type): [{ +                        "action": "permit", +                        "match": { +                            "community_list": {"id": "COMM"} +                        }, +                        "set": { +                            "community": {"num": "none"} +                        }, +                        "delete": True +                    }] +                } +            } +        } +        result = create_route_maps(tgen, input_dict_rm2) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                                expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Error : Routes are still present \n {}".\ +                format(tc_name, result)) + +        input_dict_rm2["r1"]["route_maps"]["rmap_IMP_{}".format(addr_type)][0]["delete"]=False + +        result = create_route_maps(tgen, input_dict_rm2) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +    write_test_footer(tc_name) + + +def test_routemap_operatons_with_dynamic_import_p0(request): +    """ +    TC8_FUNC_8: +    1.5.8. Verify the route-map operation along with dynamic import command. +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) +    build_config_from_json(tgen, topo) + +    if tgen.routers_have_failure(): +        check_router_status(tgen) + +    for addr_type in ADDR_TYPES: + +        step("Configure route-map to set community attribute for a specific" +            "prefix on R1 in vrf ISR") + +        input_dict_pf = { +            "r1": { +                "prefix_lists": { +                    addr_type: { +                        "pflist_ABC_{}".format(addr_type): [{ +                            "seqid": 10, +                            "network": NETWORK1_1[addr_type], +                            "action": "permit" +                        }] +                    } +                } +            } +        } +        result = create_prefix_lists(tgen, input_dict_pf) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +    input_dict_cl = { +        "r1": { +            "bgp_community_lists": [ +            { +                "community_type": "expanded", +                "action": "permit", +                "name": "COMM", +                "value": "100:100" +                } +            ] +        } +    } +    result = create_bgp_community_lists(tgen, input_dict_cl) +    assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +        tc_name, result) + +    for addr_type in ADDR_TYPES: +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_XYZ_{}".format(addr_type): [{ +                        "action": "permit", +                        "match": { +                            addr_type: { +                                "prefix_lists": +                                    "pflist_ABC_{}".format(addr_type) +                            } +                        }, +                        "set": { +                            "community": {"num": "100:100"} +                        } +                    }] +                } +            } +        } +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Apply this route-map on R1 to vrf ISR while redistributing the" +            " prefixes into BGP") + +        input_dict_1={} +        DUT = ["r1"] +        VRFS = ["ISR"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_1.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "redistribute": [{ +                                    "redist_type": "static", +                                        "attribute": { +                                            "route-map" : "rmap_XYZ_{}".\ +                                                format(addr_type) +                                        } +                                    } +                                ] +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_1) +        assert result is True, "Testcase {} :Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Configure another route-map for filtering the prefixes based on" +            " community attribute while importing into default vrf") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_IMP_{}".format(addr_type): [{ +                        "action": "permit", +                        "match": { +                            "community_list": {"id": "COMM"} +                        }, +                        "set": { +                            "community": {"num": "500:500"} +                        } +                    }] +                } +            } +        } +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Apply the route-map while Importing vrf ISR's prefixes into " +            "default vrf on router R1:") + +        input_dict_isr={} +        DUT = ["r1"] +        VRFS = ["default"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_isr.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "ISR" +                                } +                            } +                        } +                    } +                }) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "route-map rmap_IMP_{}".format(addr_type) +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify on R1 that only prefixes with community value 100:100" +            "in vrf ISR are imported to vrf default. While importing, the" +            " community value has been stripped off:") + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Applying route-map first followed by import VRF command.") +        step("Apply the route-map while Importing vrf ISR's prefixes into " +            "default vrf on router R1:") + +        input_dict_isr={} +        DUT = ["r1"] +        VRFS = ["default"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_isr.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "ISR", +                                    "delete": True +                                } +                            } +                        } +                    } +                }) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "route-map rmap_IMP_{}".format(addr_type) +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify that until 'import VRF command' is not configured, " +            "routes are not imported. After configuring 'import VRF command'" +            " repeat step-4 for verification") + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                                expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Error : Routes are still present \n {}".\ +                format(tc_name, result)) + +    for addr_type in ADDR_TYPES: + +        input_dict_isr={} +        DUT = ["r1"] +        VRFS = ["default"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_isr.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "ISR" +                                } +                            } +                        } +                    } +                }) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "route-map rmap_IMP_{}".format(addr_type) +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Delete/re-add import vrf ISR command multiple times in default" +            "vrf.") + +        input_dict_isr={} +        DUT = ["r1"] +        VRFS = ["default"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_isr.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "ISR", +                                    "delete": True +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +        step("Verify that when import vrf ISR command is deleted, " +             "all routes of vrf ISR disappear from default vrf and " +             "when it's re-configured, repeat step-4 for verification.") + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                                expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Routes are still present, Error {}". \ +                format(tc_name, result)) + +        input_dict_isr["r1"]["bgp"][0]["address_family"][addr_type]["unicast"][ +            "import"]["delete"]=False + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, ( +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result)) + +    for addr_type in ADDR_TYPES: + +        step("Delete and re-configure route-map IMP from global config when " +            "import and route-maps are applied in a ISR vrf.") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_IMP_{}".format(addr_type): [{ +                        "action": "permit", +                        "match": { +                            "community_list": {"id": "COMM"} +                        }, +                        "set": { +                            "community": {"num": "500:500"} +                        }, +                        "delete": True +                    }] +                } +            } +        } + +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                                expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Routes are still present, Error {}". \ +                format(tc_name, result)) + +        input_dict_rm["r1"]["route_maps"]["rmap_IMP_{}".\ +            format(addr_type)][0]["delete"]=False + +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        input_dict_comm = { +            "community": "500:500" +        } + +        result = verify_bgp_community(tgen, addr_type, dut, [NETWORK1_1[addr_type]], +                                      input_dict_comm) +        assert result is True, ( +            "Testcase {} : Failed \n Error: {}".format( +            tc_name, result)) + +    write_test_footer(tc_name) + + +def test_verify_cli_json_p1(request): +    """ +    TC8_FUNC_9: +    1.5.9. Verifying the JSON outputs for all supported commands: +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) +    build_config_from_json(tgen, topo) + +    if tgen.routers_have_failure(): +        check_router_status(tgen) + +    input_dict = { +        "r1":{ +            "cli": ["show bgp vrf default ipv4 summary", +                    "show bgp vrf all ipv6 summary", +                    "show bgp neighbors" +            ] +        } +    } + +    result = verify_cli_json(tgen, input_dict) +    assert result is True, "Testcase {} : Failed \n Error: {}".format( +        tc_name, result) + +    write_test_footer(tc_name) + + +if __name__ == '__main__': +    args = ["-s"] + sys.argv[1:] +    sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py new file mode 100755 index 0000000000..6c106060b8 --- /dev/null +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py @@ -0,0 +1,962 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# 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 VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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. +# + +""" +Following tests are covered to test BGP Multi-VRF Dynamic Route Leaking: + +1. Verify that Changing route-map configurations(match/set clauses) on +    the fly it takes immediate effect. +2. Verify BGP best path selection algorithm works fine when +    routes are imported from ISR to default vrf and vice versa. +""" + +import os +import sys +import json +import time +import pytest +import platform + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) +sys.path.append(os.path.join(CWD, '../lib/')) + +# Required to instantiate the topology builder class. + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topotest import version_cmp +from mininet.topo import Topo + +from lib.common_config import ( +    start_topology, write_test_header, check_address_types, +    write_test_footer, +    verify_rib, step, create_route_maps, +    create_static_routes, stop_router, start_router, +    create_prefix_lists, +    create_bgp_community_lists, +    check_router_status, +    get_frr_ipv6_linklocal, +    shutdown_bringup_interface +) + +from lib.topolog import logger +from lib.bgp import ( +    verify_bgp_convergence, create_router_bgp, +    verify_bgp_community, verify_bgp_attributes, +    verify_best_path_as_per_bgp_attribute, verify_bgp_rib +) +from lib.topojson import build_topo_from_json, build_config_from_json + +# Reading the data from JSON File for topology creation +jsonFile = "{}/bgp_vrf_dynamic_route_leak_topo2.json".format(CWD) +try: +    with open(jsonFile, "r") as topoJson: +        topo = json.load(topoJson) +except IOError: +    assert False, "Could not read file {}".format(jsonFile) + +# Global variables +NETWORK1_1 = {"ipv4": "11.11.11.1/32", "ipv6": "11:11::1/128"} +NETWORK3_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"} +NETWORK3_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"} + +PREFERRED_NEXT_HOP = "global" + + +class CreateTopo(Topo): +    """ +    Test BasicTopo - topology 1 + +    * `Topo`: Topology object +    """ + +    def build(self, *_args, **_opts): +        """Build function""" +        tgen = get_topogen(self) + +        # Building topology from json file +        build_topo_from_json(tgen, topo) + + +def setup_module(mod): +    """ +    Sets up the pytest environment + +    * `mod`: module name +    """ + +    global topo +    testsuite_run_time = time.asctime(time.localtime(time.time())) +    logger.info("Testsuite start time: {}".format(testsuite_run_time)) +    logger.info("=" * 40) + +    logger.info("Running setup_module to create topology") + +    # This function initiates the topology build with Topogen... +    tgen = Topogen(CreateTopo, mod.__name__) +    # ... and here it calls Mininet initialization functions. + +    # Starting topology, create tmp files which are loaded to routers +    #  to start deamons and then start routers +    start_topology(tgen) + +    # Run these tests for kernel version 4.19 or above +    if version_cmp(platform.release(), '4.19') < 0: +        error_msg = ('BGP vrf dynamic route leak tests will not run ' +            '(have kernel "{}", but it requires >= 4.19)'.\ +            format(platform.release())) +        pytest.skip(error_msg) + +    # Creating configuration from JSON +    build_config_from_json(tgen, topo) + +    global BGP_CONVERGENCE +    global ADDR_TYPES +    ADDR_TYPES = check_address_types() + +    BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) +    assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}". \ +        format(BGP_CONVERGENCE) + +    logger.info("Running setup_module() done") + + +def teardown_module(): +    """Teardown the pytest environment""" + +    logger.info("Running teardown_module to delete topology") + +    tgen = get_topogen() + +    # Stop toplogy and Remove tmp files +    tgen.stop_topology() + +    logger.info("Testsuite end time: {}". +                format(time.asctime(time.localtime(time.time())))) +    logger.info("=" * 40) + + +##################################################### +# +#   Testcases +# +##################################################### + +def test_bgp_best_path_with_dynamic_import_p0(request): +    """ +    TC6_FUNC_6: +    1.5.6. Verify BGP best path selection algorithm works fine when +    routes are imported from ISR to default vrf and vice versa. +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) +    build_config_from_json(tgen, topo) + +    if tgen.routers_have_failure(): +        check_router_status(tgen) + +    for addr_type in ADDR_TYPES: + +        step("Redistribute configured static routes into BGP process" +             " on R1/R2 and R3") + +        input_dict_1={} +        DUT = ["r1", "r2", "r3", "r4"] +        VRFS = ["ISR", "ISR", "default", "default"] +        AS_NUM = [100, 100, 300, 400] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_1.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "redistribute": [{ +                                    "redist_type": "static" +                                }] +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_1) +        assert result is True, "Testcase {} :Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Import from default vrf into vrf ISR on R1 and R2 as below") + +        input_dict_vrf={} +        DUT = ["r1", "r2"] +        VRFS = ["ISR", "ISR"] +        AS_NUM = [100, 100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_vrf.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "default" +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_vrf) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +        input_dict_default={} +        DUT = ["r1", "r2"] +        VRFS = ["default", "default"] +        AS_NUM = [100, 100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_default.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "ISR" +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_default) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +    step("Verify ECMP/Next-hop/Imported routes Vs Locally originated " +         "routes/eBGP routes vs iBGP routes --already covered in almost" +         " all tests") + +    for addr_type in ADDR_TYPES: + +        step("Verify Pre-emption") + +        input_routes_r3 = { +            "r3": { +                "static_routes": [{ +                    "network": [ +                        NETWORK3_3[addr_type] +                    ] +                }] +            } +        } + +        intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"] +        intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"] + +        if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: +            nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1) +            nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1) +        else: +            nh_r3_r1 = topo["routers"]["r3"]["links"]\ +                ["r1-link1"][addr_type].split("/")[0] +            nh_r4_r1 = topo["routers"]["r4"]["links"]\ +                ["r1-link1"][addr_type].split("/")[0] + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r3, +                                next_hop=[nh_r4_r1]) +        assert result is True, ( +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result)) + +    step("Shutdown interface connected to r1 from r4:") +    shutdown_bringup_interface(tgen, 'r4', intf_r4_r1, False) + +    for addr_type in ADDR_TYPES: + +        input_routes_r3 = { +            "r3": { +                "static_routes": [{ +                    "network": [ +                        NETWORK3_3[addr_type] +                    ] +                }] +            } +        } + +        intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"] +        intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"] + +        if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: +            nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1) +            nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1) +        else: +            nh_r3_r1 = topo["routers"]["r3"]["links"]\ +                ["r1-link1"][addr_type].split("/")[0] +            nh_r4_r1 = topo["routers"]["r4"]["links"]\ +                ["r1-link1"][addr_type].split("/")[0] + +        step("Verify next-hop is changed") +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r3, +                                next_hop=[nh_r3_r1]) +        assert result is True, ( +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result)) + +    step("Bringup interface connected to r1 from r4:") +    shutdown_bringup_interface(tgen, 'r4', intf_r4_r1, True) + +    for addr_type in ADDR_TYPES: + +        input_routes_r3 = { +            "r3": { +                "static_routes": [{ +                    "network": [ +                        NETWORK3_3[addr_type] +                    ] +                }] +            } +        } + +        intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"] +        intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"] + +        if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: +            nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1) +            nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1) +        else: +            nh_r3_r1 = topo["routers"]["r3"]["links"]\ +                ["r1-link1"][addr_type].split("/")[0] +            nh_r4_r1 = topo["routers"]["r4"]["links"]\ +                ["r1-link1"][addr_type].split("/")[0] + +        step("Verify next-hop is not chnaged aftr shutdown:") +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r3, +                                next_hop=[nh_r3_r1]) +        assert result is True, ( +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result)) + +    step("Active-Standby scenario(as-path prepend and Local pref)") + +    for addr_type in ADDR_TYPES: + +        step("Create prefix-list") + +        input_dict_pf = { +            "r1": { +                "prefix_lists": { +                    addr_type: { +                        "pf_ls_{}".format(addr_type): [{ +                            "seqid": 10, +                            "network": NETWORK3_4[addr_type], +                            "action": "permit" +                        }] +                    } +                } +            } +        } +        result = create_prefix_lists(tgen, input_dict_pf) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Create route-map to match prefix-list and set localpref 500") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_PATH1_{}".format(addr_type): [{ +                        "action": "permit", +                        "seq_id": 10, +                        "match": { +                            addr_type: { +                                "prefix_lists": +                                    "pf_ls_{}".format(addr_type) +                            } +                        }, +                        "set": { +                            "locPrf": 500 +                        } +                    }] +                } +            } +        } + +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        step("Create route-map to match prefix-list and set localpref 600") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_PATH2_{}".format(addr_type): [{ +                        "action": "permit", +                        "seq_id": 20, +                        "match": { +                            addr_type: { +                                "prefix_lists": +                                    "pf_ls_{}".format(addr_type) +                            } +                        }, +                        "set": { +                            "locPrf": 600 +                        } +                    }] +                } +            } +        } + +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +        input_dict_rma={ +            "r1": { +                "bgp": +                [ +                    { +                        "local_as": "100", +                        "address_family": { +                            addr_type: { +                                "unicast": { +                                    "neighbor": { +                                        "r3": { +                                            "dest_link": { +                                                "r1-link1": { +                                                    "route_maps": [{ +                                                        "name": "rmap_PATH1_{}".\ +                                                            format(addr_type), +                                                        "direction": "in" +                                                    }] +                                                } +                                            } +                                        }, +                                        "r4": { +                                            "dest_link": { +                                                "r1-link1": { +                                                    "route_maps": [{ +                                                        "name": "rmap_PATH2_{}".\ +                                                            format(addr_type), +                                                        "direction": "in" +                                                    }] +                                                } +                                            } +                                        } +                                    } +                                } +                            } +                        } +                    } +                ]} +            } + +        result = create_router_bgp(tgen, topo, input_dict_rma) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +    dut = "r1" +    attribute = "locPrf" + +    for addr_type in ADDR_TYPES: + +        step("Verify bestpath is installed as per highest localpref") + +        input_routes_r3 = { +            "r3": { +                "static_routes": [{ +                    "network": [ +                        NETWORK3_3[addr_type], \ +                        NETWORK3_4[addr_type] +                    ] +                }] +            } +        } + +        result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, +                                                        input_routes_r3, +                                                        attribute) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Create route-map to match prefix-list and set localpref 700") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_PATH1_{}".format(addr_type): [{ +                        "action": "permit", +                        "seq_id": 10, +                        "match": { +                            addr_type: { +                                "prefix_lists": +                                    "pf_ls_{}".format(addr_type) +                            } +                        }, +                        "set": { +                            "locPrf": 700 +                        } +                    }] +                } +            } +        } + +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify bestpath is changed as per highest localpref") + +        input_routes_r3 = { +            "r3": { +                "static_routes": [{ +                    "network": [ +                        NETWORK3_3[addr_type], \ +                        NETWORK3_4[addr_type] +                    ] +                }] +            } +        } + +        result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, +                                                        input_routes_r3, +                                                        attribute) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Create route-map to match prefix-list and set as-path prepend") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_PATH2_{}".format(addr_type): [{ +                        "action": "permit", +                        "seq_id": 20, +                        "match": { +                            addr_type: { +                                "prefix_lists": +                                    "pf_ls_{}".format(addr_type) +                            } +                        }, +                        "set": { +                            "localpref": 700, +                            "path": { +                                "as_num": "111", +                                "as_action": "prepend" +                            } +                        } +                    }] +                } +            } +        } + +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +    attribute = "path" + +    for addr_type in ADDR_TYPES: + +        step("Verify bestpath is changed as per shortest as-path") + +        input_routes_r3 = { +            "r3": { +                "static_routes": [{ +                    "network": [ +                        NETWORK3_3[addr_type], \ +                        NETWORK3_4[addr_type] +                    ] +                }] +            } +        } + +        result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, +                                                        input_routes_r3, +                                                        attribute) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +    write_test_footer(tc_name) + + +def test_modify_route_map_match_set_clauses_p1(request): +    """ +    TC13_CHAOS_4: +    1.5.13. Verify that Changing route-map configurations(match/set clauses) on +    the fly it takes immediate effect. +    """ + +    tgen = get_topogen() +    tc_name = request.node.name +    write_test_header(tc_name) +    build_config_from_json(tgen, topo) + +    if tgen.routers_have_failure(): +        check_router_status(tgen) + +    for addr_type in ADDR_TYPES: + +        step("Configure route-map to set community attribute for a specific" +            "prefix on R1 in vrf ISR") + +        input_dict_pf = { +            "r1": { +                "prefix_lists": { +                    addr_type: { +                        "pflist_ABC_{}".format(addr_type): [{ +                            "seqid": 10, +                            "network": NETWORK1_1[addr_type], +                            "action": "permit" +                        }] +                    } +                } +            } +        } +        result = create_prefix_lists(tgen, input_dict_pf) +        assert result is True, "Testcase {} : Failed \n Error: {}".format( +            tc_name, result) + +    input_dict_cl = { +        "r1": { +            "bgp_community_lists": [ +            { +                "community_type": "expanded", +                "action": "permit", +                "name": "COMM", +                "value": "100:100" +                } +            ] +        } +    } +    result = create_bgp_community_lists(tgen, input_dict_cl) +    assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +        tc_name, result) + +    for addr_type in ADDR_TYPES: +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_XYZ_{}".format(addr_type): [{ +                        "action": "permit", +                        "match": { +                            addr_type: { +                                "prefix_lists": +                                    "pflist_ABC_{}".format(addr_type) +                            } +                        }, +                        "set": { +                            "community": {"num": "100:100"} +                        } +                    }] +                } +            } +        } +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Apply this route-map on R1 to vrf ISR while redistributing the" +            " prefixes into BGP") + +        input_dict_1={} +        DUT = ["r1"] +        VRFS = ["ISR"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_1.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "redistribute": [{ +                                    "redist_type": "static", +                                        "attribute": { +                                            "route-map" : "rmap_XYZ_{}".\ +                                                format(addr_type) +                                        } +                                    } +                                ] +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_1) +        assert result is True, "Testcase {} :Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Configure another route-map for filtering the prefixes based on" +            " community attribute while importing into default vrf") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_IMP_{}".format(addr_type): [{ +                        "action": "permit", +                        "seq_id": 10, +                        "match": { +                            "community_list": {"id": "COMM"} +                        }, +                        "set": { +                            "community": {"num": "none"} +                        } +                    }] +                } +            } +        } +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Apply the route-map while Importing vrf ISR's prefixes into " +            "default vrf on router R1:") + +        input_dict_isr={} +        DUT = ["r1"] +        VRFS = ["default"] +        AS_NUM = [100] + +        for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): +            temp = {dut: {"bgp": []}} +            input_dict_isr.update(temp) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "ISR" +                                } +                            } +                        } +                    } +                }) + +            temp[dut]["bgp"].append( +                { +                    "local_as": as_num, +                    "vrf": vrf, +                    "address_family": { +                        addr_type: { +                            "unicast": { +                                "import": { +                                    "vrf": "route-map rmap_IMP_{}".format(addr_type) +                                } +                            } +                        } +                    } +                }) + +        result = create_router_bgp(tgen, topo, input_dict_isr) +        assert result is True, "Testcase {} : Failed \n Error: {}". \ +            format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify on R1 that only prefixes with community value 100:100" +            "in vrf ISR are imported to vrf default. While importing, the" +            " community value has been stripped off:") + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1) +        assert result is True, \ +            "Testcase {} : Failed \n Error {}". \ +                format(tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Add set clause in route-map IMP:") + +        input_dict_rm = { +            "r1": { +                "route_maps": { +                    "rmap_IMP_{}".format(addr_type): [{ +                        "action": "permit", +                        "seq_id": 10, +                        "match": { +                            "community_list": {"id": "COMM"} +                        }, +                        "set": { +                            "large_community": {"num": "100:100:100"}, +                            "locPrf": 500, +                            "path": { +                                "as_num": "100 100", +                                "as_action": "prepend" +                            } +                        } +                    }] +                } +            } +        } +        result = create_route_maps(tgen, input_dict_rm) +        assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +            tc_name, result) + +    for addr_type in ADDR_TYPES: + +        step("Verify that as we continue adding different attributes " +            "step-by-step in route-map IMP those attributes gets " +            "attached to prefixes:") + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        input_dict_comm = { +            "largeCommunity": "100:100:100" +        } + +        result = verify_bgp_community(tgen, addr_type, dut, [NETWORK1_1[addr_type]], +                                      input_dict_comm) +        assert result is True, ( +            "Testcase {} : Failed \n Error {}".format( +            tc_name, result)) + +        input_rmap = { +            "r1": { +                "route_maps": { +                    "rmap_IMP_{}".format(addr_type): [ +                        { +                            "set": { +                                "locPrf": 500 +                            } +                        } +                    ] +                } +            } +        } + +        result = verify_bgp_attributes(tgen, addr_type, "r1",\ +                                       [NETWORK1_1[addr_type]], +                                       rmap_name="rmap_IMP_{}".format(addr_type),\ +                                       input_dict=input_rmap) +        assert result is True, "Testcase  : Failed \n Error: {}".format( +                tc_name, result) + +    step("Change community-list to match a different value then " +            "100:100.") + +    input_dict_cl = { +        "r1": { +            "bgp_community_lists": [ +            { +                "community_type": "expanded", +                "action": "permit", +                "name": "COMM", +                "value": "100:100", +                "delete": True +                } +            ] +        } +    } +    result = create_bgp_community_lists(tgen, input_dict_cl) +    assert result is True, 'Testcase {} : Failed \n Error: {}'.format( +        tc_name, result) + +    for addr_type in ADDR_TYPES: + +        input_routes_r1 = { +            "r1": { +                "static_routes": [{ +                    "network": [ +                        NETWORK1_1[addr_type] +                    ], +                    "vrf": "default" +                }] +            } +        } + +        result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, +                            expected=False) +        assert result is not True, ( +            "Testcase {} : Failed \n Error : Routes are still " +            "present {}".\ +                format(tc_name, result)) + +    write_test_footer(tc_name) + + +if __name__ == '__main__': +    args = ["-s"] + sys.argv[1:] +    sys.exit(pytest.main(args)) diff --git a/tests/topotests/isis-topo1-vrf/__init__.py b/tests/topotests/isis-topo1-vrf/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/__init__.py diff --git a/tests/topotests/isis-topo1-vrf/r1/isisd.conf b/tests/topotests/isis-topo1-vrf/r1/isisd.conf new file mode 100755 index 0000000000..4ac4597015 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r1/isisd.conf @@ -0,0 +1,15 @@ +hostname r1 +debug isis adj-packets +debug isis events +debug isis update-packets +interface r1-eth0 + ip router isis 1 vrf r1-cust1 + ipv6 router isis 1 vrf r1-cust1 + isis circuit-type level-2-only +! +router isis 1 vrf r1-cust1  + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0000.00 + metric-style wide + redistribute ipv4 connected level-2 + redistribute ipv6 connected level-2 +! diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route.json b/tests/topotests/isis-topo1-vrf/r1/r1_route.json new file mode 100644 index 0000000000..790808f2cd --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r1/r1_route.json @@ -0,0 +1,57 @@ +{ +  "10.0.10.0/24": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv4",  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r1-eth0",  +          "ip": "10.0.20.1"  +        } +      ],  +      "prefix": "10.0.10.0/24",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 3, +      "vrfName": "r1-cust1" +    } +  ],  +  "10.0.20.0/24": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "afi": "ipv4",  +          "interfaceIndex": 2,  +          "interfaceName": "r1-eth0",  +          "ip": "10.0.20.1"  +        } +      ],  +      "prefix": "10.0.20.0/24",  +      "protocol": "isis",  +      "vrfId": 3, +      "vrfName": "r1-cust1" +    },  +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r1-eth0" +        } +      ],  +      "prefix": "10.0.20.0/24",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 3, +      "vrfName": "r1-cust1" +    } +  ] +} diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route6.json b/tests/topotests/isis-topo1-vrf/r1/r1_route6.json new file mode 100644 index 0000000000..332cbb3290 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r1/r1_route6.json @@ -0,0 +1,40 @@ +{ +  "2001:db8:1:1::/64": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r1-eth0" +        } +      ],  +      "prefix": "2001:db8:1:1::/64",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 3, +      "vrfName": "r1-cust1" +    } +  ],  +  "2001:db8:2:1::/64": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv6",  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r1-eth0"  +        } +      ],  +      "prefix": "2001:db8:2:1::/64",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 3, +      "vrfName": "r1-cust1" +    } +  ]  +} diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json b/tests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json new file mode 100755 index 0000000000..d1ace402ba --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r1/r1_route6_linux.json @@ -0,0 +1,14 @@ +{ +  "2001:db8:1:1::/64": { +    "dev": "r1-eth0", +    "metric": "256", +    "pref": "medium", +    "proto": "kernel" +  }, +  "2001:db8:2:1::/64": { +    "dev": "r1-eth0", +    "metric": "20", +    "pref": "medium", +    "proto": "187" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_route_linux.json b/tests/topotests/isis-topo1-vrf/r1/r1_route_linux.json new file mode 100755 index 0000000000..6af22297e9 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r1/r1_route_linux.json @@ -0,0 +1,13 @@ +{ +  "10.0.10.0/24": { +    "dev": "r1-eth0", +    "metric": "20", +    "proto": "187", +    "via": "10.0.20.1" +  }, +  "10.0.20.0/24": { +    "dev": "r1-eth0", +    "proto": "kernel", +    "scope": "link" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r1/r1_topology.json b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json new file mode 100644 index 0000000000..8e3cdc7bd6 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r1/r1_topology.json @@ -0,0 +1,80 @@ +{ +  "1": { +    "level-1": { +      "ipv4": [ +        { +          "vertex": "r1" +        } +      ],  +      "ipv6": [ +        { +          "vertex": "r1" +        } +      ] +    },  +    "level-2": { +      "ipv4": [ +        { +          "vertex": "r1" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP",  +          "vertex": "10.0.20.0/24" +        },  +        { +          "interface": "r1-eth0",  +          "metric": "10",  +          "next-hop": "r3",  +          "parent": "r1(4)",  +          "type": "TE-IS",  +          "vertex": "r3" +        },  +        { +          "interface": "r3",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r1-eth0",  +          "type": "IP",  +          "vertex": "10.0.20.0/24" +        },  +        { +          "interface": "r3",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r1-eth0",  +          "type": "IP",  +          "vertex": "10.0.10.0/24" +        } +      ],  +      "ipv6": [ +        { +          "vertex": "r1" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP6",  +          "vertex": "2001:db8:1:1::/64" +        },  +        { +          "interface": "r1-eth0",  +          "metric": "10",  +          "next-hop": "r3",  +          "parent": "r1(4)",  +          "type": "TE-IS",  +          "vertex": "r3" +        },  +        { +          "interface": "r3",  +          "metric": "internal",  +          "next-hop": "20",  +          "parent": "r1-eth0",  +          "type": "IP6",  +          "vertex": "2001:db8:2:1::/64" +        } +      ] +    } +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r1/zebra.conf b/tests/topotests/isis-topo1-vrf/r1/zebra.conf new file mode 100755 index 0000000000..fa1c02e5f8 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r1/zebra.conf @@ -0,0 +1,9 @@ +hostname r1 +interface r1-eth0 vrf r1-cust1 + ip address 10.0.20.2/24 + ipv6 address 2001:db8:1:1::2/64 +! +interface lo + ip address 10.254.0.1/32 + ipv6 address 2001:db8:F::1/128 +! diff --git a/tests/topotests/isis-topo1-vrf/r2/isisd.conf b/tests/topotests/isis-topo1-vrf/r2/isisd.conf new file mode 100755 index 0000000000..4c68540265 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r2/isisd.conf @@ -0,0 +1,15 @@ +hostname r2 +debug isis adj-packets +debug isis events +debug isis update-packets +interface r2-eth0 + ip router isis 1 vrf r2-cust1 + ipv6 router isis 1 vrf r2-cust1 + isis circuit-type level-2-only +! +router isis 1 vrf r2-cust1 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00 + metric-style wide + redistribute ipv4 connected level-2 + redistribute ipv6 connected level-2 +! diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route.json b/tests/topotests/isis-topo1-vrf/r2/r2_route.json new file mode 100644 index 0000000000..b3ac86d218 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r2/r2_route.json @@ -0,0 +1,57 @@ +{ +  "10.0.11.0/24": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv4",  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r2-eth0",  +          "ip": "10.0.21.1"  +        } +      ],  +      "prefix": "10.0.11.0/24",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 3, +      "vrfName": "r2-cust1" +    } +  ],  +  "10.0.21.0/24": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "afi": "ipv4",  +          "interfaceIndex": 2,  +          "interfaceName": "r2-eth0",  +          "ip": "10.0.21.1"  +        } +      ],  +      "prefix": "10.0.21.0/24",  +      "protocol": "isis",  +      "vrfId": 3, +      "vrfName": "r2-cust1" +    },  +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r2-eth0" +        } +      ],  +      "prefix": "10.0.21.0/24",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 3, +      "vrfName": "r2-cust1" +    } +  ] +} diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route6.json b/tests/topotests/isis-topo1-vrf/r2/r2_route6.json new file mode 100644 index 0000000000..c8d11b4922 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r2/r2_route6.json @@ -0,0 +1,40 @@ +{ +  "2001:db8:1:2::/64": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r2-eth0" +        } +      ],  +      "prefix": "2001:db8:1:2::/64",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 3, +      "vrfName": "r2-cust1" +    } +  ],  +  "2001:db8:2:2::/64": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv6",  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r2-eth0"  +        } +      ],  +      "prefix": "2001:db8:2:2::/64",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 3, +      "vrfName": "r2-cust1" +    } +  ]  +} diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json b/tests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json new file mode 100755 index 0000000000..27423e1936 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r2/r2_route6_linux.json @@ -0,0 +1,14 @@ +{ +  "2001:db8:1:2::/64": { +    "dev": "r2-eth0", +    "metric": "256", +    "pref": "medium", +    "proto": "kernel" +  }, +  "2001:db8:2:2::/64": { +    "dev": "r2-eth0", +    "metric": "20", +    "pref": "medium", +    "proto": "187" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_route_linux.json b/tests/topotests/isis-topo1-vrf/r2/r2_route_linux.json new file mode 100755 index 0000000000..744b0780f3 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r2/r2_route_linux.json @@ -0,0 +1,13 @@ +{ +  "10.0.11.0/24": { +    "dev": "r2-eth0", +    "metric": "20", +    "proto": "187", +    "via": "10.0.21.1" +  }, +  "10.0.21.0/24": { +    "dev": "r2-eth0", +    "proto": "kernel", +    "scope": "link" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r2/r2_topology.json b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json new file mode 100644 index 0000000000..72022a8167 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r2/r2_topology.json @@ -0,0 +1,80 @@ +{ +  "1": { +    "level-1": { +      "ipv4": [ +        { +          "vertex": "r2" +        } +      ],  +      "ipv6": [ +        { +          "vertex": "r2" +        } +      ] +    },  +    "level-2": { +      "ipv4": [ +        { +          "vertex": "r2" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP",  +          "vertex": "10.0.21.0/24" +        },  +        { +          "interface": "r2-eth0",  +          "metric": "10",  +          "next-hop": "r4",  +          "parent": "r2(4)",  +          "type": "TE-IS",  +          "vertex": "r4" +        },  +        { +          "interface": "r4",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r2-eth0",  +          "type": "IP",  +          "vertex": "10.0.21.0/24" +        },  +        { +          "interface": "r4",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r2-eth0",  +          "type": "IP",  +          "vertex": "10.0.11.0/24" +        } +      ],  +      "ipv6": [ +        { +          "vertex": "r2" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP6",  +          "vertex": "2001:db8:1:2::/64" +        },  +        { +          "interface": "r2-eth0",  +          "metric": "10",  +          "next-hop": "r4",  +          "parent": "r2(4)",  +          "type": "TE-IS",  +          "vertex": "r4" +        },  +        { +          "interface": "r4",  +          "metric": "internal",  +          "next-hop": "20",  +          "parent": "r2-eth0",  +          "type": "IP6",  +          "vertex": "2001:db8:2:2::/64" +        } +      ] +    } +  } +}
\ No newline at end of file diff --git a/tests/topotests/isis-topo1-vrf/r2/zebra.conf b/tests/topotests/isis-topo1-vrf/r2/zebra.conf new file mode 100755 index 0000000000..a62af1749e --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r2/zebra.conf @@ -0,0 +1,9 @@ +hostname r2 +interface r2-eth0 vrf r2-cust1 + ip address 10.0.21.2/24 + ipv6 address 2001:db8:1:2::2/64 +! +interface lo + ip address 10.254.0.2/32 + ipv6 address 2001:db8:F::2/128 +! diff --git a/tests/topotests/isis-topo1-vrf/r3/isisd.conf b/tests/topotests/isis-topo1-vrf/r3/isisd.conf new file mode 100755 index 0000000000..ca01876690 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r3/isisd.conf @@ -0,0 +1,22 @@ +hostname r3 +debug isis adj-packets +debug isis events +debug isis update-packets +interface r3-eth0 + ip router isis 1 vrf r3-cust1 + ipv6 router isis 1 vrf r3-cust1 + isis circuit-type level-2-only +! +interface r3-eth1 + ip router isis 1 vrf r3-cust1 + ipv6 router isis 1 vrf r3-cust1 + isis circuit-type level-1 +! +router isis 1 vrf r3-cust1 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv4 connected level-2 + redistribute ipv6 connected level-1 + redistribute ipv6 connected level-2 +! diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route.json b/tests/topotests/isis-topo1-vrf/r3/r3_route.json new file mode 100644 index 0000000000..709d6b9aeb --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r3/r3_route.json @@ -0,0 +1,112 @@ +{ +  "10.0.10.0/24": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "afi": "ipv4",  +          "interfaceIndex": 3,  +          "interfaceName": "r3-eth1",  +          "ip": "10.0.10.1"  +        } +      ],  +      "prefix": "10.0.10.0/24",  +      "protocol": "isis",  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    },  +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r3-eth1" +        } +      ],  +      "prefix": "10.0.10.0/24",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    } +  ],  +  "10.0.11.0/24": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv4",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r3-eth1",  +          "ip": "10.0.10.1"  +        } +      ],  +      "prefix": "10.0.11.0/24",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    } +  ],  +  "10.0.20.0/24": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "afi": "ipv4",  +          "interfaceIndex": 2,  +          "interfaceName": "r3-eth0",  +          "ip": "10.0.20.2"  +        } +      ],  +      "prefix": "10.0.20.0/24",  +      "protocol": "isis",  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    },  +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r3-eth0" +        } +      ],  +      "prefix": "10.0.20.0/24",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    } +  ],  +  "10.0.21.0/24": [ +    { +      "distance": 115,  +      "metric": 30,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv4",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r3-eth1",  +          "ip": "10.0.10.1"  +        } +      ],  +      "prefix": "10.0.21.0/24",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    } +  ] +} diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route6.json b/tests/topotests/isis-topo1-vrf/r3/r3_route6.json new file mode 100644 index 0000000000..3a7c3861fa --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r3/r3_route6.json @@ -0,0 +1,78 @@ +{ +  "2001:db8:1:1::/64": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r3-eth0" +        } +      ],  +      "prefix": "2001:db8:1:1::/64",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    } +  ],  +  "2001:db8:1:2::/64": [ +    { +      "distance": 115,  +      "metric": 30,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv6",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r3-eth1"  +        } +      ],  +      "prefix": "2001:db8:1:2::/64",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    } +  ],  +  "2001:db8:2:1::/64": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r3-eth1" +        } +      ],  +      "prefix": "2001:db8:2:1::/64",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    } +  ],  +  "2001:db8:2:2::/64": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv6",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r3-eth1"  +        } +      ],  +      "prefix": "2001:db8:2:2::/64",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r3-cust1" +    } +  ] +} diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json b/tests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json new file mode 100755 index 0000000000..bc527d2e1e --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r3/r3_route6_linux.json @@ -0,0 +1,26 @@ +{ +  "2001:db8:1:1::/64": { +    "dev": "r3-eth0", +    "metric": "256", +    "pref": "medium", +    "proto": "kernel" +  }, +  "2001:db8:1:2::/64": { +    "dev": "r3-eth1", +    "metric": "20", +    "pref": "medium", +    "proto": "187" +  }, +  "2001:db8:2:1::/64": { +    "dev": "r3-eth1", +    "metric": "256", +    "pref": "medium", +    "proto": "kernel" +  }, +  "2001:db8:2:2::/64": { +    "dev": "r3-eth1", +    "metric": "20", +    "pref": "medium", +    "proto": "187" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_route_linux.json b/tests/topotests/isis-topo1-vrf/r3/r3_route_linux.json new file mode 100755 index 0000000000..515d376475 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r3/r3_route_linux.json @@ -0,0 +1,24 @@ +{ +  "10.0.10.0/24": { +    "dev": "r3-eth1", +    "proto": "kernel", +    "scope": "link" +  }, +  "10.0.11.0/24": { +    "dev": "r3-eth1", +    "metric": "20", +    "proto": "187", +    "via": "10.0.10.1" +  }, +  "10.0.20.0/24": { +    "dev": "r3-eth0", +    "proto": "kernel", +    "scope": "link" +  }, +  "10.0.21.0/24": { +    "dev": "r3-eth1", +    "metric": "20", +    "proto": "187", +    "via": "10.0.10.1" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r3/r3_topology.json b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json new file mode 100644 index 0000000000..62b895766e --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r3/r3_topology.json @@ -0,0 +1,132 @@ +{ +  "1": { +    "level-1": { +      "ipv4": [ +        { +          "vertex": "r3" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP",  +          "vertex": "10.0.10.0/24" +        },  +        { +          "interface": "r3-eth1",  +          "metric": "10",  +          "next-hop": "r5",  +          "parent": "r3(4)",  +          "type": "TE-IS",  +          "vertex": "r5" +        },  +        { +          "interface": "r5",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r3-eth1",  +          "type": "IP",  +          "vertex": "10.0.10.0/24" +        },  +        { +          "interface": "r5",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r3-eth1",  +          "type": "IP",  +          "vertex": "10.0.11.0/24" +        },  +        { +          "interface": "r5",  +          "metric": "TE",  +          "next-hop": "30",  +          "parent": "r3-eth1",  +          "type": "IP",  +          "vertex": "10.0.21.0/24" +        } +      ],  +      "ipv6": [ +        { +          "vertex": "r3" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP6",  +          "vertex": "2001:db8:2:1::/64" +        },  +        { +          "interface": "r3-eth1",  +          "metric": "10",  +          "next-hop": "r5",  +          "parent": "r3(4)",  +          "type": "TE-IS",  +          "vertex": "r5" +        },  +        { +          "interface": "r5",  +          "metric": "internal",  +          "next-hop": "20",  +          "parent": "r3-eth1",  +          "type": "IP6",  +          "vertex": "2001:db8:2:2::/64" +        },  +        { +          "interface": "r5",  +          "metric": "internal",  +          "next-hop": "30",  +          "parent": "r3-eth1",  +          "type": "IP6",  +          "vertex": "2001:db8:1:2::/64" +        } +      ] +    },  +    "level-2": { +      "ipv4": [ +        { +          "vertex": "r3" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP",  +          "vertex": "10.0.20.0/24" +        },  +        { +          "interface": "r3-eth0",  +          "metric": "10",  +          "next-hop": "r3",  +          "parent": "r3(4)",  +          "type": "TE-IS",  +          "vertex": "r3" +        },  +        { +          "interface": "r3",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r3-eth0",  +          "type": "IP",  +          "vertex": "10.0.20.0/24" +        } +      ],  +      "ipv6": [ +        { +          "vertex": "r3" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP6",  +          "vertex": "2001:db8:1:1::/64" +        },  +        { +          "interface": "r3-eth0",  +          "metric": "10",  +          "next-hop": "r3",  +          "parent": "r3(4)",  +          "type": "TE-IS",  +          "vertex": "r3" +        } +      ] +    } +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r3/zebra.conf b/tests/topotests/isis-topo1-vrf/r3/zebra.conf new file mode 100755 index 0000000000..ac0b810fce --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r3/zebra.conf @@ -0,0 +1,13 @@ +hostname r3 +interface r3-eth0 vrf r3-cust1 + ip address 10.0.20.1/24 + ipv6 address 2001:db8:1:1::1/64 +! +interface r3-eth1 vrf r3-cust1 + ip address 10.0.10.2/24 + ipv6 address 2001:db8:2:1::2/64 +! +interface lo + ip address 10.254.0.3/32 + ipv6 address 2001:db8:F::3/128 +! diff --git a/tests/topotests/isis-topo1-vrf/r4/isisd.conf b/tests/topotests/isis-topo1-vrf/r4/isisd.conf new file mode 100755 index 0000000000..74b1603d85 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r4/isisd.conf @@ -0,0 +1,25 @@ +hostname r4 +debug isis adj-packets +debug isis events +debug isis update-packets +debug isis lsp-gen +debug isis lsp-sched + +interface r4-eth0 + ip router isis 1 vrf r4-cust1 + ipv6 router isis 1 vrf r4-cust1 + isis circuit-type level-2-only +! +interface r4-eth1 + ip router isis 1 vrf r4-cust1 + ipv6 router isis 1 vrf r4-cust1 + isis circuit-type level-1 +! +router isis 1 vrf r4-cust1 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0004.00 + metric-style wide + redistribute ipv4 connected level-1 + redistribute ipv4 connected level-2 + redistribute ipv6 connected level-1 + redistribute ipv6 connected level-2 +! diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route.json b/tests/topotests/isis-topo1-vrf/r4/r4_route.json new file mode 100644 index 0000000000..c464607a2b --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r4/r4_route.json @@ -0,0 +1,105 @@ +{ +  "10.0.10.0/24": [ +    { +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv4",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r4-eth1",  +          "ip": "10.0.11.1"  +        } +      ],  +      "prefix": "10.0.10.0/24",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    } +  ],  +  "10.0.11.0/24": [ +    { +      "nexthops": [ +        { +          "afi": "ipv4",  +          "interfaceIndex": 3,  +          "interfaceName": "r4-eth1",  +          "ip": "10.0.11.1"  +        } +      ],  +      "prefix": "10.0.11.0/24",  +      "protocol": "isis",  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    },  +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r4-eth1" +        } +      ],  +      "prefix": "10.0.11.0/24",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    } +  ],  +  "10.0.20.0/24": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv4",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r4-eth1",  +          "ip": "10.0.11.1"  +        } +      ],  +      "prefix": "10.0.20.0/24",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    } +  ],  +  "10.0.21.0/24": [ +    { +      "nexthops": [ +        { +          "afi": "ipv4",  +          "interfaceIndex": 2,  +          "interfaceName": "r4-eth0",  +          "ip": "10.0.21.2"  +        } +      ],  +      "prefix": "10.0.21.0/24",  +      "protocol": "isis",  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    },  +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r4-eth0" +        } +      ],  +      "prefix": "10.0.21.0/24",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    } +  ] +} diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route6.json b/tests/topotests/isis-topo1-vrf/r4/r4_route6.json new file mode 100644 index 0000000000..8d3ea570f0 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r4/r4_route6.json @@ -0,0 +1,78 @@ +{ +  "2001:db8:1:1::/64": [ +    { +      "distance": 115,  +      "metric": 30,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv6",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r4-eth1"  +        } +      ],  +      "prefix": "2001:db8:1:1::/64",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    } +  ],  +  "2001:db8:1:2::/64": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r4-eth0" +        } +      ],  +      "prefix": "2001:db8:1:2::/64",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    } +  ],  +  "2001:db8:2:1::/64": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv6",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r4-eth1"  +        } +      ],  +      "prefix": "2001:db8:2:1::/64",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    } +  ],  +  "2001:db8:2:2::/64": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r4-eth1" +        } +      ],  +      "prefix": "2001:db8:2:2::/64",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r4-cust1" +    } +  ]  +} diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json b/tests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json new file mode 100755 index 0000000000..b1cd5b9db9 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r4/r4_route6_linux.json @@ -0,0 +1,26 @@ +{ +  "2001:db8:1:1::/64": { +    "dev": "r4-eth1", +    "metric": "20", +    "pref": "medium", +    "proto": "187" +  }, +  "2001:db8:1:2::/64": { +    "dev": "r4-eth0", +    "metric": "256", +    "pref": "medium", +    "proto": "kernel" +  }, +  "2001:db8:2:1::/64": { +    "dev": "r4-eth1", +    "metric": "20", +    "pref": "medium", +    "proto": "187" +  }, +  "2001:db8:2:2::/64": { +    "dev": "r4-eth1", +    "metric": "256", +    "pref": "medium", +    "proto": "kernel" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_route_linux.json b/tests/topotests/isis-topo1-vrf/r4/r4_route_linux.json new file mode 100755 index 0000000000..3198b85789 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r4/r4_route_linux.json @@ -0,0 +1,24 @@ +{ +  "10.0.10.0/24": { +    "dev": "r4-eth1", +    "metric": "20", +    "proto": "187", +    "via": "10.0.11.1" +  }, +  "10.0.11.0/24": { +    "dev": "r4-eth1", +    "proto": "kernel", +    "scope": "link" +  }, +  "10.0.20.0/24": { +    "dev": "r4-eth1", +    "metric": "20", +    "proto": "187", +    "via": "10.0.11.1" +  }, +  "10.0.21.0/24": { +    "dev": "r4-eth0", +    "proto": "kernel", +    "scope": "link" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r4/r4_topology.json b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json new file mode 100644 index 0000000000..0d69550cad --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r4/r4_topology.json @@ -0,0 +1,132 @@ +{ +  "1": { +    "level-1": { +      "ipv4": [ +        { +          "vertex": "r4" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP",  +          "vertex": "10.0.11.0/24" +        },  +        { +          "interface": "r4-eth1",  +          "metric": "10",  +          "next-hop": "r5",  +          "parent": "r4(4)",  +          "type": "TE-IS",  +          "vertex": "r5" +        },  +        { +          "interface": "r5",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r4-eth1",  +          "type": "IP",  +          "vertex": "10.0.10.0/24" +        },  +        { +          "interface": "r5",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r4-eth1",  +          "type": "IP",  +          "vertex": "10.0.11.0/24" +        },  +        { +          "interface": "r5",  +          "metric": "TE",  +          "next-hop": "30",  +          "parent": "r4-eth1",  +          "type": "IP",  +          "vertex": "10.0.20.0/24" +        } +      ],  +      "ipv6": [ +        { +          "vertex": "r4" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP6",  +          "vertex": "2001:db8:2:2::/64" +        },  +        { +          "interface": "r4-eth1",  +          "metric": "10",  +          "next-hop": "r5",  +          "parent": "r4(4)",  +          "type": "TE-IS",  +          "vertex": "r5" +        },  +        { +          "interface": "r5",  +          "metric": "internal",  +          "next-hop": "20",  +          "parent": "r4-eth1",  +          "type": "IP6",  +          "vertex": "2001:db8:2:1::/64" +        },  +        { +          "interface": "r5",  +          "metric": "internal",  +          "next-hop": "30",  +          "parent": "r4-eth1",  +          "type": "IP6",  +          "vertex": "2001:db8:1:1::/64" +        } +      ] +    },  +    "level-2": { +      "ipv4": [ +        { +          "vertex": "r4" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP",  +          "vertex": "10.0.21.0/24" +        },  +        { +          "interface": "r4-eth0",  +          "metric": "10",  +          "next-hop": "r2",  +          "parent": "r4(4)",  +          "type": "TE-IS",  +          "vertex": "r2" +        },  +        { +          "interface": "r2",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r4-eth0",  +          "type": "IP",  +          "vertex": "10.0.21.0/24" +        } +      ],  +      "ipv6": [ +        { +          "vertex": "r4" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP6",  +          "vertex": "2001:db8:1:2::/64" +        },  +        { +          "interface": "r4-eth0",  +          "metric": "10",  +          "next-hop": "r2",  +          "parent": "r4(4)",  +          "type": "TE-IS",  +          "vertex": "r2" +        } +      ] +    } +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r4/zebra.conf b/tests/topotests/isis-topo1-vrf/r4/zebra.conf new file mode 100755 index 0000000000..9c8941f7a5 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r4/zebra.conf @@ -0,0 +1,13 @@ +hostname r4 +interface r4-eth0 vrf r4-cust1 + ip address 10.0.21.1/24 + ipv6 address 2001:db8:1:2::1/64 +! +interface r4-eth1 vrf r4-cust1 + ip address 10.0.11.2/24 + ipv6 address 2001:db8:2:2::2/64 +! +interface lo + ip address 10.254.0.4/32 + ipv6 address 2001:db8:F::4/128 +! diff --git a/tests/topotests/isis-topo1-vrf/r5/isisd.conf b/tests/topotests/isis-topo1-vrf/r5/isisd.conf new file mode 100755 index 0000000000..9e9b030455 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r5/isisd.conf @@ -0,0 +1,21 @@ +hostname r5 +debug isis adj-packets +debug isis events +debug isis update-packets +interface r5-eth0 + ip router isis 1 vrf r5-cust1 + ipv6 router isis 1 vrf r5-cust1 + isis circuit-type level-1 +! +interface r5-eth1 + ip router isis 1 vrf r5-cust1 + ipv6 router isis 1 vrf r5-cust1 + isis circuit-type level-1 +! +router isis 1 vrf r5-cust1 + net 10.0000.0000.0000.0000.0000.0000.0000.0000.0005.00 + metric-style wide + is-type level-1 + redistribute ipv4 connected level-1 + redistribute ipv6 connected level-1 +! diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route.json b/tests/topotests/isis-topo1-vrf/r5/r5_route.json new file mode 100644 index 0000000000..58aee5ddcc --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r5/r5_route.json @@ -0,0 +1,106 @@ +{ +  "10.0.10.0/24": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "afi": "ipv4",  +          "interfaceIndex": 2,  +          "interfaceName": "r5-eth0",  +          "ip": "10.0.10.2"  +        } +      ],  +      "prefix": "10.0.10.0/24",  +      "protocol": "isis",  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    },  +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r5-eth0" +        } +      ],  +      "prefix": "10.0.10.0/24",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    } +  ],  +  "10.0.11.0/24": [ +    { +      "nexthops": [ +        { +          "afi": "ipv4",  +          "interfaceIndex": 3,  +          "interfaceName": "r5-eth1",  +          "ip": "10.0.11.2"  +        } +      ],  +      "prefix": "10.0.11.0/24",  +      "protocol": "isis",  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    },  +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r5-eth1" +        } +      ],  +      "prefix": "10.0.11.0/24",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    } +  ],  +  "10.0.20.0/24": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv4",  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r5-eth0",  +          "ip": "10.0.10.2"  +        } +      ],  +      "prefix": "10.0.20.0/24",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    } +  ],  +  "10.0.21.0/24": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv4",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r5-eth1",  +          "ip": "10.0.11.2"  +        } +      ],  +      "prefix": "10.0.21.0/24",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    } +  ] +} diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route6.json b/tests/topotests/isis-topo1-vrf/r5/r5_route6.json new file mode 100644 index 0000000000..e32bbcc2c1 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r5/r5_route6.json @@ -0,0 +1,78 @@ +{ +  "2001:db8:1:1::/64": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv6",  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r5-eth0"  +        } +      ],  +      "prefix": "2001:db8:1:1::/64",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    } +  ],  +  "2001:db8:1:2::/64": [ +    { +      "distance": 115,  +      "metric": 20,  +      "nexthops": [ +        { +          "active": true,  +          "afi": "ipv6",  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r5-eth1"  +        } +      ],  +      "prefix": "2001:db8:1:2::/64",  +      "protocol": "isis",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    } +  ],  +  "2001:db8:2:1::/64": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 2,  +          "interfaceName": "r5-eth0" +        } +      ],  +      "prefix": "2001:db8:2:1::/64",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    } +  ],  +  "2001:db8:2:2::/64": [ +    { +      "nexthops": [ +        { +          "active": true,  +          "directlyConnected": true,  +          "fib": true,  +          "interfaceIndex": 3,  +          "interfaceName": "r5-eth1" +        } +      ],  +      "prefix": "2001:db8:2:2::/64",  +      "protocol": "connected",  +      "selected": true,  +      "vrfId": 4, +      "vrfName": "r5-cust1" +    } +  ]  +} diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json b/tests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json new file mode 100755 index 0000000000..3db3c93ea6 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r5/r5_route6_linux.json @@ -0,0 +1,26 @@ +{ +  "2001:db8:1:1::/64": { +    "dev": "r5-eth0", +    "metric": "20", +    "pref": "medium", +    "proto": "187" +  }, +  "2001:db8:1:2::/64": { +    "dev": "r5-eth1", +    "metric": "20", +    "pref": "medium", +    "proto": "187" +  }, +  "2001:db8:2:1::/64": { +    "dev": "r5-eth0", +    "metric": "256", +    "pref": "medium", +    "proto": "kernel" +  }, +  "2001:db8:2:2::/64": { +    "dev": "r5-eth1", +    "metric": "256", +    "pref": "medium", +    "proto": "kernel" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_route_linux.json b/tests/topotests/isis-topo1-vrf/r5/r5_route_linux.json new file mode 100755 index 0000000000..6a38ba864a --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r5/r5_route_linux.json @@ -0,0 +1,24 @@ +{ +  "10.0.10.0/24": { +    "dev": "r5-eth0", +    "proto": "kernel", +    "scope": "link" +  }, +  "10.0.11.0/24": { +    "dev": "r5-eth1", +    "proto": "kernel", +    "scope": "link" +  }, +  "10.0.20.0/24": { +    "dev": "r5-eth0", +    "metric": "20", +    "proto": "187", +    "via": "10.0.10.2" +  }, +  "10.0.21.0/24": { +    "dev": "r5-eth1", +    "metric": "20", +    "proto": "187", +    "via": "10.0.11.2" +  } +} diff --git a/tests/topotests/isis-topo1-vrf/r5/r5_topology.json b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json new file mode 100644 index 0000000000..b4ed6a069d --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r5/r5_topology.json @@ -0,0 +1,124 @@ +{ +  "1": { +    "level-1": { +      "ipv4": [ +        { +          "vertex": "r5" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP",  +          "vertex": "10.0.10.0/24" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP",  +          "vertex": "10.0.11.0/24" +        },  +        { +          "interface": "r5-eth0",  +          "metric": "10",  +          "next-hop": "r3",  +          "parent": "r5(4)",  +          "type": "TE-IS",  +          "vertex": "r3" +        },  +        { +          "interface": "r5-eth1",  +          "metric": "10",  +          "next-hop": "r4",  +          "parent": "r5(4)",  +          "type": "TE-IS",  +          "vertex": "r4" +        },  +        { +          "interface": "r3",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r5-eth0",  +          "type": "IP",  +          "vertex": "10.0.20.0/24" +        },  +        { +          "interface": "r3",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r5-eth0",  +          "type": "IP",  +          "vertex": "10.0.10.0/24" +        },  +        { +          "interface": "r4",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r5-eth1",  +          "type": "IP",  +          "vertex": "10.0.21.0/24" +        },  +        { +          "interface": "r4",  +          "metric": "TE",  +          "next-hop": "20",  +          "parent": "r5-eth1",  +          "type": "IP",  +          "vertex": "10.0.11.0/24" +        } +      ],  +      "ipv6": [ +        { +          "vertex": "r5" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP6",  +          "vertex": "2001:db8:2:1::/64" +        },  +        { +          "metric": "internal",  +          "parent": "0",  +          "type": "IP6",  +          "vertex": "2001:db8:2:2::/64" +        },  +        { +          "interface": "r5-eth0",  +          "metric": "10",  +          "next-hop": "r3",  +          "parent": "r5(4)",  +          "type": "TE-IS",  +          "vertex": "r3" +        },  +        { +          "interface": "r5-eth1",  +          "metric": "10",  +          "next-hop": "r4",  +          "parent": "r5(4)",  +          "type": "TE-IS",  +          "vertex": "r4" +        },  +        { +          "interface": "r3",  +          "metric": "internal",  +          "next-hop": "20",  +          "parent": "r5-eth0",  +          "type": "IP6",  +          "vertex": "2001:db8:1:1::/64" +        },  +        { +          "interface": "r4",  +          "metric": "internal",  +          "next-hop": "20",  +          "parent": "r5-eth1",  +          "type": "IP6",  +          "vertex": "2001:db8:1:2::/64" +        } +      ] +    },  +    "level-2": { +      "ipv4": [],  +      "ipv6": [] +    } +  } +}
\ No newline at end of file diff --git a/tests/topotests/isis-topo1-vrf/r5/zebra.conf b/tests/topotests/isis-topo1-vrf/r5/zebra.conf new file mode 100755 index 0000000000..c6bc6302fc --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/r5/zebra.conf @@ -0,0 +1,13 @@ +hostname r5 +interface r5-eth0 vrf r5-cust1 + ip address 10.0.10.1/24 + ipv6 address 2001:db8:2:1::1/64 +! +interface r5-eth1 vrf r5-cust1 + ip address 10.0.11.1/24 + ipv6 address 2001:db8:2:2::1/64 +! +interface lo + ip address 10.254.0.5/32 + ipv6 address 2001:db8:F::5/128 +! diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot new file mode 100755 index 0000000000..01f9ba780f --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.dot @@ -0,0 +1,100 @@ +## Color coding: +######################### +##  Main FRR: #f08080  red +##  Switches: #d0e0d0  gray +##  RIP:      #19e3d9  Cyan +##  RIPng:    #fcb314  dark yellow +##  OSPFv2:   #32b835  Green +##  OSPFv3:   #19e3d9  Cyan +##  ISIS IPv4 #fcb314  dark yellow +##  ISIS IPv6 #9a81ec  purple +##  BGP IPv4  #eee3d3  beige +##  BGP IPv6  #fdff00  yellow +##### Colors (see http://www.color-hex.com/) + +graph template { +	label="isis topo1"; + +	# Routers +	r1 [ +		shape=doubleoctagon, +		label="r1\n10.254.0.1\n2001:DB8:F::1", +		fillcolor="#f08080", +		style=filled, +	]; +	r2 [ +		shape=doubleoctagon +		label="r2\n10.254.0.2\n2001:DB8:F::2", +		fillcolor="#f08080", +		style=filled, +	]; +	r3 [ +		shape=doubleoctagon +		label="r3\n10.254.0.3\n2001:DB8:F::3", +		fillcolor="#f08080", +		style=filled, +	]; +	r4 [ +		shape=doubleoctagon +		label="r4\n10.254.0.4\n2001:DB8:F::4", +		fillcolor="#f08080", +		style=filled, +	]; +	r5 [ +		shape=doubleoctagon +		label="r5\n10.254.0.5\n2001:DB8:F::5", +		fillcolor="#f08080", +		style=filled, +	]; + +	# Switches +	sw1 [ +		shape=oval, +		label="sw1\n10.0.20.0/24\n2001:DB8:1:1::/64", +		fillcolor="#d0e0d0", +		style=filled, +	]; +	sw2 [ +		shape=oval, +		label="sw2\n10.0.21.0/24\n2001:DB8:1:2::/64", +		fillcolor="#d0e0d0", +		style=filled, +	]; +	sw3 [ +		shape=oval, +		label="sw3\n10.0.10.0/24\n2001:DB8:2:1::/64", +		fillcolor="#d0e0d0", +		style=filled, +	]; +	sw4 [ +		shape=oval, +		label="sw4\n10.0.11.0/24\n2001:DB8:2:2::/64", +		fillcolor="#d0e0d0", +		style=filled, +	]; + +	# Connections +	subgraph cluster0 { +		label="level 2"; + +		r1 -- sw1 [label="eth0\n.2"]; +		r2 -- sw2 [label="eth0\n.2"]; +	} + +	subgraph cluster1 { +		label="level 1/2"; + +		r3 -- sw1 [label="eth0\n.1"]; +		r3 -- sw3 [label="eth1\n.2"]; + +		r4 -- sw4 [label="eth1\n.2"]; +		r4 -- sw2 [label="eth0\n.1"]; +	} + +	subgraph cluster2 { +		label="level 1"; + +		r5 -- sw3 [label="eth0\n.1"]; +		r5 -- sw4 [label="eth1\n.1"]; +	} +} diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg Binary files differnew file mode 100755 index 0000000000..4ad730f2a0 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.jpg diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py new file mode 100755 index 0000000000..a0e34b71b0 --- /dev/null +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py @@ -0,0 +1,455 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2020 by  Niral Networks, Inc. ("Niral Networks") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# 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. +# + +""" +test_isis_topo1_vrf.py: Test ISIS vrf topology. +""" + +import collections +import functools +import json +import os +import re +import sys +import pytest +import platform + +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.topolog import logger + +from mininet.topo import Topo + + +class ISISTopo1(Topo): +    "Simple two layer ISIS vrf topology" + +    def build(self, *_args, **_opts): +        "Build function" +        tgen = get_topogen(self) + +        # Add ISIS routers: +        # r1      r2 +        #  | sw1  | sw2 +        # r3     r4 +        #  |      | +        # sw3    sw4 +        #   \    / +        #     r5 +        for routern in range(1, 6): +            tgen.add_router("r{}".format(routern)) + +        # r1 <- sw1 -> r3 +        sw = tgen.add_switch("sw1") +        sw.add_link(tgen.gears["r1"]) +        sw.add_link(tgen.gears["r3"]) + +        # r2 <- sw2 -> r4 +        sw = tgen.add_switch("sw2") +        sw.add_link(tgen.gears["r2"]) +        sw.add_link(tgen.gears["r4"]) + +        # r3 <- sw3 -> r5 +        sw = tgen.add_switch("sw3") +        sw.add_link(tgen.gears["r3"]) +        sw.add_link(tgen.gears["r5"]) + +        # r4 <- sw4 -> r5 +        sw = tgen.add_switch("sw4") +        sw.add_link(tgen.gears["r4"]) +        sw.add_link(tgen.gears["r5"]) + +def setup_module(mod): +    "Sets up the pytest environment" +    tgen = Topogen(ISISTopo1, mod.__name__) +    tgen.start_topology() + +    logger.info("Testing with VRF Lite support") +    krel = platform.release() + +    # May need to adjust handling of vrf traffic depending on kernel version +    l3mdev_accept = 0 +    if ( +        topotest.version_cmp(krel, "4.15") >= 0 +        and topotest.version_cmp(krel, "4.18") <= 0 +    ): +        l3mdev_accept = 1 + +    if topotest.version_cmp(krel, "5.0") >= 0: +        l3mdev_accept = 1 + +    logger.info( +        "krel '{0}' setting net.ipv4.tcp_l3mdev_accept={1}".format(krel, l3mdev_accept) +    ) + +    cmds = [ +        "ip link add {0}-cust1 type vrf table 1001", +        "ip link add loop1 type dummy", +        "ip link set {0}-eth0 master {0}-cust1", +        "ip link set {0}-eth1 master {0}-cust1", +    ] + +    # For all registered routers, load the zebra configuration file +    for rname, router in tgen.routers().iteritems(): +        # create VRF rx-cust1 and link rx-eth0 to rx-cust1 +        for cmd in cmds: +            output = tgen.net[rname].cmd(cmd.format(rname)) +        output = tgen.net[rname].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept") +        logger.info( +            "router {0}: existing tcp_l3mdev_accept was {1}".format(rname, output) +        ) + +        if l3mdev_accept: +            output = tgen.net[rname].cmd( +                "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept) +            ) + +    for rname, router in tgen.routers().iteritems(): +        router.load_config( +            TopoRouter.RD_ZEBRA,  +            os.path.join(CWD, "{}/zebra.conf".format(rname)) +        ) +        router.load_config( +            TopoRouter.RD_ISIS,  +            os.path.join(CWD, "{}/isisd.conf".format(rname)) +        ) +    # After loading the configurations, this function loads configured daemons. +    tgen.start_router() +     +    has_version_20 = False +    for router in tgen.routers().values(): +        if router.has_version("<", "4"): +            has_version_20 = True + +    if has_version_20: +        logger.info("Skipping ISIS vrf tests for FRR 2.0") +        tgen.set_error("ISIS has convergence problems with IPv6") + +def teardown_module(mod): +    "Teardown the pytest environment" +    tgen = get_topogen() +    # move back rx-eth0 to default VRF +    # delete rx-vrf +    tgen.stop_topology() + +def test_isis_convergence(): +    "Wait for the protocol to converge before starting to test" +    tgen = get_topogen() +    # Don't run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    logger.info("waiting for ISIS protocol to converge") +  +    for rname, router in tgen.routers().iteritems(): +        filename = "{0}/{1}/{1}_topology.json".format(CWD, rname) +        expected = json.loads(open(filename).read()) +        def compare_isis_topology(router, expected): +            "Helper function to test ISIS vrf topology convergence." +            actual = show_isis_topology(router) + +            return topotest.json_cmp(actual, expected) + +        test_func = functools.partial(compare_isis_topology, router, expected) +        (result, diff) = topotest.run_and_expect(test_func, None, wait=0.5, count=120) +        assert result, "ISIS did not converge on {}:\n{}".format(rname, diff) + +def test_isis_route_installation(): +    "Check whether all expected routes are present" +    tgen = get_topogen() +    # Don't run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    logger.info("Checking routers for installed ISIS vrf routes") +    # Check for routes in 'show ip route vrf {}-cust1 json' +    for rname, router in tgen.routers().iteritems(): +        filename = "{0}/{1}/{1}_route.json".format(CWD, rname) +        expected = json.loads(open(filename, "r").read()) +        actual = router.vtysh_cmd("show ip route vrf {0}-cust1 json".format(rname) , isjson=True) +        # Older FRR versions don't list interfaces in some ISIS routes +        if router.has_version("<", "3.1"): +            for network, routes in expected.iteritems(): +                for route in routes: +                    if route["protocol"] != "isis": +                        continue + +                    for nexthop in route["nexthops"]: +                        nexthop.pop("interfaceIndex", None) +                        nexthop.pop("interfaceName", None) + +        assertmsg = "Router '{}' routes mismatch".format(rname) +        assert topotest.json_cmp(actual, expected) is None, assertmsg + + +def test_isis_linux_route_installation(): + +    dist = platform.dist() + +    if (dist[1] == "16.04"): +	pytest.skip("Kernel not supported for vrf") + +    "Check whether all expected routes are present and installed in the OS" +    tgen = get_topogen() +    # Don't run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    logger.info("Checking routers for installed ISIS vrf routes in OS") +    # Check for routes in `ip route show vrf {}-cust1` +    for rname, router in tgen.routers().iteritems(): +        filename = "{0}/{1}/{1}_route_linux.json".format(CWD, rname) +        expected = json.loads(open(filename, "r").read()) +        actual = topotest.ip4_vrf_route(router) + +        # Older FRR versions install routes using different proto +        if router.has_version("<", "3.1"): +            for network, netoptions in expected.iteritems(): +                if "proto" in netoptions and netoptions["proto"] == "187": +                    netoptions["proto"] = "zebra" + +        assertmsg = "Router '{}' OS routes mismatch".format(rname) +        assert topotest.json_cmp(actual, expected) is None, assertmsg + +def test_isis_route6_installation(): +    "Check whether all expected routes are present" +    tgen = get_topogen() +    # Don't run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    logger.info("Checking routers for installed ISIS vrf IPv6 routes") +    # Check for routes in 'show ipv6 route vrf {}-cust1 json' +    for rname, router in tgen.routers().iteritems(): +        filename = "{0}/{1}/{1}_route6.json".format(CWD, rname) +        expected = json.loads(open(filename, "r").read()) +        actual = router.vtysh_cmd("show ipv6 route vrf {}-cust1 json".format(rname) , isjson=True) + +        # Older FRR versions don't list interfaces in some ISIS routes +        if router.has_version("<", "3.1"): +            for network, routes in expected.iteritems(): +                for route in routes: +                    if route["protocol"] != "isis": +                        continue + +                    for nexthop in route["nexthops"]: +                        nexthop.pop("interfaceIndex", None) +                        nexthop.pop("interfaceName", None) + +        assertmsg = "Router '{}' routes mismatch".format(rname) +        assert topotest.json_cmp(actual, expected) is None, assertmsg + +def test_isis_linux_route6_installation(): + +    dist = platform.dist() + +    if (dist[1] == "16.04"): +	pytest.skip("Kernel not supported for vrf") + +    "Check whether all expected routes are present and installed in the OS" +    tgen = get_topogen() +    # Don't run this test if we have any failure. +    if tgen.routers_have_failure(): +        pytest.skip(tgen.errors) + +    logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS") +    # Check for routes in `ip -6 route show vrf {}-cust1` +    for rname, router in tgen.routers().iteritems(): +        filename = "{0}/{1}/{1}_route6_linux.json".format(CWD, rname) +        expected = json.loads(open(filename, "r").read()) +        actual = topotest.ip6_vrf_route(router) + +        # Older FRR versions install routes using different proto +        if router.has_version("<", "3.1"): +            for network, netoptions in expected.iteritems(): +                if "proto" in netoptions and netoptions["proto"] == "187": +                    netoptions["proto"] = "zebra" + +        assertmsg = "Router '{}' OS routes mismatch".format(rname) +        assert topotest.json_cmp(actual, expected) is None, assertmsg + +def test_memory_leak(): +    "Run the memory leak test and report results." +    tgen = get_topogen() +    if not tgen.is_memleak_enabled(): +        pytest.skip("Memory leak test/report is disabled") + +    tgen.report_memory_leaks() + + +if __name__ == "__main__": +    args = ["-s"] + sys.argv[1:] +    sys.exit(pytest.main(args)) + + +# +# Auxiliary functions +# + + +def dict_merge(dct, merge_dct): +    """ +    Recursive dict merge. Inspired by :meth:``dict.update()``, instead of +    updating only top-level keys, dict_merge recurses down into dicts nested +    to an arbitrary depth, updating keys. The ``merge_dct`` is merged into +    ``dct``. +    :param dct: dict onto which the merge is executed +    :param merge_dct: dct merged into dct +    :return: None + +    Source: +    https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 +    """ +    for k, v in merge_dct.iteritems(): +        if ( +            k in dct +            and isinstance(dct[k], dict) +            and isinstance(merge_dct[k], collections.Mapping) +        ): +            dict_merge(dct[k], merge_dct[k]) +        else: +            dct[k] = merge_dct[k] + + +def parse_topology(lines, level): +    """ +    Parse the output of 'show isis topology level-X' into a Python dict. +    """ +    areas = {} +    area = None +    ipv = None + +    for line in lines: +        area_match = re.match(r"Area (.+):", line) +        if area_match: +            area = area_match.group(1) +            if area not in areas: +                areas[area] = {level: {"ipv4": [], "ipv6": []}} +            ipv = None +            continue +        elif area is None: +            continue + +        if re.match(r"IS\-IS paths to level-. routers that speak IPv6", line): +            ipv = "ipv6" +            continue +        if re.match(r"IS\-IS paths to level-. routers that speak IP", line): +            ipv = "ipv4" +            continue + +        item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line) +        if item_match is not None: +            # Skip header +            if ( +                item_match.group(1) == "Vertex" +                and item_match.group(2) == "Type" +                and item_match.group(3) == "Metric" +                and item_match.group(4) == "Next-Hop" +                and item_match.group(5) == "Interface" +                and item_match.group(6) == "Parent" +            ): +                continue + +            areas[area][level][ipv].append( +                { +                    "vertex": item_match.group(1), +                    "type": item_match.group(2), +                    "metric": item_match.group(3), +                    "next-hop": item_match.group(4), +                    "interface": item_match.group(5), +                    "parent": item_match.group(6), +                } +            ) +            continue + +        item_match = re.match(r"([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)", line) +        if item_match is not None: +            areas[area][level][ipv].append( +                { +                    "vertex": item_match.group(1), +                    "type": item_match.group(2), +                    "metric": item_match.group(3), +                    "parent": item_match.group(4), +                } +            ) +            continue + +        item_match = re.match(r"([^ ]+)", line) +        if item_match is not None: +            areas[area][level][ipv].append({"vertex": item_match.group(1)}) +            continue + +    return areas + + +def show_isis_topology(router): +    """ +    Get the ISIS vrf topology in a dictionary format. + +    Sample: +    { +      'area-name': { +        'level-1': [ +          { +            'vertex': 'r1' +          } +        ], +        'level-2': [ +          { +            'vertex': '10.0.0.1/24', +            'type': 'IP', +            'parent': '0', +            'metric': 'internal' +          } +        ] +      }, +      'area-name-2': { +        'level-2': [ +          { +            "interface": "rX-ethY", +            "metric": "Z", +            "next-hop": "rA", +            "parent": "rC(B)", +            "type": "TE-IS", +            "vertex": "rD" +          } +        ] +      } +    } +    """ +    l1out = topotest.normalize_text( +        router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name)) +    ).splitlines() +    l2out = topotest.normalize_text( +        router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name)) +    ).splitlines() + +    l1 = parse_topology(l1out, "level-1") +    l2 = parse_topology(l2out, "level-2") + +    dict_merge(l1, l2) +    return l1 + diff --git a/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf index 6daf034d18..87d5703d9e 100644 --- a/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf +++ b/tests/topotests/ldp-oc-acl-topo1/r1/ospfd.conf @@ -5,3 +5,7 @@ router ospf   router-id 1.1.1.1   network 0.0.0.0/0 area 0  ! +int r1-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf index 8678813665..51317202bb 100644 --- a/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf +++ b/tests/topotests/ldp-oc-acl-topo1/r2/ospfd.conf @@ -5,3 +5,11 @@ router ospf   router-id 2.2.2.2   network 0.0.0.0/0 area 0  ! +int r2-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf index 202be238ec..4566976b7b 100644 --- a/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf +++ b/tests/topotests/ldp-oc-acl-topo1/r3/ospfd.conf @@ -6,3 +6,7 @@ router ospf   router-id 3.3.3.3   network 0.0.0.0/0 area 0  ! +int r3-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf b/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf index 569dbc54e2..5aae885a12 100644 --- a/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf +++ b/tests/topotests/ldp-oc-acl-topo1/r4/ospfd.conf @@ -5,3 +5,7 @@ router ospf   router-id 4.4.4.4   network 0.0.0.0/0 area 0  ! +int r4-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-oc-topo1/r1/ospfd.conf b/tests/topotests/ldp-oc-topo1/r1/ospfd.conf index 6daf034d18..87d5703d9e 100644 --- a/tests/topotests/ldp-oc-topo1/r1/ospfd.conf +++ b/tests/topotests/ldp-oc-topo1/r1/ospfd.conf @@ -5,3 +5,7 @@ router ospf   router-id 1.1.1.1   network 0.0.0.0/0 area 0  ! +int r1-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-oc-topo1/r2/ospfd.conf b/tests/topotests/ldp-oc-topo1/r2/ospfd.conf index 8678813665..51317202bb 100644 --- a/tests/topotests/ldp-oc-topo1/r2/ospfd.conf +++ b/tests/topotests/ldp-oc-topo1/r2/ospfd.conf @@ -5,3 +5,11 @@ router ospf   router-id 2.2.2.2   network 0.0.0.0/0 area 0  ! +int r2-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-oc-topo1/r3/ospfd.conf b/tests/topotests/ldp-oc-topo1/r3/ospfd.conf index 202be238ec..4566976b7b 100644 --- a/tests/topotests/ldp-oc-topo1/r3/ospfd.conf +++ b/tests/topotests/ldp-oc-topo1/r3/ospfd.conf @@ -6,3 +6,7 @@ router ospf   router-id 3.3.3.3   network 0.0.0.0/0 area 0  ! +int r3-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-oc-topo1/r4/ospfd.conf b/tests/topotests/ldp-oc-topo1/r4/ospfd.conf index 569dbc54e2..5aae885a12 100644 --- a/tests/topotests/ldp-oc-topo1/r4/ospfd.conf +++ b/tests/topotests/ldp-oc-topo1/r4/ospfd.conf @@ -5,3 +5,7 @@ router ospf   router-id 4.4.4.4   network 0.0.0.0/0 area 0  ! +int r4-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-topo1/r1/ospfd.conf b/tests/topotests/ldp-topo1/r1/ospfd.conf index 6daf034d18..87d5703d9e 100644 --- a/tests/topotests/ldp-topo1/r1/ospfd.conf +++ b/tests/topotests/ldp-topo1/r1/ospfd.conf @@ -5,3 +5,7 @@ router ospf   router-id 1.1.1.1   network 0.0.0.0/0 area 0  ! +int r1-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-topo1/r2/ospfd.conf b/tests/topotests/ldp-topo1/r2/ospfd.conf index 8678813665..dbed6189c8 100644 --- a/tests/topotests/ldp-topo1/r2/ospfd.conf +++ b/tests/topotests/ldp-topo1/r2/ospfd.conf @@ -5,3 +5,15 @@ router ospf   router-id 2.2.2.2   network 0.0.0.0/0 area 0  ! +int r2-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth2 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-topo1/r3/ospfd.conf b/tests/topotests/ldp-topo1/r3/ospfd.conf index 202be238ec..bd86fe4f24 100644 --- a/tests/topotests/ldp-topo1/r3/ospfd.conf +++ b/tests/topotests/ldp-topo1/r3/ospfd.conf @@ -6,3 +6,11 @@ router ospf   router-id 3.3.3.3   network 0.0.0.0/0 area 0  ! +int r3-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r3-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-topo1/r4/ospfd.conf b/tests/topotests/ldp-topo1/r4/ospfd.conf index 569dbc54e2..5aae885a12 100644 --- a/tests/topotests/ldp-topo1/r4/ospfd.conf +++ b/tests/topotests/ldp-topo1/r4/ospfd.conf @@ -5,3 +5,7 @@ router ospf   router-id 4.4.4.4   network 0.0.0.0/0 area 0  ! +int r4-eth0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-vpls-topo1/r1/ospfd.conf b/tests/topotests/ldp-vpls-topo1/r1/ospfd.conf index 6daf034d18..76ea32fb61 100644 --- a/tests/topotests/ldp-vpls-topo1/r1/ospfd.conf +++ b/tests/topotests/ldp-vpls-topo1/r1/ospfd.conf @@ -5,3 +5,11 @@ router ospf   router-id 1.1.1.1   network 0.0.0.0/0 area 0  ! +int r1-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r1-eth2 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-vpls-topo1/r2/ospfd.conf b/tests/topotests/ldp-vpls-topo1/r2/ospfd.conf index 8678813665..7b3ddfe371 100644 --- a/tests/topotests/ldp-vpls-topo1/r2/ospfd.conf +++ b/tests/topotests/ldp-vpls-topo1/r2/ospfd.conf @@ -5,3 +5,11 @@ router ospf   router-id 2.2.2.2   network 0.0.0.0/0 area 0  ! +int r2-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r2-eth2 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ldp-vpls-topo1/r3/ospfd.conf b/tests/topotests/ldp-vpls-topo1/r3/ospfd.conf index b6bafba205..b424f2e108 100644 --- a/tests/topotests/ldp-vpls-topo1/r3/ospfd.conf +++ b/tests/topotests/ldp-vpls-topo1/r3/ospfd.conf @@ -5,3 +5,11 @@ router ospf   router-id 3.3.3.3   network 0.0.0.0/0 area 0  ! +int r3-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +int r3-eth2 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 316d4cf414..e2f887bb89 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -456,6 +456,15 @@ def __create_bgp_unicast_neighbor(                          cmd = "no {}".format(cmd)                      config_data.append(cmd) +        import_vrf_data = addr_data.setdefault("import", {}) +        if import_vrf_data: +            cmd = "import vrf {}".format(import_vrf_data["vrf"]) + +            del_action = import_vrf_data.setdefault("delete", False) +            if del_action: +                cmd = "no {}".format(cmd) +            config_data.append(cmd) +          if "neighbor" in addr_data:              neigh_data = __create_bgp_neighbor(                  topo, input_dict, router, addr_type, add_neigh @@ -2610,6 +2619,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)                                  if not isinstance(next_hop, list):                                      next_hop = [next_hop]                                      list1 = next_hop +                                  found_hops = [                                      rib_r["ip"]                                      for rib_r in rib_routes_json["routes"][st_rt][0][ @@ -2617,6 +2627,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)                                      ]                                  ]                                  list2 = found_hops +                                  missing_list_of_nexthops = set(list2).difference(list1)                                  additional_nexthops_in_required_nhs = set(                                      list1 diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index d77946b1ed..1846d43138 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -32,6 +32,7 @@ from tempfile import mkdtemp  import os  import sys +import ConfigParser  import traceback  import socket  import ipaddress @@ -1237,7 +1238,8 @@ def interface_status(tgen, topo, input_dict):      return True -def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict=False): +def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, +          return_is_dict=False):      """      Retries function execution, if return is an errormsg or exception @@ -1249,11 +1251,13 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict      """      def _retry(func): +          @wraps(func)          def func_retry(*args, **kwargs): -            _wait = kwargs.pop("wait", wait) -            _attempts = kwargs.pop("attempts", attempts) +            _wait = kwargs.pop('wait', wait) +            _attempts = kwargs.pop('attempts', attempts)              _attempts = int(_attempts) +            expected = True              if _attempts < 0:                  raise ValueError("attempts must be 0 or greater") @@ -1261,40 +1265,40 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict                  logger.info("Waiting for [%s]s as initial delay", initial_wait)                  sleep(initial_wait) -            _return_is_str = kwargs.pop("return_is_str", return_is_str) -            _return_is_dict = kwargs.pop("return_is_str", return_is_dict) +            _return_is_str = kwargs.pop('return_is_str', return_is_str) +            _return_is_dict = kwargs.pop('return_is_str', return_is_dict)              for i in range(1, _attempts + 1):                  try: -                    _expected = kwargs.setdefault("expected", True) -                    kwargs.pop("expected") +                    _expected = kwargs.setdefault('expected', True) +                    if _expected is False: +                        expected = _expected +                    kwargs.pop('expected')                      ret = func(*args, **kwargs) -                    logger.debug("Function returned %s" % ret) +                    logger.debug("Function returned %s", ret)                      if _return_is_str and isinstance(ret, bool) and _expected:                          return ret -                    if ( -                        isinstance(ret, str) or isinstance(ret, unicode) -                    ) and _expected is False: +                    if (isinstance(ret, str) or isinstance(ret, unicode)) and _expected is False:                          return ret                      if _return_is_dict and isinstance(ret, dict):                          return ret -                    if _attempts == i: +                    if _attempts == i and expected:                          generate_support_bundle()                          return ret                  except Exception as err: -                    if _attempts == i: +                    if _attempts == i and expected:                          generate_support_bundle() -                        logger.info("Max number of attempts (%r) reached", _attempts) +                        logger.info("Max number of attempts (%r) reached", +                                    _attempts)                          raise                      else:                          logger.info("Function returned %s", err)                  if i < _attempts: -                    logger.info("Retry [#%r] after sleeping for %ss" % (i, _wait)) +                    logger.info("Retry [#%r] after sleeping for %ss" +                                % (i, _wait))                      sleep(_wait) -          func_retry._original = func          return func_retry -      return _retry @@ -2517,7 +2521,7 @@ def verify_rib(      errormsg(str) or True      """ -    logger.info("Entering lib API: verify_rib()") +    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))      router_list = tgen.routers()      additional_nexthops_in_required_nhs = [] @@ -2832,7 +2836,263 @@ def verify_rib(                          " routes  are: {}\n".format(addr_type, dut, found_routes)                      ) -    logger.info("Exiting lib API: verify_rib()") +    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) +    return True + + +@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2) +def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None): +    """ +    Data will be read from input_dict or input JSON file, API will generate +    same prefixes, which were redistributed by either create_static_routes() or +    advertise_networks_using_network_command() and will verify next_hop and +    each prefix/routes is present in "show ip/ipv6 fib json" +    command o/p. + +    Parameters +    ---------- +    * `tgen` : topogen object +    * `addr_type` : ip type, ipv4/ipv6 +    * `dut`: Device Under Test, for which user wants to test the data +    * `input_dict` : input dict, has details of static routes +    * `next_hop`[optional]: next_hop which needs to be verified, +                           default: static + +    Usage +    ----- +    input_routes_r1 = { +        "r1": { +            "static_routes": [{ +                "network": ["1.1.1.1/32], +                "next_hop": "Null0", +                "vrf": "RED" +            }] +        } +    } +    result = result = verify_fib_routes(tgen, "ipv4, "r1", input_routes_r1) + +    Returns +    ------- +    errormsg(str) or True +    """ + +    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + +    router_list = tgen.routers() +    for routerInput in input_dict.keys(): +        for router, rnode in router_list.iteritems(): +            if router != dut: +                continue + +            logger.info("Checking router %s FIB routes:", router) + +            # Verifying RIB routes +            if addr_type == "ipv4": +                command = "show ip fib" +            else: +                command = "show ipv6 fib" + +            found_routes = [] +            missing_routes = [] + +            if "static_routes" in input_dict[routerInput]: +                static_routes = input_dict[routerInput]["static_routes"] + +                for static_route in static_routes: +                    if "vrf" in static_route and static_route["vrf"] is not None: + +                        logger.info( +                            "[DUT: {}]: Verifying routes for VRF:" +                            " {}".format(router, static_route["vrf"]) +                        ) + +                        cmd = "{} vrf {}".format(command, static_route["vrf"]) + +                    else: +                        cmd = "{}".format(command) + +                    cmd = "{} json".format(cmd) + +                    rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True) + +                    # Verifying output dictionary rib_routes_json is not empty +                    if bool(rib_routes_json) is False: +                        errormsg = "[DUT: {}]: No route found in fib".format(router) +                        return errormsg + +                    network = static_route["network"] +                    if "no_of_ip" in static_route: +                        no_of_ip = static_route["no_of_ip"] +                    else: +                        no_of_ip = 1 + +                    # Generating IPs for verification +                    ip_list = generate_ips(network, no_of_ip) +                    st_found = False +                    nh_found = False + +                    for st_rt in ip_list: +                        st_rt = str(ipaddress.ip_network(unicode(st_rt))) +                        #st_rt = str(ipaddr.IPNetwork(unicode(st_rt))) + +                        _addr_type = validate_ip_address(st_rt) +                        if _addr_type != addr_type: +                            continue + +                        if st_rt in rib_routes_json: +                            st_found = True +                            found_routes.append(st_rt) + +                            if next_hop: +                                if type(next_hop) is not list: +                                    next_hop = [next_hop] + +                                count = 0 +                                for nh in next_hop: +                                    for nh_dict in rib_routes_json[st_rt][0][ +                                        "nexthops" +                                    ]: +                                        if nh_dict["ip"] != nh: +                                            continue +                                        else: +                                            count += 1 + +                                if count == len(next_hop): +                                    nh_found = True +                                else: +                                    missing_routes.append(st_rt) +                                    errormsg = ( +                                        "Nexthop {} is Missing" +                                        " for route {} in " +                                        "RIB of router {}\n".format( +                                            next_hop, st_rt, dut +                                        ) +                                    ) +                                    return errormsg + +                        else: +                            missing_routes.append(st_rt) + +                if len(missing_routes) > 0: +                    errormsg = "[DUT: {}]: Missing route in FIB:" " {}".format( +                        dut, missing_routes +                    ) +                    return errormsg + +                if nh_found: +                    logger.info( +                        "Found next_hop {} for all routes in RIB" +                        " of router {}\n".format(next_hop, dut) +                    ) + +                if found_routes: +                    logger.info( +                        "[DUT: %s]: Verified routes in FIB, found" " routes are: %s\n", +                        dut, +                        found_routes, +                    ) + +                continue + +            if "bgp" in input_dict[routerInput]: +                if ( +                    "advertise_networks" +                    not in input_dict[routerInput]["bgp"]["address_family"][addr_type][ +                        "unicast" +                    ] +                ): +                    continue + +                found_routes = [] +                missing_routes = [] +                advertise_network = input_dict[routerInput]["bgp"]["address_family"][ +                    addr_type +                ]["unicast"]["advertise_networks"] + +                # Continue if there are no network advertise +                if len(advertise_network) == 0: +                    continue + +                for advertise_network_dict in advertise_network: +                    if "vrf" in advertise_network_dict: +                        cmd = "{} vrf {} json".format(command, static_route["vrf"]) +                    else: +                        cmd = "{} json".format(command) + +                rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True) + +                # Verifying output dictionary rib_routes_json is not empty +                if bool(rib_routes_json) is False: +                    errormsg = "No route found in rib of router {}..".format(router) +                    return errormsg + +                start_ip = advertise_network_dict["network"] +                if "no_of_network" in advertise_network_dict: +                    no_of_network = advertise_network_dict["no_of_network"] +                else: +                    no_of_network = 1 + +                # Generating IPs for verification +                ip_list = generate_ips(start_ip, no_of_network) +                st_found = False +                nh_found = False + +                for st_rt in ip_list: +                    #st_rt = str(ipaddr.IPNetwork(unicode(st_rt))) +                    st_rt = str(ipaddress.ip_network(unicode(st_rt))) + +                    _addr_type = validate_ip_address(st_rt) +                    if _addr_type != addr_type: +                        continue + +                    if st_rt in rib_routes_json: +                        st_found = True +                        found_routes.append(st_rt) + +                        if next_hop: +                            if type(next_hop) is not list: +                                next_hop = [next_hop] + +                            count = 0 +                            for nh in next_hop: +                                for nh_dict in rib_routes_json[st_rt][0]["nexthops"]: +                                    if nh_dict["ip"] != nh: +                                        continue +                                    else: +                                        count += 1 + +                            if count == len(next_hop): +                                nh_found = True +                            else: +                                missing_routes.append(st_rt) +                                errormsg = ( +                                    "Nexthop {} is Missing" +                                    " for route {} in " +                                    "RIB of router {}\n".format(next_hop, st_rt, dut) +                                ) +                                return errormsg +                    else: +                        missing_routes.append(st_rt) + +                if len(missing_routes) > 0: +                    errormsg = "[DUT: {}]: Missing route in FIB: " "{} \n".format( +                        dut, missing_routes +                    ) +                    return errormsg + +                if nh_found: +                    logger.info( +                        "Found next_hop {} for all routes in RIB" +                        " of router {}\n".format(next_hop, dut) +                    ) + +                if found_routes: +                    logger.info( +                        "[DUT: {}]: Verified routes FIB" +                        ", found routes  are: {}\n".format(dut, found_routes) +                    ) + +    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))      return True diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 8a40490be3..e34d1cf0be 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -720,6 +720,49 @@ def ip4_route(node):      return result +def ip4_vrf_route(node): +    """ +    Gets a structured return of the command 'ip route show vrf {0}-cust1'. +    It can be used in conjuction with json_cmp() to provide accurate assert explanations. + +    Return example: +    { +        '10.0.1.0/24': { +            'dev': 'eth0', +            'via': '172.16.0.1', +            'proto': '188', +        }, +        '10.0.2.0/24': { +            'dev': 'eth1', +            'proto': 'kernel', +        } +    } +    """ +    output = normalize_text( +            node.run("ip route show vrf {0}-cust1".format(node.name))).splitlines() + +    result = {} +    for line in output: +        columns = line.split(" ") +        route = result[columns[0]] = {} +        prev = None +        for column in columns: +            if prev == "dev": +                route["dev"] = column +            if prev == "via": +                route["via"] = column +            if prev == "proto": +                # translate protocol names back to numbers +                route["proto"] = proto_name_to_number(column) +            if prev == "metric": +                route["metric"] = column +            if prev == "scope": +                route["scope"] = column +            prev = column + +    return result + +  def ip6_route(node):      """      Gets a structured return of the command 'ip -6 route'. It can be used in @@ -760,6 +803,47 @@ def ip6_route(node):      return result +def ip6_vrf_route(node): +    """ +    Gets a structured return of the command 'ip -6 route show vrf {0}-cust1'. +    It can be used in conjuction with json_cmp() to provide accurate assert explanations. + +    Return example: +    { +        '2001:db8:1::/64': { +            'dev': 'eth0', +            'proto': '188', +        }, +        '2001:db8:2::/64': { +            'dev': 'eth1', +            'proto': 'kernel', +        } +    } +    """ +    output = normalize_text( +            node.run("ip -6 route show vrf {0}-cust1".format(node.name))).splitlines() +    result = {} +    for line in output: +        columns = line.split(" ") +        route = result[columns[0]] = {} +        prev = None +        for column in columns: +            if prev == "dev": +                route["dev"] = column +            if prev == "via": +                route["via"] = column +            if prev == "proto": +                # translate protocol names back to numbers +                route["proto"] = proto_name_to_number(column) +            if prev == "metric": +                route["metric"] = column +            if prev == "pref": +                route["pref"] = column +            prev = column + +    return result + +  def ip_rules(node):      """      Gets a structured return of the command 'ip rule'. It can be used in diff --git a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf b/tests/topotests/ospf-sr-topo1/r1/ospfd.conf index 73a272786c..0773153a76 100644 --- a/tests/topotests/ospf-sr-topo1/r1/ospfd.conf +++ b/tests/topotests/ospf-sr-topo1/r1/ospfd.conf @@ -5,10 +5,14 @@ interface lo  !  interface r1-eth0    ip ospf network point-to-point +  ip ospf hello-interval 2 +  ip ospf dead-interval 10    ip ospf area 0.0.0.0  !  interface r1-eth1    ip ospf network point-to-point +  ip ospf hello-interval 2 +  ip ospf dead-interval 10    ip ospf area 0.0.0.0  !  router ospf diff --git a/tests/topotests/ospf-sr-topo1/r2/ospfd.conf b/tests/topotests/ospf-sr-topo1/r2/ospfd.conf index b8c7b999e8..92dc2f7cd1 100644 --- a/tests/topotests/ospf-sr-topo1/r2/ospfd.conf +++ b/tests/topotests/ospf-sr-topo1/r2/ospfd.conf @@ -6,17 +6,25 @@ interface lo  !  interface r2-eth0    ip ospf network point-to-point +  ip ospf hello-interval 2 +  ip ospf dead-interval 10    ip ospf area 0.0.0.0  !  interface r2-eth1    ip ospf network point-to-point +  ip ospf hello-interval 2 +  ip ospf dead-interval 10    ip ospf area 0.0.0.0  !  interface r2-eth2    ip ospf area 0.0.0.0 +  ip ospf hello-interval 2 +  ip ospf dead-interval 10  !  interface r2-eth3    ip ospf network point-to-point +  ip ospf hello-interval 2 +  ip ospf dead-interval 10    ip ospf area 0.0.0.0  !  router ospf diff --git a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf b/tests/topotests/ospf-sr-topo1/r3/ospfd.conf index 38d525f34f..e2766f202d 100644 --- a/tests/topotests/ospf-sr-topo1/r3/ospfd.conf +++ b/tests/topotests/ospf-sr-topo1/r3/ospfd.conf @@ -1,9 +1,13 @@  !  interface lo    ip ospf area 0.0.0.0 +  ip ospf hello-interval 2 +  ip ospf dead-interval 10  !  interface r3-eth0    ip ospf area 0.0.0.0 +  ip ospf hello-interval 2 +  ip ospf dead-interval 10  !  !  router ospf diff --git a/tests/topotests/ospf-sr-topo1/r4/ospfd.conf b/tests/topotests/ospf-sr-topo1/r4/ospfd.conf index 9d0d148812..e80880af88 100644 --- a/tests/topotests/ospf-sr-topo1/r4/ospfd.conf +++ b/tests/topotests/ospf-sr-topo1/r4/ospfd.conf @@ -1,9 +1,13 @@  !  interface lo   ip ospf area 0.0.0.0 + ip ospf hello-interval 2 + ip ospf dead-interval 10  !  interface r4-eth0   ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10   ip ospf area 0.0.0.0  !  ! diff --git a/tests/topotests/ospf-topo1/r1/ospf6d.conf b/tests/topotests/ospf-topo1/r1/ospf6d.conf index 58c9e292a9..ca3497b4a5 100644 --- a/tests/topotests/ospf-topo1/r1/ospf6d.conf +++ b/tests/topotests/ospf-topo1/r1/ospf6d.conf @@ -7,3 +7,7 @@ router ospf6   interface r1-eth0 area 0.0.0.0   interface r1-eth1 area 0.0.0.0  ! +int r1-eth1 + ipv6 ospf6 dead-interval 10 + ipv6 ospf6 hello-interval 2 +! diff --git a/tests/topotests/ospf-topo1/r1/ospfd.conf b/tests/topotests/ospf-topo1/r1/ospfd.conf index 1226b72f2b..3b5aa192c5 100644 --- a/tests/topotests/ospf-topo1/r1/ospfd.conf +++ b/tests/topotests/ospf-topo1/r1/ospfd.conf @@ -7,3 +7,7 @@ router ospf    network 10.0.1.0/24 area 0    network 10.0.3.0/24 area 0  ! +int r1-eth1 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! diff --git a/tests/topotests/ospf-topo1/r2/ospf6d.conf b/tests/topotests/ospf-topo1/r2/ospf6d.conf index a4ef1469a7..44047e1a4e 100644 --- a/tests/topotests/ospf-topo1/r2/ospf6d.conf +++ b/tests/topotests/ospf-topo1/r2/ospf6d.conf @@ -7,3 +7,11 @@ router ospf6   interface r2-eth0 area 0.0.0.0   interface r2-eth1 area 0.0.0.0  ! +int r2-eth0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +int r2-eth1 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! diff --git a/tests/topotests/ospf-topo1/r2/ospfd.conf b/tests/topotests/ospf-topo1/r2/ospfd.conf index 78d980315d..1a7ccdf728 100644 --- a/tests/topotests/ospf-topo1/r2/ospfd.conf +++ b/tests/topotests/ospf-topo1/r2/ospfd.conf @@ -7,3 +7,7 @@ router ospf    network 10.0.2.0/24 area 0    network 10.0.3.0/24 area 0  ! +int r2-eth1 +  ip ospf hello-interval 2 +  ip ospf dead-interval 10 +! diff --git a/tests/topotests/ospf-topo1/r3/ospf6d.conf b/tests/topotests/ospf-topo1/r3/ospf6d.conf index 4ff53011cb..13ad9a7356 100644 --- a/tests/topotests/ospf-topo1/r3/ospf6d.conf +++ b/tests/topotests/ospf-topo1/r3/ospf6d.conf @@ -8,3 +8,15 @@ router ospf6   interface r3-eth1 area 0.0.0.0   interface r3-eth2 area 0.0.0.1  ! +int r3-eth0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +int r3-eth1 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +int r3-eth2 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! diff --git a/tests/topotests/ospf-topo1/r3/ospfd.conf b/tests/topotests/ospf-topo1/r3/ospfd.conf index dbb7215d10..3b378c0f27 100644 --- a/tests/topotests/ospf-topo1/r3/ospfd.conf +++ b/tests/topotests/ospf-topo1/r3/ospfd.conf @@ -8,3 +8,11 @@ router ospf    network 10.0.10.0/24 area 0    network 172.16.0.0/24 area 1  ! +int r3-eth0 +  ip ospf hello-interval 2 +  ip ospf dead-interval 10 +! +int r3-eth2 +  ip ospf hello-interval 2 +  ip ospf dead-interval 10 +! diff --git a/tests/topotests/ospf-topo1/r4/ospf6d.conf b/tests/topotests/ospf-topo1/r4/ospf6d.conf index 32942ea189..f9bde0e83c 100644 --- a/tests/topotests/ospf-topo1/r4/ospf6d.conf +++ b/tests/topotests/ospf-topo1/r4/ospf6d.conf @@ -7,3 +7,11 @@ router ospf6   interface r4-eth0 area 0.0.0.1   interface r4-eth1 area 0.0.0.1  ! +int r4-eth0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +int r4-eth1 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! diff --git a/tests/topotests/ospf-topo1/r4/ospfd.conf b/tests/topotests/ospf-topo1/r4/ospfd.conf index 01b29ca057..52d29322f8 100644 --- a/tests/topotests/ospf-topo1/r4/ospfd.conf +++ b/tests/topotests/ospf-topo1/r4/ospfd.conf @@ -7,3 +7,7 @@ router ospf    network 172.16.0.0/24 area 1    network 172.16.1.0/24 area 1  ! +int r4-eth0 +  ip ospf hello-interval 2 +  ip ospf dead-interval 10 +! diff --git a/tests/topotests/ospf-topo2/r1/ospfd.conf b/tests/topotests/ospf-topo2/r1/ospfd.conf index 1e1bfca569..65843cbb83 100644 --- a/tests/topotests/ospf-topo2/r1/ospfd.conf +++ b/tests/topotests/ospf-topo2/r1/ospfd.conf @@ -1,6 +1,8 @@  !  interface r1-eth1    ip ospf network point-to-point +  ip ospf hello-interval 2 +  ip ospf dead-interval 10  !  router ospf    ospf router-id 10.0.255.1 diff --git a/tests/topotests/ospf-topo2/r2/ospfd.conf b/tests/topotests/ospf-topo2/r2/ospfd.conf index af2acd8404..b032f1a8ac 100644 --- a/tests/topotests/ospf-topo2/r2/ospfd.conf +++ b/tests/topotests/ospf-topo2/r2/ospfd.conf @@ -1,6 +1,8 @@  !  interface r2-eth1    ip ospf network point-to-point +  ip ospf hello-interval 2 +  ip ospf dead-interval 10  !  router ospf    ospf router-id 10.0.255.2 diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index d3fc8bc338..4edbb7a889 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1892,10 +1892,11 @@ DEFUNSH(VTYSH_LDPD, ldp_member_pseudowire_ifname,  }  #endif -DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd, "router isis WORD", +DEFUNSH(VTYSH_ISISD, router_isis, router_isis_cmd, +	"router isis WORD [vrf NAME]",  	ROUTER_STR  	"ISO IS-IS\n" -	"ISO Routing area tag\n") +	"ISO Routing area tag\n" VRF_CMD_HELP_STR)  {  	vty->node = ISIS_NODE;  	return CMD_SUCCESS; diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang index c9e09bef4b..1e44c2569e 100644 --- a/yang/frr-filter.yang +++ b/yang/frr-filter.yang @@ -170,31 +170,22 @@ module frr-filter {                    description "Match any";                    type empty;                  } -              } -              choice extended-value { -                /* -                 * Legacy note: before using the new access-list format the -                 * cisco styled list only accepted identifiers using numbers -                 * and they had the following restriction: -                 * -                 * when "../number >= 100 and ../number <= 199 or -                 *     ../number >= 2000 and ../number <= 2699"; -                 */ -                description "Destination value to match"; -                mandatory true; - -                leaf destination-host { -                  description "Host to match"; -                  type inet:ipv4-address; -                } -                leaf destination-network { -                  description "Network to match"; -                  type inet:ipv4-prefix; -                } -                leaf destination-any { -                  description "Match any"; -                  type empty; +                choice extended-value { +                  description "Destination value to match"; + +                  leaf destination-host { +                    description "Host to match"; +                    type inet:ipv4-address; +                  } +                  leaf destination-network { +                    description "Network to match"; +                    type inet:ipv4-prefix; +                  } +                  leaf destination-any { +                    description "Match any"; +                    type empty; +                  }                  }                }              } diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang index dade9f97fe..46c03a1d1f 100644 --- a/yang/frr-interface.yang +++ b/yang/frr-interface.yang @@ -300,11 +300,7 @@ module frr-interface {        }        leaf vrf { -        type string { -          length "1..16"; -        } -        /* yang version 0.16 having issue accessing leafref. */  -        /* type frr-vrf:vrf-ref;*/ +        type frr-vrf:vrf-ref;          description            "VRF this interface is associated with.";        } diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index 1bb693a1ef..00296516ef 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -340,6 +340,13 @@ module frr-isisd {          "Area-tag associated to this circuit.";      } +    leaf vrf { +      type string; +      default "default"; +      description +        "VRF NAME."; +    } +      leaf ipv4-routing {        type boolean;        default "false"; @@ -793,7 +800,7 @@ module frr-isisd {      description        "Configuration of the IS-IS routing daemon.";      list instance { -      key "area-tag"; +      key "area-tag vrf";        description          "IS-IS routing instance.";        leaf area-tag { @@ -802,6 +809,12 @@ module frr-isisd {            "Area-tag associated to this routing instance.";        } +      leaf vrf { +        type string; +        description +          "VRF NAME."; +      } +        leaf is-type {          type level;          default "level-1-2"; diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang index 4e5795b8f7..f5775ab968 100644 --- a/yang/frr-ripd.yang +++ b/yang/frr-ripd.yang @@ -143,7 +143,7 @@ module frr-ripd {            "Enable RIP on the specified IP network.";        }        leaf-list interface { -        type string; +        type frr-interface:interface-ref;          description            "Enable RIP on the specified interface.";        } @@ -204,14 +204,14 @@ module frr-ripd {        }        leaf-list passive-interface {          when "../passive-default = 'false'"; -        type string; +        type frr-interface:interface-ref;          description            "A list of interfaces where the sending of RIP packets             is disabled.";        }        leaf-list non-passive-interface {          when "../passive-default = 'true'"; -        type string; +        type frr-interface:interface-ref;          description            "A list of interfaces where the sending of RIP packets             is enabled."; diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang index 47ae67b238..52e208b2c9 100644 --- a/yang/frr-ripngd.yang +++ b/yang/frr-ripngd.yang @@ -101,7 +101,7 @@ module frr-ripngd {            "Enable RIPng on the specified IPv6 network.";        }        leaf-list interface { -        type string; +        type frr-interface:interface-ref;          description            "Enable RIPng on the specified interface.";        } diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index b895cd12a4..c9d35938cb 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -249,7 +249,7 @@ module frr-route-map {              case interface {                when "./condition = 'interface'";                leaf interface { -                type string; +                type frr-interface:interface-ref;                }              } diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index 7762c75d68..2efc45c146 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -393,9 +393,7 @@ module frr-zebra {      }      leaf vrf { -      type string { -        length "1..36"; -      } +      type frr-vrf:vrf-ref;        description          "The tenant VRF.";      } @@ -715,9 +713,7 @@ module frr-zebra {        choice vrf-choice {          case single {            leaf vrf { -            type string { -              length "1..36"; -            } +            type frr-vrf:vrf-ref;              description                "Retrieve routes in a non-default vrf.";            } @@ -815,9 +811,7 @@ module frr-zebra {        choice vrf-choice {          case single {            leaf vrf { -            type string { -              length "1..36"; -            } +            type frr-vrf:vrf-ref;              description                "Retrieve routes in a non-default vrf.";            } @@ -853,9 +847,7 @@ module frr-zebra {      output {        list vrf-list {          leaf name { -          type string { -            length "1..36"; -          } +          type frr-vrf:vrf-ref;            description              "The VRF name";          } @@ -910,9 +902,7 @@ module frr-zebra {      output {        list vrf-vni-list {          leaf vrf-name { -          type string { -            length "1..36"; -          } +          type frr-vrf:vrf-ref;            description              "The VRF name.";          }  | 
