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