1 /* EVPN Multihoming procedures
2  *
3  * Copyright (C) 2019 Cumulus Networks, Inc.
4  * Anuradha Karuppiah
5  *
6  * This file is part of FRR.
7  *
8  * FRRouting is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation; either version 2, or (at your option) any
11  * later version.
12  *
13  * FRRouting is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  */
19 
20 #include <zebra.h>
21 
22 #include "command.h"
23 #include "filter.h"
24 #include "prefix.h"
25 #include "log.h"
26 #include "memory.h"
27 #include "stream.h"
28 #include "hash.h"
29 #include "jhash.h"
30 #include "zclient.h"
31 
32 #include "bgpd/bgp_attr_evpn.h"
33 #include "bgpd/bgpd.h"
34 #include "bgpd/bgp_table.h"
35 #include "bgpd/bgp_route.h"
36 #include "bgpd/bgp_attr.h"
37 #include "bgpd/bgp_mplsvpn.h"
38 #include "bgpd/bgp_evpn.h"
39 #include "bgpd/bgp_evpn_private.h"
40 #include "bgpd/bgp_evpn_mh.h"
41 #include "bgpd/bgp_ecommunity.h"
42 #include "bgpd/bgp_encap_types.h"
43 #include "bgpd/bgp_debug.h"
44 #include "bgpd/bgp_errors.h"
45 #include "bgpd/bgp_aspath.h"
46 #include "bgpd/bgp_zebra.h"
47 #include "bgpd/bgp_addpath.h"
48 #include "bgpd/bgp_label.h"
49 
50 static void bgp_evpn_local_es_down(struct bgp *bgp,
51 		struct bgp_evpn_es *es);
52 static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp,
53 		struct bgp_evpn_es *es);
54 static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
55 		struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr);
56 static void bgp_evpn_es_vtep_del(struct bgp *bgp,
57 		struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr);
58 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es);
59 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es);
60 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi);
61 
62 esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
63 
64 /******************************************************************************
65  * per-ES (Ethernet Segment) routing table
66  *
67  * Following routes are added to the ES's routing table -
68  * 1. Local and remote ESR (Type-4)
69  * 2. Local EAD-per-ES (Type-1).
70  *
71  * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
72  * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
73  * being added to same ES).
74  *
75  * Note the following routes go into the VNI routing table (instead of the
76  * ES routing table) -
77  * 1. Remote EAD-per-ES
78  * 2. Local and remote EAD-per-EVI
79  */
80 
81 /* Calculate the best path for a multi-homing (Type-1 or Type-4) route
82  * installed in the ES's routing table.
83  */
bgp_evpn_es_route_select_install(struct bgp * bgp,struct bgp_evpn_es * es,struct bgp_node * rn)84 static int bgp_evpn_es_route_select_install(struct bgp *bgp,
85 		struct bgp_evpn_es *es,
86 		struct bgp_node *rn)
87 {
88 	int ret = 0;
89 	afi_t afi = AFI_L2VPN;
90 	safi_t safi = SAFI_EVPN;
91 	struct bgp_path_info *old_select; /* old best */
92 	struct bgp_path_info *new_select; /* new best */
93 	struct bgp_path_info_pair old_and_new;
94 
95 	/* Compute the best path. */
96 	bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi],
97 			&old_and_new, afi, safi);
98 	old_select = old_and_new.old;
99 	new_select = old_and_new.new;
100 
101 	/*
102 	 * If the best path hasn't changed - see if something needs to be
103 	 * updated
104 	 */
105 	if (old_select && old_select == new_select
106 		&& old_select->type == ZEBRA_ROUTE_BGP
107 		&& old_select->sub_type == BGP_ROUTE_IMPORTED
108 		&& !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
109 		&& !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
110 		&& !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
111 		if (bgp_zebra_has_route_changed(old_select)) {
112 			bgp_evpn_es_vtep_add(bgp, es,
113 					old_select->attr->nexthop,
114 					true /*esr*/);
115 		}
116 		UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
117 		bgp_zebra_clear_route_change_flags(rn);
118 		return ret;
119 	}
120 
121 	/* If the user did a "clear" this flag will be set */
122 	UNSET_FLAG(rn->flags, BGP_NODE_USER_CLEAR);
123 
124 	/* bestpath has changed; update relevant fields and install or uninstall
125 	 * into the zebra RIB.
126 	 */
127 	if (old_select || new_select)
128 		bgp_bump_version(rn);
129 
130 	if (old_select)
131 		bgp_path_info_unset_flag(rn, old_select, BGP_PATH_SELECTED);
132 	if (new_select) {
133 		bgp_path_info_set_flag(rn, new_select, BGP_PATH_SELECTED);
134 		bgp_path_info_unset_flag(rn, new_select, BGP_PATH_ATTR_CHANGED);
135 		UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG);
136 	}
137 
138 	if (new_select && new_select->type == ZEBRA_ROUTE_BGP
139 			&& new_select->sub_type == BGP_ROUTE_IMPORTED) {
140 		bgp_evpn_es_vtep_add(bgp, es,
141 				new_select->attr->nexthop, true /*esr */);
142 	} else {
143 		if (old_select && old_select->type == ZEBRA_ROUTE_BGP
144 				&& old_select->sub_type == BGP_ROUTE_IMPORTED)
145 			bgp_evpn_es_vtep_del(
146 					bgp, es, old_select->attr->nexthop,
147 					true /*esr*/);
148 	}
149 
150 	/* Clear any route change flags. */
151 	bgp_zebra_clear_route_change_flags(rn);
152 
153 	/* Reap old select bgp_path_info, if it has been removed */
154 	if (old_select && CHECK_FLAG(old_select->flags, BGP_PATH_REMOVED))
155 		bgp_path_info_reap(rn, old_select);
156 
157 	return ret;
158 }
159 
160 /* Install Type-1/Type-4 route entry in the per-ES routing table */
bgp_evpn_es_route_install(struct bgp * bgp,struct bgp_evpn_es * es,struct prefix_evpn * p,struct bgp_path_info * parent_pi)161 static int bgp_evpn_es_route_install(struct bgp *bgp,
162 		struct bgp_evpn_es *es, struct prefix_evpn *p,
163 		struct bgp_path_info *parent_pi)
164 {
165 	int ret = 0;
166 	struct bgp_node *rn = NULL;
167 	struct bgp_path_info *pi = NULL;
168 	struct attr *attr_new = NULL;
169 
170 	/* Create (or fetch) route within the VNI.
171 	 * NOTE: There is no RD here.
172 	 */
173 	rn = bgp_node_get(es->route_table, (struct prefix *)p);
174 
175 	/* Check if route entry is already present. */
176 	for (pi = bgp_dest_get_bgp_path_info(rn); pi; pi = pi->next)
177 		if (pi->extra
178 				&& (struct bgp_path_info *)pi->extra->parent ==
179 				parent_pi)
180 			break;
181 
182 	if (!pi) {
183 		/* Add (or update) attribute to hash. */
184 		attr_new = bgp_attr_intern(parent_pi->attr);
185 
186 		/* Create new route with its attribute. */
187 		pi = info_make(parent_pi->type, BGP_ROUTE_IMPORTED, 0,
188 				parent_pi->peer, attr_new, rn);
189 		SET_FLAG(pi->flags, BGP_PATH_VALID);
190 		bgp_path_info_extra_get(pi);
191 		pi->extra->parent = bgp_path_info_lock(parent_pi);
192 		bgp_dest_lock_node((struct bgp_node *)parent_pi->net);
193 		bgp_path_info_add(rn, pi);
194 	} else {
195 		if (attrhash_cmp(pi->attr, parent_pi->attr)
196 				&& !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
197 			bgp_dest_unlock_node(rn);
198 			return 0;
199 		}
200 		/* The attribute has changed. */
201 		/* Add (or update) attribute to hash. */
202 		attr_new = bgp_attr_intern(parent_pi->attr);
203 
204 		/* Restore route, if needed. */
205 		if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED))
206 			bgp_path_info_restore(rn, pi);
207 
208 		/* Mark if nexthop has changed. */
209 		if (!IPV4_ADDR_SAME(&pi->attr->nexthop, &attr_new->nexthop))
210 			SET_FLAG(pi->flags, BGP_PATH_IGP_CHANGED);
211 
212 		/* Unintern existing, set to new. */
213 		bgp_attr_unintern(&pi->attr);
214 		pi->attr = attr_new;
215 		pi->uptime = bgp_clock();
216 	}
217 
218 	/* Perform route selection and update zebra, if required. */
219 	ret = bgp_evpn_es_route_select_install(bgp, es, rn);
220 
221 	bgp_dest_unlock_node(rn);
222 
223 	return ret;
224 }
225 
226 /* Uninstall Type-1/Type-4 route entry from the ES routing table */
bgp_evpn_es_route_uninstall(struct bgp * bgp,struct bgp_evpn_es * es,struct prefix_evpn * p,struct bgp_path_info * parent_pi)227 static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
228 		struct prefix_evpn *p, struct bgp_path_info *parent_pi)
229 {
230 	int ret;
231 	struct bgp_node *rn;
232 	struct bgp_path_info *pi;
233 
234 	if (!es->route_table)
235 		return 0;
236 
237 	/* Locate route within the ESI.
238 	 * NOTE: There is no RD here.
239 	 */
240 	rn = bgp_node_lookup(es->route_table, (struct prefix *)p);
241 	if (!rn)
242 		return 0;
243 
244 	/* Find matching route entry. */
245 	for (pi = bgp_dest_get_bgp_path_info(rn); pi; pi = pi->next)
246 		if (pi->extra
247 				&& (struct bgp_path_info *)pi->extra->parent ==
248 				parent_pi)
249 			break;
250 
251 	if (!pi)
252 		return 0;
253 
254 	/* Mark entry for deletion */
255 	bgp_path_info_delete(rn, pi);
256 
257 	/* Perform route selection and update zebra, if required. */
258 	ret = bgp_evpn_es_route_select_install(bgp, es, rn);
259 
260 	/* Unlock route node. */
261 	bgp_dest_unlock_node(rn);
262 
263 	return ret;
264 }
265 
266 /* Install or unistall a Tyoe-4 route in the per-ES routing table */
bgp_evpn_es_route_install_uninstall(struct bgp * bgp,struct bgp_evpn_es * es,afi_t afi,safi_t safi,struct prefix_evpn * evp,struct bgp_path_info * pi,int install)267 int bgp_evpn_es_route_install_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
268 		afi_t afi, safi_t safi, struct prefix_evpn *evp,
269 		struct bgp_path_info *pi, int install)
270 {
271 	int ret = 0;
272 
273 	if (install)
274 		ret = bgp_evpn_es_route_install(bgp, es, evp, pi);
275 	else
276 		ret = bgp_evpn_es_route_uninstall(bgp, es, evp, pi);
277 
278 	if (ret) {
279 		flog_err(
280 				EC_BGP_EVPN_FAIL,
281 				"%u: Failed to %s EVPN %s route in ESI %s",
282 				bgp->vrf_id,
283 				install ? "install" : "uninstall",
284 				"ES", es->esi_str);
285 		return ret;
286 	}
287 	return 0;
288 }
289 
290 /* Delete (and withdraw) local routes for specified ES from global and ES table.
291  * Also remove all remote routes from the per ES table. Invoked when ES
292  * is deleted.
293  */
bgp_evpn_es_route_del_all(struct bgp * bgp,struct bgp_evpn_es * es)294 static void bgp_evpn_es_route_del_all(struct bgp *bgp, struct bgp_evpn_es *es)
295 {
296 	struct bgp_node *rn;
297 	struct bgp_path_info *pi, *nextpi;
298 
299 	/* de-activate the ES */
300 	bgp_evpn_local_es_down(bgp, es);
301 	bgp_evpn_local_type1_evi_route_del(bgp, es);
302 
303 	/* Walk this ES's routing table and delete all routes. */
304 	for (rn = bgp_table_top(es->route_table); rn;
305 			rn = bgp_route_next(rn)) {
306 		for (pi = bgp_dest_get_bgp_path_info(rn);
307 				(pi != NULL) && (nextpi = pi->next, 1);
308 				pi = nextpi) {
309 			bgp_path_info_delete(rn, pi);
310 			bgp_path_info_reap(rn, pi);
311 		}
312 	}
313 }
314 
315 /*****************************************************************************
316  * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
317  * segment updates.
318  */
319 
320 /* create or update local EVPN type1/type4 route entry.
321  *
322  * This could be in -
323  *     the ES table if ESR/EAD-ES (or)
324  *     the VNI table if EAD-EVI (or)
325  *     the global table if ESR/EAD-ES/EAD-EVI
326  *
327  * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
328  * ESR).
329  */
bgp_evpn_mh_route_update(struct bgp * bgp,struct bgp_evpn_es * es,struct bgpevpn * vpn,afi_t afi,safi_t safi,struct bgp_node * rn,struct attr * attr,int add,struct bgp_path_info ** ri,int * route_changed)330 static int bgp_evpn_mh_route_update(struct bgp *bgp,
331 		struct bgp_evpn_es *es, struct bgpevpn *vpn, afi_t afi,
332 		safi_t safi, struct bgp_node *rn, struct attr *attr,
333 		int add, struct bgp_path_info **ri, int *route_changed)
334 {
335 	struct bgp_path_info *tmp_pi = NULL;
336 	struct bgp_path_info *local_pi = NULL;  /* local route entry if any */
337 	struct bgp_path_info *remote_pi = NULL; /* remote route entry if any */
338 	struct attr *attr_new = NULL;
339 	struct prefix_evpn *evp;
340 
341 	*ri = NULL;
342 	evp = (struct prefix_evpn *)&rn->p;
343 	*route_changed = 1;
344 
345 	/* locate the local and remote entries if any */
346 	for (tmp_pi = bgp_dest_get_bgp_path_info(rn); tmp_pi;
347 	     tmp_pi = tmp_pi->next) {
348 		if (tmp_pi->peer == bgp->peer_self
349 				&& tmp_pi->type == ZEBRA_ROUTE_BGP
350 				&& tmp_pi->sub_type == BGP_ROUTE_STATIC)
351 			local_pi = tmp_pi;
352 		if (tmp_pi->type == ZEBRA_ROUTE_BGP
353 				&& tmp_pi->sub_type == BGP_ROUTE_IMPORTED
354 				&& CHECK_FLAG(tmp_pi->flags, BGP_PATH_VALID))
355 			remote_pi = tmp_pi;
356 	}
357 
358 	/* we don't expect to see a remote_ri at this point as
359 	 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
360 	 * in the VNI-rt-table.
361 	 */
362 	if (remote_pi) {
363 		flog_err(
364 				EC_BGP_ES_INVALID,
365 				"%u ERROR: local es route for ESI: %s Vtep %s also learnt from remote",
366 				bgp->vrf_id, es->esi_str,
367 				inet_ntoa(es->originator_ip));
368 		return -1;
369 	}
370 
371 	if (!local_pi && !add)
372 		return 0;
373 
374 	/* create or update the entry */
375 	if (!local_pi) {
376 
377 		/* Add or update attribute to hash */
378 		attr_new = bgp_attr_intern(attr);
379 
380 		/* Create new route with its attribute. */
381 		tmp_pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
382 				bgp->peer_self, attr_new, rn);
383 		SET_FLAG(tmp_pi->flags, BGP_PATH_VALID);
384 
385 		if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) {
386 			bgp_path_info_extra_get(tmp_pi);
387 			tmp_pi->extra->num_labels = 1;
388 			if (vpn)
389 				vni2label(vpn->vni, &tmp_pi->extra->label[0]);
390 			else
391 				tmp_pi->extra->label[0] = 0;
392 		}
393 
394 		/* add the newly created path to the route-node */
395 		bgp_path_info_add(rn, tmp_pi);
396 	} else {
397 		tmp_pi = local_pi;
398 		if (attrhash_cmp(tmp_pi->attr, attr)
399 				&& !CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
400 			*route_changed = 0;
401 		else {
402 			/* The attribute has changed.
403 			 * Add (or update) attribute to hash.
404 			 */
405 			attr_new = bgp_attr_intern(attr);
406 			bgp_path_info_set_flag(rn, tmp_pi,
407 					BGP_PATH_ATTR_CHANGED);
408 
409 			/* Restore route, if needed. */
410 			if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
411 				bgp_path_info_restore(rn, tmp_pi);
412 
413 			/* Unintern existing, set to new. */
414 			bgp_attr_unintern(&tmp_pi->attr);
415 			tmp_pi->attr = attr_new;
416 			tmp_pi->uptime = bgp_clock();
417 		}
418 	}
419 
420 	if (*route_changed) {
421 		if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
422 			zlog_debug("local ES %s vni %u route-type %s nexthop %s updated",
423 					es->esi_str,
424 					vpn ? vpn->vni : 0,
425 					evp->prefix.route_type ==
426 					BGP_EVPN_ES_ROUTE ? "esr" :
427 					(vpn ? "ead-evi" : "ead-es"),
428 					inet_ntoa(attr->mp_nexthop_global_in));
429 	}
430 
431 	/* Return back the route entry. */
432 	*ri = tmp_pi;
433 	return 0;
434 }
435 
436 /* Delete local EVPN ESR (type-4) and EAD (type-1) route
437  *
438  * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
439  * ESR).
440  */
bgp_evpn_mh_route_delete(struct bgp * bgp,struct bgp_evpn_es * es,struct bgpevpn * vpn,struct prefix_evpn * p)441 static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
442 		struct bgpevpn *vpn, struct prefix_evpn *p)
443 {
444 	afi_t afi = AFI_L2VPN;
445 	safi_t safi = SAFI_EVPN;
446 	struct bgp_path_info *pi;
447 	struct bgp_node *rn = NULL; /* rn in esi table */
448 	struct bgp_node *global_rn = NULL; /* rn in global table */
449 	struct bgp_table *rt_table;
450 	struct prefix_rd *prd;
451 
452 	if (vpn) {
453 		rt_table = vpn->route_table;
454 		prd = &vpn->prd;
455 	} else {
456 		rt_table = es->route_table;
457 		prd = &es->prd;
458 	}
459 
460 	/* First, locate the route node within the ESI or VNI.
461 	 * If it doesn't exist, ther is nothing to do.
462 	 * Note: there is no RD here.
463 	 */
464 	rn = bgp_node_lookup(rt_table, (struct prefix *)p);
465 	if (!rn)
466 		return 0;
467 
468 	if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
469 		zlog_debug("local ES %s vni %u route-type %s nexthop %s delete",
470 				es->esi_str,
471 				vpn ? vpn->vni : 0,
472 				p->prefix.route_type == BGP_EVPN_ES_ROUTE ?
473 				"esr" : (vpn ? "ead-evi" : "ead-es"),
474 				inet_ntoa(es->originator_ip));
475 
476 	/* Next, locate route node in the global EVPN routing table.
477 	 * Note that this table is a 2-level tree (RD-level + Prefix-level)
478 	 */
479 	global_rn = bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
480 			(const struct prefix_evpn *)p, prd);
481 	if (global_rn) {
482 
483 		/* Delete route entry in the global EVPN table. */
484 		delete_evpn_route_entry(bgp, afi, safi, global_rn, &pi);
485 
486 		/* Schedule for processing - withdraws to peers happen from
487 		 * this table.
488 		 */
489 		if (pi)
490 			bgp_process(bgp, global_rn, afi, safi);
491 		bgp_dest_unlock_node(global_rn);
492 	}
493 
494 	/*
495 	 * Delete route entry in the ESI or VNI routing table.
496 	 * This can just be removed.
497 	 */
498 	delete_evpn_route_entry(bgp, afi, safi, rn, &pi);
499 	if (pi)
500 		bgp_path_info_reap(rn, pi);
501 	bgp_dest_unlock_node(rn);
502 	return 0;
503 }
504 
505 /*****************************************************************************
506  * Ethernet Segment (Type-4) Routes
507  * ESRs are used for BUM handling. XXX - BUM support is planned for phase-2 i.e.
508  * this code is just a place holder for now
509  */
510 /* Build extended community for EVPN ES (type-4) route */
bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es * es,struct attr * attr)511 static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es *es,
512 		struct attr *attr)
513 {
514 	struct ecommunity ecom_encap;
515 	struct ecommunity ecom_es_rt;
516 	struct ecommunity_val eval;
517 	struct ecommunity_val eval_es_rt;
518 	bgp_encap_types tnl_type;
519 	struct ethaddr mac;
520 
521 	/* Encap */
522 	tnl_type = BGP_ENCAP_TYPE_VXLAN;
523 	memset(&ecom_encap, 0, sizeof(ecom_encap));
524 	encode_encap_extcomm(tnl_type, &eval);
525 	ecom_encap.size = 1;
526 	ecom_encap.unit_size = ECOMMUNITY_SIZE;
527 	ecom_encap.val = (uint8_t *)eval.val;
528 	attr->ecommunity = ecommunity_dup(&ecom_encap);
529 
530 	/* ES import RT */
531 	memset(&mac, 0, sizeof(struct ethaddr));
532 	memset(&ecom_es_rt, 0, sizeof(ecom_es_rt));
533 	es_get_system_mac(&es->esi, &mac);
534 	encode_es_rt_extcomm(&eval_es_rt, &mac);
535 	ecom_es_rt.size = 1;
536 	ecom_es_rt.unit_size = ECOMMUNITY_SIZE;
537 	ecom_es_rt.val = (uint8_t *)eval_es_rt.val;
538 	attr->ecommunity =
539 		ecommunity_merge(attr->ecommunity, &ecom_es_rt);
540 
541 	attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
542 }
543 
544 /* Create or update local type-4 route */
bgp_evpn_type4_route_update(struct bgp * bgp,struct bgp_evpn_es * es,struct prefix_evpn * p)545 static int bgp_evpn_type4_route_update(struct bgp *bgp,
546 		struct bgp_evpn_es *es, struct prefix_evpn *p)
547 {
548 	int ret = 0;
549 	int route_changed = 0;
550 	afi_t afi = AFI_L2VPN;
551 	safi_t safi = SAFI_EVPN;
552 	struct attr attr;
553 	struct attr *attr_new = NULL;
554 	struct bgp_node *rn = NULL;
555 	struct bgp_path_info *pi = NULL;
556 
557 	memset(&attr, 0, sizeof(struct attr));
558 
559 	/* Build path-attribute for this route. */
560 	bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
561 	attr.nexthop = es->originator_ip;
562 	attr.mp_nexthop_global_in = es->originator_ip;
563 	attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
564 
565 	/* Set up extended community. */
566 	bgp_evpn_type4_route_extcomm_build(es, &attr);
567 
568 	/* First, create (or fetch) route node within the ESI. */
569 	/* NOTE: There is no RD here. */
570 	rn = bgp_node_get(es->route_table, (struct prefix *)p);
571 
572 	/* Create or update route entry. */
573 	ret = bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi,
574 			rn, &attr, 1, &pi, &route_changed);
575 	if (ret != 0) {
576 		flog_err(EC_BGP_ES_INVALID,
577 				"%u ERROR: Failed to updated ES route ESI: %s VTEP %s",
578 				bgp->vrf_id, es->esi_str,
579 				inet_ntoa(es->originator_ip));
580 	}
581 
582 	assert(pi);
583 	attr_new = pi->attr;
584 
585 	/* Perform route selection;
586 	 * this is just to set the flags correctly
587 	 * as local route in the ES always wins.
588 	 */
589 	bgp_evpn_es_route_select_install(bgp, es, rn);
590 	bgp_dest_unlock_node(rn);
591 
592 	/* If this is a new route or some attribute has changed, export the
593 	 * route to the global table. The route will be advertised to peers
594 	 * from there. Note that this table is a 2-level tree (RD-level +
595 	 * Prefix-level) similar to L3VPN routes.
596 	 */
597 	if (route_changed) {
598 		struct bgp_path_info *global_pi;
599 
600 		rn = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
601 				p, &es->prd);
602 		bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi,
603 				rn, attr_new, 1, &global_pi, &route_changed);
604 
605 		/* Schedule for processing and unlock node. */
606 		bgp_process(bgp, rn, afi, safi);
607 		bgp_dest_unlock_node(rn);
608 	}
609 
610 	/* Unintern temporary. */
611 	aspath_unintern(&attr.aspath);
612 	return 0;
613 }
614 
615 /* Delete local type-4 route */
bgp_evpn_type4_route_delete(struct bgp * bgp,struct bgp_evpn_es * es,struct prefix_evpn * p)616 static int bgp_evpn_type4_route_delete(struct bgp *bgp,
617 		struct bgp_evpn_es *es, struct prefix_evpn *p)
618 {
619 	return bgp_evpn_mh_route_delete(bgp, es, NULL /* l2vni */, p);
620 }
621 
622 /* Process remote/received EVPN type-4 route (advertise or withdraw)  */
bgp_evpn_type4_route_process(struct peer * peer,afi_t afi,safi_t safi,struct attr * attr,uint8_t * pfx,int psize,uint32_t addpath_id)623 int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi,
624 		struct attr *attr, uint8_t *pfx, int psize,
625 		uint32_t addpath_id)
626 {
627 	int ret;
628 	esi_t esi;
629 	uint8_t ipaddr_len;
630 	struct in_addr vtep_ip;
631 	struct prefix_rd prd;
632 	struct prefix_evpn p;
633 
634 	/* Type-4 route should be either 23 or 35 bytes
635 	 *  RD (8), ESI (10), ip-len (1), ip (4 or 16)
636 	 */
637 	if (psize != BGP_EVPN_TYPE4_V4_PSIZE &&
638 			psize != BGP_EVPN_TYPE4_V6_PSIZE) {
639 		flog_err(EC_BGP_EVPN_ROUTE_INVALID,
640 				"%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
641 				peer->bgp->vrf_id, peer->host, psize);
642 		return -1;
643 	}
644 
645 	/* Make prefix_rd */
646 	prd.family = AF_UNSPEC;
647 	prd.prefixlen = 64;
648 	memcpy(&prd.val, pfx, RD_BYTES);
649 	pfx += RD_BYTES;
650 
651 	/* get the ESI */
652 	memcpy(&esi, pfx, ESI_BYTES);
653 	pfx += ESI_BYTES;
654 
655 
656 	/* Get the IP. */
657 	ipaddr_len = *pfx++;
658 	if (ipaddr_len == IPV4_MAX_BITLEN) {
659 		memcpy(&vtep_ip, pfx, IPV4_MAX_BYTELEN);
660 	} else {
661 		flog_err(
662 				EC_BGP_EVPN_ROUTE_INVALID,
663 				"%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
664 				peer->bgp->vrf_id, peer->host, ipaddr_len);
665 		return -1;
666 	}
667 
668 	build_evpn_type4_prefix(&p, &esi, vtep_ip);
669 	/* Process the route. */
670 	if (attr) {
671 		ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
672 				afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
673 				&prd, NULL, 0, 0, NULL);
674 	} else {
675 		ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
676 				afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
677 				&prd, NULL, 0, NULL);
678 	}
679 	return ret;
680 }
681 
682 /* Check if a prefix belongs to the local ES */
bgp_evpn_type4_prefix_match(struct prefix_evpn * p,struct bgp_evpn_es * es)683 static bool bgp_evpn_type4_prefix_match(struct prefix_evpn *p,
684 		struct bgp_evpn_es *es)
685 {
686 	return (p->prefix.route_type == BGP_EVPN_ES_ROUTE) &&
687 		!memcmp(&p->prefix.es_addr.esi, &es->esi, sizeof(esi_t));
688 }
689 
690 /* Import remote ESRs on local ethernet segment add  */
bgp_evpn_type4_remote_routes_import(struct bgp * bgp,struct bgp_evpn_es * es,bool install)691 static int bgp_evpn_type4_remote_routes_import(struct bgp *bgp,
692 		struct bgp_evpn_es *es, bool install)
693 {
694 	int ret;
695 	afi_t afi;
696 	safi_t safi;
697 	char buf[PREFIX_STRLEN];
698 	struct bgp_node *rd_rn, *rn;
699 	struct bgp_table *table;
700 	struct bgp_path_info *pi;
701 
702 	afi = AFI_L2VPN;
703 	safi = SAFI_EVPN;
704 
705 	/* Walk entire global routing table and evaluate routes which could be
706 	 * imported into this Ethernet Segment.
707 	 */
708 	for (rd_rn = bgp_table_top(bgp->rib[afi][safi]); rd_rn;
709 			rd_rn = bgp_route_next(rd_rn)) {
710 		table = bgp_dest_get_bgp_table_info(rd_rn);
711 		if (!table)
712 			continue;
713 
714 		for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
715 			struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
716 
717 			for (pi = bgp_dest_get_bgp_path_info(rn); pi;
718 					pi = pi->next) {
719 				/*
720 				 * Consider "valid" remote routes applicable for
721 				 * this ES.
722 				 */
723 				if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
724 					&& pi->type == ZEBRA_ROUTE_BGP
725 					&& pi->sub_type == BGP_ROUTE_NORMAL))
726 					continue;
727 
728 				if (!bgp_evpn_type4_prefix_match(evp, es))
729 					continue;
730 
731 				if (install)
732 					ret = bgp_evpn_es_route_install(
733 							bgp, es, evp, pi);
734 				else
735 					ret = bgp_evpn_es_route_uninstall(
736 							bgp, es, evp, pi);
737 
738 				if (ret) {
739 					flog_err(
740 							EC_BGP_EVPN_FAIL,
741 							"Failed to %s EVPN %s route in ESI %s",
742 							install ? "install"
743 							: "uninstall",
744 							prefix2str(evp, buf,
745 								sizeof(buf)),
746 							es->esi_str);
747 
748 					bgp_dest_unlock_node(rd_rn);
749 					bgp_dest_unlock_node(rn);
750 					return ret;
751 				}
752 			}
753 		}
754 	}
755 	return 0;
756 }
757 
758 /*****************************************************************************
759  * Ethernet Auto Discovery (EAD/Type-1) route handling
760  * There are two types of EAD routes -
761  * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
762  * 2. EAD-per-EVI - Key: {ESI, ET=0}
763  */
764 
765 /* Extended communities associated with EAD-per-ES */
bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es * es,struct attr * attr)766 static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es *es,
767 		struct attr *attr)
768 {
769 	struct ecommunity ecom_encap;
770 	struct ecommunity ecom_esi_label;
771 	struct ecommunity_val eval;
772 	struct ecommunity_val eval_esi_label;
773 	bgp_encap_types tnl_type;
774 	struct listnode *evi_node, *rt_node;
775 	struct ecommunity *ecom;
776 	struct bgp_evpn_es_evi *es_evi;
777 
778 	/* Encap */
779 	tnl_type = BGP_ENCAP_TYPE_VXLAN;
780 	memset(&ecom_encap, 0, sizeof(ecom_encap));
781 	encode_encap_extcomm(tnl_type, &eval);
782 	ecom_encap.size = 1;
783 	ecom_encap.unit_size = ECOMMUNITY_SIZE;
784 	ecom_encap.val = (uint8_t *)eval.val;
785 	attr->ecommunity = ecommunity_dup(&ecom_encap);
786 
787 	/* ESI label */
788 	encode_esi_label_extcomm(&eval_esi_label,
789 			false /*single_active*/);
790 	ecom_esi_label.size = 1;
791 	ecom_esi_label.unit_size = ECOMMUNITY_SIZE;
792 	ecom_esi_label.val = (uint8_t *)eval_esi_label.val;
793 	attr->ecommunity =
794 		ecommunity_merge(attr->ecommunity, &ecom_esi_label);
795 
796 	/* Add export RTs for all L2-VNIs associated with this ES */
797 	/* XXX - suppress EAD-ES advertisment if there are no EVIs associated
798 	 * with it.
799 	 */
800 	for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
801 				evi_node, es_evi)) {
802 		if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
803 			continue;
804 		for (ALL_LIST_ELEMENTS_RO(es_evi->vpn->export_rtl,
805 					rt_node, ecom))
806 			attr->ecommunity = ecommunity_merge(attr->ecommunity,
807 					ecom);
808 	}
809 
810 	attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
811 }
812 
813 /* Extended communities associated with EAD-per-EVI */
bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es * es,struct bgpevpn * vpn,struct attr * attr)814 static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es *es,
815 		struct bgpevpn *vpn, struct attr *attr)
816 {
817 	struct ecommunity ecom_encap;
818 	struct ecommunity_val eval;
819 	bgp_encap_types tnl_type;
820 	struct listnode *rt_node;
821 	struct ecommunity *ecom;
822 
823 	/* Encap */
824 	tnl_type = BGP_ENCAP_TYPE_VXLAN;
825 	memset(&ecom_encap, 0, sizeof(ecom_encap));
826 	encode_encap_extcomm(tnl_type, &eval);
827 	ecom_encap.size = 1;
828 	ecom_encap.unit_size = ECOMMUNITY_SIZE;
829 	ecom_encap.val = (uint8_t *)eval.val;
830 	attr->ecommunity = ecommunity_dup(&ecom_encap);
831 
832 	/* Add export RTs for the L2-VNI */
833 	for (ALL_LIST_ELEMENTS_RO(vpn->export_rtl, rt_node, ecom))
834 		attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
835 
836 	attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
837 }
838 
839 /* Update EVPN EAD (type-1) route -
840  * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
841  */
bgp_evpn_type1_route_update(struct bgp * bgp,struct bgp_evpn_es * es,struct bgpevpn * vpn,struct prefix_evpn * p)842 static int bgp_evpn_type1_route_update(struct bgp *bgp,
843 		struct bgp_evpn_es *es, struct bgpevpn *vpn,
844 		struct prefix_evpn *p)
845 {
846 	int ret = 0;
847 	afi_t afi = AFI_L2VPN;
848 	safi_t safi = SAFI_EVPN;
849 	struct attr attr;
850 	struct attr *attr_new = NULL;
851 	struct bgp_node *rn = NULL;
852 	struct bgp_path_info *pi = NULL;
853 	int route_changed = 0;
854 	struct prefix_rd *global_rd;
855 
856 	memset(&attr, 0, sizeof(struct attr));
857 
858 	/* Build path-attribute for this route. */
859 	bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
860 	attr.nexthop = es->originator_ip;
861 	attr.mp_nexthop_global_in = es->originator_ip;
862 	attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
863 
864 	if (vpn) {
865 		/* EAD-EVI route update */
866 		/* MPLS label */
867 		vni2label(vpn->vni, &(attr.label));
868 
869 		/* Set up extended community */
870 		bgp_evpn_type1_evi_route_extcomm_build(es, vpn, &attr);
871 
872 		/* First, create (or fetch) route node within the VNI. */
873 		rn = bgp_node_get(vpn->route_table, (struct prefix *)p);
874 
875 		/* Create or update route entry. */
876 		ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi,
877 				rn, &attr, 1, &pi, &route_changed);
878 		if (ret != 0) {
879 			flog_err(EC_BGP_ES_INVALID,
880 					"%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %s",
881 					bgp->vrf_id, es->esi_str, vpn->vni,
882 					inet_ntoa(es->originator_ip));
883 		}
884 		global_rd = &vpn->prd;
885 	} else {
886 		/* EAD-ES route update */
887 		/* MPLS label is 0 for EAD-ES route */
888 
889 		/* Set up extended community */
890 		bgp_evpn_type1_es_route_extcomm_build(es, &attr);
891 
892 		/* First, create (or fetch) route node within the ES. */
893 		/* NOTE: There is no RD here. */
894 		/* XXX: fragment ID must be included as a part of the prefix. */
895 		rn = bgp_node_get(es->route_table, (struct prefix *)p);
896 
897 		/* Create or update route entry. */
898 		ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi,
899 				rn, &attr, 1, &pi, &route_changed);
900 		if (ret != 0) {
901 			flog_err(EC_BGP_ES_INVALID,
902 					"%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %s",
903 					bgp->vrf_id, es->esi_str,
904 					inet_ntoa(es->originator_ip));
905 		}
906 		global_rd = &es->prd;
907 	}
908 
909 
910 	assert(pi);
911 	attr_new = pi->attr;
912 
913 	/* Perform route selection;
914 	 * this is just to set the flags correctly as local route in
915 	 * the ES always wins.
916 	 */
917 	evpn_route_select_install(bgp, vpn, rn);
918 	bgp_dest_unlock_node(rn);
919 
920 	/* If this is a new route or some attribute has changed, export the
921 	 * route to the global table. The route will be advertised to peers
922 	 * from there. Note that this table is a 2-level tree (RD-level +
923 	 * Prefix-level) similar to L3VPN routes.
924 	 */
925 	if (route_changed) {
926 		struct bgp_path_info *global_pi;
927 
928 		rn = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
929 				p, global_rd);
930 		bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi,
931 				rn, attr_new, 1, &global_pi, &route_changed);
932 
933 		/* Schedule for processing and unlock node. */
934 		bgp_process(bgp, rn, afi, safi);
935 		bgp_dest_unlock_node(rn);
936 	}
937 
938 	/* Unintern temporary. */
939 	aspath_unintern(&attr.aspath);
940 	return 0;
941 }
942 
943 /* Delete local Type-1 route */
bgp_evpn_type1_es_route_delete(struct bgp * bgp,struct bgp_evpn_es * es,struct prefix_evpn * p)944 static int bgp_evpn_type1_es_route_delete(struct bgp *bgp,
945 		struct bgp_evpn_es *es, struct prefix_evpn *p)
946 {
947 	return bgp_evpn_mh_route_delete(bgp, es, NULL /* l2vni */, p);
948 }
949 
bgp_evpn_type1_evi_route_delete(struct bgp * bgp,struct bgp_evpn_es * es,struct bgpevpn * vpn,struct prefix_evpn * p)950 static int bgp_evpn_type1_evi_route_delete(struct bgp *bgp,
951 		struct bgp_evpn_es *es, struct bgpevpn *vpn,
952 		struct prefix_evpn *p)
953 {
954 	return bgp_evpn_mh_route_delete(bgp, es, vpn, p);
955 }
956 
957 /* Generate EAD-EVI for all VNIs */
bgp_evpn_local_type1_evi_route_add(struct bgp * bgp,struct bgp_evpn_es * es)958 static void bgp_evpn_local_type1_evi_route_add(struct bgp *bgp,
959 		struct bgp_evpn_es *es)
960 {
961 	struct listnode *evi_node;
962 	struct prefix_evpn p;
963 	struct bgp_evpn_es_evi *es_evi;
964 
965 	if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
966 		/* EAD-EVI route add for this ES is already done */
967 		return;
968 
969 	SET_FLAG(es->flags, BGP_EVPNES_ADV_EVI);
970 	build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
971 			&es->esi, es->originator_ip);
972 
973 	for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, evi_node, es_evi)) {
974 		if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
975 			continue;
976 		if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn, &p))
977 			flog_err(EC_BGP_EVPN_ROUTE_CREATE,
978 					"%u: Type4 route creation failure for ESI %s",
979 					bgp->vrf_id, es->esi_str);
980 	}
981 }
982 
983 /*
984  * Withdraw EAD-EVI for all VNIs
985  */
bgp_evpn_local_type1_evi_route_del(struct bgp * bgp,struct bgp_evpn_es * es)986 static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp,
987 		struct bgp_evpn_es *es)
988 {
989 	struct listnode *evi_node;
990 	struct prefix_evpn p;
991 	struct bgp_evpn_es_evi *es_evi;
992 
993 	/* Delete and withdraw locally learnt EAD-EVI route */
994 	if (!CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
995 		/* EAD-EVI route has not been advertised for this ES */
996 		return;
997 
998 	UNSET_FLAG(es->flags, BGP_EVPNES_ADV_EVI);
999 	build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
1000 			&es->esi, es->originator_ip);
1001 	for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, evi_node, es_evi)) {
1002 		if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
1003 			continue;
1004 		if (bgp_evpn_mh_route_delete(bgp, es, es_evi->vpn, &p))
1005 			flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1006 					"%u: Type4 route creation failure for ESI %s",
1007 					bgp->vrf_id, es->esi_str);
1008 	}
1009 }
1010 
1011 /*
1012  * Process received EVPN type-1 route (advertise or withdraw).
1013  */
bgp_evpn_type1_route_process(struct peer * peer,afi_t afi,safi_t safi,struct attr * attr,uint8_t * pfx,int psize,uint32_t addpath_id)1014 int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
1015 		struct attr *attr, uint8_t *pfx, int psize,
1016 		uint32_t addpath_id)
1017 {
1018 	int ret;
1019 	struct prefix_rd prd;
1020 	esi_t esi;
1021 	uint32_t eth_tag;
1022 	mpls_label_t label;
1023 	struct in_addr vtep_ip;
1024 	struct prefix_evpn p;
1025 
1026 	if (psize != BGP_EVPN_TYPE1_PSIZE) {
1027 		flog_err(EC_BGP_EVPN_ROUTE_INVALID,
1028 				"%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1029 				peer->bgp->vrf_id, peer->host, psize);
1030 		return -1;
1031 	}
1032 
1033 	/* Make prefix_rd */
1034 	prd.family = AF_UNSPEC;
1035 	prd.prefixlen = 64;
1036 	memcpy(&prd.val, pfx, RD_BYTES);
1037 	pfx += RD_BYTES;
1038 
1039 	/* get the ESI */
1040 	memcpy(&esi, pfx, ESI_BYTES);
1041 	pfx += ESI_BYTES;
1042 
1043 	/* Copy Ethernet Tag */
1044 	memcpy(&eth_tag, pfx, EVPN_ETH_TAG_BYTES);
1045 	eth_tag = ntohl(eth_tag);
1046 	pfx += EVPN_ETH_TAG_BYTES;
1047 
1048 	memcpy(&label, pfx, BGP_LABEL_BYTES);
1049 
1050 	/* EAD route prefix doesn't include the nexthop in the global
1051 	 * table
1052 	 */
1053 	vtep_ip.s_addr = 0;
1054 	build_evpn_type1_prefix(&p, eth_tag, &esi, vtep_ip);
1055 	/* Process the route. */
1056 	if (attr) {
1057 		ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
1058 				afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
1059 				&prd, NULL, 0, 0, NULL);
1060 	} else {
1061 		ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
1062 				afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
1063 				&prd, NULL, 0, NULL);
1064 	}
1065 	return ret;
1066 }
1067 
1068 /*****************************************************************************/
1069 /* Ethernet Segment Management
1070  * 1. Ethernet Segment is a collection of links attached to the same
1071  *    server (MHD) or switch (MHN)
1072  * 2. An Ethernet Segment can span multiple PEs and is identified by the
1073  *    10-byte ES-ID.
1074  * 3. Local ESs are configured in zebra and sent to BGP
1075  * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1076  *    created on first reference and release on last de-reference
1077  * 5. An ES can be both local and remote. Infact most local ESs are expected
1078  *    to have an ES peer.
1079  */
1080 
1081 /* A list of remote VTEPs is maintained for each ES. This list includes -
1082  * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1083  * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1084  *    have been imported into one or more VNIs
1085  */
bgp_evpn_es_vtep_cmp(void * p1,void * p2)1086 static int bgp_evpn_es_vtep_cmp(void *p1, void *p2)
1087 {
1088 	const struct bgp_evpn_es_vtep *es_vtep1 = p1;
1089 	const struct bgp_evpn_es_vtep *es_vtep2 = p2;
1090 
1091 	return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
1092 }
1093 
bgp_evpn_es_vtep_new(struct bgp_evpn_es * es,struct in_addr vtep_ip)1094 static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_new(struct bgp_evpn_es *es,
1095 		struct in_addr vtep_ip)
1096 {
1097 	struct bgp_evpn_es_vtep *es_vtep;
1098 
1099 	es_vtep = XCALLOC(MTYPE_BGP_EVPN_ES_VTEP, sizeof(*es_vtep));
1100 
1101 	es_vtep->es = es;
1102 	es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
1103 	listnode_init(&es_vtep->es_listnode, es_vtep);
1104 	listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
1105 
1106 	return es_vtep;
1107 }
1108 
bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep * es_vtep)1109 static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep *es_vtep)
1110 {
1111 	struct bgp_evpn_es *es = es_vtep->es;
1112 
1113 	if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR) ||
1114 			es_vtep->evi_cnt)
1115 		/* as long as there is some reference we can't free it */
1116 		return;
1117 
1118 	list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
1119 	XFREE(MTYPE_BGP_EVPN_ES_VTEP, es_vtep);
1120 }
1121 
1122 /* check if VTEP is already part of the list */
bgp_evpn_es_vtep_find(struct bgp_evpn_es * es,struct in_addr vtep_ip)1123 static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_find(struct bgp_evpn_es *es,
1124 		struct in_addr vtep_ip)
1125 {
1126 	struct listnode *node = NULL;
1127 	struct bgp_evpn_es_vtep *es_vtep;
1128 
1129 	for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1130 		if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1131 			return es_vtep;
1132 	}
1133 	return NULL;
1134 }
1135 
1136 /* Send the remote ES to zebra for NHG programming */
bgp_zebra_send_remote_es_vtep(struct bgp * bgp,struct bgp_evpn_es_vtep * es_vtep,bool add)1137 static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp,
1138 		struct bgp_evpn_es_vtep *es_vtep, bool add)
1139 {
1140 	struct bgp_evpn_es *es = es_vtep->es;
1141 	struct stream *s;
1142 
1143 	/* Check socket. */
1144 	if (!zclient || zclient->sock < 0)
1145 		return 0;
1146 
1147 	/* Don't try to register if Zebra doesn't know of this instance. */
1148 	if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
1149 		if (BGP_DEBUG(zebra, ZEBRA))
1150 			zlog_debug("No zebra instance, not installing remote es %s",
1151 					es->esi_str);
1152 		return 0;
1153 	}
1154 
1155 	s = zclient->obuf;
1156 	stream_reset(s);
1157 
1158 	zclient_create_header(s,
1159 		add ? ZEBRA_REMOTE_ES_VTEP_ADD : ZEBRA_REMOTE_ES_VTEP_DEL,
1160 		bgp->vrf_id);
1161 	stream_put(s, &es->esi, sizeof(esi_t));
1162 	stream_put_ipv4(s, es_vtep->vtep_ip.s_addr);
1163 
1164 	stream_putw_at(s, 0, stream_get_endp(s));
1165 
1166 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1167 		zlog_debug("Tx %s Remote ESI %s VTEP %s",
1168 				add ? "ADD" : "DEL", es->esi_str,
1169 				inet_ntoa(es_vtep->vtep_ip));
1170 
1171 	return zclient_send_message(zclient);
1172 }
1173 
bgp_evpn_es_vtep_re_eval_active(struct bgp * bgp,struct bgp_evpn_es_vtep * es_vtep)1174 static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
1175 		struct bgp_evpn_es_vtep *es_vtep)
1176 {
1177 	bool old_active;
1178 	bool new_active;
1179 
1180 	old_active = !!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1181 	/* currently we need an active EVI reference to use the VTEP as
1182 	 * a nexthop. this may change...
1183 	 */
1184 	if (es_vtep->evi_cnt)
1185 		SET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1186 	else
1187 		UNSET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1188 
1189 	new_active = !!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1190 
1191 	if (old_active == new_active)
1192 		return;
1193 
1194 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1195 		zlog_debug("es %s vtep %s %s",
1196 				es_vtep->es->esi_str,
1197 				inet_ntoa(es_vtep->vtep_ip),
1198 				new_active ? "active" : "inactive");
1199 
1200 	/* send remote ES to zebra */
1201 	bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active);
1202 
1203 	/* queue up the es for background consistency checks */
1204 	bgp_evpn_es_cons_checks_pend_add(es_vtep->es);
1205 }
1206 
bgp_evpn_es_vtep_add(struct bgp * bgp,struct bgp_evpn_es * es,struct in_addr vtep_ip,bool esr)1207 static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
1208 		struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr)
1209 {
1210 	struct bgp_evpn_es_vtep *es_vtep;
1211 
1212 	es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip);
1213 
1214 	if (!es_vtep)
1215 		es_vtep = bgp_evpn_es_vtep_new(es, vtep_ip);
1216 
1217 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1218 		zlog_debug("es %s vtep %s add %s",
1219 				es_vtep->es->esi_str,
1220 				inet_ntoa(es_vtep->vtep_ip),
1221 				esr ? "esr" : "ead");
1222 
1223 	if (esr)
1224 		SET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR);
1225 	else
1226 		++es_vtep->evi_cnt;
1227 
1228 	bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep);
1229 
1230 	return es_vtep;
1231 }
1232 
bgp_evpn_es_vtep_do_del(struct bgp * bgp,struct bgp_evpn_es_vtep * es_vtep,bool esr)1233 static void bgp_evpn_es_vtep_do_del(struct bgp *bgp,
1234 		struct bgp_evpn_es_vtep *es_vtep, bool esr)
1235 {
1236 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1237 		zlog_debug("es %s vtep %s del %s",
1238 				es_vtep->es->esi_str,
1239 				inet_ntoa(es_vtep->vtep_ip),
1240 				esr ? "esr" : "ead");
1241 	if (esr) {
1242 		UNSET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR);
1243 	} else {
1244 		if (es_vtep->evi_cnt)
1245 			--es_vtep->evi_cnt;
1246 	}
1247 
1248 	bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep);
1249 	bgp_evpn_es_vtep_free(es_vtep);
1250 }
1251 
bgp_evpn_es_vtep_del(struct bgp * bgp,struct bgp_evpn_es * es,struct in_addr vtep_ip,bool esr)1252 static void bgp_evpn_es_vtep_del(struct bgp *bgp,
1253 		struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr)
1254 {
1255 	struct bgp_evpn_es_vtep *es_vtep;
1256 
1257 	es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip);
1258 	if (es_vtep)
1259 		bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr);
1260 }
1261 
1262 /* compare ES-IDs for the global ES RB tree */
bgp_es_rb_cmp(const struct bgp_evpn_es * es1,const struct bgp_evpn_es * es2)1263 static int bgp_es_rb_cmp(const struct bgp_evpn_es *es1,
1264 		const struct bgp_evpn_es *es2)
1265 {
1266 	return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
1267 }
1268 RB_GENERATE(bgp_es_rb_head, bgp_evpn_es, rb_node, bgp_es_rb_cmp);
1269 
bgp_evpn_es_find(const esi_t * esi)1270 struct bgp_evpn_es *bgp_evpn_es_find(const esi_t *esi)
1271 {
1272 	struct bgp_evpn_es tmp;
1273 
1274 	memcpy(&tmp.esi, esi, sizeof(esi_t));
1275 	return RB_FIND(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, &tmp);
1276 }
1277 
bgp_evpn_es_new(struct bgp * bgp,const esi_t * esi)1278 static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
1279 {
1280 	struct bgp_evpn_es *es;
1281 
1282 	if (!bgp)
1283 		return NULL;
1284 
1285 	es = XCALLOC(MTYPE_BGP_EVPN_ES, sizeof(struct bgp_evpn_es));
1286 
1287 	/* set the ESI */
1288 	memcpy(&es->esi, esi, sizeof(esi_t));
1289 
1290 	/* Initialise the VTEP list */
1291 	es->es_vtep_list = list_new();
1292 	listset_app_node_mem(es->es_vtep_list);
1293 	es->es_vtep_list->cmp = bgp_evpn_es_vtep_cmp;
1294 
1295 	esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
1296 
1297 	/* Initialize the ES routing table */
1298 	es->route_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
1299 
1300 	/* Add to rb_tree */
1301 	if (RB_INSERT(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, es)) {
1302 		XFREE(MTYPE_BGP_EVPN_ES, es);
1303 		return NULL;
1304 	}
1305 
1306 	/* Initialise the ES-EVI list */
1307 	es->es_evi_list = list_new();
1308 	listset_app_node_mem(es->es_evi_list);
1309 
1310 	QOBJ_REG(es, bgp_evpn_es);
1311 
1312 	return es;
1313 }
1314 
1315 /* Free a given ES -
1316  * This just frees appropriate memory, caller should have taken other
1317  * needed actions.
1318  */
bgp_evpn_es_free(struct bgp_evpn_es * es,const char * caller)1319 static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
1320 {
1321 	if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))
1322 		return;
1323 
1324 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1325 		zlog_debug("%s: es %s free", caller, es->esi_str);
1326 
1327 	/* cleanup resources maintained against the ES */
1328 	list_delete(&es->es_evi_list);
1329 	list_delete(&es->es_vtep_list);
1330 	bgp_table_unlock(es->route_table);
1331 
1332 	/* remove the entry from various databases */
1333 	RB_REMOVE(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, es);
1334 	bgp_evpn_es_cons_checks_pend_del(es);
1335 
1336 	QOBJ_UNREG(es);
1337 	XFREE(MTYPE_BGP_EVPN_ES, es);
1338 }
1339 
1340 /* init local info associated with the ES */
bgp_evpn_es_local_info_set(struct bgp * bgp,struct bgp_evpn_es * es)1341 static void bgp_evpn_es_local_info_set(struct bgp *bgp, struct bgp_evpn_es *es)
1342 {
1343 	char buf[BGP_EVPN_PREFIX_RD_LEN];
1344 
1345 	if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1346 		return;
1347 
1348 	SET_FLAG(es->flags, BGP_EVPNES_LOCAL);
1349 	listnode_init(&es->es_listnode, es);
1350 	listnode_add(bgp_mh_info->local_es_list, &es->es_listnode);
1351 
1352 	/* auto derive RD for this es */
1353 	bf_assign_index(bm->rd_idspace, es->rd_id);
1354 	es->prd.family = AF_UNSPEC;
1355 	es->prd.prefixlen = 64;
1356 	snprintf(buf, sizeof(buf), "%s:%hu", inet_ntoa(bgp->router_id),
1357 		 es->rd_id);
1358 	(void)str2prefix_rd(buf, &es->prd);
1359 }
1360 
1361 /* clear any local info associated with the ES */
bgp_evpn_es_local_info_clear(struct bgp_evpn_es * es)1362 static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es *es)
1363 {
1364 	if (!CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1365 		return;
1366 
1367 	UNSET_FLAG(es->flags, BGP_EVPNES_LOCAL);
1368 
1369 	/* remove from the ES local list */
1370 	list_delete_node(bgp_mh_info->local_es_list, &es->es_listnode);
1371 
1372 	bf_release_index(bm->rd_idspace, es->rd_id);
1373 
1374 	bgp_evpn_es_free(es, __func__);
1375 }
1376 
1377 /* eval remote info associated with the ES */
bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es * es)1378 static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es *es)
1379 {
1380 	if (es->remote_es_evi_cnt) {
1381 		SET_FLAG(es->flags, BGP_EVPNES_REMOTE);
1382 	} else {
1383 		if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE)) {
1384 			UNSET_FLAG(es->flags, BGP_EVPNES_REMOTE);
1385 			bgp_evpn_es_free(es, __func__);
1386 		}
1387 	}
1388 }
1389 
1390 /* Process ES link oper-down by withdrawing ES-EAD and ESR */
bgp_evpn_local_es_down(struct bgp * bgp,struct bgp_evpn_es * es)1391 static void bgp_evpn_local_es_down(struct bgp *bgp,
1392 		struct bgp_evpn_es *es)
1393 {
1394 	struct prefix_evpn p;
1395 	int ret;
1396 
1397 	if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP))
1398 		return;
1399 
1400 	UNSET_FLAG(es->flags, BGP_EVPNES_OPER_UP);
1401 
1402 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1403 		zlog_debug("local es %s down", es->esi_str);
1404 
1405 	/* withdraw ESR */
1406 	/* Delete and withdraw locally learnt ES route */
1407 	build_evpn_type4_prefix(&p, &es->esi, es->originator_ip);
1408 	ret = bgp_evpn_type4_route_delete(bgp, es, &p);
1409 	if (ret) {
1410 		flog_err(EC_BGP_EVPN_ROUTE_DELETE,
1411 				"%u failed to delete type-4 route for ESI %s",
1412 				bgp->vrf_id, es->esi_str);
1413 	}
1414 
1415 	/* withdraw EAD-EVI */
1416 	if (!bgp_mh_info->ead_evi_adv_for_down_links)
1417 		bgp_evpn_local_type1_evi_route_del(bgp, es);
1418 
1419 	/* withdraw EAD-ES */
1420 	build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
1421 			&es->esi, es->originator_ip);
1422 	ret = bgp_evpn_type1_es_route_delete(bgp, es, &p);
1423 	if (ret) {
1424 		flog_err(EC_BGP_EVPN_ROUTE_DELETE,
1425 				"%u failed to delete type-1 route for ESI %s",
1426 				bgp->vrf_id, es->esi_str);
1427 	}
1428 }
1429 
1430 /* Process ES link oper-up by generating ES-EAD and ESR */
bgp_evpn_local_es_up(struct bgp * bgp,struct bgp_evpn_es * es)1431 static void bgp_evpn_local_es_up(struct bgp *bgp, struct bgp_evpn_es *es)
1432 {
1433 	struct prefix_evpn p;
1434 
1435 	if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP))
1436 		return;
1437 
1438 	SET_FLAG(es->flags, BGP_EVPNES_OPER_UP);
1439 
1440 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1441 		zlog_debug("local es %s up", es->esi_str);
1442 
1443 	/* generate ESR */
1444 	build_evpn_type4_prefix(&p, &es->esi, es->originator_ip);
1445 	if (bgp_evpn_type4_route_update(bgp, es, &p))
1446 		flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1447 				"%u: Type4 route creation failure for ESI %s",
1448 				bgp->vrf_id, es->esi_str);
1449 
1450 	/* generate EAD-EVI */
1451 	bgp_evpn_local_type1_evi_route_add(bgp, es);
1452 
1453 	/* generate EAD-ES */
1454 	build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
1455 			&es->esi, es->originator_ip);
1456 	bgp_evpn_type1_route_update(bgp, es, NULL, &p);
1457 }
1458 
bgp_evpn_local_es_do_del(struct bgp * bgp,struct bgp_evpn_es * es)1459 static void bgp_evpn_local_es_do_del(struct bgp *bgp, struct bgp_evpn_es *es)
1460 {
1461 	struct bgp_evpn_es_evi *es_evi;
1462 	struct listnode *evi_node, *evi_next_node;
1463 
1464 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1465 		zlog_debug("del local es %s", es->esi_str);
1466 
1467 	/* Delete all local EVPN ES routes from ESI table
1468 	 * and schedule for processing (to withdraw from peers))
1469 	 */
1470 	bgp_evpn_es_route_del_all(bgp, es);
1471 
1472 	/* release all local ES EVIs associated with the ES */
1473 	for (ALL_LIST_ELEMENTS(es->es_evi_list, evi_node,
1474 				evi_next_node, es_evi)) {
1475 		bgp_evpn_local_es_evi_do_del(es_evi);
1476 	}
1477 
1478 	/* Clear local info associated with the ES and free it up if there is
1479 	 * no remote reference
1480 	 */
1481 	bgp_evpn_es_local_info_clear(es);
1482 }
1483 
bgp_evpn_is_esi_local(esi_t * esi)1484 bool bgp_evpn_is_esi_local(esi_t *esi)
1485 {
1486 	struct bgp_evpn_es *es = NULL;
1487 
1488 	/* Lookup ESI hash - should exist. */
1489 	es = bgp_evpn_es_find(esi);
1490 	return es ? !!(es->flags & BGP_EVPNES_LOCAL) : false;
1491 }
1492 
bgp_evpn_local_es_del(struct bgp * bgp,esi_t * esi)1493 int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi)
1494 {
1495 	struct bgp_evpn_es *es = NULL;
1496 
1497 	/* Lookup ESI hash - should exist. */
1498 	es = bgp_evpn_es_find(esi);
1499 	if (!es) {
1500 		flog_warn(EC_BGP_EVPN_ESI,
1501 			  "%u: ES %s missing at local ES DEL",
1502 			  bgp->vrf_id, es->esi_str);
1503 		return -1;
1504 	}
1505 
1506 	bgp_evpn_local_es_do_del(bgp, es);
1507 	return 0;
1508 }
1509 
1510 /* Handle device to ES id association. Results in the creation of a local
1511  * ES.
1512  */
bgp_evpn_local_es_add(struct bgp * bgp,esi_t * esi,struct in_addr originator_ip,bool oper_up)1513 int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi,
1514 		struct in_addr originator_ip, bool oper_up)
1515 {
1516 	char buf[ESI_STR_LEN];
1517 	struct bgp_evpn_es *es;
1518 	bool new_es = true;
1519 
1520 	/* create the new es */
1521 	es = bgp_evpn_es_find(esi);
1522 	if (es) {
1523 		if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1524 			new_es = false;
1525 	} else {
1526 		es = bgp_evpn_es_new(bgp, esi);
1527 		if (!es) {
1528 			flog_err(EC_BGP_ES_CREATE,
1529 				"%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
1530 				bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
1531 			return -1;
1532 		}
1533 	}
1534 
1535 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1536 		zlog_debug("add local es %s orig-ip %s",
1537 				es->esi_str,
1538 				inet_ntoa(originator_ip));
1539 
1540 	es->originator_ip = originator_ip;
1541 	bgp_evpn_es_local_info_set(bgp, es);
1542 
1543 	/* import all remote Type-4 routes in the ES table */
1544 	if (new_es)
1545 		bgp_evpn_type4_remote_routes_import(bgp, es,
1546 				true /* install */);
1547 
1548 	/* create and advertise EAD-EVI routes for the ES -
1549 	 * XXX - till an ES-EVI reference is created there is really nothing to
1550 	 * advertise
1551 	 */
1552 	if (bgp_mh_info->ead_evi_adv_for_down_links)
1553 		bgp_evpn_local_type1_evi_route_add(bgp, es);
1554 
1555 	/* If the ES link is operationally up generate EAD-ES. EAD-EVI
1556 	 * can be generated even if the link is inactive.
1557 	 */
1558 	if (oper_up)
1559 		bgp_evpn_local_es_up(bgp, es);
1560 	else
1561 		bgp_evpn_local_es_down(bgp, es);
1562 
1563 	return 0;
1564 }
1565 
bgp_evpn_es_vteps_str(char * vtep_str,struct bgp_evpn_es * es,uint8_t vtep_str_size)1566 static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es,
1567 				   uint8_t vtep_str_size)
1568 {
1569 	char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
1570 	struct listnode *node;
1571 	struct bgp_evpn_es_vtep *es_vtep;
1572 	bool first = true;
1573 
1574 	vtep_str[0] = '\0';
1575 	for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1576 		vtep_flag_str[0] = '\0';
1577 		if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
1578 			strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
1579 		if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
1580 			strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
1581 
1582 		if (!strlen(vtep_flag_str))
1583 			strlcat(vtep_flag_str, "-", sizeof(vtep_flag_str));
1584 		if (first)
1585 			first = false;
1586 		else
1587 			strlcat(vtep_str, ",", vtep_str_size);
1588 		strlcat(vtep_str, inet_ntoa(es_vtep->vtep_ip), vtep_str_size);
1589 		strlcat(vtep_str, "(", vtep_str_size);
1590 		strlcat(vtep_str, vtep_flag_str, vtep_str_size);
1591 		strlcat(vtep_str, ")", vtep_str_size);
1592 	}
1593 
1594 	return vtep_str;
1595 }
1596 
json_array_string_add(json_object * json,const char * str)1597 static inline void json_array_string_add(json_object *json, const char *str)
1598 {
1599 	json_object_array_add(json, json_object_new_string(str));
1600 }
1601 
bgp_evpn_es_json_vtep_fill(json_object * json_vteps,struct bgp_evpn_es_vtep * es_vtep)1602 static void bgp_evpn_es_json_vtep_fill(json_object *json_vteps,
1603 		struct bgp_evpn_es_vtep *es_vtep)
1604 {
1605 	json_object *json_vtep_entry;
1606 	json_object *json_flags;
1607 
1608 	json_vtep_entry = json_object_new_object();
1609 
1610 	json_object_string_add(json_vtep_entry, "vtep_ip",
1611 			inet_ntoa(es_vtep->vtep_ip));
1612 	if (es_vtep->flags & (BGP_EVPNES_VTEP_ESR |
1613 			 BGP_EVPNES_VTEP_ACTIVE)) {
1614 		json_flags = json_object_new_array();
1615 		if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
1616 			json_array_string_add(json_flags, "esr");
1617 		if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
1618 			json_array_string_add(json_flags, "active");
1619 		json_object_object_add(json_vtep_entry, "flags", json_flags);
1620 	}
1621 
1622 	json_object_array_add(json_vteps,
1623 			json_vtep_entry);
1624 }
1625 
bgp_evpn_es_show_entry(struct vty * vty,struct bgp_evpn_es * es,json_object * json)1626 static void bgp_evpn_es_show_entry(struct vty *vty,
1627 		struct bgp_evpn_es *es, json_object *json)
1628 {
1629 	char buf1[RD_ADDRSTRLEN];
1630 	struct listnode *node;
1631 	struct bgp_evpn_es_vtep *es_vtep;
1632 
1633 	if (json) {
1634 		json_object *json_vteps;
1635 		json_object *json_types;
1636 
1637 		json_object_string_add(json, "esi", es->esi_str);
1638 		json_object_string_add(json, "rd",
1639 				prefix_rd2str(&es->prd, buf1,
1640 					sizeof(buf1)));
1641 
1642 		if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) {
1643 			json_types = json_object_new_array();
1644 			if (es->flags & BGP_EVPNES_LOCAL)
1645 				json_array_string_add(json_types, "local");
1646 			if (es->flags & BGP_EVPNES_REMOTE)
1647 				json_array_string_add(json_types, "remote");
1648 			json_object_object_add(json, "type", json_types);
1649 		}
1650 
1651 		if (listcount(es->es_vtep_list)) {
1652 			json_vteps = json_object_new_array();
1653 			for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list,
1654 						node, es_vtep)) {
1655 				bgp_evpn_es_json_vtep_fill(json_vteps, es_vtep);
1656 			}
1657 			json_object_object_add(json, "vteps", json_vteps);
1658 		}
1659 		json_object_int_add(json, "vniCount",
1660 				listcount(es->es_evi_list));
1661 	} else {
1662 		char type_str[4];
1663 		char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
1664 
1665 		type_str[0] = '\0';
1666 		if (es->flags & BGP_EVPNES_LOCAL)
1667 			strlcat(type_str, "L", sizeof(type_str));
1668 		if (es->flags & BGP_EVPNES_REMOTE)
1669 			strlcat(type_str, "R", sizeof(type_str));
1670 		if (es->inconsistencies)
1671 			strlcat(type_str, "I", sizeof(type_str));
1672 
1673 		bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
1674 
1675 		if (es->flags & BGP_EVPNES_LOCAL)
1676 			prefix_rd2str(&es->prd, buf1, sizeof(buf1));
1677 		else
1678 			strlcpy(buf1, "-", sizeof(buf1));
1679 
1680 		vty_out(vty, "%-30s %-5s %-21s %-8d %s\n",
1681 				es->esi_str, type_str, buf1,
1682 				listcount(es->es_evi_list), vtep_str);
1683 	}
1684 }
1685 
bgp_evpn_es_show_entry_detail(struct vty * vty,struct bgp_evpn_es * es,json_object * json)1686 static void bgp_evpn_es_show_entry_detail(struct vty *vty,
1687 		struct bgp_evpn_es *es, json_object *json)
1688 {
1689 	if (json) {
1690 		json_object *json_flags;
1691 		json_object *json_incons;
1692 
1693 		/* Add the "brief" info first */
1694 		bgp_evpn_es_show_entry(vty, es, json);
1695 		if (es->flags & (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI)) {
1696 			json_flags = json_object_new_array();
1697 			if (es->flags & BGP_EVPNES_OPER_UP)
1698 				json_array_string_add(json_flags, "up");
1699 			if (es->flags & BGP_EVPNES_ADV_EVI)
1700 				json_array_string_add(json_flags,
1701 						"advertiseEVI");
1702 			json_object_object_add(json, "flags", json_flags);
1703 		}
1704 		json_object_string_add(json, "originator_ip",
1705 				inet_ntoa(es->originator_ip));
1706 		json_object_int_add(json, "remoteVniCount",
1707 				es->remote_es_evi_cnt);
1708 		json_object_int_add(json, "inconsistentVniVtepCount",
1709 				es->incons_evi_vtep_cnt);
1710 		if (es->inconsistencies) {
1711 			json_incons = json_object_new_array();
1712 			if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
1713 				json_array_string_add(json_incons,
1714 						"vni-vtep-mismatch");
1715 			json_object_object_add(json, "inconsistencies",
1716 					json_incons);
1717 		}
1718 	} else {
1719 		char incons_str[BGP_EVPNES_INCONS_STR_SZ];
1720 		char type_str[4];
1721 		char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
1722 		char buf1[RD_ADDRSTRLEN];
1723 
1724 		type_str[0] = '\0';
1725 		if (es->flags & BGP_EVPNES_LOCAL)
1726 			strlcat(type_str, "L", sizeof(type_str));
1727 		if (es->flags & BGP_EVPNES_REMOTE)
1728 			strlcat(type_str, "R", sizeof(type_str));
1729 
1730 		bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
1731 		if (!strlen(vtep_str))
1732 			strlcpy(buf1, "-", sizeof(buf1));
1733 
1734 		if (es->flags & BGP_EVPNES_LOCAL)
1735 			prefix_rd2str(&es->prd, buf1, sizeof(buf1));
1736 		else
1737 			strlcpy(buf1, "-", sizeof(buf1));
1738 
1739 		vty_out(vty, "ESI: %s\n", es->esi_str);
1740 		vty_out(vty, " Type: %s\n", type_str);
1741 		vty_out(vty, " RD: %s\n", buf1);
1742 		vty_out(vty, " Originator-IP: %s\n",
1743 				inet_ntoa(es->originator_ip));
1744 		vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
1745 		vty_out(vty, " Remote VNI Count: %d\n",
1746 				es->remote_es_evi_cnt);
1747 		vty_out(vty, " Inconsistent VNI VTEP Count: %d\n",
1748 				es->incons_evi_vtep_cnt);
1749 		if (es->inconsistencies) {
1750 			incons_str[0] = '\0';
1751 			if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
1752 				strlcat(incons_str, "vni-vtep-mismatch",
1753 					sizeof(incons_str));
1754 		} else {
1755 			strlcpy(incons_str, "-", sizeof(incons_str));
1756 		}
1757 		vty_out(vty, " Inconsistencies: %s\n",
1758 				incons_str);
1759 		vty_out(vty, " VTEPs: %s\n", vtep_str);
1760 		vty_out(vty, "\n");
1761 	}
1762 }
1763 
1764 /* Display all ESs */
bgp_evpn_es_show(struct vty * vty,bool uj,bool detail)1765 void bgp_evpn_es_show(struct vty *vty, bool uj, bool detail)
1766 {
1767 	struct bgp_evpn_es *es;
1768 	json_object *json_array = NULL;
1769 	json_object *json = NULL;
1770 
1771 	if (uj) {
1772 		/* create an array of ESs */
1773 		json_array = json_object_new_array();
1774 	} else {
1775 		if (!detail) {
1776 			vty_out(vty,
1777 				"ES Flags: L local, R remote, I inconsistent\n");
1778 			vty_out(vty,
1779 				"VTEP Flags: E ESR/Type-4, A active nexthop\n");
1780 			vty_out(vty,
1781 				"%-30s %-5s %-21s %-8s %s\n",
1782 				"ESI", "Flags", "RD", "#VNIs", "VTEPs");
1783 		}
1784 	}
1785 
1786 	RB_FOREACH(es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
1787 		if (uj)
1788 			/* create a separate json object for each ES */
1789 			json = json_object_new_object();
1790 		if (detail)
1791 			bgp_evpn_es_show_entry_detail(vty, es, json);
1792 		else
1793 			bgp_evpn_es_show_entry(vty, es, json);
1794 		/* add ES to the json array */
1795 		if (uj)
1796 			json_object_array_add(json_array, json);
1797 	}
1798 
1799 	/* print the array of json-ESs */
1800 	if (uj) {
1801 		vty_out(vty, "%s\n", json_object_to_json_string_ext(
1802 					json_array, JSON_C_TO_STRING_PRETTY));
1803 		json_object_free(json_array);
1804 	}
1805 }
1806 
1807 /* Display specific ES */
bgp_evpn_es_show_esi(struct vty * vty,esi_t * esi,bool uj)1808 void bgp_evpn_es_show_esi(struct vty *vty, esi_t *esi, bool uj)
1809 {
1810 	struct bgp_evpn_es *es;
1811 	json_object *json = NULL;
1812 
1813 	if (uj)
1814 		json = json_object_new_object();
1815 
1816 	es = bgp_evpn_es_find(esi);
1817 	if (es) {
1818 		bgp_evpn_es_show_entry_detail(vty, es, json);
1819 	} else {
1820 		if (!uj)
1821 			vty_out(vty, "ESI not found\n");
1822 	}
1823 
1824 	if (uj) {
1825 		vty_out(vty, "%s\n", json_object_to_json_string_ext(
1826 					json, JSON_C_TO_STRING_PRETTY));
1827 		json_object_free(json);
1828 	}
1829 }
1830 
1831 /*****************************************************************************/
1832 /* Ethernet Segment to EVI association -
1833  * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
1834  * (bgpevpn->es_evi_rb_tree).
1835  * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
1836  * advertises an EAD-EVI (Type-1 EVPN) route
1837  * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
1838  * it.
1839  */
1840 
1841 /* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
1842  * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
1843  * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
1844  * VTEPs for which both routes have been rxed are activated. Activation
1845  * creates a NHG in the parent ES.
1846  */
bgp_evpn_es_evi_vtep_cmp(void * p1,void * p2)1847 static int bgp_evpn_es_evi_vtep_cmp(void *p1, void *p2)
1848 {
1849 	const struct bgp_evpn_es_evi_vtep *evi_vtep1 = p1;
1850 	const struct bgp_evpn_es_evi_vtep *evi_vtep2 = p2;
1851 
1852 	return evi_vtep1->vtep_ip.s_addr - evi_vtep2->vtep_ip.s_addr;
1853 }
1854 
bgp_evpn_es_evi_vtep_new(struct bgp_evpn_es_evi * es_evi,struct in_addr vtep_ip)1855 static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_new(
1856 		struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip)
1857 {
1858 	struct bgp_evpn_es_evi_vtep *evi_vtep;
1859 
1860 	evi_vtep = XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP, sizeof(*evi_vtep));
1861 
1862 	evi_vtep->es_evi = es_evi;
1863 	evi_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
1864 	listnode_init(&evi_vtep->es_evi_listnode, evi_vtep);
1865 	listnode_add_sort(es_evi->es_evi_vtep_list, &evi_vtep->es_evi_listnode);
1866 
1867 	return evi_vtep;
1868 }
1869 
bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep * evi_vtep)1870 static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep *evi_vtep)
1871 {
1872 	struct bgp_evpn_es_evi *es_evi = evi_vtep->es_evi;
1873 
1874 	if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD))
1875 		/* as long as there is some reference we can't free it */
1876 		return;
1877 
1878 	list_delete_node(es_evi->es_evi_vtep_list, &evi_vtep->es_evi_listnode);
1879 	XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP, evi_vtep);
1880 }
1881 
1882 /* check if VTEP is already part of the list */
bgp_evpn_es_evi_vtep_find(struct bgp_evpn_es_evi * es_evi,struct in_addr vtep_ip)1883 static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_find(
1884 		struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip)
1885 {
1886 	struct listnode *node = NULL;
1887 	struct bgp_evpn_es_evi_vtep *evi_vtep;
1888 
1889 	for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
1890 		if (evi_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1891 			return evi_vtep;
1892 	}
1893 	return NULL;
1894 }
1895 
1896 /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
1897  * EAD-per-EVI routes are rxed from it.
1898  */
bgp_evpn_es_evi_vtep_re_eval_active(struct bgp * bgp,struct bgp_evpn_es_evi_vtep * evi_vtep)1899 static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
1900 		struct bgp_evpn_es_evi_vtep *evi_vtep)
1901 {
1902 	bool old_active;
1903 	bool new_active;
1904 
1905 	old_active = !!CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
1906 
1907 	/* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
1908 	 * before it can be activated.
1909 	 */
1910 	if ((evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD) ==
1911 			BGP_EVPN_EVI_VTEP_EAD)
1912 		SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
1913 	else
1914 		UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
1915 
1916 	new_active = !!CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
1917 
1918 	if (old_active == new_active)
1919 		return;
1920 
1921 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1922 		zlog_debug("es %s evi %u vtep %s %s",
1923 				evi_vtep->es_evi->es->esi_str,
1924 				evi_vtep->es_evi->vpn->vni,
1925 				inet_ntoa(evi_vtep->vtep_ip),
1926 				new_active ? "active" : "inactive");
1927 
1928 	/* add VTEP to parent es */
1929 	if (new_active) {
1930 		struct bgp_evpn_es_vtep *es_vtep;
1931 
1932 		es_vtep = bgp_evpn_es_vtep_add(bgp, evi_vtep->es_evi->es,
1933 				evi_vtep->vtep_ip, false /*esr*/);
1934 		evi_vtep->es_vtep = es_vtep;
1935 	} else {
1936 		if (evi_vtep->es_vtep) {
1937 			bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep,
1938 					false /*esr*/);
1939 			evi_vtep->es_vtep = NULL;
1940 		}
1941 	}
1942 	/* queue up the parent es for background consistency checks */
1943 	bgp_evpn_es_cons_checks_pend_add(evi_vtep->es_evi->es);
1944 }
1945 
bgp_evpn_es_evi_vtep_add(struct bgp * bgp,struct bgp_evpn_es_evi * es_evi,struct in_addr vtep_ip,bool ead_es)1946 static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp,
1947 		struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
1948 		bool ead_es)
1949 {
1950 	struct bgp_evpn_es_evi_vtep *evi_vtep;
1951 
1952 	evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip);
1953 
1954 	if (!evi_vtep)
1955 		evi_vtep = bgp_evpn_es_evi_vtep_new(es_evi, vtep_ip);
1956 
1957 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1958 		zlog_debug("add es %s evi %u vtep %s %s",
1959 				evi_vtep->es_evi->es->esi_str,
1960 				evi_vtep->es_evi->vpn->vni,
1961 				inet_ntoa(evi_vtep->vtep_ip),
1962 				ead_es ? "ead_es" : "ead_evi");
1963 
1964 	if (ead_es)
1965 		SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES);
1966 	else
1967 		SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
1968 
1969 	bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
1970 }
1971 
bgp_evpn_es_evi_vtep_del(struct bgp * bgp,struct bgp_evpn_es_evi * es_evi,struct in_addr vtep_ip,bool ead_es)1972 static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp,
1973 		struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
1974 		bool ead_es)
1975 {
1976 	struct bgp_evpn_es_evi_vtep *evi_vtep;
1977 
1978 	evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip);
1979 	if (!evi_vtep)
1980 		return;
1981 
1982 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1983 		zlog_debug("del es %s evi %u vtep %s %s",
1984 				evi_vtep->es_evi->es->esi_str,
1985 				evi_vtep->es_evi->vpn->vni,
1986 				inet_ntoa(evi_vtep->vtep_ip),
1987 				ead_es ? "ead_es" : "ead_evi");
1988 
1989 	if (ead_es)
1990 		UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES);
1991 	else
1992 		UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
1993 
1994 	bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
1995 	bgp_evpn_es_evi_vtep_free(evi_vtep);
1996 }
1997 
1998 /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi * es_evi1,const struct bgp_evpn_es_evi * es_evi2)1999 static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi *es_evi1,
2000 		const struct bgp_evpn_es_evi *es_evi2)
2001 {
2002 	return memcmp(&es_evi1->es->esi, &es_evi2->es->esi, ESI_BYTES);
2003 }
2004 RB_GENERATE(bgp_es_evi_rb_head, bgp_evpn_es_evi, rb_node, bgp_es_evi_rb_cmp);
2005 
2006 /* find the ES-EVI in the per-L2-VNI RB tree */
bgp_evpn_es_evi_find(struct bgp_evpn_es * es,struct bgpevpn * vpn)2007 static struct bgp_evpn_es_evi *bgp_evpn_es_evi_find(struct bgp_evpn_es *es,
2008 		struct bgpevpn *vpn)
2009 {
2010 	struct bgp_evpn_es_evi es_evi;
2011 
2012 	es_evi.es = es;
2013 
2014 	return RB_FIND(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, &es_evi);
2015 }
2016 
2017 /* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
2018  * tables.
2019  */
bgp_evpn_es_evi_new(struct bgp_evpn_es * es,struct bgpevpn * vpn)2020 static struct bgp_evpn_es_evi *bgp_evpn_es_evi_new(struct bgp_evpn_es *es,
2021 		struct bgpevpn *vpn)
2022 {
2023 	struct bgp_evpn_es_evi *es_evi;
2024 
2025 	es_evi = XCALLOC(MTYPE_BGP_EVPN_ES_EVI, sizeof(*es_evi));
2026 
2027 	es_evi->es = es;
2028 	es_evi->vpn = vpn;
2029 
2030 	/* Initialise the VTEP list */
2031 	es_evi->es_evi_vtep_list = list_new();
2032 	listset_app_node_mem(es_evi->es_evi_vtep_list);
2033 	es_evi->es_evi_vtep_list->cmp = bgp_evpn_es_evi_vtep_cmp;
2034 
2035 	/* insert into the VNI-ESI rb tree */
2036 	if (RB_INSERT(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, es_evi)) {
2037 		XFREE(MTYPE_BGP_EVPN_ES_EVI, es_evi);
2038 		return NULL;
2039 	}
2040 
2041 	/* add to the ES's VNI list */
2042 	listnode_init(&es_evi->es_listnode, es_evi);
2043 	listnode_add(es->es_evi_list, &es_evi->es_listnode);
2044 
2045 	return es_evi;
2046 }
2047 
2048 /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
2049  * up the memory.
2050  */
bgp_evpn_es_evi_free(struct bgp_evpn_es_evi * es_evi)2051 static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi)
2052 {
2053 	struct bgp_evpn_es *es = es_evi->es;
2054 	struct bgpevpn *vpn = es_evi->vpn;
2055 
2056 	/* cannot free the element as long as there is a local or remote
2057 	 * reference
2058 	 */
2059 	if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE))
2060 		return;
2061 
2062 	/* remove from the ES's VNI list */
2063 	list_delete_node(es->es_evi_list, &es_evi->es_listnode);
2064 
2065 	/* remove from the VNI-ESI rb tree */
2066 	RB_REMOVE(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, es_evi);
2067 
2068 	/* free the VTEP list */
2069 	list_delete(&es_evi->es_evi_vtep_list);
2070 
2071 	/* remove from the VNI-ESI rb tree */
2072 	XFREE(MTYPE_BGP_EVPN_ES_EVI, es_evi);
2073 }
2074 
2075 /* init local info associated with the ES-EVI */
bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi * es_evi)2076 static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi *es_evi)
2077 {
2078 	struct bgpevpn *vpn = es_evi->vpn;
2079 
2080 	if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2081 		return;
2082 
2083 	SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
2084 	listnode_init(&es_evi->l2vni_listnode, es_evi);
2085 	listnode_add(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
2086 }
2087 
2088 /* clear any local info associated with the ES-EVI */
bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi * es_evi)2089 static void bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi *es_evi)
2090 {
2091 	struct bgpevpn *vpn = es_evi->vpn;
2092 
2093 	if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2094 		return;
2095 
2096 	UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
2097 	list_delete_node(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
2098 
2099 	bgp_evpn_es_evi_free(es_evi);
2100 }
2101 
2102 /* eval remote info associated with the ES */
bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi * es_evi)2103 static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi *es_evi)
2104 {
2105 	struct bgp_evpn_es *es = es_evi->es;
2106 
2107 	/* if there are remote VTEPs the ES-EVI is classified as "remote" */
2108 	if (listcount(es_evi->es_evi_vtep_list)) {
2109 		if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) {
2110 			SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE);
2111 			++es->remote_es_evi_cnt;
2112 			/* set remote on the parent es */
2113 			bgp_evpn_es_remote_info_re_eval(es);
2114 		}
2115 	} else {
2116 		if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) {
2117 			UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE);
2118 			if (es->remote_es_evi_cnt)
2119 				--es->remote_es_evi_cnt;
2120 			bgp_evpn_es_evi_free(es_evi);
2121 			/* check if "remote" can be cleared from the
2122 			 * parent es.
2123 			 */
2124 			bgp_evpn_es_remote_info_re_eval(es);
2125 		}
2126 	}
2127 }
2128 
bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi * es_evi)2129 static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi)
2130 {
2131 	struct prefix_evpn p;
2132 	struct bgp_evpn_es *es = es_evi->es;
2133 	struct bgp *bgp;
2134 
2135 	if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2136 		return;
2137 
2138 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2139 		zlog_debug("del local es %s evi %u",
2140 				es_evi->es->esi_str,
2141 				es_evi->vpn->vni);
2142 
2143 	bgp = bgp_get_evpn();
2144 
2145 	if (bgp) {
2146 		/* update EAD-ES with new list of VNIs */
2147 		if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
2148 			build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
2149 					&es->esi, es->originator_ip);
2150 			if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
2151 				flog_err(EC_BGP_EVPN_ROUTE_CREATE,
2152 					"%u: EAD-ES route update failure for ESI %s VNI %u",
2153 					bgp->vrf_id, es->esi_str,
2154 					es_evi->vpn->vni);
2155 		}
2156 
2157 		/* withdraw and delete EAD-EVI */
2158 		if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
2159 			build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
2160 					&es->esi, es->originator_ip);
2161 			if (bgp_evpn_type1_evi_route_delete(bgp,
2162 						es, es_evi->vpn, &p))
2163 				flog_err(EC_BGP_EVPN_ROUTE_DELETE,
2164 					"%u: EAD-EVI route deletion failure for ESI %s VNI %u",
2165 					bgp->vrf_id, es->esi_str,
2166 					es_evi->vpn->vni);
2167 		}
2168 	}
2169 
2170 	bgp_evpn_es_evi_local_info_clear(es_evi);
2171 
2172 }
2173 
bgp_evpn_local_es_evi_del(struct bgp * bgp,esi_t * esi,vni_t vni)2174 int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni)
2175 {
2176 	struct bgpevpn *vpn;
2177 	struct bgp_evpn_es *es;
2178 	struct bgp_evpn_es_evi *es_evi;
2179 	char buf[ESI_STR_LEN];
2180 
2181 	es = bgp_evpn_es_find(esi);
2182 	if (!es) {
2183 		flog_err(
2184 				EC_BGP_ES_CREATE,
2185 				"%u: Failed to deref VNI %d from ESI %s; ES not present",
2186 				bgp->vrf_id, vni,
2187 				esi_to_str(esi, buf, sizeof(buf)));
2188 		return -1;
2189 	}
2190 
2191 	vpn = bgp_evpn_lookup_vni(bgp, vni);
2192 	if (!vpn) {
2193 		flog_err(
2194 				EC_BGP_ES_CREATE,
2195 				"%u: Failed to deref VNI %d from ESI %s; VNI not present",
2196 				bgp->vrf_id, vni, es->esi_str);
2197 		return -1;
2198 	}
2199 
2200 	es_evi = bgp_evpn_es_evi_find(es, vpn);
2201 	if (!es_evi) {
2202 		flog_err(
2203 				EC_BGP_ES_CREATE,
2204 				"%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
2205 				bgp->vrf_id, vni, es->esi_str);
2206 		return -1;
2207 	}
2208 
2209 	bgp_evpn_local_es_evi_do_del(es_evi);
2210 	return 0;
2211 }
2212 
2213 /* Create ES-EVI and advertise the corresponding EAD routes */
bgp_evpn_local_es_evi_add(struct bgp * bgp,esi_t * esi,vni_t vni)2214 int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni)
2215 {
2216 	struct bgpevpn *vpn;
2217 	struct prefix_evpn p;
2218 	struct bgp_evpn_es *es;
2219 	struct bgp_evpn_es_evi *es_evi;
2220 	char buf[ESI_STR_LEN];
2221 
2222 	es = bgp_evpn_es_find(esi);
2223 	if (!es) {
2224 		flog_err(
2225 				EC_BGP_ES_CREATE,
2226 				"%u: Failed to associate VNI %d with ESI %s; ES not present",
2227 				bgp->vrf_id, vni,
2228 				esi_to_str(esi, buf, sizeof(buf)));
2229 		return -1;
2230 	}
2231 
2232 	vpn = bgp_evpn_lookup_vni(bgp, vni);
2233 	if (!vpn) {
2234 		flog_err(
2235 				EC_BGP_ES_CREATE,
2236 				"%u: Failed to associate VNI %d with ESI %s; VNI not present",
2237 				bgp->vrf_id, vni, es->esi_str);
2238 		return -1;
2239 	}
2240 
2241 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2242 		zlog_debug("add local es %s evi %u",
2243 				es->esi_str, vni);
2244 
2245 	es_evi = bgp_evpn_es_evi_find(es, vpn);
2246 
2247 	if (es_evi) {
2248 		if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2249 			/* dup */
2250 			return 0;
2251 	} else {
2252 		es_evi = bgp_evpn_es_evi_new(es, vpn);
2253 		if (!es_evi)
2254 			return -1;
2255 	}
2256 
2257 	bgp_evpn_es_evi_local_info_set(es_evi);
2258 
2259 	/* generate an EAD-EVI for this new VNI */
2260 	build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
2261 			&es->esi, es->originator_ip);
2262 	if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
2263 		if (bgp_evpn_type1_route_update(bgp, es, vpn, &p))
2264 			flog_err(EC_BGP_EVPN_ROUTE_CREATE,
2265 					"%u: EAD-EVI route creation failure for ESI %s VNI %u",
2266 					bgp->vrf_id, es->esi_str, vni);
2267 	}
2268 
2269 	/* update EAD-ES */
2270 	build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
2271 			&es->esi, es->originator_ip);
2272 	if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
2273 		if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
2274 			flog_err(EC_BGP_EVPN_ROUTE_CREATE,
2275 					"%u: EAD-ES route creation failure for ESI %s VNI %u",
2276 					bgp->vrf_id, es->esi_str, vni);
2277 	}
2278 
2279 	return 0;
2280 }
2281 
2282 /* Add remote ES-EVI entry. This is actually the remote VTEP add and the
2283  * ES-EVI is implicity created on first VTEP's reference.
2284  */
bgp_evpn_remote_es_evi_add(struct bgp * bgp,struct bgpevpn * vpn,const struct prefix_evpn * p)2285 int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
2286 		const struct prefix_evpn *p)
2287 {
2288 	char buf[ESI_STR_LEN];
2289 	struct bgp_evpn_es *es;
2290 	struct bgp_evpn_es_evi *es_evi;
2291 	bool ead_es;
2292 	const esi_t *esi = &p->prefix.ead_addr.esi;
2293 
2294 	if (!vpn)
2295 		/* local EAD-ES need not be sent back to zebra */
2296 		return 0;
2297 
2298 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2299 		zlog_debug("add remote %s es %s evi %u vtep %s",
2300 				p->prefix.ead_addr.eth_tag ?
2301 				"ead-es" : "ead-evi",
2302 				esi_to_str(esi, buf,
2303 					sizeof(buf)),
2304 				vpn->vni,
2305 				inet_ntoa(p->prefix.ead_addr.ip.ipaddr_v4));
2306 
2307 	es = bgp_evpn_es_find(esi);
2308 	if (!es) {
2309 		es = bgp_evpn_es_new(bgp, esi);
2310 		if (!es) {
2311 			flog_err(EC_BGP_ES_CREATE,
2312 				"%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
2313 				bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
2314 			return -1;
2315 		}
2316 	}
2317 
2318 	es_evi = bgp_evpn_es_evi_find(es, vpn);
2319 	if (!es_evi) {
2320 		es_evi = bgp_evpn_es_evi_new(es, vpn);
2321 		if (!es_evi) {
2322 			bgp_evpn_es_free(es, __func__);
2323 			return -1;
2324 		}
2325 	}
2326 
2327 	ead_es = !!p->prefix.ead_addr.eth_tag;
2328 	bgp_evpn_es_evi_vtep_add(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
2329 			ead_es);
2330 
2331 	bgp_evpn_es_evi_remote_info_re_eval(es_evi);
2332 	return 0;
2333 }
2334 
2335 /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
2336  * parent es-evi freed up implicitly in last VTEP's deref.
2337  */
bgp_evpn_remote_es_evi_del(struct bgp * bgp,struct bgpevpn * vpn,const struct prefix_evpn * p)2338 int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
2339 		const struct prefix_evpn *p)
2340 {
2341 	char buf[ESI_STR_LEN];
2342 	struct bgp_evpn_es *es;
2343 	struct bgp_evpn_es_evi *es_evi;
2344 	bool ead_es;
2345 
2346 	if (!vpn)
2347 		/* local EAD-ES need not be sent back to zebra */
2348 		return 0;
2349 
2350 	if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2351 		zlog_debug("del remote %s es %s evi %u vtep %s",
2352 				p->prefix.ead_addr.eth_tag ?
2353 				"ead-es" : "ead-evi",
2354 				esi_to_str(&p->prefix.ead_addr.esi, buf,
2355 					sizeof(buf)),
2356 				vpn->vni,
2357 				inet_ntoa(p->prefix.ead_addr.ip.ipaddr_v4));
2358 
2359 	es = bgp_evpn_es_find(&p->prefix.ead_addr.esi);
2360 	if (!es)
2361 		/* XXX - error logs */
2362 		return 0;
2363 	es_evi = bgp_evpn_es_evi_find(es, vpn);
2364 	if (!es_evi)
2365 		/* XXX - error logs */
2366 		return 0;
2367 
2368 	ead_es = !!p->prefix.ead_addr.eth_tag;
2369 	bgp_evpn_es_evi_vtep_del(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
2370 			ead_es);
2371 	bgp_evpn_es_evi_remote_info_re_eval(es_evi);
2372 	return 0;
2373 }
2374 
2375 /* Initialize the ES tables maintained per-L2_VNI */
bgp_evpn_vni_es_init(struct bgpevpn * vpn)2376 void bgp_evpn_vni_es_init(struct bgpevpn *vpn)
2377 {
2378 	/* Initialize the ES-EVI RB tree */
2379 	RB_INIT(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree);
2380 
2381 	/* Initialize the local list maintained for quick walks by type */
2382 	vpn->local_es_evi_list = list_new();
2383 	listset_app_node_mem(vpn->local_es_evi_list);
2384 }
2385 
2386 /* Cleanup the ES info maintained per-L2_VNI */
bgp_evpn_vni_es_cleanup(struct bgpevpn * vpn)2387 void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn)
2388 {
2389 	struct bgp_evpn_es_evi *es_evi;
2390 	struct bgp_evpn_es_evi *es_evi_next;
2391 
2392 	RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head,
2393 			&vpn->es_evi_rb_tree, es_evi_next) {
2394 		bgp_evpn_local_es_evi_do_del(es_evi);
2395 	}
2396 
2397 	list_delete(&vpn->local_es_evi_list);
2398 }
2399 
bgp_evpn_es_evi_vteps_str(char * vtep_str,struct bgp_evpn_es_evi * es_evi,uint8_t vtep_str_size)2400 static char *bgp_evpn_es_evi_vteps_str(char *vtep_str,
2401 				       struct bgp_evpn_es_evi *es_evi,
2402 				       uint8_t vtep_str_size)
2403 {
2404 	char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
2405 	struct listnode *node;
2406 	struct bgp_evpn_es_evi_vtep *evi_vtep;
2407 	bool first = true;
2408 
2409 	vtep_str[0] = '\0';
2410 	for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
2411 		vtep_flag_str[0] = '\0';
2412 		if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
2413 			strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
2414 		if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
2415 			strlcat(vtep_flag_str, "V", sizeof(vtep_flag_str));
2416 
2417 		if (!strnlen(vtep_flag_str, sizeof(vtep_flag_str)))
2418 			strlcpy(vtep_flag_str, "-", sizeof(vtep_flag_str));
2419 		if (first)
2420 			first = false;
2421 		else
2422 			strlcat(vtep_str, ",", vtep_str_size);
2423 		strlcat(vtep_str, inet_ntoa(evi_vtep->vtep_ip), vtep_str_size);
2424 		strlcat(vtep_str, "(", vtep_str_size);
2425 		strlcat(vtep_str, vtep_flag_str, vtep_str_size);
2426 		strlcat(vtep_str, ")", vtep_str_size);
2427 	}
2428 
2429 	return vtep_str;
2430 }
2431 
bgp_evpn_es_evi_json_vtep_fill(json_object * json_vteps,struct bgp_evpn_es_evi_vtep * evi_vtep)2432 static void bgp_evpn_es_evi_json_vtep_fill(json_object *json_vteps,
2433 		struct bgp_evpn_es_evi_vtep *evi_vtep)
2434 {
2435 	json_object *json_vtep_entry;
2436 	json_object *json_flags;
2437 
2438 	json_vtep_entry = json_object_new_object();
2439 
2440 	json_object_string_add(json_vtep_entry,
2441 			"vtep_ip",
2442 			inet_ntoa(evi_vtep->vtep_ip));
2443 	if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
2444 			 BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) {
2445 		json_flags = json_object_new_array();
2446 		if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
2447 			json_array_string_add(json_flags, "ead-per-es");
2448 		if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
2449 			json_array_string_add(json_flags, "ed-per-evi");
2450 		json_object_object_add(json_vtep_entry,
2451 				"flags", json_flags);
2452 	}
2453 
2454 	json_object_array_add(json_vteps,
2455 			json_vtep_entry);
2456 }
2457 
bgp_evpn_es_evi_show_entry(struct vty * vty,struct bgp_evpn_es_evi * es_evi,json_object * json)2458 static void bgp_evpn_es_evi_show_entry(struct vty *vty,
2459 		struct bgp_evpn_es_evi *es_evi, json_object *json)
2460 {
2461 	struct listnode *node;
2462 	struct bgp_evpn_es_evi_vtep *evi_vtep;
2463 
2464 	if (json) {
2465 		json_object *json_vteps;
2466 		json_object *json_types;
2467 
2468 		json_object_string_add(json, "esi", es_evi->es->esi_str);
2469 		json_object_int_add(json, "vni", es_evi->vpn->vni);
2470 
2471 		if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL |
2472 					BGP_EVPNES_EVI_REMOTE)) {
2473 			json_types = json_object_new_array();
2474 			if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
2475 				json_array_string_add(json_types, "local");
2476 			if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
2477 				json_array_string_add(json_types, "remote");
2478 			json_object_object_add(json, "type", json_types);
2479 		}
2480 
2481 		if (listcount(es_evi->es_evi_vtep_list)) {
2482 			json_vteps = json_object_new_array();
2483 			for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list,
2484 						node, evi_vtep)) {
2485 				bgp_evpn_es_evi_json_vtep_fill(json_vteps,
2486 						evi_vtep);
2487 			}
2488 			json_object_object_add(json, "vteps", json_vteps);
2489 		}
2490 	} else {
2491 		char type_str[4];
2492 		char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
2493 
2494 		type_str[0] = '\0';
2495 		if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
2496 			strlcat(type_str, "L", sizeof(type_str));
2497 		if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
2498 			strlcat(type_str, "R", sizeof(type_str));
2499 		if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST)
2500 			strlcat(type_str, "I", sizeof(type_str));
2501 
2502 		bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
2503 
2504 		vty_out(vty, "%-8d %-30s %-5s %s\n",
2505 				es_evi->vpn->vni, es_evi->es->esi_str,
2506 				type_str, vtep_str);
2507 	}
2508 }
2509 
bgp_evpn_es_evi_show_entry_detail(struct vty * vty,struct bgp_evpn_es_evi * es_evi,json_object * json)2510 static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
2511 		struct bgp_evpn_es_evi *es_evi, json_object *json)
2512 {
2513 	if (json) {
2514 		json_object *json_flags;
2515 
2516 		/* Add the "brief" info first */
2517 		bgp_evpn_es_evi_show_entry(vty, es_evi, json);
2518 		if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) {
2519 			json_flags = json_object_new_array();
2520 			json_array_string_add(json_flags, "es-vtep-mismatch");
2521 			json_object_object_add(json, "flags", json_flags);
2522 		}
2523 	} else {
2524 		char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
2525 		char type_str[4];
2526 
2527 		type_str[0] = '\0';
2528 		if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
2529 			strlcat(type_str, "L", sizeof(type_str));
2530 		if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
2531 			strlcat(type_str, "R", sizeof(type_str));
2532 
2533 		bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
2534 		if (!strlen(vtep_str))
2535 			strlcpy(vtep_str, "-", sizeof(type_str));
2536 
2537 		vty_out(vty, "VNI: %d ESI: %s\n",
2538 				es_evi->vpn->vni, es_evi->es->esi_str);
2539 		vty_out(vty, " Type: %s\n", type_str);
2540 		vty_out(vty, " Inconsistencies: %s\n",
2541 			(es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
2542 			"es-vtep-mismatch":"-");
2543 		vty_out(vty, " VTEPs: %s\n", vtep_str);
2544 		vty_out(vty, "\n");
2545 	}
2546 }
2547 
bgp_evpn_es_evi_show_one_vni(struct bgpevpn * vpn,struct vty * vty,json_object * json_array,bool detail)2548 static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn *vpn, struct vty *vty,
2549 		json_object *json_array, bool detail)
2550 {
2551 	struct bgp_evpn_es_evi *es_evi;
2552 	json_object *json = NULL;
2553 
2554 	RB_FOREACH(es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree) {
2555 		if (json_array)
2556 			/* create a separate json object for each ES */
2557 			json = json_object_new_object();
2558 		if (detail)
2559 			bgp_evpn_es_evi_show_entry_detail(vty, es_evi, json);
2560 		else
2561 			bgp_evpn_es_evi_show_entry(vty, es_evi, json);
2562 		/* add ES to the json array */
2563 		if (json_array)
2564 			json_object_array_add(json_array, json);
2565 	}
2566 }
2567 
2568 struct es_evi_show_ctx {
2569 	struct vty *vty;
2570 	json_object *json;
2571 	int detail;
2572 };
2573 
bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket * bucket,void * ctxt)2574 static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket *bucket,
2575 		void *ctxt)
2576 {
2577 	struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
2578 	struct es_evi_show_ctx *wctx = (struct es_evi_show_ctx *)ctxt;
2579 
2580 	bgp_evpn_es_evi_show_one_vni(vpn, wctx->vty, wctx->json, wctx->detail);
2581 }
2582 
2583 /* Display all ES EVIs */
bgp_evpn_es_evi_show(struct vty * vty,bool uj,bool detail)2584 void bgp_evpn_es_evi_show(struct vty *vty, bool uj, bool detail)
2585 {
2586 	json_object *json_array = NULL;
2587 	struct es_evi_show_ctx wctx;
2588 	struct bgp *bgp;
2589 
2590 	if (uj) {
2591 		/* create an array of ES-EVIs */
2592 		json_array = json_object_new_array();
2593 	}
2594 
2595 	wctx.vty = vty;
2596 	wctx.json = json_array;
2597 	wctx.detail = detail;
2598 
2599 	bgp = bgp_get_evpn();
2600 
2601 	if (!json_array && !detail) {
2602 		vty_out(vty, "Flags: L local, R remote, I inconsistent\n");
2603 		vty_out(vty, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
2604 		vty_out(vty, "%-8s %-30s %-5s %s\n",
2605 				"VNI", "ESI", "Flags", "VTEPs");
2606 	}
2607 
2608 	if (bgp)
2609 		hash_iterate(bgp->vnihash,
2610 				(void (*)(struct hash_bucket *,
2611 				  void *))bgp_evpn_es_evi_show_one_vni_hash_cb,
2612 				&wctx);
2613 	if (uj) {
2614 		vty_out(vty, "%s\n", json_object_to_json_string_ext(
2615 					json_array, JSON_C_TO_STRING_PRETTY));
2616 		json_object_free(json_array);
2617 	}
2618 }
2619 
2620 /* Display specific ES EVI */
bgp_evpn_es_evi_show_vni(struct vty * vty,vni_t vni,bool uj,bool detail)2621 void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni,
2622 		bool uj, bool detail)
2623 {
2624 	struct bgpevpn *vpn = NULL;
2625 	json_object *json_array = NULL;
2626 	struct bgp *bgp;
2627 
2628 	if (uj) {
2629 		/* create an array of ES-EVIs */
2630 		json_array = json_object_new_array();
2631 	}
2632 
2633 	bgp = bgp_get_evpn();
2634 	if (bgp)
2635 		vpn = bgp_evpn_lookup_vni(bgp, vni);
2636 
2637 	if (vpn) {
2638 		if (!json_array && !detail) {
2639 			vty_out(vty, "Flags: L local, R remote, I inconsistent\n");
2640 			vty_out(vty, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
2641 			vty_out(vty, "%-8s %-30s %-5s %s\n",
2642 					"VNI", "ESI", "Flags", "VTEPs");
2643 		}
2644 
2645 		bgp_evpn_es_evi_show_one_vni(vpn, vty, json_array, detail);
2646 	} else {
2647 		if (!uj)
2648 			vty_out(vty, "VNI not found\n");
2649 	}
2650 
2651 	if (uj) {
2652 		vty_out(vty, "%s\n", json_object_to_json_string_ext(
2653 					json_array, JSON_C_TO_STRING_PRETTY));
2654 		json_object_free(json_array);
2655 	}
2656 }
2657 
2658 /*****************************************************************************
2659  * Ethernet Segment Consistency checks
2660  *     Consistency checking is done to detect misconfig or mis-cabling. When
2661  * an inconsistency is detected it is simply logged (and displayed via
2662  * show commands) at this point. A more drastic action can be executed (based
2663  * on user config) in the future.
2664  */
2665 /* queue up the es for background consistency checks */
bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es * es)2666 static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es)
2667 {
2668 	if (!bgp_mh_info->consistency_checking)
2669 		/* consistency checking is not enabled */
2670 		return;
2671 
2672 	if (CHECK_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND))
2673 		/* already queued for consistency checking */
2674 		return;
2675 
2676 	SET_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND);
2677 	listnode_init(&es->pend_es_listnode, es);
2678 	listnode_add_after(bgp_mh_info->pend_es_list,
2679 			listtail_unchecked(bgp_mh_info->pend_es_list),
2680 			&es->pend_es_listnode);
2681 }
2682 
2683 /* pull the ES from the consistency check list */
bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es * es)2684 static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es)
2685 {
2686 	if (!CHECK_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND))
2687 		return;
2688 
2689 	UNSET_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND);
2690 	list_delete_node(bgp_mh_info->pend_es_list,
2691 			&es->pend_es_listnode);
2692 }
2693 
2694 /* Number of active VTEPs associated with the ES-per-EVI */
bgp_evpn_es_evi_get_active_vtep_cnt(struct bgp_evpn_es_evi * es_evi)2695 static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
2696 		struct bgp_evpn_es_evi *es_evi)
2697 {
2698 	struct bgp_evpn_es_evi_vtep *evi_vtep;
2699 	struct listnode *node;
2700 	uint32_t vtep_cnt = 0;
2701 
2702 	for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
2703 		if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE))
2704 			++vtep_cnt;
2705 	}
2706 
2707 	return vtep_cnt;
2708 }
2709 
2710 /* Number of active VTEPs associated with the ES */
bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es * es)2711 static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es)
2712 {
2713 	struct listnode *node;
2714 	uint32_t vtep_cnt = 0;
2715 	struct bgp_evpn_es_vtep *es_vtep;
2716 
2717 	for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
2718 		if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
2719 			++vtep_cnt;
2720 	}
2721 
2722 	return vtep_cnt;
2723 }
2724 
bgp_evpn_es_get_next_active_vtep(struct bgp_evpn_es * es,struct bgp_evpn_es_vtep * es_vtep)2725 static struct bgp_evpn_es_vtep *bgp_evpn_es_get_next_active_vtep(
2726 		struct bgp_evpn_es *es, struct bgp_evpn_es_vtep *es_vtep)
2727 {
2728 	struct listnode *node;
2729 	struct bgp_evpn_es_vtep *next_es_vtep;
2730 
2731 	if (es_vtep)
2732 		node = listnextnode_unchecked(&es_vtep->es_listnode);
2733 	else
2734 		node = listhead(es->es_vtep_list);
2735 
2736 	for (; node; node = listnextnode_unchecked(node)) {
2737 		next_es_vtep = listgetdata(node);
2738 		if (CHECK_FLAG(next_es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
2739 			return next_es_vtep;
2740 	}
2741 
2742 	return NULL;
2743 }
2744 
bgp_evpn_es_evi_get_next_active_vtep(struct bgp_evpn_es_evi * es_evi,struct bgp_evpn_es_evi_vtep * evi_vtep)2745 static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_get_next_active_vtep(
2746 	struct bgp_evpn_es_evi *es_evi,
2747 	struct bgp_evpn_es_evi_vtep *evi_vtep)
2748 {
2749 	struct listnode *node;
2750 	struct bgp_evpn_es_evi_vtep *next_evi_vtep;
2751 
2752 	if (evi_vtep)
2753 		node = listnextnode_unchecked(&evi_vtep->es_evi_listnode);
2754 	else
2755 		node = listhead(es_evi->es_evi_vtep_list);
2756 
2757 	for (; node; node = listnextnode_unchecked(node)) {
2758 		next_evi_vtep = listgetdata(node);
2759 		if (CHECK_FLAG(next_evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE))
2760 			return next_evi_vtep;
2761 	}
2762 
2763 	return NULL;
2764 }
2765 
bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi * es_evi)2766 static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi *es_evi)
2767 {
2768 	if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST)) {
2769 		if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2770 			zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
2771 					es_evi->es->esi_str,
2772 					es_evi->vpn->vni);
2773 		SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST);
2774 
2775 		/* update parent ES with the incosistency setting */
2776 		if (!es_evi->es->incons_evi_vtep_cnt &&
2777 				BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2778 			zlog_debug("inconsistency detected - es %s vtep list mismatch",
2779 					es_evi->es->esi_str);
2780 		++es_evi->es->incons_evi_vtep_cnt;
2781 		SET_FLAG(es_evi->es->inconsistencies,
2782 				BGP_EVPNES_INCONS_VTEP_LIST);
2783 	}
2784 }
2785 
bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es * es)2786 static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es *es)
2787 {
2788 	int proc_cnt = 0;
2789 	int es_active_vtep_cnt;
2790 	int evi_active_vtep_cnt;
2791 	struct bgp_evpn_es_evi *es_evi;
2792 	struct listnode *evi_node;
2793 	struct bgp_evpn_es_vtep *es_vtep;
2794 	struct bgp_evpn_es_evi_vtep *evi_vtep;
2795 
2796 	/* reset the inconsistencies and re-evaluate */
2797 	es->incons_evi_vtep_cnt = 0;
2798 	es->inconsistencies = 0;
2799 
2800 	es_active_vtep_cnt = bgp_evpn_es_get_active_vtep_cnt(es);
2801 	for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
2802 				evi_node, es_evi)) {
2803 		++proc_cnt;
2804 
2805 		/* reset the inconsistencies on the EVI and re-evaluate*/
2806 		UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST);
2807 
2808 		evi_active_vtep_cnt =
2809 			bgp_evpn_es_evi_get_active_vtep_cnt(es_evi);
2810 		if (es_active_vtep_cnt != evi_active_vtep_cnt) {
2811 			bgp_evpn_es_evi_set_inconsistent(es_evi);
2812 			continue;
2813 		}
2814 
2815 		if (!es_active_vtep_cnt)
2816 			continue;
2817 
2818 		es_vtep = NULL;
2819 		evi_vtep = NULL;
2820 		while ((es_vtep = bgp_evpn_es_get_next_active_vtep(
2821 						es, es_vtep))) {
2822 			evi_vtep = bgp_evpn_es_evi_get_next_active_vtep(es_evi,
2823 					evi_vtep);
2824 			if (!evi_vtep) {
2825 				bgp_evpn_es_evi_set_inconsistent(es_evi);
2826 				break;
2827 			}
2828 			if (es_vtep->vtep_ip.s_addr !=
2829 					evi_vtep->vtep_ip.s_addr) {
2830 				/* inconsistency detected; set it and move
2831 				 * to the next evi
2832 				 */
2833 				bgp_evpn_es_evi_set_inconsistent(es_evi);
2834 				break;
2835 			}
2836 		}
2837 	}
2838 
2839 	return proc_cnt;
2840 }
2841 
bgp_evpn_run_consistency_checks(struct thread * t)2842 static int bgp_evpn_run_consistency_checks(struct thread *t)
2843 {
2844 	int proc_cnt = 0;
2845 	int es_cnt = 0;
2846 	struct listnode *node;
2847 	struct listnode *nextnode;
2848 	struct bgp_evpn_es *es;
2849 
2850 	for (ALL_LIST_ELEMENTS(bgp_mh_info->pend_es_list,
2851 				node, nextnode, es)) {
2852 		++es_cnt;
2853 		++proc_cnt;
2854 		/* run consistency checks on the ES and remove it from the
2855 		 * pending list
2856 		 */
2857 		proc_cnt += bgp_evpn_es_run_consistency_checks(es);
2858 		bgp_evpn_es_cons_checks_pend_del(es);
2859 		if (proc_cnt > 500)
2860 			break;
2861 	}
2862 
2863 	/* restart the timer */
2864 	thread_add_timer(bm->master, bgp_evpn_run_consistency_checks, NULL,
2865 			BGP_EVPN_CONS_CHECK_INTERVAL,
2866 			&bgp_mh_info->t_cons_check);
2867 
2868 	return 0;
2869 }
2870 
2871 /*****************************************************************************/
bgp_evpn_mh_init(void)2872 void bgp_evpn_mh_init(void)
2873 {
2874 	bm->mh_info = XCALLOC(MTYPE_BGP_EVPN_MH_INFO, sizeof(*bm->mh_info));
2875 
2876 	/* setup ES tables */
2877 	RB_INIT(bgp_es_rb_head, &bgp_mh_info->es_rb_tree);
2878 	/* local ES list */
2879 	bgp_mh_info->local_es_list = list_new();
2880 	listset_app_node_mem(bgp_mh_info->local_es_list);
2881 	/* list of ESs with pending processing */
2882 	bgp_mh_info->pend_es_list = list_new();
2883 	listset_app_node_mem(bgp_mh_info->pend_es_list);
2884 
2885 	/* config knobs - XXX add cli to control it */
2886 	bgp_mh_info->ead_evi_adv_for_down_links = true;
2887 	bgp_mh_info->consistency_checking = true;
2888 
2889 	if (bgp_mh_info->consistency_checking)
2890 		thread_add_timer(bm->master, bgp_evpn_run_consistency_checks,
2891 				NULL, BGP_EVPN_CONS_CHECK_INTERVAL,
2892 				&bgp_mh_info->t_cons_check);
2893 
2894 	memset(&zero_esi_buf, 0, sizeof(esi_t));
2895 }
2896 
bgp_evpn_mh_finish(void)2897 void bgp_evpn_mh_finish(void)
2898 {
2899 	struct bgp_evpn_es *es;
2900 	struct bgp_evpn_es *es_next;
2901 
2902 	if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
2903 		zlog_debug("evpn mh finish");
2904 
2905 	RB_FOREACH_SAFE (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree,
2906 			 es_next) {
2907 		bgp_evpn_es_local_info_clear(es);
2908 	}
2909 	thread_cancel(bgp_mh_info->t_cons_check);
2910 	list_delete(&bgp_mh_info->local_es_list);
2911 	list_delete(&bgp_mh_info->pend_es_list);
2912 
2913 	XFREE(MTYPE_BGP_EVPN_MH_INFO, bgp_mh_info);
2914 }
2915