]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_evpn_mh.c
Merge pull request #7726 from chiragshah6/mdev
[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
23d0a753
DA
32#include "lib/printfrr.h"
33
185fb14a
AK
34#include "bgpd/bgp_attr_evpn.h"
35#include "bgpd/bgpd.h"
36#include "bgpd/bgp_table.h"
37#include "bgpd/bgp_route.h"
38#include "bgpd/bgp_attr.h"
39#include "bgpd/bgp_mplsvpn.h"
40#include "bgpd/bgp_evpn.h"
41#include "bgpd/bgp_evpn_private.h"
42#include "bgpd/bgp_evpn_mh.h"
43#include "bgpd/bgp_ecommunity.h"
44#include "bgpd/bgp_encap_types.h"
45#include "bgpd/bgp_debug.h"
46#include "bgpd/bgp_errors.h"
47#include "bgpd/bgp_aspath.h"
48#include "bgpd/bgp_zebra.h"
49#include "bgpd/bgp_addpath.h"
c44ab6f1 50#include "bgpd/bgp_label.h"
c589d847 51#include "bgpd/bgp_nht.h"
6348981a 52#include "bgpd/bgp_mpath.h"
c44ab6f1
AK
53
54static void bgp_evpn_local_es_down(struct bgp *bgp,
55 struct bgp_evpn_es *es);
56static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp,
57 struct bgp_evpn_es *es);
58static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
74e2bd89
AK
59 struct bgp_evpn_es *es,
60 struct in_addr vtep_ip,
61 bool esr, uint8_t df_alg,
62 uint16_t df_pref);
c44ab6f1
AK
63static void bgp_evpn_es_vtep_del(struct bgp *bgp,
64 struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr);
65static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es);
66static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es);
67static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi);
c589d847
AK
68static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es);
69static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es);
26c03e43
AK
70static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi);
71static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller);
72static void bgp_evpn_es_path_all_update(struct bgp_evpn_es_vtep *es_vtep,
73 bool active);
c44ab6f1
AK
74
75esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
76
77/******************************************************************************
78 * per-ES (Ethernet Segment) routing table
79 *
80 * Following routes are added to the ES's routing table -
81 * 1. Local and remote ESR (Type-4)
82 * 2. Local EAD-per-ES (Type-1).
83 *
84 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
85 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
86 * being added to same ES).
87 *
88 * Note the following routes go into the VNI routing table (instead of the
89 * ES routing table) -
90 * 1. Remote EAD-per-ES
91 * 2. Local and remote EAD-per-EVI
185fb14a 92 */
185fb14a 93
c44ab6f1
AK
94/* Calculate the best path for a multi-homing (Type-1 or Type-4) route
95 * installed in the ES's routing table.
185fb14a 96 */
c44ab6f1 97static int bgp_evpn_es_route_select_install(struct bgp *bgp,
09319b4e
DS
98 struct bgp_evpn_es *es,
99 struct bgp_dest *dest)
185fb14a
AK
100{
101 int ret = 0;
102 afi_t afi = AFI_L2VPN;
103 safi_t safi = SAFI_EVPN;
104 struct bgp_path_info *old_select; /* old best */
105 struct bgp_path_info *new_select; /* new best */
106 struct bgp_path_info_pair old_and_new;
107
108 /* Compute the best path. */
09319b4e
DS
109 bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new,
110 afi, safi);
185fb14a
AK
111 old_select = old_and_new.old;
112 new_select = old_and_new.new;
113
114 /*
115 * If the best path hasn't changed - see if something needs to be
116 * updated
117 */
118 if (old_select && old_select == new_select
09319b4e
DS
119 && old_select->type == ZEBRA_ROUTE_BGP
120 && old_select->sub_type == BGP_ROUTE_IMPORTED
121 && !CHECK_FLAG(dest->flags, BGP_NODE_USER_CLEAR)
122 && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
123 && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
185fb14a 124 if (bgp_zebra_has_route_changed(old_select)) {
74e2bd89
AK
125 bgp_evpn_es_vtep_add(bgp, es, old_select->attr->nexthop,
126 true /*esr*/,
127 old_select->attr->df_alg,
128 old_select->attr->df_pref);
185fb14a
AK
129 }
130 UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
09319b4e 131 bgp_zebra_clear_route_change_flags(dest);
185fb14a
AK
132 return ret;
133 }
134
135 /* If the user did a "clear" this flag will be set */
09319b4e 136 UNSET_FLAG(dest->flags, BGP_NODE_USER_CLEAR);
185fb14a 137
c44ab6f1 138 /* bestpath has changed; update relevant fields and install or uninstall
185fb14a
AK
139 * into the zebra RIB.
140 */
141 if (old_select || new_select)
09319b4e 142 bgp_bump_version(dest);
185fb14a
AK
143
144 if (old_select)
09319b4e 145 bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED);
185fb14a 146 if (new_select) {
09319b4e
DS
147 bgp_path_info_set_flag(dest, new_select, BGP_PATH_SELECTED);
148 bgp_path_info_unset_flag(dest, new_select,
149 BGP_PATH_ATTR_CHANGED);
185fb14a
AK
150 UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG);
151 }
152
153 if (new_select && new_select->type == ZEBRA_ROUTE_BGP
c44ab6f1 154 && new_select->sub_type == BGP_ROUTE_IMPORTED) {
74e2bd89
AK
155 bgp_evpn_es_vtep_add(bgp, es, new_select->attr->nexthop,
156 true /*esr */, new_select->attr->df_alg,
157 new_select->attr->df_pref);
185fb14a
AK
158 } else {
159 if (old_select && old_select->type == ZEBRA_ROUTE_BGP
c44ab6f1
AK
160 && old_select->sub_type == BGP_ROUTE_IMPORTED)
161 bgp_evpn_es_vtep_del(
162 bgp, es, old_select->attr->nexthop,
163 true /*esr*/);
185fb14a
AK
164 }
165
166 /* Clear any route change flags. */
09319b4e 167 bgp_zebra_clear_route_change_flags(dest);
185fb14a
AK
168
169 /* Reap old select bgp_path_info, if it has been removed */
170 if (old_select && CHECK_FLAG(old_select->flags, BGP_PATH_REMOVED))
09319b4e 171 bgp_path_info_reap(dest, old_select);
185fb14a
AK
172
173 return ret;
174}
175
c44ab6f1
AK
176/* Install Type-1/Type-4 route entry in the per-ES routing table */
177static int bgp_evpn_es_route_install(struct bgp *bgp,
178 struct bgp_evpn_es *es, struct prefix_evpn *p,
179 struct bgp_path_info *parent_pi)
180{
181 int ret = 0;
09319b4e 182 struct bgp_dest *dest = NULL;
c44ab6f1
AK
183 struct bgp_path_info *pi = NULL;
184 struct attr *attr_new = NULL;
185
186 /* Create (or fetch) route within the VNI.
187 * NOTE: There is no RD here.
188 */
09319b4e 189 dest = bgp_node_get(es->route_table, (struct prefix *)p);
c44ab6f1
AK
190
191 /* Check if route entry is already present. */
09319b4e 192 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
c44ab6f1
AK
193 if (pi->extra
194 && (struct bgp_path_info *)pi->extra->parent ==
195 parent_pi)
196 break;
197
198 if (!pi) {
199 /* Add (or update) attribute to hash. */
200 attr_new = bgp_attr_intern(parent_pi->attr);
201
202 /* Create new route with its attribute. */
203 pi = info_make(parent_pi->type, BGP_ROUTE_IMPORTED, 0,
09319b4e 204 parent_pi->peer, attr_new, dest);
c44ab6f1
AK
205 SET_FLAG(pi->flags, BGP_PATH_VALID);
206 bgp_path_info_extra_get(pi);
207 pi->extra->parent = bgp_path_info_lock(parent_pi);
09319b4e
DS
208 bgp_dest_lock_node((struct bgp_dest *)parent_pi->net);
209 bgp_path_info_add(dest, pi);
c44ab6f1
AK
210 } else {
211 if (attrhash_cmp(pi->attr, parent_pi->attr)
212 && !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
09319b4e 213 bgp_dest_unlock_node(dest);
c44ab6f1
AK
214 return 0;
215 }
216 /* The attribute has changed. */
217 /* Add (or update) attribute to hash. */
218 attr_new = bgp_attr_intern(parent_pi->attr);
219
220 /* Restore route, if needed. */
221 if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED))
09319b4e 222 bgp_path_info_restore(dest, pi);
c44ab6f1
AK
223
224 /* Mark if nexthop has changed. */
225 if (!IPV4_ADDR_SAME(&pi->attr->nexthop, &attr_new->nexthop))
226 SET_FLAG(pi->flags, BGP_PATH_IGP_CHANGED);
227
228 /* Unintern existing, set to new. */
229 bgp_attr_unintern(&pi->attr);
230 pi->attr = attr_new;
231 pi->uptime = bgp_clock();
232 }
233
234 /* Perform route selection and update zebra, if required. */
09319b4e 235 ret = bgp_evpn_es_route_select_install(bgp, es, dest);
c44ab6f1 236
09319b4e 237 bgp_dest_unlock_node(dest);
c44ab6f1
AK
238
239 return ret;
240}
241
242/* Uninstall Type-1/Type-4 route entry from the ES routing table */
243static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
244 struct prefix_evpn *p, struct bgp_path_info *parent_pi)
245{
246 int ret;
09319b4e 247 struct bgp_dest *dest;
c44ab6f1
AK
248 struct bgp_path_info *pi;
249
250 if (!es->route_table)
251 return 0;
252
253 /* Locate route within the ESI.
254 * NOTE: There is no RD here.
255 */
09319b4e
DS
256 dest = bgp_node_lookup(es->route_table, (struct prefix *)p);
257 if (!dest)
c44ab6f1
AK
258 return 0;
259
260 /* Find matching route entry. */
09319b4e 261 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
c44ab6f1
AK
262 if (pi->extra
263 && (struct bgp_path_info *)pi->extra->parent ==
264 parent_pi)
265 break;
266
267 if (!pi)
268 return 0;
269
270 /* Mark entry for deletion */
09319b4e 271 bgp_path_info_delete(dest, pi);
c44ab6f1
AK
272
273 /* Perform route selection and update zebra, if required. */
09319b4e 274 ret = bgp_evpn_es_route_select_install(bgp, es, dest);
c44ab6f1
AK
275
276 /* Unlock route node. */
09319b4e 277 bgp_dest_unlock_node(dest);
c44ab6f1
AK
278
279 return ret;
280}
281
282/* Install or unistall a Tyoe-4 route in the per-ES routing table */
283int bgp_evpn_es_route_install_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
284 afi_t afi, safi_t safi, struct prefix_evpn *evp,
285 struct bgp_path_info *pi, int install)
286{
287 int ret = 0;
288
289 if (install)
290 ret = bgp_evpn_es_route_install(bgp, es, evp, pi);
291 else
292 ret = bgp_evpn_es_route_uninstall(bgp, es, evp, pi);
293
294 if (ret) {
295 flog_err(
296 EC_BGP_EVPN_FAIL,
297 "%u: Failed to %s EVPN %s route in ESI %s",
298 bgp->vrf_id,
299 install ? "install" : "uninstall",
300 "ES", es->esi_str);
301 return ret;
302 }
303 return 0;
304}
305
306/* Delete (and withdraw) local routes for specified ES from global and ES table.
307 * Also remove all remote routes from the per ES table. Invoked when ES
308 * is deleted.
185fb14a 309 */
c44ab6f1
AK
310static void bgp_evpn_es_route_del_all(struct bgp *bgp, struct bgp_evpn_es *es)
311{
09319b4e 312 struct bgp_dest *dest;
c44ab6f1
AK
313 struct bgp_path_info *pi, *nextpi;
314
315 /* de-activate the ES */
316 bgp_evpn_local_es_down(bgp, es);
317 bgp_evpn_local_type1_evi_route_del(bgp, es);
318
319 /* Walk this ES's routing table and delete all routes. */
09319b4e
DS
320 for (dest = bgp_table_top(es->route_table); dest;
321 dest = bgp_route_next(dest)) {
322 for (pi = bgp_dest_get_bgp_path_info(dest);
323 (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
324 bgp_path_info_delete(dest, pi);
325 bgp_path_info_reap(dest, pi);
c44ab6f1
AK
326 }
327 }
328}
329
330/*****************************************************************************
331 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
332 * segment updates.
333 */
334
335/* create or update local EVPN type1/type4 route entry.
336 *
337 * This could be in -
338 * the ES table if ESR/EAD-ES (or)
339 * the VNI table if EAD-EVI (or)
340 * the global table if ESR/EAD-ES/EAD-EVI
341 *
342 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
343 * ESR).
344 */
09319b4e
DS
345static int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
346 struct bgpevpn *vpn, afi_t afi, safi_t safi,
347 struct bgp_dest *dest, struct attr *attr,
348 int add, struct bgp_path_info **ri,
349 int *route_changed)
185fb14a 350{
185fb14a
AK
351 struct bgp_path_info *tmp_pi = NULL;
352 struct bgp_path_info *local_pi = NULL; /* local route entry if any */
353 struct bgp_path_info *remote_pi = NULL; /* remote route entry if any */
354 struct attr *attr_new = NULL;
c44ab6f1 355 struct prefix_evpn *evp;
185fb14a
AK
356
357 *ri = NULL;
752eed47 358 evp = (struct prefix_evpn *)bgp_dest_get_prefix(dest);
c44ab6f1 359 *route_changed = 1;
185fb14a
AK
360
361 /* locate the local and remote entries if any */
09319b4e 362 for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
185fb14a
AK
363 tmp_pi = tmp_pi->next) {
364 if (tmp_pi->peer == bgp->peer_self
c44ab6f1
AK
365 && tmp_pi->type == ZEBRA_ROUTE_BGP
366 && tmp_pi->sub_type == BGP_ROUTE_STATIC)
185fb14a
AK
367 local_pi = tmp_pi;
368 if (tmp_pi->type == ZEBRA_ROUTE_BGP
c44ab6f1
AK
369 && tmp_pi->sub_type == BGP_ROUTE_IMPORTED
370 && CHECK_FLAG(tmp_pi->flags, BGP_PATH_VALID))
185fb14a
AK
371 remote_pi = tmp_pi;
372 }
373
c44ab6f1
AK
374 /* we don't expect to see a remote_ri at this point as
375 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
376 * in the VNI-rt-table.
185fb14a
AK
377 */
378 if (remote_pi) {
379 flog_err(
23d0a753
DA
380 EC_BGP_ES_INVALID,
381 "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
382 bgp->vrf_id, es->esi_str, &es->originator_ip);
185fb14a
AK
383 return -1;
384 }
385
386 if (!local_pi && !add)
387 return 0;
388
389 /* create or update the entry */
390 if (!local_pi) {
391
392 /* Add or update attribute to hash */
393 attr_new = bgp_attr_intern(attr);
394
395 /* Create new route with its attribute. */
396 tmp_pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
09319b4e 397 bgp->peer_self, attr_new, dest);
185fb14a
AK
398 SET_FLAG(tmp_pi->flags, BGP_PATH_VALID);
399
c44ab6f1
AK
400 if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) {
401 bgp_path_info_extra_get(tmp_pi);
402 tmp_pi->extra->num_labels = 1;
403 if (vpn)
404 vni2label(vpn->vni, &tmp_pi->extra->label[0]);
405 else
406 tmp_pi->extra->label[0] = 0;
407 }
408
185fb14a 409 /* add the newly created path to the route-node */
09319b4e 410 bgp_path_info_add(dest, tmp_pi);
185fb14a
AK
411 } else {
412 tmp_pi = local_pi;
413 if (attrhash_cmp(tmp_pi->attr, attr)
c44ab6f1 414 && !CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
185fb14a
AK
415 *route_changed = 0;
416 else {
417 /* The attribute has changed.
418 * Add (or update) attribute to hash.
419 */
420 attr_new = bgp_attr_intern(attr);
09319b4e
DS
421 bgp_path_info_set_flag(dest, tmp_pi,
422 BGP_PATH_ATTR_CHANGED);
185fb14a
AK
423
424 /* Restore route, if needed. */
425 if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
09319b4e 426 bgp_path_info_restore(dest, tmp_pi);
185fb14a
AK
427
428 /* Unintern existing, set to new. */
429 bgp_attr_unintern(&tmp_pi->attr);
430 tmp_pi->attr = attr_new;
431 tmp_pi->uptime = bgp_clock();
432 }
433 }
434
c44ab6f1
AK
435 if (*route_changed) {
436 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
23d0a753
DA
437 zlog_debug(
438 "local ES %s vni %u route-type %s nexthop %pI4 updated",
439 es->esi_str, vpn ? vpn->vni : 0,
440 evp->prefix.route_type == BGP_EVPN_ES_ROUTE
441 ? "esr"
442 : (vpn ? "ead-evi" : "ead-es"),
443 &attr->mp_nexthop_global_in);
c44ab6f1
AK
444 }
445
185fb14a
AK
446 /* Return back the route entry. */
447 *ri = tmp_pi;
448 return 0;
449}
450
c44ab6f1
AK
451/* Delete local EVPN ESR (type-4) and EAD (type-1) route
452 *
453 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
454 * ESR).
455 */
456static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
457 struct bgpevpn *vpn, struct prefix_evpn *p)
185fb14a 458{
185fb14a
AK
459 afi_t afi = AFI_L2VPN;
460 safi_t safi = SAFI_EVPN;
c44ab6f1 461 struct bgp_path_info *pi;
09319b4e
DS
462 struct bgp_dest *dest = NULL; /* dest in esi table */
463 struct bgp_dest *global_dest = NULL; /* dest in global table */
c44ab6f1
AK
464 struct bgp_table *rt_table;
465 struct prefix_rd *prd;
185fb14a 466
c44ab6f1
AK
467 if (vpn) {
468 rt_table = vpn->route_table;
469 prd = &vpn->prd;
470 } else {
471 rt_table = es->route_table;
472 prd = &es->prd;
473 }
185fb14a 474
c44ab6f1
AK
475 /* First, locate the route node within the ESI or VNI.
476 * If it doesn't exist, ther is nothing to do.
477 * Note: there is no RD here.
478 */
09319b4e
DS
479 dest = bgp_node_lookup(rt_table, (struct prefix *)p);
480 if (!dest)
c44ab6f1 481 return 0;
185fb14a 482
c44ab6f1 483 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
23d0a753
DA
484 zlog_debug(
485 "local ES %s vni %u route-type %s nexthop %pI4 delete",
486 es->esi_str, vpn ? vpn->vni : 0,
487 p->prefix.route_type == BGP_EVPN_ES_ROUTE
488 ? "esr"
489 : (vpn ? "ead-evi" : "ead-es"),
490 &es->originator_ip);
185fb14a 491
c44ab6f1
AK
492 /* Next, locate route node in the global EVPN routing table.
493 * Note that this table is a 2-level tree (RD-level + Prefix-level)
494 */
09319b4e
DS
495 global_dest =
496 bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
497 (const struct prefix_evpn *)p, prd);
498 if (global_dest) {
185fb14a 499
c44ab6f1 500 /* Delete route entry in the global EVPN table. */
09319b4e 501 delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
185fb14a
AK
502
503 /* Schedule for processing - withdraws to peers happen from
504 * this table.
505 */
506 if (pi)
09319b4e
DS
507 bgp_process(bgp, global_dest, afi, safi);
508 bgp_dest_unlock_node(global_dest);
185fb14a
AK
509 }
510
511 /*
c44ab6f1 512 * Delete route entry in the ESI or VNI routing table.
185fb14a
AK
513 * This can just be removed.
514 */
09319b4e 515 delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
185fb14a 516 if (pi)
09319b4e
DS
517 bgp_path_info_reap(dest, pi);
518 bgp_dest_unlock_node(dest);
185fb14a
AK
519 return 0;
520}
521
c44ab6f1
AK
522/*****************************************************************************
523 * Ethernet Segment (Type-4) Routes
74e2bd89
AK
524 * ESRs are used for DF election. Currently service-carving described in
525 * RFC 7432 is NOT supported. Instead preference based DF election is
526 * used by default.
527 * Reference: draft-ietf-bess-evpn-pref-df
185fb14a 528 */
c44ab6f1
AK
529/* Build extended community for EVPN ES (type-4) route */
530static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es *es,
531 struct attr *attr)
185fb14a 532{
c44ab6f1
AK
533 struct ecommunity ecom_encap;
534 struct ecommunity ecom_es_rt;
74e2bd89 535 struct ecommunity ecom_df;
c44ab6f1
AK
536 struct ecommunity_val eval;
537 struct ecommunity_val eval_es_rt;
74e2bd89 538 struct ecommunity_val eval_df;
c44ab6f1
AK
539 bgp_encap_types tnl_type;
540 struct ethaddr mac;
185fb14a 541
c44ab6f1
AK
542 /* Encap */
543 tnl_type = BGP_ENCAP_TYPE_VXLAN;
544 memset(&ecom_encap, 0, sizeof(ecom_encap));
545 encode_encap_extcomm(tnl_type, &eval);
546 ecom_encap.size = 1;
34540b0d 547 ecom_encap.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
548 ecom_encap.val = (uint8_t *)eval.val;
549 attr->ecommunity = ecommunity_dup(&ecom_encap);
185fb14a 550
c44ab6f1
AK
551 /* ES import RT */
552 memset(&mac, 0, sizeof(struct ethaddr));
553 memset(&ecom_es_rt, 0, sizeof(ecom_es_rt));
554 es_get_system_mac(&es->esi, &mac);
555 encode_es_rt_extcomm(&eval_es_rt, &mac);
556 ecom_es_rt.size = 1;
34540b0d 557 ecom_es_rt.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
558 ecom_es_rt.val = (uint8_t *)eval_es_rt.val;
559 attr->ecommunity =
560 ecommunity_merge(attr->ecommunity, &ecom_es_rt);
185fb14a 561
74e2bd89
AK
562 /* DF election extended community */
563 memset(&ecom_df, 0, sizeof(ecom_df));
564 encode_df_elect_extcomm(&eval_df, es->df_pref);
565 ecom_df.size = 1;
566 ecom_df.val = (uint8_t *)eval_df.val;
567 attr->ecommunity = ecommunity_merge(attr->ecommunity, &ecom_df);
568
c44ab6f1 569 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
185fb14a
AK
570}
571
c44ab6f1
AK
572/* Create or update local type-4 route */
573static int bgp_evpn_type4_route_update(struct bgp *bgp,
574 struct bgp_evpn_es *es, struct prefix_evpn *p)
185fb14a
AK
575{
576 int ret = 0;
c44ab6f1
AK
577 int route_changed = 0;
578 afi_t afi = AFI_L2VPN;
579 safi_t safi = SAFI_EVPN;
580 struct attr attr;
581 struct attr *attr_new = NULL;
09319b4e 582 struct bgp_dest *dest = NULL;
185fb14a 583 struct bgp_path_info *pi = NULL;
185fb14a 584
c44ab6f1
AK
585 memset(&attr, 0, sizeof(struct attr));
586
587 /* Build path-attribute for this route. */
588 bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
589 attr.nexthop = es->originator_ip;
590 attr.mp_nexthop_global_in = es->originator_ip;
591 attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
592
593 /* Set up extended community. */
594 bgp_evpn_type4_route_extcomm_build(es, &attr);
595
596 /* First, create (or fetch) route node within the ESI. */
597 /* NOTE: There is no RD here. */
09319b4e 598 dest = bgp_node_get(es->route_table, (struct prefix *)p);
185fb14a 599
c44ab6f1 600 /* Create or update route entry. */
09319b4e
DS
601 ret = bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest, &attr, 1,
602 &pi, &route_changed);
ec779825 603 if (ret != 0)
23d0a753
DA
604 flog_err(
605 EC_BGP_ES_INVALID,
606 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
607 bgp->vrf_id, es->esi_str, &es->originator_ip);
185fb14a 608
c44ab6f1
AK
609 assert(pi);
610 attr_new = pi->attr;
185fb14a 611
c44ab6f1
AK
612 /* Perform route selection;
613 * this is just to set the flags correctly
614 * as local route in the ES always wins.
615 */
09319b4e
DS
616 bgp_evpn_es_route_select_install(bgp, es, dest);
617 bgp_dest_unlock_node(dest);
185fb14a 618
c44ab6f1
AK
619 /* If this is a new route or some attribute has changed, export the
620 * route to the global table. The route will be advertised to peers
621 * from there. Note that this table is a 2-level tree (RD-level +
622 * Prefix-level) similar to L3VPN routes.
623 */
624 if (route_changed) {
625 struct bgp_path_info *global_pi;
185fb14a 626
09319b4e
DS
627 dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
628 p, &es->prd);
629 bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest,
630 attr_new, 1, &global_pi,
631 &route_changed);
185fb14a 632
c44ab6f1 633 /* Schedule for processing and unlock node. */
09319b4e
DS
634 bgp_process(bgp, dest, afi, safi);
635 bgp_dest_unlock_node(dest);
185fb14a
AK
636 }
637
c44ab6f1
AK
638 /* Unintern temporary. */
639 aspath_unintern(&attr.aspath);
640 return 0;
185fb14a
AK
641}
642
c44ab6f1
AK
643/* Delete local type-4 route */
644static int bgp_evpn_type4_route_delete(struct bgp *bgp,
645 struct bgp_evpn_es *es, struct prefix_evpn *p)
185fb14a 646{
c44ab6f1
AK
647 return bgp_evpn_mh_route_delete(bgp, es, NULL /* l2vni */, p);
648}
185fb14a 649
c44ab6f1
AK
650/* Process remote/received EVPN type-4 route (advertise or withdraw) */
651int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi,
652 struct attr *attr, uint8_t *pfx, int psize,
653 uint32_t addpath_id)
654{
655 int ret;
656 esi_t esi;
657 uint8_t ipaddr_len;
658 struct in_addr vtep_ip;
659 struct prefix_rd prd;
660 struct prefix_evpn p;
185fb14a 661
c44ab6f1
AK
662 /* Type-4 route should be either 23 or 35 bytes
663 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
185fb14a 664 */
c44ab6f1
AK
665 if (psize != BGP_EVPN_TYPE4_V4_PSIZE &&
666 psize != BGP_EVPN_TYPE4_V6_PSIZE) {
667 flog_err(EC_BGP_EVPN_ROUTE_INVALID,
668 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
669 peer->bgp->vrf_id, peer->host, psize);
670 return -1;
671 }
185fb14a 672
c44ab6f1
AK
673 /* Make prefix_rd */
674 prd.family = AF_UNSPEC;
675 prd.prefixlen = 64;
676 memcpy(&prd.val, pfx, RD_BYTES);
677 pfx += RD_BYTES;
185fb14a 678
c44ab6f1
AK
679 /* get the ESI */
680 memcpy(&esi, pfx, ESI_BYTES);
681 pfx += ESI_BYTES;
185fb14a 682
185fb14a 683
c44ab6f1
AK
684 /* Get the IP. */
685 ipaddr_len = *pfx++;
686 if (ipaddr_len == IPV4_MAX_BITLEN) {
687 memcpy(&vtep_ip, pfx, IPV4_MAX_BYTELEN);
688 } else {
689 flog_err(
690 EC_BGP_EVPN_ROUTE_INVALID,
691 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
692 peer->bgp->vrf_id, peer->host, ipaddr_len);
693 return -1;
694 }
185fb14a 695
c44ab6f1
AK
696 build_evpn_type4_prefix(&p, &esi, vtep_ip);
697 /* Process the route. */
698 if (attr) {
699 ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
700 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
701 &prd, NULL, 0, 0, NULL);
702 } else {
703 ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
704 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
705 &prd, NULL, 0, NULL);
706 }
185fb14a
AK
707 return ret;
708}
709
c44ab6f1
AK
710/* Check if a prefix belongs to the local ES */
711static bool bgp_evpn_type4_prefix_match(struct prefix_evpn *p,
712 struct bgp_evpn_es *es)
185fb14a 713{
c44ab6f1
AK
714 return (p->prefix.route_type == BGP_EVPN_ES_ROUTE) &&
715 !memcmp(&p->prefix.es_addr.esi, &es->esi, sizeof(esi_t));
185fb14a
AK
716}
717
c44ab6f1
AK
718/* Import remote ESRs on local ethernet segment add */
719static int bgp_evpn_type4_remote_routes_import(struct bgp *bgp,
720 struct bgp_evpn_es *es, bool install)
185fb14a
AK
721{
722 int ret;
723 afi_t afi;
724 safi_t safi;
09319b4e 725 struct bgp_dest *rd_dest, *dest;
185fb14a
AK
726 struct bgp_table *table;
727 struct bgp_path_info *pi;
728
729 afi = AFI_L2VPN;
730 safi = SAFI_EVPN;
731
c44ab6f1
AK
732 /* Walk entire global routing table and evaluate routes which could be
733 * imported into this Ethernet Segment.
185fb14a 734 */
09319b4e
DS
735 for (rd_dest = bgp_table_top(bgp->rib[afi][safi]); rd_dest;
736 rd_dest = bgp_route_next(rd_dest)) {
737 table = bgp_dest_get_bgp_table_info(rd_dest);
185fb14a
AK
738 if (!table)
739 continue;
740
09319b4e
DS
741 for (dest = bgp_table_top(table); dest;
742 dest = bgp_route_next(dest)) {
743 struct prefix_evpn *evp =
752eed47 744 (struct prefix_evpn *)bgp_dest_get_prefix(dest);
185fb14a 745
09319b4e
DS
746 for (pi = bgp_dest_get_bgp_path_info(dest); pi;
747 pi = pi->next) {
185fb14a
AK
748 /*
749 * Consider "valid" remote routes applicable for
750 * this ES.
751 */
752 if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
c44ab6f1
AK
753 && pi->type == ZEBRA_ROUTE_BGP
754 && pi->sub_type == BGP_ROUTE_NORMAL))
185fb14a
AK
755 continue;
756
c44ab6f1 757 if (!bgp_evpn_type4_prefix_match(evp, es))
185fb14a
AK
758 continue;
759
760 if (install)
c44ab6f1
AK
761 ret = bgp_evpn_es_route_install(
762 bgp, es, evp, pi);
185fb14a 763 else
c44ab6f1
AK
764 ret = bgp_evpn_es_route_uninstall(
765 bgp, es, evp, pi);
185fb14a
AK
766
767 if (ret) {
768 flog_err(
2dbe669b
DA
769 EC_BGP_EVPN_FAIL,
770 "Failed to %s EVPN %pFX route in ESI %s",
771 install ? "install"
185fb14a 772 : "uninstall",
2dbe669b 773 evp, es->esi_str);
dc52bece
DS
774
775 bgp_dest_unlock_node(rd_dest);
776 bgp_dest_unlock_node(dest);
185fb14a
AK
777 return ret;
778 }
779 }
780 }
781 }
782 return 0;
783}
784
c44ab6f1
AK
785/*****************************************************************************
786 * Ethernet Auto Discovery (EAD/Type-1) route handling
787 * There are two types of EAD routes -
788 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
789 * 2. EAD-per-EVI - Key: {ESI, ET=0}
185fb14a 790 */
185fb14a 791
c44ab6f1
AK
792/* Extended communities associated with EAD-per-ES */
793static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es *es,
794 struct attr *attr)
185fb14a 795{
c44ab6f1
AK
796 struct ecommunity ecom_encap;
797 struct ecommunity ecom_esi_label;
798 struct ecommunity_val eval;
799 struct ecommunity_val eval_esi_label;
800 bgp_encap_types tnl_type;
801 struct listnode *evi_node, *rt_node;
802 struct ecommunity *ecom;
803 struct bgp_evpn_es_evi *es_evi;
185fb14a 804
c44ab6f1
AK
805 /* Encap */
806 tnl_type = BGP_ENCAP_TYPE_VXLAN;
807 memset(&ecom_encap, 0, sizeof(ecom_encap));
808 encode_encap_extcomm(tnl_type, &eval);
809 ecom_encap.size = 1;
34540b0d 810 ecom_encap.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
811 ecom_encap.val = (uint8_t *)eval.val;
812 attr->ecommunity = ecommunity_dup(&ecom_encap);
185fb14a 813
c44ab6f1
AK
814 /* ESI label */
815 encode_esi_label_extcomm(&eval_esi_label,
816 false /*single_active*/);
817 ecom_esi_label.size = 1;
34540b0d 818 ecom_esi_label.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
819 ecom_esi_label.val = (uint8_t *)eval_esi_label.val;
820 attr->ecommunity =
821 ecommunity_merge(attr->ecommunity, &ecom_esi_label);
822
823 /* Add export RTs for all L2-VNIs associated with this ES */
824 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
825 * with it.
826 */
827 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
828 evi_node, es_evi)) {
829 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
830 continue;
831 for (ALL_LIST_ELEMENTS_RO(es_evi->vpn->export_rtl,
832 rt_node, ecom))
833 attr->ecommunity = ecommunity_merge(attr->ecommunity,
834 ecom);
835 }
836
837 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
838}
839
840/* Extended communities associated with EAD-per-EVI */
841static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es *es,
842 struct bgpevpn *vpn, struct attr *attr)
843{
844 struct ecommunity ecom_encap;
845 struct ecommunity_val eval;
846 bgp_encap_types tnl_type;
847 struct listnode *rt_node;
848 struct ecommunity *ecom;
849
850 /* Encap */
851 tnl_type = BGP_ENCAP_TYPE_VXLAN;
852 memset(&ecom_encap, 0, sizeof(ecom_encap));
853 encode_encap_extcomm(tnl_type, &eval);
854 ecom_encap.size = 1;
7659ad68 855 ecom_encap.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
856 ecom_encap.val = (uint8_t *)eval.val;
857 attr->ecommunity = ecommunity_dup(&ecom_encap);
858
859 /* Add export RTs for the L2-VNI */
860 for (ALL_LIST_ELEMENTS_RO(vpn->export_rtl, rt_node, ecom))
861 attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
862
863 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
864}
865
866/* Update EVPN EAD (type-1) route -
867 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
868 */
869static int bgp_evpn_type1_route_update(struct bgp *bgp,
870 struct bgp_evpn_es *es, struct bgpevpn *vpn,
871 struct prefix_evpn *p)
872{
873 int ret = 0;
874 afi_t afi = AFI_L2VPN;
875 safi_t safi = SAFI_EVPN;
876 struct attr attr;
877 struct attr *attr_new = NULL;
09319b4e 878 struct bgp_dest *dest = NULL;
c44ab6f1
AK
879 struct bgp_path_info *pi = NULL;
880 int route_changed = 0;
881 struct prefix_rd *global_rd;
882
883 memset(&attr, 0, sizeof(struct attr));
884
885 /* Build path-attribute for this route. */
886 bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
887 attr.nexthop = es->originator_ip;
888 attr.mp_nexthop_global_in = es->originator_ip;
889 attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
890
891 if (vpn) {
892 /* EAD-EVI route update */
893 /* MPLS label */
894 vni2label(vpn->vni, &(attr.label));
895
896 /* Set up extended community */
897 bgp_evpn_type1_evi_route_extcomm_build(es, vpn, &attr);
898
899 /* First, create (or fetch) route node within the VNI. */
09319b4e 900 dest = bgp_node_get(vpn->route_table, (struct prefix *)p);
c44ab6f1
AK
901
902 /* Create or update route entry. */
09319b4e
DS
903 ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
904 &attr, 1, &pi, &route_changed);
ec779825 905 if (ret != 0)
23d0a753
DA
906 flog_err(
907 EC_BGP_ES_INVALID,
908 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
909 bgp->vrf_id, es->esi_str, vpn->vni,
910 &es->originator_ip);
c44ab6f1
AK
911 global_rd = &vpn->prd;
912 } else {
913 /* EAD-ES route update */
914 /* MPLS label is 0 for EAD-ES route */
915
916 /* Set up extended community */
917 bgp_evpn_type1_es_route_extcomm_build(es, &attr);
918
919 /* First, create (or fetch) route node within the ES. */
920 /* NOTE: There is no RD here. */
921 /* XXX: fragment ID must be included as a part of the prefix. */
09319b4e 922 dest = bgp_node_get(es->route_table, (struct prefix *)p);
c44ab6f1
AK
923
924 /* Create or update route entry. */
09319b4e
DS
925 ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
926 &attr, 1, &pi, &route_changed);
c44ab6f1 927 if (ret != 0) {
23d0a753
DA
928 flog_err(
929 EC_BGP_ES_INVALID,
930 "%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %pI4",
931 bgp->vrf_id, es->esi_str, &es->originator_ip);
c44ab6f1
AK
932 }
933 global_rd = &es->prd;
934 }
935
936
937 assert(pi);
938 attr_new = pi->attr;
939
940 /* Perform route selection;
941 * this is just to set the flags correctly as local route in
942 * the ES always wins.
943 */
09319b4e
DS
944 evpn_route_select_install(bgp, vpn, dest);
945 bgp_dest_unlock_node(dest);
c44ab6f1
AK
946
947 /* If this is a new route or some attribute has changed, export the
948 * route to the global table. The route will be advertised to peers
949 * from there. Note that this table is a 2-level tree (RD-level +
950 * Prefix-level) similar to L3VPN routes.
951 */
952 if (route_changed) {
953 struct bgp_path_info *global_pi;
954
09319b4e
DS
955 dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
956 p, global_rd);
957 bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
958 attr_new, 1, &global_pi,
959 &route_changed);
c44ab6f1
AK
960
961 /* Schedule for processing and unlock node. */
09319b4e
DS
962 bgp_process(bgp, dest, afi, safi);
963 bgp_dest_unlock_node(dest);
c44ab6f1
AK
964 }
965
966 /* Unintern temporary. */
967 aspath_unintern(&attr.aspath);
968 return 0;
969}
970
971/* Delete local Type-1 route */
972static int bgp_evpn_type1_es_route_delete(struct bgp *bgp,
973 struct bgp_evpn_es *es, struct prefix_evpn *p)
974{
975 return bgp_evpn_mh_route_delete(bgp, es, NULL /* l2vni */, p);
976}
977
978static int bgp_evpn_type1_evi_route_delete(struct bgp *bgp,
979 struct bgp_evpn_es *es, struct bgpevpn *vpn,
980 struct prefix_evpn *p)
981{
982 return bgp_evpn_mh_route_delete(bgp, es, vpn, p);
983}
984
985/* Generate EAD-EVI for all VNIs */
986static void bgp_evpn_local_type1_evi_route_add(struct bgp *bgp,
987 struct bgp_evpn_es *es)
988{
989 struct listnode *evi_node;
990 struct prefix_evpn p;
991 struct bgp_evpn_es_evi *es_evi;
992
993 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
994 /* EAD-EVI route add for this ES is already done */
995 return;
996
997 SET_FLAG(es->flags, BGP_EVPNES_ADV_EVI);
998 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
999 &es->esi, es->originator_ip);
1000
1001 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, evi_node, es_evi)) {
1002 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
1003 continue;
1004 if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn, &p))
1005 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1006 "%u: Type4 route creation failure for ESI %s",
1007 bgp->vrf_id, es->esi_str);
1008 }
1009}
1010
1011/*
1012 * Withdraw EAD-EVI for all VNIs
1013 */
1014static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp,
1015 struct bgp_evpn_es *es)
1016{
1017 struct listnode *evi_node;
1018 struct prefix_evpn p;
1019 struct bgp_evpn_es_evi *es_evi;
1020
1021 /* Delete and withdraw locally learnt EAD-EVI route */
1022 if (!CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
1023 /* EAD-EVI route has not been advertised for this ES */
1024 return;
1025
1026 UNSET_FLAG(es->flags, BGP_EVPNES_ADV_EVI);
1027 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
1028 &es->esi, es->originator_ip);
1029 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, evi_node, es_evi)) {
1030 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
1031 continue;
1032 if (bgp_evpn_mh_route_delete(bgp, es, es_evi->vpn, &p))
1033 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1034 "%u: Type4 route creation failure for ESI %s",
1035 bgp->vrf_id, es->esi_str);
1036 }
1037}
185fb14a
AK
1038
1039/*
c44ab6f1 1040 * Process received EVPN type-1 route (advertise or withdraw).
185fb14a 1041 */
c44ab6f1
AK
1042int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
1043 struct attr *attr, uint8_t *pfx, int psize,
1044 uint32_t addpath_id)
185fb14a
AK
1045{
1046 int ret;
c44ab6f1 1047 struct prefix_rd prd;
185fb14a 1048 esi_t esi;
c44ab6f1
AK
1049 uint32_t eth_tag;
1050 mpls_label_t label;
185fb14a 1051 struct in_addr vtep_ip;
185fb14a
AK
1052 struct prefix_evpn p;
1053
c44ab6f1 1054 if (psize != BGP_EVPN_TYPE1_PSIZE) {
185fb14a 1055 flog_err(EC_BGP_EVPN_ROUTE_INVALID,
c44ab6f1
AK
1056 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1057 peer->bgp->vrf_id, peer->host, psize);
185fb14a
AK
1058 return -1;
1059 }
1060
1061 /* Make prefix_rd */
1062 prd.family = AF_UNSPEC;
1063 prd.prefixlen = 64;
c44ab6f1
AK
1064 memcpy(&prd.val, pfx, RD_BYTES);
1065 pfx += RD_BYTES;
185fb14a
AK
1066
1067 /* get the ESI */
1068 memcpy(&esi, pfx, ESI_BYTES);
1069 pfx += ESI_BYTES;
1070
c44ab6f1
AK
1071 /* Copy Ethernet Tag */
1072 memcpy(&eth_tag, pfx, EVPN_ETH_TAG_BYTES);
1073 eth_tag = ntohl(eth_tag);
1074 pfx += EVPN_ETH_TAG_BYTES;
185fb14a 1075
c44ab6f1 1076 memcpy(&label, pfx, BGP_LABEL_BYTES);
185fb14a 1077
c44ab6f1
AK
1078 /* EAD route prefix doesn't include the nexthop in the global
1079 * table
1080 */
1081 vtep_ip.s_addr = 0;
1082 build_evpn_type1_prefix(&p, eth_tag, &esi, vtep_ip);
185fb14a
AK
1083 /* Process the route. */
1084 if (attr) {
1085 ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
c44ab6f1
AK
1086 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
1087 &prd, NULL, 0, 0, NULL);
185fb14a
AK
1088 } else {
1089 ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
c44ab6f1
AK
1090 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
1091 &prd, NULL, 0, NULL);
185fb14a
AK
1092 }
1093 return ret;
1094}
1095
c44ab6f1
AK
1096/*****************************************************************************/
1097/* Ethernet Segment Management
1098 * 1. Ethernet Segment is a collection of links attached to the same
1099 * server (MHD) or switch (MHN)
1100 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1101 * 10-byte ES-ID.
1102 * 3. Local ESs are configured in zebra and sent to BGP
1103 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1104 * created on first reference and release on last de-reference
1105 * 5. An ES can be both local and remote. Infact most local ESs are expected
1106 * to have an ES peer.
1107 */
1108
1109/* A list of remote VTEPs is maintained for each ES. This list includes -
1110 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1111 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1112 * have been imported into one or more VNIs
185fb14a 1113 */
c44ab6f1
AK
1114static int bgp_evpn_es_vtep_cmp(void *p1, void *p2)
1115{
1116 const struct bgp_evpn_es_vtep *es_vtep1 = p1;
1117 const struct bgp_evpn_es_vtep *es_vtep2 = p2;
1118
1119 return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
1120}
1121
1122static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_new(struct bgp_evpn_es *es,
1123 struct in_addr vtep_ip)
1124{
1125 struct bgp_evpn_es_vtep *es_vtep;
1126
1127 es_vtep = XCALLOC(MTYPE_BGP_EVPN_ES_VTEP, sizeof(*es_vtep));
1128
1129 es_vtep->es = es;
1130 es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
1131 listnode_init(&es_vtep->es_listnode, es_vtep);
1132 listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
1133
1134 return es_vtep;
1135}
1136
1137static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep *es_vtep)
1138{
1139 struct bgp_evpn_es *es = es_vtep->es;
1140
1141 if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR) ||
1142 es_vtep->evi_cnt)
1143 /* as long as there is some reference we can't free it */
1144 return;
1145
1146 list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
1147 XFREE(MTYPE_BGP_EVPN_ES_VTEP, es_vtep);
1148}
1149
1150/* check if VTEP is already part of the list */
1151static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_find(struct bgp_evpn_es *es,
1152 struct in_addr vtep_ip)
1153{
1154 struct listnode *node = NULL;
1155 struct bgp_evpn_es_vtep *es_vtep;
1156
1157 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1158 if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1159 return es_vtep;
1160 }
1161 return NULL;
1162}
1163
1164/* Send the remote ES to zebra for NHG programming */
1165static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp,
1166 struct bgp_evpn_es_vtep *es_vtep, bool add)
1167{
1168 struct bgp_evpn_es *es = es_vtep->es;
1169 struct stream *s;
74e2bd89 1170 uint32_t flags = 0;
c44ab6f1
AK
1171
1172 /* Check socket. */
1173 if (!zclient || zclient->sock < 0)
1174 return 0;
1175
1176 /* Don't try to register if Zebra doesn't know of this instance. */
1177 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
1178 if (BGP_DEBUG(zebra, ZEBRA))
1179 zlog_debug("No zebra instance, not installing remote es %s",
1180 es->esi_str);
1181 return 0;
1182 }
1183
74e2bd89
AK
1184 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
1185 flags |= ZAPI_ES_VTEP_FLAG_ESR_RXED;
1186
c44ab6f1
AK
1187 s = zclient->obuf;
1188 stream_reset(s);
1189
1190 zclient_create_header(s,
1191 add ? ZEBRA_REMOTE_ES_VTEP_ADD : ZEBRA_REMOTE_ES_VTEP_DEL,
1192 bgp->vrf_id);
1193 stream_put(s, &es->esi, sizeof(esi_t));
1194 stream_put_ipv4(s, es_vtep->vtep_ip.s_addr);
74e2bd89
AK
1195 if (add) {
1196 stream_putl(s, flags);
1197 stream_putc(s, es_vtep->df_alg);
1198 stream_putw(s, es_vtep->df_pref);
1199 }
c44ab6f1
AK
1200
1201 stream_putw_at(s, 0, stream_get_endp(s));
1202
1203 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1204 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add ? "ADD" : "DEL",
1205 es->esi_str, &es_vtep->vtep_ip);
c44ab6f1
AK
1206
1207 return zclient_send_message(zclient);
1208}
1209
1210static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
74e2bd89
AK
1211 struct bgp_evpn_es_vtep *es_vtep,
1212 bool param_change)
c44ab6f1
AK
1213{
1214 bool old_active;
1215 bool new_active;
1216
1217 old_active = !!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1218 /* currently we need an active EVI reference to use the VTEP as
1219 * a nexthop. this may change...
1220 */
1221 if (es_vtep->evi_cnt)
1222 SET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1223 else
1224 UNSET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1225
1226 new_active = !!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1227
74e2bd89 1228 if ((old_active != new_active) || (new_active && param_change)) {
c44ab6f1 1229
74e2bd89
AK
1230 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1231 zlog_debug("es %s vtep %pI4 %s df %u/%u",
1232 es_vtep->es->esi_str, &es_vtep->vtep_ip,
1233 new_active ? "active" : "inactive",
1234 es_vtep->df_alg, es_vtep->df_pref);
c44ab6f1 1235
74e2bd89
AK
1236 /* send remote ES to zebra */
1237 bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active);
c44ab6f1 1238
8bcb09a1
AK
1239 /* The NHG is updated first for efficient failover handling.
1240 * Note the NHG can be de-activated while there are bgp
1241 * routes referencing it. Zebra is capable of handling that
1242 * elegantly by holding the NHG till all routes using it are
1243 * removed.
26c03e43 1244 */
8bcb09a1
AK
1245 bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep->es);
1246 bgp_evpn_es_path_all_update(es_vtep, new_active);
c589d847 1247
74e2bd89
AK
1248 /* queue up the es for background consistency checks */
1249 bgp_evpn_es_cons_checks_pend_add(es_vtep->es);
1250 }
c44ab6f1
AK
1251}
1252
1253static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
74e2bd89
AK
1254 struct bgp_evpn_es *es,
1255 struct in_addr vtep_ip,
1256 bool esr, uint8_t df_alg,
1257 uint16_t df_pref)
c44ab6f1
AK
1258{
1259 struct bgp_evpn_es_vtep *es_vtep;
74e2bd89 1260 bool param_change = false;
c44ab6f1
AK
1261
1262 es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip);
1263
1264 if (!es_vtep)
1265 es_vtep = bgp_evpn_es_vtep_new(es, vtep_ip);
1266
1267 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
74e2bd89
AK
1268 zlog_debug("es %s vtep %pI4 add %s df %u/%u",
1269 es_vtep->es->esi_str, &es_vtep->vtep_ip,
1270 esr ? "esr" : "ead", df_alg, df_pref);
c44ab6f1 1271
74e2bd89 1272 if (esr) {
c44ab6f1 1273 SET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR);
74e2bd89
AK
1274 if ((es_vtep->df_pref != df_pref)
1275 || (es_vtep->df_alg != df_alg)) {
1276 param_change = true;
1277 es_vtep->df_pref = df_pref;
1278 es_vtep->df_alg = df_alg;
1279 }
1280 } else {
c44ab6f1 1281 ++es_vtep->evi_cnt;
74e2bd89 1282 }
c44ab6f1 1283
74e2bd89 1284 bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change);
c44ab6f1
AK
1285
1286 return es_vtep;
1287}
1288
1289static void bgp_evpn_es_vtep_do_del(struct bgp *bgp,
1290 struct bgp_evpn_es_vtep *es_vtep, bool esr)
1291{
74e2bd89
AK
1292 bool param_change = false;
1293
c44ab6f1 1294 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1295 zlog_debug("es %s vtep %pI4 del %s", es_vtep->es->esi_str,
1296 &es_vtep->vtep_ip, esr ? "esr" : "ead");
c44ab6f1
AK
1297 if (esr) {
1298 UNSET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR);
74e2bd89
AK
1299 if (es_vtep->df_pref || es_vtep->df_alg) {
1300 param_change = true;
1301 es_vtep->df_pref = 0;
1302 es_vtep->df_alg = 0;
1303 }
c44ab6f1
AK
1304 } else {
1305 if (es_vtep->evi_cnt)
1306 --es_vtep->evi_cnt;
1307 }
1308
74e2bd89 1309 bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change);
c44ab6f1
AK
1310 bgp_evpn_es_vtep_free(es_vtep);
1311}
1312
1313static void bgp_evpn_es_vtep_del(struct bgp *bgp,
1314 struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr)
1315{
1316 struct bgp_evpn_es_vtep *es_vtep;
1317
1318 es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip);
1319 if (es_vtep)
1320 bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr);
1321}
1322
26c03e43
AK
1323bool bgp_evpn_es_is_vtep_active(esi_t *esi, struct in_addr nh)
1324{
1325 struct bgp_evpn_es *es;
1326 struct bgp_evpn_es_vtep *es_vtep;
1327 struct listnode *node = NULL;
1328 bool rc = false;
1329
1330 if (!memcmp(esi, zero_esi, sizeof(*esi)) || !nh.s_addr)
1331 return true;
1332
1333 es = bgp_evpn_es_find(esi);
1334 if (!es)
1335 return false;
1336
1337 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1338 if (es_vtep->vtep_ip.s_addr == nh.s_addr) {
1339 if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
1340 rc = true;
1341 break;
1342 }
1343 }
1344 return rc;
1345}
1346
1347/********************** ES MAC-IP paths *************************************
1348 * MAC-IP routes in the VNI routing table are linked to the destination
1349 * ES for efficient updates on ES changes (such as VTEP add/del).
1350 ****************************************************************************/
1351void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info)
1352{
1353 bgp_evpn_path_es_unlink(es_info);
1354 XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO, es_info);
1355}
1356
1357static struct bgp_path_es_info *
1358bgp_evpn_path_es_info_new(struct bgp_path_info *pi, vni_t vni)
1359{
1360 struct bgp_path_info_extra *e;
1361
1362 e = bgp_path_info_extra_get(pi);
1363
1364 /* If es_info doesn't exist allocate it */
1365 if (!e->es_info) {
1366 e->es_info = XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO,
1367 sizeof(struct bgp_path_es_info));
1368 e->es_info->pi = pi;
1369 e->es_info->vni = vni;
1370 }
1371
1372 return e->es_info;
1373}
1374
1375void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info)
1376{
1377 struct bgp_evpn_es *es = es_info->es;
1378 struct bgp_path_info *pi;
26c03e43
AK
1379
1380 if (!es)
1381 return;
1382
1383 pi = es_info->pi;
1384 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
229587fb
AK
1385 zlog_debug("vni %u path %pFX unlinked from es %s", es_info->vni,
1386 &pi->net->p, es->esi_str);
26c03e43
AK
1387
1388 list_delete_node(es->macip_path_list, &es_info->es_listnode);
1389 es_info->es = NULL;
1390
1391 /* if there are no other references against the ES it
1392 * needs to be freed
1393 */
1394 bgp_evpn_es_free(es, __func__);
1395
1396 /* Note we don't free the path es_info on unlink; it will be freed up
1397 * along with the path.
1398 */
1399}
1400
1401void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
1402{
1403 struct bgp_path_es_info *es_info;
1404 struct bgp_evpn_es *es;
1405 struct bgp *bgp_evpn = bgp_get_evpn();
26c03e43
AK
1406
1407 es_info = pi->extra ? pi->extra->es_info : NULL;
1408 /* if the esi is zero just unlink the path from the old es */
1409 if (!esi || !memcmp(esi, zero_esi, sizeof(*esi))) {
1410 if (es_info)
1411 bgp_evpn_path_es_unlink(es_info);
1412 return;
1413 }
1414
1415 if (!bgp_evpn)
1416 return;
1417
1418 /* setup es_info against the path if it doesn't aleady exist */
1419 if (!es_info)
1420 es_info = bgp_evpn_path_es_info_new(pi, vni);
1421
1422 /* find-create ES */
1423 es = bgp_evpn_es_find(esi);
1424 if (!es)
f61fbf21 1425 es = bgp_evpn_es_new(bgp_evpn, esi);
26c03e43
AK
1426
1427 /* dup check */
1428 if (es_info->es == es)
1429 return;
1430
1431 /* unlink old ES if any */
1432 bgp_evpn_path_es_unlink(es_info);
1433
1434 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
229587fb
AK
1435 zlog_debug("vni %u path %pFX linked to es %s", vni, &pi->net->p,
1436 es->esi_str);
26c03e43
AK
1437
1438 /* link mac-ip path to the new destination ES */
1439 es_info->es = es;
1440 listnode_init(&es_info->es_listnode, es_info);
229587fb 1441 listnode_add(es->macip_path_list, &es_info->es_listnode);
26c03e43
AK
1442}
1443
1444static void bgp_evpn_es_path_all_update(struct bgp_evpn_es_vtep *es_vtep,
1445 bool active)
1446{
1447 struct listnode *node;
1448 struct bgp_path_es_info *es_info;
1449 struct bgp_path_info *pi;
1450 struct bgp_path_info *parent_pi;
1451 struct bgp_evpn_es *es = es_vtep->es;
1452 char prefix_buf[PREFIX_STRLEN];
1453
1454 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
1455 zlog_debug("update all paths linked to es %s", es->esi_str);
1456
1457 for (ALL_LIST_ELEMENTS_RO(es->macip_path_list, node, es_info)) {
1458 pi = es_info->pi;
229587fb
AK
1459 if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID))
1460 continue;
1461
26c03e43
AK
1462 if (pi->sub_type != BGP_ROUTE_IMPORTED)
1463 continue;
1464
1465 parent_pi = pi->extra ? pi->extra->parent : NULL;
1466 if (!parent_pi || !parent_pi->attr)
1467 continue;
1468
1469 if (es_vtep->vtep_ip.s_addr != parent_pi->attr->nexthop.s_addr)
1470 continue;
1471
1472 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
1473 zlog_debug("update path %s linked to es %s",
1474 prefix2str(&parent_pi->net->p, prefix_buf,
1475 sizeof(prefix_buf)),
1476 es->esi_str);
1477 bgp_evpn_import_route_in_vrfs(parent_pi, active ? 1 : 0);
1478 }
1479}
1480
c44ab6f1
AK
1481/* compare ES-IDs for the global ES RB tree */
1482static int bgp_es_rb_cmp(const struct bgp_evpn_es *es1,
1483 const struct bgp_evpn_es *es2)
1484{
1485 return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
1486}
1487RB_GENERATE(bgp_es_rb_head, bgp_evpn_es, rb_node, bgp_es_rb_cmp);
1488
1489struct bgp_evpn_es *bgp_evpn_es_find(const esi_t *esi)
185fb14a 1490{
c44ab6f1 1491 struct bgp_evpn_es tmp;
185fb14a 1492
185fb14a 1493 memcpy(&tmp.esi, esi, sizeof(esi_t));
c44ab6f1 1494 return RB_FIND(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, &tmp);
185fb14a
AK
1495}
1496
c44ab6f1 1497static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
185fb14a 1498{
c44ab6f1 1499 struct bgp_evpn_es *es;
185fb14a
AK
1500
1501 if (!bgp)
1502 return NULL;
1503
c44ab6f1 1504 es = XCALLOC(MTYPE_BGP_EVPN_ES, sizeof(struct bgp_evpn_es));
185fb14a 1505
c44ab6f1 1506 /* set the ESI */
185fb14a 1507 memcpy(&es->esi, esi, sizeof(esi_t));
185fb14a
AK
1508
1509 /* Initialise the VTEP list */
c44ab6f1
AK
1510 es->es_vtep_list = list_new();
1511 listset_app_node_mem(es->es_vtep_list);
1512 es->es_vtep_list->cmp = bgp_evpn_es_vtep_cmp;
185fb14a 1513
c44ab6f1 1514 esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
185fb14a 1515
c44ab6f1 1516 /* Initialize the ES routing table */
185fb14a
AK
1517 es->route_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
1518
c44ab6f1
AK
1519 /* Add to rb_tree */
1520 if (RB_INSERT(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, es)) {
185fb14a
AK
1521 XFREE(MTYPE_BGP_EVPN_ES, es);
1522 return NULL;
1523 }
1524
c44ab6f1
AK
1525 /* Initialise the ES-EVI list */
1526 es->es_evi_list = list_new();
1527 listset_app_node_mem(es->es_evi_list);
1528
c589d847
AK
1529 /* Initialise the ES-VRF list used for L3NHG management */
1530 es->es_vrf_list = list_new();
1531 listset_app_node_mem(es->es_vrf_list);
1532
26c03e43
AK
1533 /* Initialise the route list used for efficient event handling */
1534 es->macip_path_list = list_new();
1535 listset_app_node_mem(es->macip_path_list);
1536
c44ab6f1
AK
1537 QOBJ_REG(es, bgp_evpn_es);
1538
185fb14a
AK
1539 return es;
1540}
1541
c44ab6f1 1542/* Free a given ES -
185fb14a
AK
1543 * This just frees appropriate memory, caller should have taken other
1544 * needed actions.
1545 */
45a859f1 1546static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
185fb14a 1547{
26c03e43
AK
1548 if ((es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))
1549 || listcount(es->macip_path_list))
c44ab6f1
AK
1550 return;
1551
45a859f1
AK
1552 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1553 zlog_debug("%s: es %s free", caller, es->esi_str);
1554
c44ab6f1
AK
1555 /* cleanup resources maintained against the ES */
1556 list_delete(&es->es_evi_list);
c589d847 1557 list_delete(&es->es_vrf_list);
c44ab6f1 1558 list_delete(&es->es_vtep_list);
26c03e43 1559 list_delete(&es->macip_path_list);
185fb14a 1560 bgp_table_unlock(es->route_table);
c44ab6f1
AK
1561
1562 /* remove the entry from various databases */
1563 RB_REMOVE(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, es);
1564 bgp_evpn_es_cons_checks_pend_del(es);
1565
185fb14a
AK
1566 QOBJ_UNREG(es);
1567 XFREE(MTYPE_BGP_EVPN_ES, es);
1568}
1569
c44ab6f1
AK
1570/* init local info associated with the ES */
1571static void bgp_evpn_es_local_info_set(struct bgp *bgp, struct bgp_evpn_es *es)
185fb14a 1572{
c44ab6f1 1573 char buf[BGP_EVPN_PREFIX_RD_LEN];
185fb14a 1574
c44ab6f1
AK
1575 if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1576 return;
185fb14a 1577
c44ab6f1
AK
1578 SET_FLAG(es->flags, BGP_EVPNES_LOCAL);
1579 listnode_init(&es->es_listnode, es);
1580 listnode_add(bgp_mh_info->local_es_list, &es->es_listnode);
185fb14a 1581
c44ab6f1
AK
1582 /* auto derive RD for this es */
1583 bf_assign_index(bm->rd_idspace, es->rd_id);
1584 es->prd.family = AF_UNSPEC;
1585 es->prd.prefixlen = 64;
23d0a753 1586 snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, es->rd_id);
c44ab6f1
AK
1587 (void)str2prefix_rd(buf, &es->prd);
1588}
1589
1590/* clear any local info associated with the ES */
1591static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es *es)
1592{
1593 if (!CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1594 return;
185fb14a 1595
c44ab6f1 1596 UNSET_FLAG(es->flags, BGP_EVPNES_LOCAL);
185fb14a 1597
c44ab6f1
AK
1598 /* remove from the ES local list */
1599 list_delete_node(bgp_mh_info->local_es_list, &es->es_listnode);
1600
1601 bf_release_index(bm->rd_idspace, es->rd_id);
1602
45a859f1 1603 bgp_evpn_es_free(es, __func__);
185fb14a
AK
1604}
1605
c44ab6f1
AK
1606/* eval remote info associated with the ES */
1607static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es *es)
1608{
1609 if (es->remote_es_evi_cnt) {
1610 SET_FLAG(es->flags, BGP_EVPNES_REMOTE);
1611 } else {
1612 if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE)) {
1613 UNSET_FLAG(es->flags, BGP_EVPNES_REMOTE);
45a859f1 1614 bgp_evpn_es_free(es, __func__);
c44ab6f1
AK
1615 }
1616 }
1617}
1618
1619/* Process ES link oper-down by withdrawing ES-EAD and ESR */
1620static void bgp_evpn_local_es_down(struct bgp *bgp,
1621 struct bgp_evpn_es *es)
185fb14a 1622{
185fb14a 1623 struct prefix_evpn p;
c44ab6f1 1624 int ret;
185fb14a 1625
c44ab6f1
AK
1626 if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP))
1627 return;
185fb14a 1628
c44ab6f1 1629 UNSET_FLAG(es->flags, BGP_EVPNES_OPER_UP);
185fb14a 1630
c44ab6f1
AK
1631 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1632 zlog_debug("local es %s down", es->esi_str);
1633
1634 /* withdraw ESR */
1635 /* Delete and withdraw locally learnt ES route */
1636 build_evpn_type4_prefix(&p, &es->esi, es->originator_ip);
1637 ret = bgp_evpn_type4_route_delete(bgp, es, &p);
1638 if (ret) {
1639 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
1640 "%u failed to delete type-4 route for ESI %s",
1641 bgp->vrf_id, es->esi_str);
185fb14a
AK
1642 }
1643
c44ab6f1
AK
1644 /* withdraw EAD-EVI */
1645 if (!bgp_mh_info->ead_evi_adv_for_down_links)
1646 bgp_evpn_local_type1_evi_route_del(bgp, es);
185fb14a 1647
c44ab6f1
AK
1648 /* withdraw EAD-ES */
1649 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
1650 &es->esi, es->originator_ip);
1651 ret = bgp_evpn_type1_es_route_delete(bgp, es, &p);
1652 if (ret) {
1653 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
1654 "%u failed to delete type-1 route for ESI %s",
1655 bgp->vrf_id, es->esi_str);
1656 }
1657}
1658
1659/* Process ES link oper-up by generating ES-EAD and ESR */
74e2bd89
AK
1660static void bgp_evpn_local_es_up(struct bgp *bgp, struct bgp_evpn_es *es,
1661 bool regen_esr)
c44ab6f1
AK
1662{
1663 struct prefix_evpn p;
74e2bd89 1664 bool regen_ead = false;
c44ab6f1 1665
74e2bd89
AK
1666 if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
1667 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1668 zlog_debug("local es %s up", es->esi_str);
c44ab6f1 1669
74e2bd89
AK
1670 SET_FLAG(es->flags, BGP_EVPNES_OPER_UP);
1671 regen_esr = true;
1672 regen_ead = true;
1673 }
c44ab6f1 1674
74e2bd89
AK
1675 if (regen_esr) {
1676 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1677 zlog_debug("local es %s generate ESR", es->esi_str);
1678 /* generate ESR */
1679 build_evpn_type4_prefix(&p, &es->esi, es->originator_ip);
1680 if (bgp_evpn_type4_route_update(bgp, es, &p))
1681 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1682 "%u: Type4 route creation failure for ESI %s",
1683 bgp->vrf_id, es->esi_str);
1684 }
c44ab6f1 1685
74e2bd89
AK
1686 if (regen_ead) {
1687 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1688 zlog_debug("local es %s generate EAD", es->esi_str);
1689 /* generate EAD-EVI */
1690 bgp_evpn_local_type1_evi_route_add(bgp, es);
c44ab6f1 1691
74e2bd89
AK
1692 /* generate EAD-ES */
1693 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG, &es->esi,
1694 es->originator_ip);
1695 bgp_evpn_type1_route_update(bgp, es, NULL, &p);
1696 }
c44ab6f1
AK
1697}
1698
1699static void bgp_evpn_local_es_do_del(struct bgp *bgp, struct bgp_evpn_es *es)
1700{
1701 struct bgp_evpn_es_evi *es_evi;
1702 struct listnode *evi_node, *evi_next_node;
1703
1704 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1705 zlog_debug("del local es %s", es->esi_str);
1706
1707 /* Delete all local EVPN ES routes from ESI table
1708 * and schedule for processing (to withdraw from peers))
1709 */
1710 bgp_evpn_es_route_del_all(bgp, es);
1711
1712 /* release all local ES EVIs associated with the ES */
1713 for (ALL_LIST_ELEMENTS(es->es_evi_list, evi_node,
1714 evi_next_node, es_evi)) {
1715 bgp_evpn_local_es_evi_do_del(es_evi);
1716 }
1717
1718 /* Clear local info associated with the ES and free it up if there is
1719 * no remote reference
1720 */
1721 bgp_evpn_es_local_info_clear(es);
1722}
1723
7904e9fd
AK
1724bool bgp_evpn_is_esi_local(esi_t *esi)
1725{
1726 struct bgp_evpn_es *es = NULL;
1727
1728 /* Lookup ESI hash - should exist. */
1729 es = bgp_evpn_es_find(esi);
1730 return es ? !!(es->flags & BGP_EVPNES_LOCAL) : false;
1731}
1732
c44ab6f1
AK
1733int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi)
1734{
1735 struct bgp_evpn_es *es = NULL;
1736
1737 /* Lookup ESI hash - should exist. */
1738 es = bgp_evpn_es_find(esi);
1739 if (!es) {
1740 flog_warn(EC_BGP_EVPN_ESI,
1741 "%u: ES %s missing at local ES DEL",
1742 bgp->vrf_id, es->esi_str);
1743 return -1;
1744 }
1745
1746 bgp_evpn_local_es_do_del(bgp, es);
1747 return 0;
1748}
1749
1750/* Handle device to ES id association. Results in the creation of a local
1751 * ES.
1752 */
1753int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi,
74e2bd89
AK
1754 struct in_addr originator_ip, bool oper_up,
1755 uint16_t df_pref)
c44ab6f1
AK
1756{
1757 char buf[ESI_STR_LEN];
1758 struct bgp_evpn_es *es;
1759 bool new_es = true;
74e2bd89 1760 bool regen_esr = false;
c44ab6f1
AK
1761
1762 /* create the new es */
1763 es = bgp_evpn_es_find(esi);
1764 if (es) {
1765 if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1766 new_es = false;
1767 } else {
1768 es = bgp_evpn_es_new(bgp, esi);
1769 if (!es) {
1770 flog_err(EC_BGP_ES_CREATE,
1771 "%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
1772 bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
1773 return -1;
1774 }
1775 }
1776
1777 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
74e2bd89
AK
1778 zlog_debug("add local es %s orig-ip %pI4 df_pref %u", es->esi_str,
1779 &originator_ip, df_pref);
c44ab6f1
AK
1780
1781 es->originator_ip = originator_ip;
74e2bd89
AK
1782 if (df_pref != es->df_pref) {
1783 es->df_pref = df_pref;
1784 regen_esr = true;
1785 }
c44ab6f1
AK
1786 bgp_evpn_es_local_info_set(bgp, es);
1787
1788 /* import all remote Type-4 routes in the ES table */
1789 if (new_es)
1790 bgp_evpn_type4_remote_routes_import(bgp, es,
1791 true /* install */);
1792
1793 /* create and advertise EAD-EVI routes for the ES -
1794 * XXX - till an ES-EVI reference is created there is really nothing to
1795 * advertise
1796 */
1797 if (bgp_mh_info->ead_evi_adv_for_down_links)
1798 bgp_evpn_local_type1_evi_route_add(bgp, es);
1799
1800 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
1801 * can be generated even if the link is inactive.
1802 */
1803 if (oper_up)
74e2bd89 1804 bgp_evpn_local_es_up(bgp, es, regen_esr);
c44ab6f1
AK
1805 else
1806 bgp_evpn_local_es_down(bgp, es);
1807
1808 return 0;
1809}
1810
9e0c2fd1
AK
1811static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es,
1812 uint8_t vtep_str_size)
c44ab6f1
AK
1813{
1814 char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
1815 struct listnode *node;
1816 struct bgp_evpn_es_vtep *es_vtep;
1817 bool first = true;
ec779825 1818 char ip_buf[INET6_ADDRSTRLEN];
c44ab6f1
AK
1819
1820 vtep_str[0] = '\0';
1821 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1822 vtep_flag_str[0] = '\0';
23d0a753 1823
c44ab6f1 1824 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
9e0c2fd1 1825 strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
c44ab6f1 1826 if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
9e0c2fd1 1827 strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
c44ab6f1
AK
1828
1829 if (!strlen(vtep_flag_str))
9e0c2fd1
AK
1830 strlcat(vtep_flag_str, "-", sizeof(vtep_flag_str));
1831 if (first)
c44ab6f1 1832 first = false;
9e0c2fd1
AK
1833 else
1834 strlcat(vtep_str, ",", vtep_str_size);
23d0a753 1835 strlcat(vtep_str,
ec779825
AK
1836 inet_ntop(AF_INET, &es_vtep->vtep_ip, ip_buf,
1837 sizeof(ip_buf)),
23d0a753 1838 vtep_str_size);
9e0c2fd1
AK
1839 strlcat(vtep_str, "(", vtep_str_size);
1840 strlcat(vtep_str, vtep_flag_str, vtep_str_size);
1841 strlcat(vtep_str, ")", vtep_str_size);
c44ab6f1
AK
1842 }
1843
1844 return vtep_str;
1845}
1846
c44ab6f1
AK
1847static void bgp_evpn_es_json_vtep_fill(json_object *json_vteps,
1848 struct bgp_evpn_es_vtep *es_vtep)
1849{
1850 json_object *json_vtep_entry;
1851 json_object *json_flags;
ec779825 1852 char ip_buf[INET6_ADDRSTRLEN];
c44ab6f1
AK
1853
1854 json_vtep_entry = json_object_new_object();
1855
ec779825
AK
1856 json_object_string_add(
1857 json_vtep_entry, "vtep_ip",
1858 inet_ntop(AF_INET, &es_vtep->vtep_ip, ip_buf, sizeof(ip_buf)));
c44ab6f1
AK
1859 if (es_vtep->flags & (BGP_EVPNES_VTEP_ESR |
1860 BGP_EVPNES_VTEP_ACTIVE)) {
1861 json_flags = json_object_new_array();
1862 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
1863 json_array_string_add(json_flags, "esr");
1864 if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
1865 json_array_string_add(json_flags, "active");
1866 json_object_object_add(json_vtep_entry, "flags", json_flags);
74e2bd89
AK
1867 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) {
1868 json_object_int_add(json_vtep_entry, "dfPreference",
1869 es_vtep->df_pref);
1870 json_object_int_add(json_vtep_entry, "dfAlgorithm",
1871 es_vtep->df_pref);
1872 }
c44ab6f1
AK
1873 }
1874
1875 json_object_array_add(json_vteps,
1876 json_vtep_entry);
1877}
1878
74e2bd89
AK
1879static void bgp_evpn_es_vteps_show_detail(struct vty *vty,
1880 struct bgp_evpn_es *es)
1881{
1882 char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
1883 struct listnode *node;
1884 struct bgp_evpn_es_vtep *es_vtep;
1885 char alg_buf[EVPN_DF_ALG_STR_LEN];
1886
1887 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1888 vtep_flag_str[0] = '\0';
1889 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
1890 strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
1891 if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
1892 strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
1893
1894 if (!strlen(vtep_flag_str))
1895 strlcat(vtep_flag_str, "-", sizeof(vtep_flag_str));
1896
ec779825 1897 vty_out(vty, " %pI4 flags: %s", &es_vtep->vtep_ip,
74e2bd89
AK
1898 vtep_flag_str);
1899
1900 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
1901 vty_out(vty, " df_alg: %s df_pref: %u\n",
1902 evpn_es_df_alg2str(es_vtep->df_alg, alg_buf,
1903 sizeof(alg_buf)),
1904 es_vtep->df_pref);
1905 else
1906 vty_out(vty, "\n");
1907 }
1908}
1909
c44ab6f1
AK
1910static void bgp_evpn_es_show_entry(struct vty *vty,
1911 struct bgp_evpn_es *es, json_object *json)
1912{
1913 char buf1[RD_ADDRSTRLEN];
1914 struct listnode *node;
1915 struct bgp_evpn_es_vtep *es_vtep;
1916
1917 if (json) {
1918 json_object *json_vteps;
1919 json_object *json_types;
1920
1921 json_object_string_add(json, "esi", es->esi_str);
1922 json_object_string_add(json, "rd",
1923 prefix_rd2str(&es->prd, buf1,
1924 sizeof(buf1)));
1925
1926 if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) {
1927 json_types = json_object_new_array();
1928 if (es->flags & BGP_EVPNES_LOCAL)
1929 json_array_string_add(json_types, "local");
1930 if (es->flags & BGP_EVPNES_REMOTE)
1931 json_array_string_add(json_types, "remote");
1932 json_object_object_add(json, "type", json_types);
1933 }
1934
1935 if (listcount(es->es_vtep_list)) {
1936 json_vteps = json_object_new_array();
1937 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list,
1938 node, es_vtep)) {
1939 bgp_evpn_es_json_vtep_fill(json_vteps, es_vtep);
1940 }
1941 json_object_object_add(json, "vteps", json_vteps);
1942 }
1943 json_object_int_add(json, "vniCount",
1944 listcount(es->es_evi_list));
1945 } else {
1946 char type_str[4];
1947 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
1948
1949 type_str[0] = '\0';
1950 if (es->flags & BGP_EVPNES_LOCAL)
9e0c2fd1 1951 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 1952 if (es->flags & BGP_EVPNES_REMOTE)
9e0c2fd1 1953 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 1954 if (es->inconsistencies)
9e0c2fd1 1955 strlcat(type_str, "I", sizeof(type_str));
c44ab6f1 1956
9e0c2fd1 1957 bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
c44ab6f1
AK
1958
1959 if (es->flags & BGP_EVPNES_LOCAL)
1960 prefix_rd2str(&es->prd, buf1, sizeof(buf1));
1961 else
9e0c2fd1 1962 strlcpy(buf1, "-", sizeof(buf1));
c44ab6f1
AK
1963
1964 vty_out(vty, "%-30s %-5s %-21s %-8d %s\n",
1965 es->esi_str, type_str, buf1,
1966 listcount(es->es_evi_list), vtep_str);
1967 }
1968}
1969
1970static void bgp_evpn_es_show_entry_detail(struct vty *vty,
1971 struct bgp_evpn_es *es, json_object *json)
1972{
ec779825 1973 char ip_buf[INET6_ADDRSTRLEN];
23d0a753 1974
c44ab6f1
AK
1975 if (json) {
1976 json_object *json_flags;
1977 json_object *json_incons;
74e2bd89
AK
1978 json_object *json_vteps;
1979 struct listnode *node;
1980 struct bgp_evpn_es_vtep *es_vtep;
c44ab6f1
AK
1981
1982 /* Add the "brief" info first */
1983 bgp_evpn_es_show_entry(vty, es, json);
1984 if (es->flags & (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI)) {
1985 json_flags = json_object_new_array();
1986 if (es->flags & BGP_EVPNES_OPER_UP)
1987 json_array_string_add(json_flags, "up");
1988 if (es->flags & BGP_EVPNES_ADV_EVI)
1989 json_array_string_add(json_flags,
1990 "advertiseEVI");
1991 json_object_object_add(json, "flags", json_flags);
1992 }
1993 json_object_string_add(json, "originator_ip",
23d0a753 1994 inet_ntop(AF_INET, &es->originator_ip,
ec779825 1995 ip_buf, sizeof(ip_buf)));
c44ab6f1
AK
1996 json_object_int_add(json, "remoteVniCount",
1997 es->remote_es_evi_cnt);
229587fb
AK
1998 json_object_int_add(json, "vrfCount",
1999 listcount(es->es_vrf_list));
2000 json_object_int_add(json, "macipPathCount",
2001 listcount(es->macip_path_list));
c44ab6f1
AK
2002 json_object_int_add(json, "inconsistentVniVtepCount",
2003 es->incons_evi_vtep_cnt);
74e2bd89
AK
2004 if (listcount(es->es_vtep_list)) {
2005 json_vteps = json_object_new_array();
2006 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node,
2007 es_vtep)) {
2008 bgp_evpn_es_json_vtep_fill(json_vteps, es_vtep);
2009 }
2010 json_object_object_add(json, "vteps", json_vteps);
2011 }
c44ab6f1
AK
2012 if (es->inconsistencies) {
2013 json_incons = json_object_new_array();
2014 if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
2015 json_array_string_add(json_incons,
2016 "vni-vtep-mismatch");
2017 json_object_object_add(json, "inconsistencies",
2018 json_incons);
2019 }
2020 } else {
2021 char incons_str[BGP_EVPNES_INCONS_STR_SZ];
2022 char type_str[4];
c44ab6f1
AK
2023 char buf1[RD_ADDRSTRLEN];
2024
2025 type_str[0] = '\0';
2026 if (es->flags & BGP_EVPNES_LOCAL)
9e0c2fd1 2027 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 2028 if (es->flags & BGP_EVPNES_REMOTE)
9e0c2fd1 2029 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 2030
c44ab6f1
AK
2031 if (es->flags & BGP_EVPNES_LOCAL)
2032 prefix_rd2str(&es->prd, buf1, sizeof(buf1));
2033 else
9e0c2fd1 2034 strlcpy(buf1, "-", sizeof(buf1));
c44ab6f1
AK
2035
2036 vty_out(vty, "ESI: %s\n", es->esi_str);
2037 vty_out(vty, " Type: %s\n", type_str);
2038 vty_out(vty, " RD: %s\n", buf1);
23d0a753 2039 vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip);
74e2bd89
AK
2040 if (es->flags & BGP_EVPNES_LOCAL)
2041 vty_out(vty, " Local ES DF preference: %u\n",
2042 es->df_pref);
c44ab6f1
AK
2043 vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
2044 vty_out(vty, " Remote VNI Count: %d\n",
2045 es->remote_es_evi_cnt);
229587fb
AK
2046 vty_out(vty, " VRF Count: %d\n", listcount(es->es_vrf_list));
2047 vty_out(vty, " MACIP Path Count: %d\n",
2048 listcount(es->macip_path_list));
c44ab6f1
AK
2049 vty_out(vty, " Inconsistent VNI VTEP Count: %d\n",
2050 es->incons_evi_vtep_cnt);
2051 if (es->inconsistencies) {
2052 incons_str[0] = '\0';
2053 if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
9e0c2fd1
AK
2054 strlcat(incons_str, "vni-vtep-mismatch",
2055 sizeof(incons_str));
c44ab6f1 2056 } else {
9e0c2fd1 2057 strlcpy(incons_str, "-", sizeof(incons_str));
c44ab6f1
AK
2058 }
2059 vty_out(vty, " Inconsistencies: %s\n",
2060 incons_str);
74e2bd89
AK
2061 if (listcount(es->es_vtep_list)) {
2062 vty_out(vty, " VTEPs:\n");
2063 bgp_evpn_es_vteps_show_detail(vty, es);
2064 }
c44ab6f1
AK
2065 vty_out(vty, "\n");
2066 }
2067}
2068
2069/* Display all ESs */
2070void bgp_evpn_es_show(struct vty *vty, bool uj, bool detail)
2071{
2072 struct bgp_evpn_es *es;
9c7edc03 2073 json_object *json_array = NULL;
c44ab6f1
AK
2074 json_object *json = NULL;
2075
2076 if (uj) {
2077 /* create an array of ESs */
2078 json_array = json_object_new_array();
2079 } else {
2080 if (!detail) {
2081 vty_out(vty,
2082 "ES Flags: L local, R remote, I inconsistent\n");
2083 vty_out(vty,
2084 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
2085 vty_out(vty,
2086 "%-30s %-5s %-21s %-8s %s\n",
2087 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
2088 }
2089 }
2090
2091 RB_FOREACH(es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
2092 if (uj)
2093 /* create a separate json object for each ES */
2094 json = json_object_new_object();
2095 if (detail)
2096 bgp_evpn_es_show_entry_detail(vty, es, json);
2097 else
2098 bgp_evpn_es_show_entry(vty, es, json);
2099 /* add ES to the json array */
2100 if (uj)
2101 json_object_array_add(json_array, json);
2102 }
2103
2104 /* print the array of json-ESs */
2105 if (uj) {
2106 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2107 json_array, JSON_C_TO_STRING_PRETTY));
2108 json_object_free(json_array);
2109 }
2110}
2111
2112/* Display specific ES */
2113void bgp_evpn_es_show_esi(struct vty *vty, esi_t *esi, bool uj)
2114{
2115 struct bgp_evpn_es *es;
2116 json_object *json = NULL;
2117
2118 if (uj)
2119 json = json_object_new_object();
2120
2121 es = bgp_evpn_es_find(esi);
2122 if (es) {
2123 bgp_evpn_es_show_entry_detail(vty, es, json);
2124 } else {
2125 if (!uj)
2126 vty_out(vty, "ESI not found\n");
2127 }
2128
2129 if (uj) {
2130 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2131 json, JSON_C_TO_STRING_PRETTY));
2132 json_object_free(json);
2133 }
2134}
2135
c589d847
AK
2136/*****************************************************************************/
2137/* Ethernet Segment to VRF association -
2138 * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
2139 * triggers the creation of an ES-VRF entry.
2140 * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
2141 * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
2142 * a /32 or host route entry in the dataplane. If the destination of
2143 * the host route is a remote-ES the route is programmed with the
2144 * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
2145 * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
2146 * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
2147 * instead of updating all the dependent routes the NHG's contents are updated.
2148 * This reduces the amount of datplane updates (nhg updates vs. route updates)
2149 * allowing for a faster failover.
2150 *
2151 * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
2152 * association? If yes we need to handle that by updating all the L3 NHGs
2153 * in that VRF.
2154 */
2155/******************************** L3 NHG management *************************/
8bcb09a1
AK
2156static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf,
2157 bool v4_nhg)
c589d847 2158{
8bcb09a1
AK
2159 uint32_t nhg_id = v4_nhg ? es_vrf->nhg_id : es_vrf->v6_nhg_id;
2160 struct bgp_evpn_es *es = es_vrf->es;
c589d847
AK
2161 struct listnode *node;
2162 struct bgp_evpn_es_vtep *es_vtep;
8bcb09a1
AK
2163 struct nexthop nh;
2164 struct zapi_nexthop *api_nh;
2165 struct zapi_nhg api_nhg = {};
2166
2167 /* Skip installation of L3-NHG if host routes used */
2168 if (!nhg_id)
2169 return;
c589d847
AK
2170
2171 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1
AK
2172 zlog_debug("es %s vrf %u %s nhg %u to zebra", es->esi_str,
2173 es_vrf->bgp_vrf->vrf_id,
2174 v4_nhg ? "v4_nhg" : "v6_nhg", nhg_id);
2175
2176 /* only the gateway ip changes for each NH. rest of the params
2177 * are constant
2178 */
2179 memset(&nh, 0, sizeof(nh));
2180 nh.vrf_id = es_vrf->bgp_vrf->vrf_id;
2181 nh.flags = NEXTHOP_FLAG_ONLINK;
2182 nh.ifindex = es_vrf->bgp_vrf->l3vni_svi_ifindex;
2183 nh.weight = 1;
2184 nh.type =
2185 v4_nhg ? NEXTHOP_TYPE_IPV4_IFINDEX : NEXTHOP_TYPE_IPV6_IFINDEX;
2186
2187 api_nhg.id = nhg_id;
c589d847 2188 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
8bcb09a1
AK
2189 if (!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
2190 continue;
2191
2192 /* overwrite the gw */
2193 if (v4_nhg)
2194 nh.gate.ipv4 = es_vtep->vtep_ip;
2195 else
2196 ipv4_to_ipv4_mapped_ipv6(&nh.gate.ipv6,
2197 es_vtep->vtep_ip);
2198
2199 /* convert to zapi format */
2200 api_nh = &api_nhg.nexthops[api_nhg.nexthop_num];
2201 zapi_nexthop_from_nexthop(api_nh, &nh);
2202
2203 ++api_nhg.nexthop_num;
2204 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2205 zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg.id,
2206 &es_vtep->vtep_ip,
2207 es_vrf->bgp_vrf->l3vni_svi_ifindex);
c589d847
AK
2208 }
2209
8bcb09a1
AK
2210 if (!api_nhg.nexthop_num)
2211 return;
2212
2213 if (api_nhg.nexthop_num > MULTIPATH_NUM)
2214 return;
2215
2216 zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg);
c589d847
AK
2217}
2218
8bcb09a1
AK
2219static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf *es_vrf)
2220{
2221 if (!bgp_mh_info->host_routes_use_l3nhg && !bgp_mh_info->install_l3nhg)
2222 return false;
2223
2224 /* Check socket. */
2225 if (!zclient || zclient->sock < 0)
2226 return false;
2227
2228 return true;
2229}
2230
2231static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf *es_vrf)
c589d847 2232{
8bcb09a1
AK
2233 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf))
2234 return;
2235
2236 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf, true /*v4_nhg*/);
2237 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf, false /*v4_nhg*/);
2238}
2239
2240static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf,
2241 bool v4_nhg)
2242{
2243 struct zapi_nhg api_nhg = {};
2244
2245 api_nhg.id = v4_nhg ? es_vrf->nhg_id : es_vrf->v6_nhg_id;
2246
2247 /* Skip installation of L3-NHG if host routes used */
2248 if (!api_nhg.id)
2249 return;
2250
c589d847 2251 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1 2252 zlog_debug("es %s vrf %u %s nhg %u to zebra",
c589d847 2253 es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
8bcb09a1
AK
2254 v4_nhg ? "v4_nhg" : "v6_nhg", api_nhg.id);
2255
2256 zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg);
2257}
c589d847 2258
8bcb09a1
AK
2259static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf *es_vrf)
2260{
2261 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf))
2262 return;
2263
2264 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf, true /*v4_nhg*/);
2265 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf, false /*v4_nhg*/);
c589d847
AK
2266}
2267
2268static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf)
2269{
2270 if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
2271 return;
2272
2273 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1 2274 zlog_debug("es %s vrf %u nhg %u de-activate",
c589d847
AK
2275 es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
2276 es_vrf->nhg_id);
2277 bgp_evpn_l3nhg_zebra_del(es_vrf);
2278 es_vrf->flags &= ~BGP_EVPNES_VRF_NHG_ACTIVE;
2279}
2280
2281static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update)
2282{
2283 if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf->es)) {
2284 bgp_evpn_l3nhg_deactivate(es_vrf);
2285 return;
2286 }
2287
2288 if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) {
2289 if (!update)
2290 return;
2291 } else {
2292 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1 2293 zlog_debug("es %s vrf %u nhg %u activate",
c589d847
AK
2294 es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
2295 es_vrf->nhg_id);
2296 es_vrf->flags |= BGP_EVPNES_VRF_NHG_ACTIVE;
2297 }
2298
2299 bgp_evpn_l3nhg_zebra_add(es_vrf);
2300}
2301
2302/* when a VTEP is activated or de-activated against an ES associated
2303 * VRFs' NHG needs to be updated
2304 */
2305static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es)
2306{
2307 struct bgp_evpn_es_vrf *es_vrf;
2308 struct listnode *es_vrf_node;
2309
2310 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2311 zlog_debug("es %s nhg update on vtep chg", es->esi_str);
2312
2313 for (ALL_LIST_ELEMENTS_RO(es->es_vrf_list, es_vrf_node, es_vrf))
2314 bgp_evpn_l3nhg_activate(es_vrf, true /* update */);
2315}
2316
2317/* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
2318static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf *es_vrf1,
2319 const struct bgp_evpn_es_vrf *es_vrf2)
2320{
2321 return memcmp(&es_vrf1->es->esi, &es_vrf2->es->esi, ESI_BYTES);
2322}
2323RB_GENERATE(bgp_es_vrf_rb_head, bgp_evpn_es_vrf, rb_node, bgp_es_vrf_rb_cmp);
2324
2325/* Initialize the ES tables maintained per-tenant vrf */
2326void bgp_evpn_vrf_es_init(struct bgp *bgp_vrf)
2327{
2328 /* Initialize the ES-VRF RB tree */
2329 RB_INIT(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree);
2330}
2331
2332/* find the ES-VRF in the per-VRF RB tree */
2333static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_find(struct bgp_evpn_es *es,
2334 struct bgp *bgp_vrf)
2335{
2336 struct bgp_evpn_es_vrf es_vrf;
2337
2338 es_vrf.es = es;
2339
2340 return RB_FIND(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, &es_vrf);
2341}
2342
2343/* allocate a new ES-VRF and setup L3NHG for it */
2344static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es,
2345 struct bgp *bgp_vrf)
2346{
2347 struct bgp_evpn_es_vrf *es_vrf;
2348
2349 es_vrf = XCALLOC(MTYPE_BGP_EVPN_ES_VRF, sizeof(*es_vrf));
2350
2351 es_vrf->es = es;
2352 es_vrf->bgp_vrf = bgp_vrf;
2353
2354 /* insert into the VRF-ESI rb tree */
2355 if (RB_INSERT(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, es_vrf)) {
2356 XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf);
2357 return NULL;
2358 }
2359
2360 /* add to the ES's VRF list */
2361 listnode_init(&es_vrf->es_listnode, es_vrf);
2362 listnode_add(es->es_vrf_list, &es_vrf->es_listnode);
2363
2364 /* setup the L3 NHG id for the ES */
2365 es_vrf->nhg_id = bgp_l3nhg_id_alloc();
8bcb09a1
AK
2366 es_vrf->v6_nhg_id = bgp_l3nhg_id_alloc();
2367
c589d847 2368 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1
AK
2369 zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es->esi_str,
2370 bgp_vrf->vrf_id, es_vrf->nhg_id, es_vrf->v6_nhg_id);
c589d847
AK
2371 bgp_evpn_l3nhg_activate(es_vrf, false /* update */);
2372
2373 return es_vrf;
2374}
2375
2376/* remove the L3-NHG associated with the ES-VRF and free it */
2377static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf)
2378{
2379 struct bgp_evpn_es *es = es_vrf->es;
2380 struct bgp *bgp_vrf = es_vrf->bgp_vrf;
2381
2382 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1 2383 zlog_debug("es %s vrf %u nhg %u delete", es->esi_str,
c589d847
AK
2384 bgp_vrf->vrf_id, es_vrf->nhg_id);
2385
2386 /* Remove the NHG resources */
2387 bgp_evpn_l3nhg_deactivate(es_vrf);
2388 if (es_vrf->nhg_id)
2389 bgp_l3nhg_id_free(es_vrf->nhg_id);
2390 es_vrf->nhg_id = 0;
8bcb09a1
AK
2391 if (es_vrf->v6_nhg_id)
2392 bgp_l3nhg_id_free(es_vrf->v6_nhg_id);
2393 es_vrf->v6_nhg_id = 0;
c589d847
AK
2394
2395 /* remove from the ES's VRF list */
2396 list_delete_node(es->es_vrf_list, &es_vrf->es_listnode);
2397
2398 /* remove from the VRF-ESI rb tree */
2399 RB_REMOVE(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, es_vrf);
2400
2401 XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf);
2402}
2403
2404/* deref and delete if there are no references */
2405void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi *es_evi)
2406{
2407 struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf;
2408
2409 if (!es_vrf)
2410 return;
2411
2412 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2413 zlog_debug("es-evi %s vni %u vrf %u de-ref",
2414 es_evi->es->esi_str, es_evi->vpn->vni,
2415 es_vrf->bgp_vrf->vrf_id);
2416
2417 es_evi->es_vrf = NULL;
2418 if (es_vrf->ref_cnt)
2419 --es_vrf->ref_cnt;
2420
2421 if (!es_vrf->ref_cnt)
2422 bgp_evpn_es_vrf_delete(es_vrf);
2423}
2424
2425/* find or create and reference */
2426void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi *es_evi, struct bgp *bgp_vrf)
2427{
2428 struct bgp_evpn_es *es = es_evi->es;
2429 struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf;
2430 struct bgp *old_bgp_vrf = NULL;
2431
2432 if (es_vrf)
2433 old_bgp_vrf = es_vrf->bgp_vrf;
2434
2435 if (old_bgp_vrf == bgp_vrf)
2436 return;
2437
2438 /* deref the old ES-VRF */
2439 bgp_evpn_es_vrf_deref(es_evi);
2440
2441 if (!bgp_vrf)
2442 return;
2443
2444 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2445 zlog_debug("es-evi %s vni %u vrf %u ref", es_evi->es->esi_str,
2446 es_evi->vpn->vni, bgp_vrf->vrf_id);
2447
2448 /* find-create the new ES-VRF */
2449 es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
2450 if (!es_vrf)
2451 es_vrf = bgp_evpn_es_vrf_create(es, bgp_vrf);
2452 if (!es_vrf)
2453 return;
2454
2455 es_evi->es_vrf = es_vrf;
2456 ++es_vrf->ref_cnt;
2457}
2458
2459/* When the L2-VNI is associated with a L3-VNI/VRF update all the
2460 * associated ES-EVI entries
2461 */
2462void bgp_evpn_es_evi_vrf_deref(struct bgpevpn *vpn)
2463{
2464 struct bgp_evpn_es_evi *es_evi;
2465
2466 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2467 zlog_debug("es-vrf de-ref for vni %u", vpn->vni);
2468
2469 RB_FOREACH (es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree)
2470 bgp_evpn_es_vrf_deref(es_evi);
2471}
2472void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn)
2473{
2474 struct bgp_evpn_es_evi *es_evi;
2475
2476 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2477 zlog_debug("es-vrf ref for vni %u", vpn->vni);
2478
2479 RB_FOREACH (es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree)
2480 bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
2481}
2482
6348981a
AK
2483/* returns false if legacy-exploded mp needs to be used for route install */
2484bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
2485 uint32_t *nhg_p)
2486{
2487 esi_t *esi;
2488 struct bgp_evpn_es *es;
2489 struct bgp_evpn_es_vrf *es_vrf;
2490 struct bgp_path_info *parent_pi;
2491 struct bgp_node *rn;
2492 struct prefix_evpn *evp;
2493 struct bgp_path_info *mpinfo;
2494
2495 *nhg_p = 0;
2496
229587fb
AK
2497 /* L3NHG support is disabled, use legacy-exploded multipath */
2498 if (!bgp_mh_info->host_routes_use_l3nhg)
2499 return false;
2500
6348981a
AK
2501 parent_pi = get_route_parent_evpn(pi);
2502 if (!parent_pi)
2503 return false;
2504
2505 rn = parent_pi->net;
2506 if (!rn)
2507 return false;
2508
2509 evp = (struct prefix_evpn *)&rn->p;
2510 if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
2511 return false;
2512
6348981a
AK
2513 /* non-es path, use legacy-exploded multipath */
2514 esi = bgp_evpn_attr_get_esi(parent_pi->attr);
2515 if (!memcmp(esi, zero_esi, sizeof(*esi)))
2516 return false;
2517
2518 /* if the ES-VRF is not setup or if the NHG has not been installed
2519 * we cannot install the route yet, return a 0-NHG to indicate
2520 * that
2521 */
2522 es = bgp_evpn_es_find(esi);
2523 if (!es)
2524 return true;
2525 es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
2526 if (!es_vrf || !(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
2527 return true;
2528
2529 /* this needs to be set the v6NHG if v6route */
8bcb09a1 2530 if (is_evpn_prefix_ipaddr_v6(evp))
6348981a
AK
2531 *nhg_p = es_vrf->v6_nhg_id;
2532 else
2533 *nhg_p = es_vrf->nhg_id;
2534
2535 for (mpinfo = bgp_path_info_mpath_next(pi); mpinfo;
2536 mpinfo = bgp_path_info_mpath_next(mpinfo)) {
2537 /* if any of the paths of have a different ESI we can't use
2538 * the NHG associated with the ES. fallback to legacy-exploded
2539 * multipath
2540 */
2541 if (memcmp(esi, bgp_evpn_attr_get_esi(mpinfo->attr),
2542 sizeof(*esi)))
2543 return false;
2544 }
2545
2546 return true;
2547}
2548
229587fb
AK
2549static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
2550 struct bgp_evpn_es_vrf *es_vrf,
2551 json_object *json)
2552{
2553 struct bgp_evpn_es *es = es_vrf->es;
2554 struct bgp *bgp_vrf = es_vrf->bgp_vrf;
2555
2556 if (json) {
2557 json_object *json_types;
2558
2559 json_object_string_add(json, "esi", es->esi_str);
2560 json_object_string_add(json, "vrf", bgp_vrf->name);
2561
2562 if (es_vrf->flags & (BGP_EVPNES_VRF_NHG_ACTIVE)) {
2563 json_types = json_object_new_array();
2564 if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
2565 json_array_string_add(json_types, "active");
2566 json_object_object_add(json, "flags", json_types);
2567 }
2568
2569 json_object_int_add(json, "ipv4NHG", es_vrf->nhg_id);
2570 json_object_int_add(json, "ipv6NHG", es_vrf->v6_nhg_id);
2571 json_object_int_add(json, "refCount", es_vrf->ref_cnt);
2572 } else {
2573 char flags_str[4];
2574
2575 flags_str[0] = '\0';
2576 if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
2577 strlcat(flags_str, "A", sizeof(flags_str));
2578
2579 vty_out(vty, "%-30s %-15s %-5s %-8u %-8u %u\n", es->esi_str,
2580 bgp_vrf->name, flags_str, es_vrf->nhg_id,
2581 es_vrf->v6_nhg_id, es_vrf->ref_cnt);
2582 }
2583}
2584
2585static void bgp_evpn_es_vrf_show_es(struct vty *vty, json_object *json_array,
2586 struct bgp_evpn_es *es)
2587{
2588 json_object *json = NULL;
2589 struct listnode *es_vrf_node;
2590 struct bgp_evpn_es_vrf *es_vrf;
2591
2592 for (ALL_LIST_ELEMENTS_RO(es->es_vrf_list, es_vrf_node, es_vrf)) {
2593 /* create a separate json object for each ES-VRF */
2594 if (json_array)
2595 json = json_object_new_object();
2596 bgp_evpn_es_vrf_show_entry(vty, es_vrf, json);
2597 /* add ES-VRF to the json array */
2598 if (json_array)
2599 json_object_array_add(json_array, json);
2600 }
2601}
2602
2603/* Display all ES VRFs */
2604void bgp_evpn_es_vrf_show(struct vty *vty, bool uj, struct bgp_evpn_es *es)
2605{
2606 json_object *json_array = NULL;
2607
2608 if (uj) {
2609 /* create an array of ESs */
2610 json_array = json_object_new_array();
2611 } else {
2612 vty_out(vty, "ES-VRF Flags: A Active\n");
2613 vty_out(vty, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
2614 "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
2615 }
2616
2617 if (es) {
2618 bgp_evpn_es_vrf_show_es(vty, json_array, es);
2619 } else {
2620 RB_FOREACH (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree)
2621 bgp_evpn_es_vrf_show_es(vty, json_array, es);
2622 }
2623
2624 /* print the array of json-ESs */
2625 if (uj) {
2626 vty_out(vty, "%s\n",
2627 json_object_to_json_string_ext(
2628 json_array, JSON_C_TO_STRING_PRETTY));
2629 json_object_free(json_array);
2630 }
2631}
2632
2633/* Display specific ES VRF */
2634void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj)
2635{
2636 struct bgp_evpn_es *es;
2637
2638 es = bgp_evpn_es_find(esi);
2639 if (es) {
2640 bgp_evpn_es_vrf_show(vty, uj, es);
2641 } else {
2642 if (!uj)
2643 vty_out(vty, "ESI not found\n");
2644 }
2645}
2646
c44ab6f1
AK
2647/*****************************************************************************/
2648/* Ethernet Segment to EVI association -
2649 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
2650 * (bgpevpn->es_evi_rb_tree).
2651 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
2652 * advertises an EAD-EVI (Type-1 EVPN) route
2653 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
2654 * it.
2655 */
2656
2657/* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
2658 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
2659 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
2660 * VTEPs for which both routes have been rxed are activated. Activation
2661 * creates a NHG in the parent ES.
2662 */
2663static int bgp_evpn_es_evi_vtep_cmp(void *p1, void *p2)
2664{
2665 const struct bgp_evpn_es_evi_vtep *evi_vtep1 = p1;
2666 const struct bgp_evpn_es_evi_vtep *evi_vtep2 = p2;
2667
2668 return evi_vtep1->vtep_ip.s_addr - evi_vtep2->vtep_ip.s_addr;
2669}
2670
2671static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_new(
2672 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip)
2673{
2674 struct bgp_evpn_es_evi_vtep *evi_vtep;
2675
2676 evi_vtep = XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP, sizeof(*evi_vtep));
2677
2678 evi_vtep->es_evi = es_evi;
2679 evi_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
2680 listnode_init(&evi_vtep->es_evi_listnode, evi_vtep);
2681 listnode_add_sort(es_evi->es_evi_vtep_list, &evi_vtep->es_evi_listnode);
2682
2683 return evi_vtep;
2684}
2685
2686static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep *evi_vtep)
2687{
2688 struct bgp_evpn_es_evi *es_evi = evi_vtep->es_evi;
2689
2690 if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD))
2691 /* as long as there is some reference we can't free it */
2692 return;
2693
2694 list_delete_node(es_evi->es_evi_vtep_list, &evi_vtep->es_evi_listnode);
2695 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP, evi_vtep);
2696}
2697
2698/* check if VTEP is already part of the list */
2699static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_find(
2700 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip)
2701{
2702 struct listnode *node = NULL;
2703 struct bgp_evpn_es_evi_vtep *evi_vtep;
2704
2705 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
2706 if (evi_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
2707 return evi_vtep;
2708 }
2709 return NULL;
2710}
2711
2712/* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
2713 * EAD-per-EVI routes are rxed from it.
2714 */
2715static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
2716 struct bgp_evpn_es_evi_vtep *evi_vtep)
2717{
2718 bool old_active;
2719 bool new_active;
2720
2721 old_active = !!CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
2722
2723 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
2724 * before it can be activated.
2725 */
2726 if ((evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD) ==
2727 BGP_EVPN_EVI_VTEP_EAD)
2728 SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
2729 else
2730 UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
2731
2732 new_active = !!CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
2733
2734 if (old_active == new_active)
2735 return;
2736
2737 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
2738 zlog_debug("es %s evi %u vtep %pI4 %s",
2739 evi_vtep->es_evi->es->esi_str,
2740 evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip,
2741 new_active ? "active" : "inactive");
c44ab6f1
AK
2742
2743 /* add VTEP to parent es */
2744 if (new_active) {
2745 struct bgp_evpn_es_vtep *es_vtep;
2746
2747 es_vtep = bgp_evpn_es_vtep_add(bgp, evi_vtep->es_evi->es,
74e2bd89
AK
2748 evi_vtep->vtep_ip, false /*esr*/,
2749 0, 0);
c44ab6f1
AK
2750 evi_vtep->es_vtep = es_vtep;
2751 } else {
2752 if (evi_vtep->es_vtep) {
2753 bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep,
2754 false /*esr*/);
2755 evi_vtep->es_vtep = NULL;
2756 }
2757 }
2758 /* queue up the parent es for background consistency checks */
2759 bgp_evpn_es_cons_checks_pend_add(evi_vtep->es_evi->es);
2760}
2761
2762static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp,
2763 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
2764 bool ead_es)
2765{
2766 struct bgp_evpn_es_evi_vtep *evi_vtep;
2767
2768 evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip);
2769
2770 if (!evi_vtep)
2771 evi_vtep = bgp_evpn_es_evi_vtep_new(es_evi, vtep_ip);
2772
2773 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
2774 zlog_debug("add es %s evi %u vtep %pI4 %s",
2775 evi_vtep->es_evi->es->esi_str,
2776 evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip,
2777 ead_es ? "ead_es" : "ead_evi");
c44ab6f1
AK
2778
2779 if (ead_es)
2780 SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES);
2781 else
2782 SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
2783
2784 bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
2785}
2786
2787static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp,
2788 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
2789 bool ead_es)
2790{
2791 struct bgp_evpn_es_evi_vtep *evi_vtep;
2792
2793 evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip);
2794 if (!evi_vtep)
2795 return;
2796
2797 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
2798 zlog_debug("del es %s evi %u vtep %pI4 %s",
2799 evi_vtep->es_evi->es->esi_str,
2800 evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip,
2801 ead_es ? "ead_es" : "ead_evi");
c44ab6f1
AK
2802
2803 if (ead_es)
2804 UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES);
2805 else
2806 UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
2807
2808 bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
2809 bgp_evpn_es_evi_vtep_free(evi_vtep);
2810}
2811
2812/* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
2813static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi *es_evi1,
2814 const struct bgp_evpn_es_evi *es_evi2)
2815{
2816 return memcmp(&es_evi1->es->esi, &es_evi2->es->esi, ESI_BYTES);
2817}
2818RB_GENERATE(bgp_es_evi_rb_head, bgp_evpn_es_evi, rb_node, bgp_es_evi_rb_cmp);
2819
2820/* find the ES-EVI in the per-L2-VNI RB tree */
2821static struct bgp_evpn_es_evi *bgp_evpn_es_evi_find(struct bgp_evpn_es *es,
2822 struct bgpevpn *vpn)
2823{
2824 struct bgp_evpn_es_evi es_evi;
2825
2826 es_evi.es = es;
2827
2828 return RB_FIND(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, &es_evi);
2829}
2830
2831/* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
2832 * tables.
2833 */
2834static struct bgp_evpn_es_evi *bgp_evpn_es_evi_new(struct bgp_evpn_es *es,
2835 struct bgpevpn *vpn)
2836{
2837 struct bgp_evpn_es_evi *es_evi;
2838
2839 es_evi = XCALLOC(MTYPE_BGP_EVPN_ES_EVI, sizeof(*es_evi));
2840
2841 es_evi->es = es;
2842 es_evi->vpn = vpn;
2843
2844 /* Initialise the VTEP list */
2845 es_evi->es_evi_vtep_list = list_new();
2846 listset_app_node_mem(es_evi->es_evi_vtep_list);
2847 es_evi->es_evi_vtep_list->cmp = bgp_evpn_es_evi_vtep_cmp;
2848
2849 /* insert into the VNI-ESI rb tree */
2850 if (RB_INSERT(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, es_evi)) {
2851 XFREE(MTYPE_BGP_EVPN_ES_EVI, es_evi);
2852 return NULL;
2853 }
2854
2855 /* add to the ES's VNI list */
2856 listnode_init(&es_evi->es_listnode, es_evi);
2857 listnode_add(es->es_evi_list, &es_evi->es_listnode);
2858
c589d847
AK
2859 bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
2860
c44ab6f1
AK
2861 return es_evi;
2862}
2863
2864/* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
2865 * up the memory.
2866 */
2867static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi)
2868{
2869 struct bgp_evpn_es *es = es_evi->es;
2870 struct bgpevpn *vpn = es_evi->vpn;
2871
2872 /* cannot free the element as long as there is a local or remote
2873 * reference
2874 */
2875 if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE))
2876 return;
2877
c589d847
AK
2878 bgp_evpn_es_vrf_deref(es_evi);
2879
c44ab6f1
AK
2880 /* remove from the ES's VNI list */
2881 list_delete_node(es->es_evi_list, &es_evi->es_listnode);
2882
2883 /* remove from the VNI-ESI rb tree */
2884 RB_REMOVE(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, es_evi);
2885
2886 /* free the VTEP list */
2887 list_delete(&es_evi->es_evi_vtep_list);
2888
2889 /* remove from the VNI-ESI rb tree */
2890 XFREE(MTYPE_BGP_EVPN_ES_EVI, es_evi);
2891}
2892
2893/* init local info associated with the ES-EVI */
2894static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi *es_evi)
2895{
2896 struct bgpevpn *vpn = es_evi->vpn;
2897
2898 if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2899 return;
2900
2901 SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
2902 listnode_init(&es_evi->l2vni_listnode, es_evi);
2903 listnode_add(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
2904}
2905
2906/* clear any local info associated with the ES-EVI */
2907static void bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi *es_evi)
2908{
2909 struct bgpevpn *vpn = es_evi->vpn;
2910
2911 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2912 return;
2913
2914 UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
2915 list_delete_node(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
2916
2917 bgp_evpn_es_evi_free(es_evi);
2918}
2919
2920/* eval remote info associated with the ES */
2921static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi *es_evi)
2922{
2923 struct bgp_evpn_es *es = es_evi->es;
2924
2925 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2926 if (listcount(es_evi->es_evi_vtep_list)) {
2927 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) {
2928 SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE);
2929 ++es->remote_es_evi_cnt;
2930 /* set remote on the parent es */
2931 bgp_evpn_es_remote_info_re_eval(es);
2932 }
2933 } else {
2934 if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) {
2935 UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE);
2936 if (es->remote_es_evi_cnt)
2937 --es->remote_es_evi_cnt;
2938 bgp_evpn_es_evi_free(es_evi);
2939 /* check if "remote" can be cleared from the
2940 * parent es.
2941 */
2942 bgp_evpn_es_remote_info_re_eval(es);
2943 }
2944 }
2945}
2946
2947static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi)
2948{
2949 struct prefix_evpn p;
2950 struct bgp_evpn_es *es = es_evi->es;
2951 struct bgp *bgp;
2952
2953 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2954 return;
2955
2956 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2957 zlog_debug("del local es %s evi %u",
2958 es_evi->es->esi_str,
2959 es_evi->vpn->vni);
2960
2961 bgp = bgp_get_evpn();
2962
2963 if (bgp) {
2964 /* update EAD-ES with new list of VNIs */
2965 if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
2966 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
2967 &es->esi, es->originator_ip);
2968 if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
2969 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
2970 "%u: EAD-ES route update failure for ESI %s VNI %u",
2971 bgp->vrf_id, es->esi_str,
2972 es_evi->vpn->vni);
2973 }
2974
2975 /* withdraw and delete EAD-EVI */
2976 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
2977 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
2978 &es->esi, es->originator_ip);
2979 if (bgp_evpn_type1_evi_route_delete(bgp,
2980 es, es_evi->vpn, &p))
2981 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
2982 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
2983 bgp->vrf_id, es->esi_str,
2984 es_evi->vpn->vni);
2985 }
2986 }
2987
2988 bgp_evpn_es_evi_local_info_clear(es_evi);
185fb14a 2989
c44ab6f1
AK
2990}
2991
2992int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni)
2993{
2994 struct bgpevpn *vpn;
2995 struct bgp_evpn_es *es;
2996 struct bgp_evpn_es_evi *es_evi;
2997 char buf[ESI_STR_LEN];
2998
2999 es = bgp_evpn_es_find(esi);
3000 if (!es) {
3001 flog_err(
3002 EC_BGP_ES_CREATE,
3003 "%u: Failed to deref VNI %d from ESI %s; ES not present",
3004 bgp->vrf_id, vni,
3005 esi_to_str(esi, buf, sizeof(buf)));
3006 return -1;
3007 }
3008
3009 vpn = bgp_evpn_lookup_vni(bgp, vni);
3010 if (!vpn) {
3011 flog_err(
3012 EC_BGP_ES_CREATE,
3013 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
3014 bgp->vrf_id, vni, es->esi_str);
3015 return -1;
3016 }
3017
3018 es_evi = bgp_evpn_es_evi_find(es, vpn);
3019 if (!es_evi) {
3020 flog_err(
3021 EC_BGP_ES_CREATE,
3022 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
3023 bgp->vrf_id, vni, es->esi_str);
3024 return -1;
3025 }
3026
3027 bgp_evpn_local_es_evi_do_del(es_evi);
3028 return 0;
3029}
3030
3031/* Create ES-EVI and advertise the corresponding EAD routes */
3032int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni)
3033{
3034 struct bgpevpn *vpn;
3035 struct prefix_evpn p;
3036 struct bgp_evpn_es *es;
3037 struct bgp_evpn_es_evi *es_evi;
3038 char buf[ESI_STR_LEN];
3039
3040 es = bgp_evpn_es_find(esi);
3041 if (!es) {
3042 flog_err(
3043 EC_BGP_ES_CREATE,
3044 "%u: Failed to associate VNI %d with ESI %s; ES not present",
3045 bgp->vrf_id, vni,
3046 esi_to_str(esi, buf, sizeof(buf)));
3047 return -1;
3048 }
3049
3050 vpn = bgp_evpn_lookup_vni(bgp, vni);
3051 if (!vpn) {
3052 flog_err(
3053 EC_BGP_ES_CREATE,
3054 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
3055 bgp->vrf_id, vni, es->esi_str);
3056 return -1;
3057 }
3058
3059 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
3060 zlog_debug("add local es %s evi %u",
3061 es->esi_str, vni);
3062
3063 es_evi = bgp_evpn_es_evi_find(es, vpn);
3064
3065 if (es_evi) {
3066 if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
3067 /* dup */
3068 return 0;
3069 } else {
3070 es_evi = bgp_evpn_es_evi_new(es, vpn);
3071 if (!es_evi)
3072 return -1;
3073 }
3074
3075 bgp_evpn_es_evi_local_info_set(es_evi);
3076
3077 /* generate an EAD-EVI for this new VNI */
3078 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
3079 &es->esi, es->originator_ip);
3080 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
3081 if (bgp_evpn_type1_route_update(bgp, es, vpn, &p))
3082 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
3083 "%u: EAD-EVI route creation failure for ESI %s VNI %u",
3084 bgp->vrf_id, es->esi_str, vni);
3085 }
3086
3087 /* update EAD-ES */
3088 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
3089 &es->esi, es->originator_ip);
3090 if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
3091 if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
3092 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
3093 "%u: EAD-ES route creation failure for ESI %s VNI %u",
3094 bgp->vrf_id, es->esi_str, vni);
3095 }
3096
3097 return 0;
3098}
3099
3100/* Add remote ES-EVI entry. This is actually the remote VTEP add and the
3101 * ES-EVI is implicity created on first VTEP's reference.
3102 */
3103int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
3104 const struct prefix_evpn *p)
3105{
3106 char buf[ESI_STR_LEN];
3107 struct bgp_evpn_es *es;
3108 struct bgp_evpn_es_evi *es_evi;
3109 bool ead_es;
3110 const esi_t *esi = &p->prefix.ead_addr.esi;
3111
3112 if (!vpn)
3113 /* local EAD-ES need not be sent back to zebra */
3114 return 0;
3115
3116 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
3117 zlog_debug("add remote %s es %s evi %u vtep %pI4",
3118 p->prefix.ead_addr.eth_tag ? "ead-es" : "ead-evi",
3119 esi_to_str(esi, buf, sizeof(buf)), vpn->vni,
3120 &p->prefix.ead_addr.ip.ipaddr_v4);
c44ab6f1
AK
3121
3122 es = bgp_evpn_es_find(esi);
3123 if (!es) {
3124 es = bgp_evpn_es_new(bgp, esi);
3125 if (!es) {
3126 flog_err(EC_BGP_ES_CREATE,
3127 "%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
3128 bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
3129 return -1;
3130 }
3131 }
3132
3133 es_evi = bgp_evpn_es_evi_find(es, vpn);
3134 if (!es_evi) {
3135 es_evi = bgp_evpn_es_evi_new(es, vpn);
3136 if (!es_evi) {
45a859f1 3137 bgp_evpn_es_free(es, __func__);
c44ab6f1
AK
3138 return -1;
3139 }
3140 }
3141
3142 ead_es = !!p->prefix.ead_addr.eth_tag;
3143 bgp_evpn_es_evi_vtep_add(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
3144 ead_es);
3145
3146 bgp_evpn_es_evi_remote_info_re_eval(es_evi);
3147 return 0;
3148}
3149
3150/* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
3151 * parent es-evi freed up implicitly in last VTEP's deref.
3152 */
3153int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
3154 const struct prefix_evpn *p)
3155{
3156 char buf[ESI_STR_LEN];
3157 struct bgp_evpn_es *es;
3158 struct bgp_evpn_es_evi *es_evi;
3159 bool ead_es;
3160
3161 if (!vpn)
3162 /* local EAD-ES need not be sent back to zebra */
3163 return 0;
3164
3165 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
3166 zlog_debug(
3167 "del remote %s es %s evi %u vtep %pI4",
3168 p->prefix.ead_addr.eth_tag ? "ead-es" : "ead-evi",
3169 esi_to_str(&p->prefix.ead_addr.esi, buf, sizeof(buf)),
3170 vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4);
c44ab6f1
AK
3171
3172 es = bgp_evpn_es_find(&p->prefix.ead_addr.esi);
3173 if (!es)
3174 /* XXX - error logs */
3175 return 0;
3176 es_evi = bgp_evpn_es_evi_find(es, vpn);
3177 if (!es_evi)
3178 /* XXX - error logs */
3179 return 0;
3180
3181 ead_es = !!p->prefix.ead_addr.eth_tag;
3182 bgp_evpn_es_evi_vtep_del(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
3183 ead_es);
3184 bgp_evpn_es_evi_remote_info_re_eval(es_evi);
3185 return 0;
3186}
3187
3188/* Initialize the ES tables maintained per-L2_VNI */
3189void bgp_evpn_vni_es_init(struct bgpevpn *vpn)
3190{
3191 /* Initialize the ES-EVI RB tree */
3192 RB_INIT(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree);
3193
3194 /* Initialize the local list maintained for quick walks by type */
3195 vpn->local_es_evi_list = list_new();
3196 listset_app_node_mem(vpn->local_es_evi_list);
3197}
3198
3199/* Cleanup the ES info maintained per-L2_VNI */
3200void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn)
3201{
3202 struct bgp_evpn_es_evi *es_evi;
3203 struct bgp_evpn_es_evi *es_evi_next;
3204
3205 RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head,
3206 &vpn->es_evi_rb_tree, es_evi_next) {
3207 bgp_evpn_local_es_evi_do_del(es_evi);
3208 }
3209
3210 list_delete(&vpn->local_es_evi_list);
3211}
3212
3213static char *bgp_evpn_es_evi_vteps_str(char *vtep_str,
9e0c2fd1
AK
3214 struct bgp_evpn_es_evi *es_evi,
3215 uint8_t vtep_str_size)
c44ab6f1
AK
3216{
3217 char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
3218 struct listnode *node;
3219 struct bgp_evpn_es_evi_vtep *evi_vtep;
3220 bool first = true;
ec779825 3221 char ip_buf[INET6_ADDRSTRLEN];
c44ab6f1
AK
3222
3223 vtep_str[0] = '\0';
3224 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
3225 vtep_flag_str[0] = '\0';
3226 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
9e0c2fd1 3227 strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
c44ab6f1 3228 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
9e0c2fd1 3229 strlcat(vtep_flag_str, "V", sizeof(vtep_flag_str));
c44ab6f1 3230
9e0c2fd1
AK
3231 if (!strnlen(vtep_flag_str, sizeof(vtep_flag_str)))
3232 strlcpy(vtep_flag_str, "-", sizeof(vtep_flag_str));
3233 if (first)
c44ab6f1 3234 first = false;
9e0c2fd1
AK
3235 else
3236 strlcat(vtep_str, ",", vtep_str_size);
23d0a753 3237 strlcat(vtep_str,
ec779825
AK
3238 inet_ntop(AF_INET, &evi_vtep->vtep_ip, ip_buf,
3239 sizeof(ip_buf)),
23d0a753 3240 vtep_str_size);
9e0c2fd1
AK
3241 strlcat(vtep_str, "(", vtep_str_size);
3242 strlcat(vtep_str, vtep_flag_str, vtep_str_size);
3243 strlcat(vtep_str, ")", vtep_str_size);
c44ab6f1
AK
3244 }
3245
3246 return vtep_str;
3247}
3248
3249static void bgp_evpn_es_evi_json_vtep_fill(json_object *json_vteps,
3250 struct bgp_evpn_es_evi_vtep *evi_vtep)
3251{
3252 json_object *json_vtep_entry;
3253 json_object *json_flags;
ec779825 3254 char ip_buf[INET6_ADDRSTRLEN];
c44ab6f1
AK
3255
3256 json_vtep_entry = json_object_new_object();
3257
ec779825
AK
3258 json_object_string_add(
3259 json_vtep_entry, "vtep_ip",
3260 inet_ntop(AF_INET, &evi_vtep->vtep_ip, ip_buf, sizeof(ip_buf)));
c44ab6f1
AK
3261 if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
3262 BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) {
3263 json_flags = json_object_new_array();
3264 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
3265 json_array_string_add(json_flags, "ead-per-es");
3266 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
3267 json_array_string_add(json_flags, "ed-per-evi");
3268 json_object_object_add(json_vtep_entry,
3269 "flags", json_flags);
3270 }
3271
3272 json_object_array_add(json_vteps,
3273 json_vtep_entry);
3274}
3275
3276static void bgp_evpn_es_evi_show_entry(struct vty *vty,
3277 struct bgp_evpn_es_evi *es_evi, json_object *json)
3278{
3279 struct listnode *node;
3280 struct bgp_evpn_es_evi_vtep *evi_vtep;
3281
3282 if (json) {
3283 json_object *json_vteps;
3284 json_object *json_types;
3285
3286 json_object_string_add(json, "esi", es_evi->es->esi_str);
3287 json_object_int_add(json, "vni", es_evi->vpn->vni);
3288
3289 if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL |
3290 BGP_EVPNES_EVI_REMOTE)) {
3291 json_types = json_object_new_array();
3292 if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
3293 json_array_string_add(json_types, "local");
3294 if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
3295 json_array_string_add(json_types, "remote");
3296 json_object_object_add(json, "type", json_types);
3297 }
3298
3299 if (listcount(es_evi->es_evi_vtep_list)) {
3300 json_vteps = json_object_new_array();
3301 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list,
3302 node, evi_vtep)) {
3303 bgp_evpn_es_evi_json_vtep_fill(json_vteps,
3304 evi_vtep);
3305 }
3306 json_object_object_add(json, "vteps", json_vteps);
3307 }
3308 } else {
3309 char type_str[4];
3310 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
3311
3312 type_str[0] = '\0';
3313 if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
9e0c2fd1 3314 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 3315 if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
9e0c2fd1 3316 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 3317 if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST)
9e0c2fd1 3318 strlcat(type_str, "I", sizeof(type_str));
c44ab6f1 3319
9e0c2fd1 3320 bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
c44ab6f1
AK
3321
3322 vty_out(vty, "%-8d %-30s %-5s %s\n",
3323 es_evi->vpn->vni, es_evi->es->esi_str,
3324 type_str, vtep_str);
3325 }
3326}
3327
3328static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
3329 struct bgp_evpn_es_evi *es_evi, json_object *json)
3330{
3331 if (json) {
3332 json_object *json_flags;
3333
3334 /* Add the "brief" info first */
3335 bgp_evpn_es_evi_show_entry(vty, es_evi, json);
3336 if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) {
3337 json_flags = json_object_new_array();
3338 json_array_string_add(json_flags, "es-vtep-mismatch");
3339 json_object_object_add(json, "flags", json_flags);
3340 }
3341 } else {
3342 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
3343 char type_str[4];
3344
3345 type_str[0] = '\0';
3346 if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
9e0c2fd1 3347 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 3348 if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
9e0c2fd1 3349 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 3350
9e0c2fd1 3351 bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
c44ab6f1 3352 if (!strlen(vtep_str))
9e0c2fd1 3353 strlcpy(vtep_str, "-", sizeof(type_str));
c44ab6f1
AK
3354
3355 vty_out(vty, "VNI: %d ESI: %s\n",
3356 es_evi->vpn->vni, es_evi->es->esi_str);
3357 vty_out(vty, " Type: %s\n", type_str);
3358 vty_out(vty, " Inconsistencies: %s\n",
3359 (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
3360 "es-vtep-mismatch":"-");
3361 vty_out(vty, " VTEPs: %s\n", vtep_str);
3362 vty_out(vty, "\n");
3363 }
3364}
3365
3366static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn *vpn, struct vty *vty,
3367 json_object *json_array, bool detail)
3368{
3369 struct bgp_evpn_es_evi *es_evi;
3370 json_object *json = NULL;
3371
3372 RB_FOREACH(es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree) {
3373 if (json_array)
3374 /* create a separate json object for each ES */
3375 json = json_object_new_object();
3376 if (detail)
3377 bgp_evpn_es_evi_show_entry_detail(vty, es_evi, json);
3378 else
3379 bgp_evpn_es_evi_show_entry(vty, es_evi, json);
3380 /* add ES to the json array */
3381 if (json_array)
3382 json_object_array_add(json_array, json);
3383 }
3384}
3385
3386struct es_evi_show_ctx {
3387 struct vty *vty;
3388 json_object *json;
3389 int detail;
3390};
3391
3392static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket *bucket,
3393 void *ctxt)
3394{
3395 struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
3396 struct es_evi_show_ctx *wctx = (struct es_evi_show_ctx *)ctxt;
3397
3398 bgp_evpn_es_evi_show_one_vni(vpn, wctx->vty, wctx->json, wctx->detail);
3399}
3400
3401/* Display all ES EVIs */
3402void bgp_evpn_es_evi_show(struct vty *vty, bool uj, bool detail)
3403{
3404 json_object *json_array = NULL;
3405 struct es_evi_show_ctx wctx;
3406 struct bgp *bgp;
3407
3408 if (uj) {
3409 /* create an array of ES-EVIs */
3410 json_array = json_object_new_array();
3411 }
3412
3413 wctx.vty = vty;
3414 wctx.json = json_array;
3415 wctx.detail = detail;
3416
3417 bgp = bgp_get_evpn();
3418
3419 if (!json_array && !detail) {
3420 vty_out(vty, "Flags: L local, R remote, I inconsistent\n");
3421 vty_out(vty, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3422 vty_out(vty, "%-8s %-30s %-5s %s\n",
3423 "VNI", "ESI", "Flags", "VTEPs");
3424 }
3425
3426 if (bgp)
3427 hash_iterate(bgp->vnihash,
3428 (void (*)(struct hash_bucket *,
3429 void *))bgp_evpn_es_evi_show_one_vni_hash_cb,
3430 &wctx);
3431 if (uj) {
3432 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3433 json_array, JSON_C_TO_STRING_PRETTY));
3434 json_object_free(json_array);
3435 }
3436}
3437
3438/* Display specific ES EVI */
3439void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni,
3440 bool uj, bool detail)
3441{
3442 struct bgpevpn *vpn = NULL;
3443 json_object *json_array = NULL;
3444 struct bgp *bgp;
3445
3446 if (uj) {
3447 /* create an array of ES-EVIs */
3448 json_array = json_object_new_array();
3449 }
3450
3451 bgp = bgp_get_evpn();
3452 if (bgp)
3453 vpn = bgp_evpn_lookup_vni(bgp, vni);
3454
3455 if (vpn) {
3456 if (!json_array && !detail) {
3457 vty_out(vty, "Flags: L local, R remote, I inconsistent\n");
3458 vty_out(vty, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3459 vty_out(vty, "%-8s %-30s %-5s %s\n",
3460 "VNI", "ESI", "Flags", "VTEPs");
3461 }
3462
3463 bgp_evpn_es_evi_show_one_vni(vpn, vty, json_array, detail);
3464 } else {
3465 if (!uj)
3466 vty_out(vty, "VNI not found\n");
3467 }
3468
3469 if (uj) {
3470 vty_out(vty, "%s\n", json_object_to_json_string_ext(
3471 json_array, JSON_C_TO_STRING_PRETTY));
3472 json_object_free(json_array);
3473 }
3474}
3475
3476/*****************************************************************************
3477 * Ethernet Segment Consistency checks
3478 * Consistency checking is done to detect misconfig or mis-cabling. When
3479 * an inconsistency is detected it is simply logged (and displayed via
3480 * show commands) at this point. A more drastic action can be executed (based
3481 * on user config) in the future.
3482 */
3483/* queue up the es for background consistency checks */
3484static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es)
3485{
3486 if (!bgp_mh_info->consistency_checking)
3487 /* consistency checking is not enabled */
3488 return;
3489
3490 if (CHECK_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND))
3491 /* already queued for consistency checking */
3492 return;
3493
3494 SET_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND);
3495 listnode_init(&es->pend_es_listnode, es);
3496 listnode_add_after(bgp_mh_info->pend_es_list,
3497 listtail_unchecked(bgp_mh_info->pend_es_list),
3498 &es->pend_es_listnode);
3499}
3500
3501/* pull the ES from the consistency check list */
3502static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es)
3503{
3504 if (!CHECK_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND))
3505 return;
3506
3507 UNSET_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND);
3508 list_delete_node(bgp_mh_info->pend_es_list,
3509 &es->pend_es_listnode);
3510}
3511
3512/* Number of active VTEPs associated with the ES-per-EVI */
3513static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
3514 struct bgp_evpn_es_evi *es_evi)
3515{
3516 struct bgp_evpn_es_evi_vtep *evi_vtep;
3517 struct listnode *node;
3518 uint32_t vtep_cnt = 0;
3519
3520 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
3521 if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE))
3522 ++vtep_cnt;
3523 }
3524
3525 return vtep_cnt;
3526}
3527
3528/* Number of active VTEPs associated with the ES */
3529static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es)
3530{
3531 struct listnode *node;
3532 uint32_t vtep_cnt = 0;
3533 struct bgp_evpn_es_vtep *es_vtep;
3534
3535 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
3536 if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
3537 ++vtep_cnt;
3538 }
3539
3540 return vtep_cnt;
3541}
3542
3543static struct bgp_evpn_es_vtep *bgp_evpn_es_get_next_active_vtep(
3544 struct bgp_evpn_es *es, struct bgp_evpn_es_vtep *es_vtep)
3545{
3546 struct listnode *node;
3547 struct bgp_evpn_es_vtep *next_es_vtep;
3548
3549 if (es_vtep)
3550 node = listnextnode_unchecked(&es_vtep->es_listnode);
3551 else
3552 node = listhead(es->es_vtep_list);
3553
3554 for (; node; node = listnextnode_unchecked(node)) {
3555 next_es_vtep = listgetdata(node);
3556 if (CHECK_FLAG(next_es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
3557 return next_es_vtep;
3558 }
3559
3560 return NULL;
3561}
3562
3563static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_get_next_active_vtep(
3564 struct bgp_evpn_es_evi *es_evi,
3565 struct bgp_evpn_es_evi_vtep *evi_vtep)
3566{
3567 struct listnode *node;
3568 struct bgp_evpn_es_evi_vtep *next_evi_vtep;
3569
3570 if (evi_vtep)
3571 node = listnextnode_unchecked(&evi_vtep->es_evi_listnode);
3572 else
3573 node = listhead(es_evi->es_evi_vtep_list);
3574
3575 for (; node; node = listnextnode_unchecked(node)) {
3576 next_evi_vtep = listgetdata(node);
3577 if (CHECK_FLAG(next_evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE))
3578 return next_evi_vtep;
3579 }
3580
3581 return NULL;
3582}
3583
3584static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi *es_evi)
3585{
3586 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST)) {
3587 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
3588 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
3589 es_evi->es->esi_str,
3590 es_evi->vpn->vni);
3591 SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST);
3592
3593 /* update parent ES with the incosistency setting */
3594 if (!es_evi->es->incons_evi_vtep_cnt &&
3595 BGP_DEBUG(evpn_mh, EVPN_MH_ES))
3596 zlog_debug("inconsistency detected - es %s vtep list mismatch",
3597 es_evi->es->esi_str);
3598 ++es_evi->es->incons_evi_vtep_cnt;
3599 SET_FLAG(es_evi->es->inconsistencies,
3600 BGP_EVPNES_INCONS_VTEP_LIST);
3601 }
3602}
3603
3604static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es *es)
3605{
3606 int proc_cnt = 0;
3607 int es_active_vtep_cnt;
3608 int evi_active_vtep_cnt;
3609 struct bgp_evpn_es_evi *es_evi;
3610 struct listnode *evi_node;
3611 struct bgp_evpn_es_vtep *es_vtep;
3612 struct bgp_evpn_es_evi_vtep *evi_vtep;
3613
3614 /* reset the inconsistencies and re-evaluate */
3615 es->incons_evi_vtep_cnt = 0;
3616 es->inconsistencies = 0;
3617
3618 es_active_vtep_cnt = bgp_evpn_es_get_active_vtep_cnt(es);
3619 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
3620 evi_node, es_evi)) {
3621 ++proc_cnt;
3622
3623 /* reset the inconsistencies on the EVI and re-evaluate*/
3624 UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST);
3625
3626 evi_active_vtep_cnt =
3627 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi);
3628 if (es_active_vtep_cnt != evi_active_vtep_cnt) {
3629 bgp_evpn_es_evi_set_inconsistent(es_evi);
3630 continue;
3631 }
3632
3633 if (!es_active_vtep_cnt)
3634 continue;
3635
3636 es_vtep = NULL;
3637 evi_vtep = NULL;
3638 while ((es_vtep = bgp_evpn_es_get_next_active_vtep(
3639 es, es_vtep))) {
3640 evi_vtep = bgp_evpn_es_evi_get_next_active_vtep(es_evi,
3641 evi_vtep);
3642 if (!evi_vtep) {
3643 bgp_evpn_es_evi_set_inconsistent(es_evi);
3644 break;
3645 }
3646 if (es_vtep->vtep_ip.s_addr !=
3647 evi_vtep->vtep_ip.s_addr) {
3648 /* inconsistency detected; set it and move
3649 * to the next evi
3650 */
3651 bgp_evpn_es_evi_set_inconsistent(es_evi);
3652 break;
3653 }
3654 }
3655 }
3656
3657 return proc_cnt;
3658}
3659
3660static int bgp_evpn_run_consistency_checks(struct thread *t)
3661{
3662 int proc_cnt = 0;
3663 int es_cnt = 0;
3664 struct listnode *node;
3665 struct listnode *nextnode;
3666 struct bgp_evpn_es *es;
3667
3668 for (ALL_LIST_ELEMENTS(bgp_mh_info->pend_es_list,
3669 node, nextnode, es)) {
3670 ++es_cnt;
3671 ++proc_cnt;
3672 /* run consistency checks on the ES and remove it from the
3673 * pending list
3674 */
3675 proc_cnt += bgp_evpn_es_run_consistency_checks(es);
3676 bgp_evpn_es_cons_checks_pend_del(es);
3677 if (proc_cnt > 500)
3678 break;
3679 }
3680
3681 /* restart the timer */
3682 thread_add_timer(bm->master, bgp_evpn_run_consistency_checks, NULL,
3683 BGP_EVPN_CONS_CHECK_INTERVAL,
3684 &bgp_mh_info->t_cons_check);
3685
3686 return 0;
3687}
3688
3689/*****************************************************************************/
3690void bgp_evpn_mh_init(void)
3691{
3692 bm->mh_info = XCALLOC(MTYPE_BGP_EVPN_MH_INFO, sizeof(*bm->mh_info));
3693
3694 /* setup ES tables */
3695 RB_INIT(bgp_es_rb_head, &bgp_mh_info->es_rb_tree);
3696 /* local ES list */
3697 bgp_mh_info->local_es_list = list_new();
3698 listset_app_node_mem(bgp_mh_info->local_es_list);
3699 /* list of ESs with pending processing */
3700 bgp_mh_info->pend_es_list = list_new();
3701 listset_app_node_mem(bgp_mh_info->pend_es_list);
3702
3703 /* config knobs - XXX add cli to control it */
3704 bgp_mh_info->ead_evi_adv_for_down_links = true;
3705 bgp_mh_info->consistency_checking = true;
2867823e
AK
3706 bgp_mh_info->install_l3nhg = false;
3707 bgp_mh_info->host_routes_use_l3nhg = BGP_EVPN_MH_USE_ES_L3NHG_DEF;
c44ab6f1
AK
3708
3709 if (bgp_mh_info->consistency_checking)
3710 thread_add_timer(bm->master, bgp_evpn_run_consistency_checks,
3711 NULL, BGP_EVPN_CONS_CHECK_INTERVAL,
3712 &bgp_mh_info->t_cons_check);
3713
3714 memset(&zero_esi_buf, 0, sizeof(esi_t));
3715}
3716
3717void bgp_evpn_mh_finish(void)
3718{
3719 struct bgp_evpn_es *es;
3720 struct bgp_evpn_es *es_next;
c44ab6f1 3721
45a859f1
AK
3722 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
3723 zlog_debug("evpn mh finish");
3724
3725 RB_FOREACH_SAFE (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree,
3726 es_next) {
3727 bgp_evpn_es_local_info_clear(es);
c44ab6f1 3728 }
b3d6bc6e 3729 thread_cancel(&bgp_mh_info->t_cons_check);
c44ab6f1
AK
3730 list_delete(&bgp_mh_info->local_es_list);
3731 list_delete(&bgp_mh_info->pend_es_list);
3732
3733 XFREE(MTYPE_BGP_EVPN_MH_INFO, bgp_mh_info);
3734}