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