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