]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_evpn_mh.c
Merge pull request #10813 from opensourcerouting/fix/include_prune_stats_for_pim_traf...
[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"
23aa35ad 53#include "bgpd/bgp_trace.h"
c44ab6f1
AK
54
55static void bgp_evpn_local_es_down(struct bgp *bgp,
56 struct bgp_evpn_es *es);
57static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp,
58 struct bgp_evpn_es *es);
59static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
74e2bd89
AK
60 struct bgp_evpn_es *es,
61 struct in_addr vtep_ip,
62 bool esr, uint8_t df_alg,
63 uint16_t df_pref);
c44ab6f1
AK
64static void bgp_evpn_es_vtep_del(struct bgp *bgp,
65 struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr);
66static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es);
67static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es);
333ad64b
AK
68static struct bgp_evpn_es_evi *
69bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi);
c589d847
AK
70static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es);
71static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es);
26c03e43
AK
72static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi);
73static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller);
60605cbc 74static void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info);
74efb822
AK
75static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es *es,
76 bool is_local);
c44ab6f1
AK
77
78esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
cc9f21da 79static void bgp_evpn_run_consistency_checks(struct thread *t);
090efa2f
AK
80static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info *nh_info);
81static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info);
c44ab6f1
AK
82
83/******************************************************************************
84 * per-ES (Ethernet Segment) routing table
85 *
86 * Following routes are added to the ES's routing table -
87 * 1. Local and remote ESR (Type-4)
88 * 2. Local EAD-per-ES (Type-1).
89 *
90 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
91 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
92 * being added to same ES).
93 *
94 * Note the following routes go into the VNI routing table (instead of the
95 * ES routing table) -
96 * 1. Remote EAD-per-ES
97 * 2. Local and remote EAD-per-EVI
185fb14a 98 */
185fb14a 99
c44ab6f1
AK
100/* Calculate the best path for a multi-homing (Type-1 or Type-4) route
101 * installed in the ES's routing table.
185fb14a 102 */
c44ab6f1 103static int bgp_evpn_es_route_select_install(struct bgp *bgp,
09319b4e
DS
104 struct bgp_evpn_es *es,
105 struct bgp_dest *dest)
185fb14a
AK
106{
107 int ret = 0;
108 afi_t afi = AFI_L2VPN;
109 safi_t safi = SAFI_EVPN;
110 struct bgp_path_info *old_select; /* old best */
111 struct bgp_path_info *new_select; /* new best */
112 struct bgp_path_info_pair old_and_new;
113
114 /* Compute the best path. */
09319b4e
DS
115 bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new,
116 afi, safi);
185fb14a
AK
117 old_select = old_and_new.old;
118 new_select = old_and_new.new;
119
120 /*
121 * If the best path hasn't changed - see if something needs to be
122 * updated
123 */
124 if (old_select && old_select == new_select
09319b4e
DS
125 && old_select->type == ZEBRA_ROUTE_BGP
126 && old_select->sub_type == BGP_ROUTE_IMPORTED
127 && !CHECK_FLAG(dest->flags, BGP_NODE_USER_CLEAR)
128 && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
129 && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
185fb14a 130 if (bgp_zebra_has_route_changed(old_select)) {
74e2bd89
AK
131 bgp_evpn_es_vtep_add(bgp, es, old_select->attr->nexthop,
132 true /*esr*/,
133 old_select->attr->df_alg,
134 old_select->attr->df_pref);
185fb14a
AK
135 }
136 UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
09319b4e 137 bgp_zebra_clear_route_change_flags(dest);
185fb14a
AK
138 return ret;
139 }
140
141 /* If the user did a "clear" this flag will be set */
09319b4e 142 UNSET_FLAG(dest->flags, BGP_NODE_USER_CLEAR);
185fb14a 143
c44ab6f1 144 /* bestpath has changed; update relevant fields and install or uninstall
185fb14a
AK
145 * into the zebra RIB.
146 */
147 if (old_select || new_select)
09319b4e 148 bgp_bump_version(dest);
185fb14a
AK
149
150 if (old_select)
09319b4e 151 bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED);
185fb14a 152 if (new_select) {
09319b4e
DS
153 bgp_path_info_set_flag(dest, new_select, BGP_PATH_SELECTED);
154 bgp_path_info_unset_flag(dest, new_select,
155 BGP_PATH_ATTR_CHANGED);
185fb14a
AK
156 UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG);
157 }
158
159 if (new_select && new_select->type == ZEBRA_ROUTE_BGP
c44ab6f1 160 && new_select->sub_type == BGP_ROUTE_IMPORTED) {
74e2bd89
AK
161 bgp_evpn_es_vtep_add(bgp, es, new_select->attr->nexthop,
162 true /*esr */, new_select->attr->df_alg,
163 new_select->attr->df_pref);
185fb14a
AK
164 } else {
165 if (old_select && old_select->type == ZEBRA_ROUTE_BGP
c44ab6f1
AK
166 && old_select->sub_type == BGP_ROUTE_IMPORTED)
167 bgp_evpn_es_vtep_del(
168 bgp, es, old_select->attr->nexthop,
169 true /*esr*/);
185fb14a
AK
170 }
171
172 /* Clear any route change flags. */
09319b4e 173 bgp_zebra_clear_route_change_flags(dest);
185fb14a
AK
174
175 /* Reap old select bgp_path_info, if it has been removed */
176 if (old_select && CHECK_FLAG(old_select->flags, BGP_PATH_REMOVED))
09319b4e 177 bgp_path_info_reap(dest, old_select);
185fb14a
AK
178
179 return ret;
180}
181
c44ab6f1
AK
182/* Install Type-1/Type-4 route entry in the per-ES routing table */
183static int bgp_evpn_es_route_install(struct bgp *bgp,
184 struct bgp_evpn_es *es, struct prefix_evpn *p,
185 struct bgp_path_info *parent_pi)
186{
187 int ret = 0;
09319b4e 188 struct bgp_dest *dest = NULL;
c44ab6f1
AK
189 struct bgp_path_info *pi = NULL;
190 struct attr *attr_new = NULL;
191
192 /* Create (or fetch) route within the VNI.
193 * NOTE: There is no RD here.
194 */
09319b4e 195 dest = bgp_node_get(es->route_table, (struct prefix *)p);
c44ab6f1
AK
196
197 /* Check if route entry is already present. */
09319b4e 198 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
c44ab6f1
AK
199 if (pi->extra
200 && (struct bgp_path_info *)pi->extra->parent ==
201 parent_pi)
202 break;
203
204 if (!pi) {
205 /* Add (or update) attribute to hash. */
206 attr_new = bgp_attr_intern(parent_pi->attr);
207
208 /* Create new route with its attribute. */
209 pi = info_make(parent_pi->type, BGP_ROUTE_IMPORTED, 0,
09319b4e 210 parent_pi->peer, attr_new, dest);
c44ab6f1
AK
211 SET_FLAG(pi->flags, BGP_PATH_VALID);
212 bgp_path_info_extra_get(pi);
213 pi->extra->parent = bgp_path_info_lock(parent_pi);
09319b4e
DS
214 bgp_dest_lock_node((struct bgp_dest *)parent_pi->net);
215 bgp_path_info_add(dest, pi);
c44ab6f1
AK
216 } else {
217 if (attrhash_cmp(pi->attr, parent_pi->attr)
218 && !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
09319b4e 219 bgp_dest_unlock_node(dest);
c44ab6f1
AK
220 return 0;
221 }
222 /* The attribute has changed. */
223 /* Add (or update) attribute to hash. */
224 attr_new = bgp_attr_intern(parent_pi->attr);
225
226 /* Restore route, if needed. */
227 if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED))
09319b4e 228 bgp_path_info_restore(dest, pi);
c44ab6f1
AK
229
230 /* Mark if nexthop has changed. */
231 if (!IPV4_ADDR_SAME(&pi->attr->nexthop, &attr_new->nexthop))
232 SET_FLAG(pi->flags, BGP_PATH_IGP_CHANGED);
233
234 /* Unintern existing, set to new. */
235 bgp_attr_unintern(&pi->attr);
236 pi->attr = attr_new;
237 pi->uptime = bgp_clock();
238 }
239
240 /* Perform route selection and update zebra, if required. */
09319b4e 241 ret = bgp_evpn_es_route_select_install(bgp, es, dest);
c44ab6f1 242
09319b4e 243 bgp_dest_unlock_node(dest);
c44ab6f1
AK
244
245 return ret;
246}
247
248/* Uninstall Type-1/Type-4 route entry from the ES routing table */
249static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
250 struct prefix_evpn *p, struct bgp_path_info *parent_pi)
251{
252 int ret;
09319b4e 253 struct bgp_dest *dest;
c44ab6f1
AK
254 struct bgp_path_info *pi;
255
256 if (!es->route_table)
257 return 0;
258
259 /* Locate route within the ESI.
260 * NOTE: There is no RD here.
261 */
09319b4e
DS
262 dest = bgp_node_lookup(es->route_table, (struct prefix *)p);
263 if (!dest)
c44ab6f1
AK
264 return 0;
265
266 /* Find matching route entry. */
09319b4e 267 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
c44ab6f1
AK
268 if (pi->extra
269 && (struct bgp_path_info *)pi->extra->parent ==
270 parent_pi)
271 break;
272
e71ad4b6
DA
273 if (!pi) {
274 bgp_dest_unlock_node(dest);
c44ab6f1 275 return 0;
e71ad4b6 276 }
c44ab6f1
AK
277
278 /* Mark entry for deletion */
09319b4e 279 bgp_path_info_delete(dest, pi);
c44ab6f1
AK
280
281 /* Perform route selection and update zebra, if required. */
09319b4e 282 ret = bgp_evpn_es_route_select_install(bgp, es, dest);
c44ab6f1
AK
283
284 /* Unlock route node. */
09319b4e 285 bgp_dest_unlock_node(dest);
c44ab6f1
AK
286
287 return ret;
288}
289
290/* Install or unistall a Tyoe-4 route in the per-ES routing table */
291int bgp_evpn_es_route_install_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
292 afi_t afi, safi_t safi, struct prefix_evpn *evp,
293 struct bgp_path_info *pi, int install)
294{
295 int ret = 0;
296
297 if (install)
298 ret = bgp_evpn_es_route_install(bgp, es, evp, pi);
299 else
300 ret = bgp_evpn_es_route_uninstall(bgp, es, evp, pi);
301
302 if (ret) {
303 flog_err(
304 EC_BGP_EVPN_FAIL,
305 "%u: Failed to %s EVPN %s route in ESI %s",
306 bgp->vrf_id,
307 install ? "install" : "uninstall",
308 "ES", es->esi_str);
309 return ret;
310 }
311 return 0;
312}
313
314/* Delete (and withdraw) local routes for specified ES from global and ES table.
315 * Also remove all remote routes from the per ES table. Invoked when ES
316 * is deleted.
185fb14a 317 */
c44ab6f1
AK
318static void bgp_evpn_es_route_del_all(struct bgp *bgp, struct bgp_evpn_es *es)
319{
09319b4e 320 struct bgp_dest *dest;
c44ab6f1
AK
321 struct bgp_path_info *pi, *nextpi;
322
323 /* de-activate the ES */
324 bgp_evpn_local_es_down(bgp, es);
325 bgp_evpn_local_type1_evi_route_del(bgp, es);
326
327 /* Walk this ES's routing table and delete all routes. */
09319b4e
DS
328 for (dest = bgp_table_top(es->route_table); dest;
329 dest = bgp_route_next(dest)) {
330 for (pi = bgp_dest_get_bgp_path_info(dest);
331 (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
332 bgp_path_info_delete(dest, pi);
333 bgp_path_info_reap(dest, pi);
c44ab6f1
AK
334 }
335 }
336}
337
338/*****************************************************************************
339 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
340 * segment updates.
341 */
342
343/* create or update local EVPN type1/type4 route entry.
344 *
345 * This could be in -
346 * the ES table if ESR/EAD-ES (or)
347 * the VNI table if EAD-EVI (or)
348 * the global table if ESR/EAD-ES/EAD-EVI
349 *
350 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
351 * ESR).
352 */
d60f63f0
AD
353int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
354 struct bgpevpn *vpn, afi_t afi, safi_t safi,
355 struct bgp_dest *dest, struct attr *attr, int add,
356 struct bgp_path_info **ri, int *route_changed)
185fb14a 357{
185fb14a
AK
358 struct bgp_path_info *tmp_pi = NULL;
359 struct bgp_path_info *local_pi = NULL; /* local route entry if any */
360 struct bgp_path_info *remote_pi = NULL; /* remote route entry if any */
361 struct attr *attr_new = NULL;
c44ab6f1 362 struct prefix_evpn *evp;
185fb14a
AK
363
364 *ri = NULL;
752eed47 365 evp = (struct prefix_evpn *)bgp_dest_get_prefix(dest);
c44ab6f1 366 *route_changed = 1;
185fb14a
AK
367
368 /* locate the local and remote entries if any */
09319b4e 369 for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
185fb14a
AK
370 tmp_pi = tmp_pi->next) {
371 if (tmp_pi->peer == bgp->peer_self
c44ab6f1
AK
372 && tmp_pi->type == ZEBRA_ROUTE_BGP
373 && tmp_pi->sub_type == BGP_ROUTE_STATIC)
185fb14a
AK
374 local_pi = tmp_pi;
375 if (tmp_pi->type == ZEBRA_ROUTE_BGP
c44ab6f1
AK
376 && tmp_pi->sub_type == BGP_ROUTE_IMPORTED
377 && CHECK_FLAG(tmp_pi->flags, BGP_PATH_VALID))
185fb14a
AK
378 remote_pi = tmp_pi;
379 }
380
c44ab6f1
AK
381 /* we don't expect to see a remote_ri at this point as
382 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
383 * in the VNI-rt-table.
185fb14a
AK
384 */
385 if (remote_pi) {
386 flog_err(
23d0a753
DA
387 EC_BGP_ES_INVALID,
388 "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
d60f63f0
AD
389 bgp->vrf_id, es ? es->esi_str : "Null",
390 &es->originator_ip);
185fb14a
AK
391 return -1;
392 }
393
394 if (!local_pi && !add)
395 return 0;
396
397 /* create or update the entry */
398 if (!local_pi) {
399
400 /* Add or update attribute to hash */
401 attr_new = bgp_attr_intern(attr);
402
403 /* Create new route with its attribute. */
404 tmp_pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
09319b4e 405 bgp->peer_self, attr_new, dest);
185fb14a
AK
406 SET_FLAG(tmp_pi->flags, BGP_PATH_VALID);
407
c44ab6f1
AK
408 if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) {
409 bgp_path_info_extra_get(tmp_pi);
410 tmp_pi->extra->num_labels = 1;
411 if (vpn)
412 vni2label(vpn->vni, &tmp_pi->extra->label[0]);
413 else
414 tmp_pi->extra->label[0] = 0;
415 }
416
185fb14a 417 /* add the newly created path to the route-node */
09319b4e 418 bgp_path_info_add(dest, tmp_pi);
185fb14a
AK
419 } else {
420 tmp_pi = local_pi;
421 if (attrhash_cmp(tmp_pi->attr, attr)
c44ab6f1 422 && !CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
185fb14a
AK
423 *route_changed = 0;
424 else {
425 /* The attribute has changed.
426 * Add (or update) attribute to hash.
427 */
428 attr_new = bgp_attr_intern(attr);
09319b4e
DS
429 bgp_path_info_set_flag(dest, tmp_pi,
430 BGP_PATH_ATTR_CHANGED);
185fb14a
AK
431
432 /* Restore route, if needed. */
433 if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
09319b4e 434 bgp_path_info_restore(dest, tmp_pi);
185fb14a
AK
435
436 /* Unintern existing, set to new. */
437 bgp_attr_unintern(&tmp_pi->attr);
438 tmp_pi->attr = attr_new;
439 tmp_pi->uptime = bgp_clock();
440 }
441 }
442
c44ab6f1
AK
443 if (*route_changed) {
444 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
23d0a753
DA
445 zlog_debug(
446 "local ES %s vni %u route-type %s nexthop %pI4 updated",
d60f63f0 447 es ? es->esi_str : "Null", vpn ? vpn->vni : 0,
23d0a753
DA
448 evp->prefix.route_type == BGP_EVPN_ES_ROUTE
449 ? "esr"
450 : (vpn ? "ead-evi" : "ead-es"),
451 &attr->mp_nexthop_global_in);
c44ab6f1
AK
452 }
453
185fb14a
AK
454 /* Return back the route entry. */
455 *ri = tmp_pi;
456 return 0;
457}
458
c44ab6f1
AK
459/* Delete local EVPN ESR (type-4) and EAD (type-1) route
460 *
461 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
462 * ESR).
463 */
464static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
465 struct bgpevpn *vpn, struct prefix_evpn *p)
185fb14a 466{
185fb14a
AK
467 afi_t afi = AFI_L2VPN;
468 safi_t safi = SAFI_EVPN;
c44ab6f1 469 struct bgp_path_info *pi;
09319b4e
DS
470 struct bgp_dest *dest = NULL; /* dest in esi table */
471 struct bgp_dest *global_dest = NULL; /* dest in global table */
c44ab6f1
AK
472 struct bgp_table *rt_table;
473 struct prefix_rd *prd;
185fb14a 474
c44ab6f1
AK
475 if (vpn) {
476 rt_table = vpn->route_table;
477 prd = &vpn->prd;
478 } else {
479 rt_table = es->route_table;
480 prd = &es->prd;
481 }
185fb14a 482
c44ab6f1
AK
483 /* First, locate the route node within the ESI or VNI.
484 * If it doesn't exist, ther is nothing to do.
485 * Note: there is no RD here.
486 */
09319b4e
DS
487 dest = bgp_node_lookup(rt_table, (struct prefix *)p);
488 if (!dest)
c44ab6f1 489 return 0;
185fb14a 490
c44ab6f1 491 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
23d0a753
DA
492 zlog_debug(
493 "local ES %s vni %u route-type %s nexthop %pI4 delete",
494 es->esi_str, vpn ? vpn->vni : 0,
495 p->prefix.route_type == BGP_EVPN_ES_ROUTE
496 ? "esr"
497 : (vpn ? "ead-evi" : "ead-es"),
498 &es->originator_ip);
185fb14a 499
c44ab6f1
AK
500 /* Next, locate route node in the global EVPN routing table.
501 * Note that this table is a 2-level tree (RD-level + Prefix-level)
502 */
09319b4e
DS
503 global_dest =
504 bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
505 (const struct prefix_evpn *)p, prd);
506 if (global_dest) {
185fb14a 507
c44ab6f1 508 /* Delete route entry in the global EVPN table. */
09319b4e 509 delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
185fb14a
AK
510
511 /* Schedule for processing - withdraws to peers happen from
512 * this table.
513 */
514 if (pi)
09319b4e
DS
515 bgp_process(bgp, global_dest, afi, safi);
516 bgp_dest_unlock_node(global_dest);
185fb14a
AK
517 }
518
519 /*
c44ab6f1 520 * Delete route entry in the ESI or VNI routing table.
185fb14a
AK
521 * This can just be removed.
522 */
09319b4e 523 delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
185fb14a 524 if (pi)
09319b4e
DS
525 bgp_path_info_reap(dest, pi);
526 bgp_dest_unlock_node(dest);
185fb14a
AK
527 return 0;
528}
529
d60f63f0
AD
530/*
531 * This function is called when the VNI RD changes.
532 * Delete all EAD/EVI local routes for this VNI from the global routing table.
533 * These routes are scheduled for withdraw from peers.
534 */
535int delete_global_ead_evi_routes(struct bgp *bgp, struct bgpevpn *vpn)
536{
537 afi_t afi;
538 safi_t safi;
539 struct bgp_dest *rdrn, *rn;
540 struct bgp_table *table;
541 struct bgp_path_info *pi;
542
543 afi = AFI_L2VPN;
544 safi = SAFI_EVPN;
545
546 /* Find the RD node for the VNI in the global table */
547 rdrn = bgp_node_lookup(bgp->rib[afi][safi], (struct prefix *)&vpn->prd);
548 if (rdrn && bgp_dest_has_bgp_path_info_data(rdrn)) {
549 table = bgp_dest_get_bgp_table_info(rdrn);
550
551 /*
552 * Iterate over all the routes in this table and delete EAD/EVI
553 * routes
554 */
555 for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
556 struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
557
558 if (evp->prefix.route_type != BGP_EVPN_AD_ROUTE)
559 continue;
560
561 delete_evpn_route_entry(bgp, afi, safi, rn, &pi);
562 if (pi)
563 bgp_process(bgp, rn, afi, safi);
564 }
565 }
566
567 /* Unlock RD node. */
568 if (rdrn)
569 bgp_dest_unlock_node(rdrn);
570
571 return 0;
572}
573
c44ab6f1
AK
574/*****************************************************************************
575 * Ethernet Segment (Type-4) Routes
74e2bd89
AK
576 * ESRs are used for DF election. Currently service-carving described in
577 * RFC 7432 is NOT supported. Instead preference based DF election is
578 * used by default.
579 * Reference: draft-ietf-bess-evpn-pref-df
185fb14a 580 */
c44ab6f1
AK
581/* Build extended community for EVPN ES (type-4) route */
582static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es *es,
583 struct attr *attr)
185fb14a 584{
c44ab6f1
AK
585 struct ecommunity ecom_encap;
586 struct ecommunity ecom_es_rt;
74e2bd89 587 struct ecommunity ecom_df;
c44ab6f1
AK
588 struct ecommunity_val eval;
589 struct ecommunity_val eval_es_rt;
74e2bd89 590 struct ecommunity_val eval_df;
c44ab6f1
AK
591 bgp_encap_types tnl_type;
592 struct ethaddr mac;
185fb14a 593
c44ab6f1
AK
594 /* Encap */
595 tnl_type = BGP_ENCAP_TYPE_VXLAN;
596 memset(&ecom_encap, 0, sizeof(ecom_encap));
597 encode_encap_extcomm(tnl_type, &eval);
598 ecom_encap.size = 1;
34540b0d 599 ecom_encap.unit_size = ECOMMUNITY_SIZE;
c44ab6f1 600 ecom_encap.val = (uint8_t *)eval.val;
b53e67a3 601 bgp_attr_set_ecommunity(attr, ecommunity_dup(&ecom_encap));
185fb14a 602
c44ab6f1
AK
603 /* ES import RT */
604 memset(&mac, 0, sizeof(struct ethaddr));
605 memset(&ecom_es_rt, 0, sizeof(ecom_es_rt));
606 es_get_system_mac(&es->esi, &mac);
607 encode_es_rt_extcomm(&eval_es_rt, &mac);
608 ecom_es_rt.size = 1;
34540b0d 609 ecom_es_rt.unit_size = ECOMMUNITY_SIZE;
c44ab6f1 610 ecom_es_rt.val = (uint8_t *)eval_es_rt.val;
b53e67a3
DA
611 bgp_attr_set_ecommunity(
612 attr,
613 ecommunity_merge(bgp_attr_get_ecommunity(attr), &ecom_es_rt));
185fb14a 614
74e2bd89
AK
615 /* DF election extended community */
616 memset(&ecom_df, 0, sizeof(ecom_df));
617 encode_df_elect_extcomm(&eval_df, es->df_pref);
618 ecom_df.size = 1;
619 ecom_df.val = (uint8_t *)eval_df.val;
b53e67a3
DA
620 bgp_attr_set_ecommunity(
621 attr,
622 ecommunity_merge(bgp_attr_get_ecommunity(attr), &ecom_df));
74e2bd89 623
c44ab6f1 624 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
185fb14a
AK
625}
626
c44ab6f1
AK
627/* Create or update local type-4 route */
628static int bgp_evpn_type4_route_update(struct bgp *bgp,
629 struct bgp_evpn_es *es, struct prefix_evpn *p)
185fb14a
AK
630{
631 int ret = 0;
c44ab6f1
AK
632 int route_changed = 0;
633 afi_t afi = AFI_L2VPN;
634 safi_t safi = SAFI_EVPN;
635 struct attr attr;
636 struct attr *attr_new = NULL;
09319b4e 637 struct bgp_dest *dest = NULL;
185fb14a 638 struct bgp_path_info *pi = NULL;
185fb14a 639
c44ab6f1
AK
640 memset(&attr, 0, sizeof(struct attr));
641
642 /* Build path-attribute for this route. */
643 bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
644 attr.nexthop = es->originator_ip;
645 attr.mp_nexthop_global_in = es->originator_ip;
646 attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
647
648 /* Set up extended community. */
649 bgp_evpn_type4_route_extcomm_build(es, &attr);
650
651 /* First, create (or fetch) route node within the ESI. */
652 /* NOTE: There is no RD here. */
09319b4e 653 dest = bgp_node_get(es->route_table, (struct prefix *)p);
185fb14a 654
c44ab6f1 655 /* Create or update route entry. */
09319b4e
DS
656 ret = bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest, &attr, 1,
657 &pi, &route_changed);
ec779825 658 if (ret != 0)
23d0a753
DA
659 flog_err(
660 EC_BGP_ES_INVALID,
661 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
662 bgp->vrf_id, es->esi_str, &es->originator_ip);
185fb14a 663
c44ab6f1
AK
664 assert(pi);
665 attr_new = pi->attr;
185fb14a 666
c44ab6f1
AK
667 /* Perform route selection;
668 * this is just to set the flags correctly
669 * as local route in the ES always wins.
670 */
09319b4e
DS
671 bgp_evpn_es_route_select_install(bgp, es, dest);
672 bgp_dest_unlock_node(dest);
185fb14a 673
c44ab6f1
AK
674 /* If this is a new route or some attribute has changed, export the
675 * route to the global table. The route will be advertised to peers
676 * from there. Note that this table is a 2-level tree (RD-level +
677 * Prefix-level) similar to L3VPN routes.
678 */
679 if (route_changed) {
680 struct bgp_path_info *global_pi;
185fb14a 681
09319b4e
DS
682 dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
683 p, &es->prd);
684 bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest,
685 attr_new, 1, &global_pi,
686 &route_changed);
185fb14a 687
c44ab6f1 688 /* Schedule for processing and unlock node. */
09319b4e
DS
689 bgp_process(bgp, dest, afi, safi);
690 bgp_dest_unlock_node(dest);
185fb14a
AK
691 }
692
c44ab6f1
AK
693 /* Unintern temporary. */
694 aspath_unintern(&attr.aspath);
695 return 0;
185fb14a
AK
696}
697
c44ab6f1
AK
698/* Delete local type-4 route */
699static int bgp_evpn_type4_route_delete(struct bgp *bgp,
700 struct bgp_evpn_es *es, struct prefix_evpn *p)
185fb14a 701{
c44ab6f1
AK
702 return bgp_evpn_mh_route_delete(bgp, es, NULL /* l2vni */, p);
703}
185fb14a 704
c44ab6f1
AK
705/* Process remote/received EVPN type-4 route (advertise or withdraw) */
706int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi,
707 struct attr *attr, uint8_t *pfx, int psize,
708 uint32_t addpath_id)
709{
710 int ret;
711 esi_t esi;
712 uint8_t ipaddr_len;
713 struct in_addr vtep_ip;
714 struct prefix_rd prd;
715 struct prefix_evpn p;
185fb14a 716
c44ab6f1
AK
717 /* Type-4 route should be either 23 or 35 bytes
718 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
185fb14a 719 */
c44ab6f1
AK
720 if (psize != BGP_EVPN_TYPE4_V4_PSIZE &&
721 psize != BGP_EVPN_TYPE4_V6_PSIZE) {
722 flog_err(EC_BGP_EVPN_ROUTE_INVALID,
723 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
724 peer->bgp->vrf_id, peer->host, psize);
725 return -1;
726 }
185fb14a 727
c44ab6f1
AK
728 /* Make prefix_rd */
729 prd.family = AF_UNSPEC;
730 prd.prefixlen = 64;
731 memcpy(&prd.val, pfx, RD_BYTES);
732 pfx += RD_BYTES;
185fb14a 733
c44ab6f1
AK
734 /* get the ESI */
735 memcpy(&esi, pfx, ESI_BYTES);
736 pfx += ESI_BYTES;
185fb14a 737
185fb14a 738
c44ab6f1
AK
739 /* Get the IP. */
740 ipaddr_len = *pfx++;
741 if (ipaddr_len == IPV4_MAX_BITLEN) {
742 memcpy(&vtep_ip, pfx, IPV4_MAX_BYTELEN);
743 } else {
744 flog_err(
745 EC_BGP_EVPN_ROUTE_INVALID,
746 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
747 peer->bgp->vrf_id, peer->host, ipaddr_len);
748 return -1;
749 }
185fb14a 750
c44ab6f1
AK
751 build_evpn_type4_prefix(&p, &esi, vtep_ip);
752 /* Process the route. */
753 if (attr) {
754 ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
755 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
756 &prd, NULL, 0, 0, NULL);
757 } else {
758 ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
759 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
760 &prd, NULL, 0, NULL);
761 }
185fb14a
AK
762 return ret;
763}
764
c44ab6f1
AK
765/* Check if a prefix belongs to the local ES */
766static bool bgp_evpn_type4_prefix_match(struct prefix_evpn *p,
767 struct bgp_evpn_es *es)
185fb14a 768{
c44ab6f1
AK
769 return (p->prefix.route_type == BGP_EVPN_ES_ROUTE) &&
770 !memcmp(&p->prefix.es_addr.esi, &es->esi, sizeof(esi_t));
185fb14a
AK
771}
772
c44ab6f1
AK
773/* Import remote ESRs on local ethernet segment add */
774static int bgp_evpn_type4_remote_routes_import(struct bgp *bgp,
775 struct bgp_evpn_es *es, bool install)
185fb14a
AK
776{
777 int ret;
778 afi_t afi;
779 safi_t safi;
09319b4e 780 struct bgp_dest *rd_dest, *dest;
185fb14a
AK
781 struct bgp_table *table;
782 struct bgp_path_info *pi;
783
784 afi = AFI_L2VPN;
785 safi = SAFI_EVPN;
786
c44ab6f1
AK
787 /* Walk entire global routing table and evaluate routes which could be
788 * imported into this Ethernet Segment.
185fb14a 789 */
09319b4e
DS
790 for (rd_dest = bgp_table_top(bgp->rib[afi][safi]); rd_dest;
791 rd_dest = bgp_route_next(rd_dest)) {
792 table = bgp_dest_get_bgp_table_info(rd_dest);
185fb14a
AK
793 if (!table)
794 continue;
795
09319b4e
DS
796 for (dest = bgp_table_top(table); dest;
797 dest = bgp_route_next(dest)) {
798 struct prefix_evpn *evp =
752eed47 799 (struct prefix_evpn *)bgp_dest_get_prefix(dest);
185fb14a 800
09319b4e
DS
801 for (pi = bgp_dest_get_bgp_path_info(dest); pi;
802 pi = pi->next) {
185fb14a
AK
803 /*
804 * Consider "valid" remote routes applicable for
805 * this ES.
806 */
807 if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
c44ab6f1
AK
808 && pi->type == ZEBRA_ROUTE_BGP
809 && pi->sub_type == BGP_ROUTE_NORMAL))
185fb14a
AK
810 continue;
811
c44ab6f1 812 if (!bgp_evpn_type4_prefix_match(evp, es))
185fb14a
AK
813 continue;
814
815 if (install)
c44ab6f1
AK
816 ret = bgp_evpn_es_route_install(
817 bgp, es, evp, pi);
185fb14a 818 else
c44ab6f1
AK
819 ret = bgp_evpn_es_route_uninstall(
820 bgp, es, evp, pi);
185fb14a
AK
821
822 if (ret) {
823 flog_err(
2dbe669b
DA
824 EC_BGP_EVPN_FAIL,
825 "Failed to %s EVPN %pFX route in ESI %s",
826 install ? "install"
185fb14a 827 : "uninstall",
2dbe669b 828 evp, es->esi_str);
dc52bece
DS
829
830 bgp_dest_unlock_node(rd_dest);
831 bgp_dest_unlock_node(dest);
185fb14a
AK
832 return ret;
833 }
834 }
835 }
836 }
837 return 0;
838}
839
c44ab6f1
AK
840/*****************************************************************************
841 * Ethernet Auto Discovery (EAD/Type-1) route handling
842 * There are two types of EAD routes -
843 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
844 * 2. EAD-per-EVI - Key: {ESI, ET=0}
185fb14a 845 */
185fb14a 846
c44ab6f1
AK
847/* Extended communities associated with EAD-per-ES */
848static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es *es,
849 struct attr *attr)
185fb14a 850{
c44ab6f1
AK
851 struct ecommunity ecom_encap;
852 struct ecommunity ecom_esi_label;
853 struct ecommunity_val eval;
854 struct ecommunity_val eval_esi_label;
855 bgp_encap_types tnl_type;
856 struct listnode *evi_node, *rt_node;
857 struct ecommunity *ecom;
858 struct bgp_evpn_es_evi *es_evi;
185fb14a 859
c44ab6f1
AK
860 /* Encap */
861 tnl_type = BGP_ENCAP_TYPE_VXLAN;
862 memset(&ecom_encap, 0, sizeof(ecom_encap));
863 encode_encap_extcomm(tnl_type, &eval);
864 ecom_encap.size = 1;
34540b0d 865 ecom_encap.unit_size = ECOMMUNITY_SIZE;
c44ab6f1 866 ecom_encap.val = (uint8_t *)eval.val;
b53e67a3 867 bgp_attr_set_ecommunity(attr, ecommunity_dup(&ecom_encap));
185fb14a 868
c44ab6f1
AK
869 /* ESI label */
870 encode_esi_label_extcomm(&eval_esi_label,
871 false /*single_active*/);
872 ecom_esi_label.size = 1;
34540b0d 873 ecom_esi_label.unit_size = ECOMMUNITY_SIZE;
c44ab6f1 874 ecom_esi_label.val = (uint8_t *)eval_esi_label.val;
b53e67a3
DA
875 bgp_attr_set_ecommunity(attr,
876 ecommunity_merge(bgp_attr_get_ecommunity(attr),
877 &ecom_esi_label));
c44ab6f1
AK
878
879 /* Add export RTs for all L2-VNIs associated with this ES */
880 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
881 * with it.
882 */
883 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
884 evi_node, es_evi)) {
885 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
886 continue;
887 for (ALL_LIST_ELEMENTS_RO(es_evi->vpn->export_rtl,
888 rt_node, ecom))
b53e67a3
DA
889 bgp_attr_set_ecommunity(
890 attr,
891 ecommunity_merge(bgp_attr_get_ecommunity(attr),
892 ecom));
c44ab6f1
AK
893 }
894
895 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
896}
897
898/* Extended communities associated with EAD-per-EVI */
899static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es *es,
900 struct bgpevpn *vpn, struct attr *attr)
901{
902 struct ecommunity ecom_encap;
903 struct ecommunity_val eval;
904 bgp_encap_types tnl_type;
905 struct listnode *rt_node;
906 struct ecommunity *ecom;
907
908 /* Encap */
909 tnl_type = BGP_ENCAP_TYPE_VXLAN;
910 memset(&ecom_encap, 0, sizeof(ecom_encap));
911 encode_encap_extcomm(tnl_type, &eval);
912 ecom_encap.size = 1;
7659ad68 913 ecom_encap.unit_size = ECOMMUNITY_SIZE;
c44ab6f1 914 ecom_encap.val = (uint8_t *)eval.val;
b53e67a3 915 bgp_attr_set_ecommunity(attr, ecommunity_dup(&ecom_encap));
c44ab6f1
AK
916
917 /* Add export RTs for the L2-VNI */
918 for (ALL_LIST_ELEMENTS_RO(vpn->export_rtl, rt_node, ecom))
b53e67a3
DA
919 bgp_attr_set_ecommunity(
920 attr,
921 ecommunity_merge(bgp_attr_get_ecommunity(attr), ecom));
c44ab6f1
AK
922
923 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
924}
925
926/* Update EVPN EAD (type-1) route -
927 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
928 */
929static int bgp_evpn_type1_route_update(struct bgp *bgp,
930 struct bgp_evpn_es *es, struct bgpevpn *vpn,
931 struct prefix_evpn *p)
932{
933 int ret = 0;
934 afi_t afi = AFI_L2VPN;
935 safi_t safi = SAFI_EVPN;
936 struct attr attr;
937 struct attr *attr_new = NULL;
09319b4e 938 struct bgp_dest *dest = NULL;
c44ab6f1
AK
939 struct bgp_path_info *pi = NULL;
940 int route_changed = 0;
941 struct prefix_rd *global_rd;
942
943 memset(&attr, 0, sizeof(struct attr));
944
945 /* Build path-attribute for this route. */
946 bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
947 attr.nexthop = es->originator_ip;
948 attr.mp_nexthop_global_in = es->originator_ip;
949 attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
950
951 if (vpn) {
952 /* EAD-EVI route update */
953 /* MPLS label */
954 vni2label(vpn->vni, &(attr.label));
955
956 /* Set up extended community */
957 bgp_evpn_type1_evi_route_extcomm_build(es, vpn, &attr);
958
959 /* First, create (or fetch) route node within the VNI. */
09319b4e 960 dest = bgp_node_get(vpn->route_table, (struct prefix *)p);
c44ab6f1
AK
961
962 /* Create or update route entry. */
09319b4e
DS
963 ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
964 &attr, 1, &pi, &route_changed);
ec779825 965 if (ret != 0)
23d0a753
DA
966 flog_err(
967 EC_BGP_ES_INVALID,
968 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
969 bgp->vrf_id, es->esi_str, vpn->vni,
970 &es->originator_ip);
c44ab6f1
AK
971 global_rd = &vpn->prd;
972 } else {
973 /* EAD-ES route update */
974 /* MPLS label is 0 for EAD-ES route */
975
976 /* Set up extended community */
977 bgp_evpn_type1_es_route_extcomm_build(es, &attr);
978
979 /* First, create (or fetch) route node within the ES. */
980 /* NOTE: There is no RD here. */
981 /* XXX: fragment ID must be included as a part of the prefix. */
09319b4e 982 dest = bgp_node_get(es->route_table, (struct prefix *)p);
c44ab6f1
AK
983
984 /* Create or update route entry. */
09319b4e
DS
985 ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
986 &attr, 1, &pi, &route_changed);
c44ab6f1 987 if (ret != 0) {
23d0a753
DA
988 flog_err(
989 EC_BGP_ES_INVALID,
990 "%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %pI4",
991 bgp->vrf_id, es->esi_str, &es->originator_ip);
c44ab6f1
AK
992 }
993 global_rd = &es->prd;
994 }
995
996
997 assert(pi);
998 attr_new = pi->attr;
999
1000 /* Perform route selection;
1001 * this is just to set the flags correctly as local route in
1002 * the ES always wins.
1003 */
09319b4e
DS
1004 evpn_route_select_install(bgp, vpn, dest);
1005 bgp_dest_unlock_node(dest);
c44ab6f1
AK
1006
1007 /* If this is a new route or some attribute has changed, export the
1008 * route to the global table. The route will be advertised to peers
1009 * from there. Note that this table is a 2-level tree (RD-level +
1010 * Prefix-level) similar to L3VPN routes.
1011 */
1012 if (route_changed) {
1013 struct bgp_path_info *global_pi;
1014
09319b4e
DS
1015 dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
1016 p, global_rd);
1017 bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
1018 attr_new, 1, &global_pi,
1019 &route_changed);
c44ab6f1
AK
1020
1021 /* Schedule for processing and unlock node. */
09319b4e
DS
1022 bgp_process(bgp, dest, afi, safi);
1023 bgp_dest_unlock_node(dest);
c44ab6f1
AK
1024 }
1025
1026 /* Unintern temporary. */
1027 aspath_unintern(&attr.aspath);
1028 return 0;
1029}
1030
9c49ac74
AD
1031/*
1032 * This function is called when the export RT for a VNI changes.
1033 * Update all type-1 local routes for this VNI from VNI/ES tables and the global
1034 * table and advertise these routes to peers.
1035 */
1036
1037void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn)
1038{
1039 struct prefix_evpn p;
1040 struct bgp_evpn_es *es;
1041 struct bgp_evpn_es_evi *es_evi;
1042 struct bgp_evpn_es_evi *es_evi_next;
1043
1044 RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head,
1045 &vpn->es_evi_rb_tree, es_evi_next) {
1046 es = es_evi->es;
1047
1048 /* Update EAD-ES */
1049 if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
1050 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
1051 &es->esi, es->originator_ip);
1052 if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
1053 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1054 "%u: EAD-ES route update failure for ESI %s VNI %u",
1055 bgp->vrf_id, es->esi_str,
1056 es_evi->vpn->vni);
1057 }
1058
1059 /* Update EAD-EVI */
1060 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
1061 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
1062 &es->esi, es->originator_ip);
1063 if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn,
1064 &p))
1065 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
1066 "%u: EAD-EVI route update failure for ESI %s VNI %u",
1067 bgp->vrf_id, es->esi_str,
1068 es_evi->vpn->vni);
1069 }
1070 }
1071}
1072
c44ab6f1
AK
1073/* Delete local Type-1 route */
1074static int bgp_evpn_type1_es_route_delete(struct bgp *bgp,
1075 struct bgp_evpn_es *es, struct prefix_evpn *p)
1076{
1077 return bgp_evpn_mh_route_delete(bgp, es, NULL /* l2vni */, p);
1078}
1079
1080static int bgp_evpn_type1_evi_route_delete(struct bgp *bgp,
1081 struct bgp_evpn_es *es, struct bgpevpn *vpn,
1082 struct prefix_evpn *p)
1083{
1084 return bgp_evpn_mh_route_delete(bgp, es, vpn, p);
1085}
1086
1087/* Generate EAD-EVI for all VNIs */
1088static void bgp_evpn_local_type1_evi_route_add(struct bgp *bgp,
1089 struct bgp_evpn_es *es)
1090{
1091 struct listnode *evi_node;
1092 struct prefix_evpn p;
1093 struct bgp_evpn_es_evi *es_evi;
1094
fe8293c3
AK
1095 /* EAD-per-EVI routes have been suppressed */
1096 if (!bgp_mh_info->ead_evi_tx)
1097 return;
1098
c44ab6f1
AK
1099 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
1100 /* EAD-EVI route add for this ES is already done */
1101 return;
1102
1103 SET_FLAG(es->flags, BGP_EVPNES_ADV_EVI);
1104 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
1105 &es->esi, es->originator_ip);
1106
1107 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, evi_node, es_evi)) {
1108 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
1109 continue;
1110 if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn, &p))
1111 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1112 "%u: Type4 route creation failure for ESI %s",
1113 bgp->vrf_id, es->esi_str);
1114 }
1115}
1116
1117/*
1118 * Withdraw EAD-EVI for all VNIs
1119 */
1120static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp,
1121 struct bgp_evpn_es *es)
1122{
1123 struct listnode *evi_node;
1124 struct prefix_evpn p;
1125 struct bgp_evpn_es_evi *es_evi;
1126
1127 /* Delete and withdraw locally learnt EAD-EVI route */
1128 if (!CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
1129 /* EAD-EVI route has not been advertised for this ES */
1130 return;
1131
1132 UNSET_FLAG(es->flags, BGP_EVPNES_ADV_EVI);
1133 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
1134 &es->esi, es->originator_ip);
1135 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, evi_node, es_evi)) {
1136 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
1137 continue;
1138 if (bgp_evpn_mh_route_delete(bgp, es, es_evi->vpn, &p))
1139 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1140 "%u: Type4 route creation failure for ESI %s",
1141 bgp->vrf_id, es->esi_str);
1142 }
1143}
185fb14a
AK
1144
1145/*
c44ab6f1 1146 * Process received EVPN type-1 route (advertise or withdraw).
185fb14a 1147 */
c44ab6f1
AK
1148int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
1149 struct attr *attr, uint8_t *pfx, int psize,
1150 uint32_t addpath_id)
185fb14a
AK
1151{
1152 int ret;
c44ab6f1 1153 struct prefix_rd prd;
185fb14a 1154 esi_t esi;
c44ab6f1
AK
1155 uint32_t eth_tag;
1156 mpls_label_t label;
185fb14a 1157 struct in_addr vtep_ip;
185fb14a
AK
1158 struct prefix_evpn p;
1159
c44ab6f1 1160 if (psize != BGP_EVPN_TYPE1_PSIZE) {
185fb14a 1161 flog_err(EC_BGP_EVPN_ROUTE_INVALID,
c44ab6f1
AK
1162 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1163 peer->bgp->vrf_id, peer->host, psize);
185fb14a
AK
1164 return -1;
1165 }
1166
1167 /* Make prefix_rd */
1168 prd.family = AF_UNSPEC;
1169 prd.prefixlen = 64;
c44ab6f1
AK
1170 memcpy(&prd.val, pfx, RD_BYTES);
1171 pfx += RD_BYTES;
185fb14a
AK
1172
1173 /* get the ESI */
1174 memcpy(&esi, pfx, ESI_BYTES);
1175 pfx += ESI_BYTES;
1176
c44ab6f1
AK
1177 /* Copy Ethernet Tag */
1178 memcpy(&eth_tag, pfx, EVPN_ETH_TAG_BYTES);
1179 eth_tag = ntohl(eth_tag);
1180 pfx += EVPN_ETH_TAG_BYTES;
185fb14a 1181
c44ab6f1 1182 memcpy(&label, pfx, BGP_LABEL_BYTES);
185fb14a 1183
c44ab6f1
AK
1184 /* EAD route prefix doesn't include the nexthop in the global
1185 * table
1186 */
3a6290bd 1187 vtep_ip.s_addr = INADDR_ANY;
c44ab6f1 1188 build_evpn_type1_prefix(&p, eth_tag, &esi, vtep_ip);
185fb14a
AK
1189 /* Process the route. */
1190 if (attr) {
1191 ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
c44ab6f1
AK
1192 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
1193 &prd, NULL, 0, 0, NULL);
185fb14a
AK
1194 } else {
1195 ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
c44ab6f1
AK
1196 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
1197 &prd, NULL, 0, NULL);
185fb14a
AK
1198 }
1199 return ret;
1200}
1201
c44ab6f1
AK
1202/*****************************************************************************/
1203/* Ethernet Segment Management
1204 * 1. Ethernet Segment is a collection of links attached to the same
1205 * server (MHD) or switch (MHN)
1206 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1207 * 10-byte ES-ID.
1208 * 3. Local ESs are configured in zebra and sent to BGP
1209 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1210 * created on first reference and release on last de-reference
1211 * 5. An ES can be both local and remote. Infact most local ESs are expected
1212 * to have an ES peer.
1213 */
1214
1215/* A list of remote VTEPs is maintained for each ES. This list includes -
1216 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1217 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1218 * have been imported into one or more VNIs
185fb14a 1219 */
c44ab6f1
AK
1220static int bgp_evpn_es_vtep_cmp(void *p1, void *p2)
1221{
1222 const struct bgp_evpn_es_vtep *es_vtep1 = p1;
1223 const struct bgp_evpn_es_vtep *es_vtep2 = p2;
1224
1225 return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
1226}
1227
1228static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_new(struct bgp_evpn_es *es,
1229 struct in_addr vtep_ip)
1230{
1231 struct bgp_evpn_es_vtep *es_vtep;
1232
1233 es_vtep = XCALLOC(MTYPE_BGP_EVPN_ES_VTEP, sizeof(*es_vtep));
1234
1235 es_vtep->es = es;
1236 es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
23aa35ad
AK
1237 inet_ntop(AF_INET, &es_vtep->vtep_ip, es_vtep->vtep_str,
1238 sizeof(es_vtep->vtep_str));
c44ab6f1
AK
1239 listnode_init(&es_vtep->es_listnode, es_vtep);
1240 listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
1241
1242 return es_vtep;
1243}
1244
1245static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep *es_vtep)
1246{
1247 struct bgp_evpn_es *es = es_vtep->es;
1248
1249 if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR) ||
1250 es_vtep->evi_cnt)
1251 /* as long as there is some reference we can't free it */
1252 return;
1253
1254 list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
1255 XFREE(MTYPE_BGP_EVPN_ES_VTEP, es_vtep);
1256}
1257
1258/* check if VTEP is already part of the list */
1259static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_find(struct bgp_evpn_es *es,
1260 struct in_addr vtep_ip)
1261{
1262 struct listnode *node = NULL;
1263 struct bgp_evpn_es_vtep *es_vtep;
1264
1265 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1266 if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1267 return es_vtep;
1268 }
1269 return NULL;
1270}
1271
1272/* Send the remote ES to zebra for NHG programming */
1273static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp,
1274 struct bgp_evpn_es_vtep *es_vtep, bool add)
1275{
1276 struct bgp_evpn_es *es = es_vtep->es;
1277 struct stream *s;
74e2bd89 1278 uint32_t flags = 0;
c44ab6f1
AK
1279
1280 /* Check socket. */
1281 if (!zclient || zclient->sock < 0)
1282 return 0;
1283
1284 /* Don't try to register if Zebra doesn't know of this instance. */
1285 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
1286 if (BGP_DEBUG(zebra, ZEBRA))
1287 zlog_debug("No zebra instance, not installing remote es %s",
1288 es->esi_str);
1289 return 0;
1290 }
1291
74e2bd89
AK
1292 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
1293 flags |= ZAPI_ES_VTEP_FLAG_ESR_RXED;
1294
c44ab6f1
AK
1295 s = zclient->obuf;
1296 stream_reset(s);
1297
1298 zclient_create_header(s,
1299 add ? ZEBRA_REMOTE_ES_VTEP_ADD : ZEBRA_REMOTE_ES_VTEP_DEL,
1300 bgp->vrf_id);
1301 stream_put(s, &es->esi, sizeof(esi_t));
1302 stream_put_ipv4(s, es_vtep->vtep_ip.s_addr);
74e2bd89
AK
1303 if (add) {
1304 stream_putl(s, flags);
1305 stream_putc(s, es_vtep->df_alg);
1306 stream_putw(s, es_vtep->df_pref);
1307 }
c44ab6f1
AK
1308
1309 stream_putw_at(s, 0, stream_get_endp(s));
1310
1311 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1312 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add ? "ADD" : "DEL",
1313 es->esi_str, &es_vtep->vtep_ip);
c44ab6f1 1314
23aa35ad
AK
1315 frrtrace(3, frr_bgp, evpn_mh_vtep_zsend, add, es, es_vtep);
1316
c44ab6f1
AK
1317 return zclient_send_message(zclient);
1318}
1319
1320static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
74e2bd89
AK
1321 struct bgp_evpn_es_vtep *es_vtep,
1322 bool param_change)
c44ab6f1
AK
1323{
1324 bool old_active;
1325 bool new_active;
1326
d4980edf 1327 old_active = CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
c44ab6f1
AK
1328 /* currently we need an active EVI reference to use the VTEP as
1329 * a nexthop. this may change...
1330 */
1331 if (es_vtep->evi_cnt)
1332 SET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1333 else
1334 UNSET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1335
d4980edf 1336 new_active = CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
c44ab6f1 1337
74e2bd89 1338 if ((old_active != new_active) || (new_active && param_change)) {
c44ab6f1 1339
74e2bd89
AK
1340 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1341 zlog_debug("es %s vtep %pI4 %s df %u/%u",
1342 es_vtep->es->esi_str, &es_vtep->vtep_ip,
1343 new_active ? "active" : "inactive",
1344 es_vtep->df_alg, es_vtep->df_pref);
c44ab6f1 1345
74e2bd89
AK
1346 /* send remote ES to zebra */
1347 bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active);
c44ab6f1 1348
8bcb09a1
AK
1349 /* The NHG is updated first for efficient failover handling.
1350 * Note the NHG can be de-activated while there are bgp
1351 * routes referencing it. Zebra is capable of handling that
1352 * elegantly by holding the NHG till all routes using it are
1353 * removed.
26c03e43 1354 */
8bcb09a1 1355 bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep->es);
74e2bd89
AK
1356 /* queue up the es for background consistency checks */
1357 bgp_evpn_es_cons_checks_pend_add(es_vtep->es);
1358 }
c44ab6f1
AK
1359}
1360
1361static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
74e2bd89
AK
1362 struct bgp_evpn_es *es,
1363 struct in_addr vtep_ip,
1364 bool esr, uint8_t df_alg,
1365 uint16_t df_pref)
c44ab6f1
AK
1366{
1367 struct bgp_evpn_es_vtep *es_vtep;
74e2bd89 1368 bool param_change = false;
c44ab6f1
AK
1369
1370 es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip);
1371
1372 if (!es_vtep)
1373 es_vtep = bgp_evpn_es_vtep_new(es, vtep_ip);
1374
1375 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
74e2bd89
AK
1376 zlog_debug("es %s vtep %pI4 add %s df %u/%u",
1377 es_vtep->es->esi_str, &es_vtep->vtep_ip,
1378 esr ? "esr" : "ead", df_alg, df_pref);
c44ab6f1 1379
74e2bd89 1380 if (esr) {
c44ab6f1 1381 SET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR);
74e2bd89
AK
1382 if ((es_vtep->df_pref != df_pref)
1383 || (es_vtep->df_alg != df_alg)) {
1384 param_change = true;
1385 es_vtep->df_pref = df_pref;
1386 es_vtep->df_alg = df_alg;
1387 }
1388 } else {
c44ab6f1 1389 ++es_vtep->evi_cnt;
74e2bd89 1390 }
c44ab6f1 1391
74e2bd89 1392 bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change);
c44ab6f1
AK
1393
1394 return es_vtep;
1395}
1396
1397static void bgp_evpn_es_vtep_do_del(struct bgp *bgp,
1398 struct bgp_evpn_es_vtep *es_vtep, bool esr)
1399{
74e2bd89
AK
1400 bool param_change = false;
1401
c44ab6f1 1402 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1403 zlog_debug("es %s vtep %pI4 del %s", es_vtep->es->esi_str,
1404 &es_vtep->vtep_ip, esr ? "esr" : "ead");
c44ab6f1
AK
1405 if (esr) {
1406 UNSET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR);
74e2bd89
AK
1407 if (es_vtep->df_pref || es_vtep->df_alg) {
1408 param_change = true;
1409 es_vtep->df_pref = 0;
1410 es_vtep->df_alg = 0;
1411 }
c44ab6f1
AK
1412 } else {
1413 if (es_vtep->evi_cnt)
1414 --es_vtep->evi_cnt;
1415 }
1416
74e2bd89 1417 bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change);
c44ab6f1
AK
1418 bgp_evpn_es_vtep_free(es_vtep);
1419}
1420
1421static void bgp_evpn_es_vtep_del(struct bgp *bgp,
1422 struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr)
1423{
1424 struct bgp_evpn_es_vtep *es_vtep;
1425
1426 es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip);
1427 if (es_vtep)
1428 bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr);
1429}
1430
26c03e43 1431/********************** ES MAC-IP paths *************************************
58bff4d1
AK
1432 * 1. Local MAC-IP routes in the VNI routing table are linked to the
1433 * destination ES (macip_evi_path_list) for efficient updates on ES oper
1434 * state changes.
1435 * 2. Non-local MAC-IP routes in the global routing table are linked to
1436 * the detination for efficient updates on -
1437 * a. VTEP add/del - this results in a L3NHG update.
1438 * b. ES-VRF add/del - this may result in the host route being migrated to
1439 * L3NHG or vice versa (flat multipath list).
26c03e43 1440 ****************************************************************************/
60605cbc 1441static void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info)
26c03e43
AK
1442{
1443 bgp_evpn_path_es_unlink(es_info);
1444 XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO, es_info);
1445}
1446
60605cbc
AK
1447void bgp_evpn_path_mh_info_free(struct bgp_path_mh_info *mh_info)
1448{
1449 if (mh_info->es_info)
1450 bgp_evpn_path_es_info_free(mh_info->es_info);
090efa2f
AK
1451 if (mh_info->nh_info)
1452 bgp_evpn_path_nh_info_free(mh_info->nh_info);
60605cbc
AK
1453 XFREE(MTYPE_BGP_EVPN_PATH_MH_INFO, mh_info);
1454}
1455
26c03e43
AK
1456static struct bgp_path_es_info *
1457bgp_evpn_path_es_info_new(struct bgp_path_info *pi, vni_t vni)
1458{
1459 struct bgp_path_info_extra *e;
60605cbc
AK
1460 struct bgp_path_mh_info *mh_info;
1461 struct bgp_path_es_info *es_info;
26c03e43
AK
1462
1463 e = bgp_path_info_extra_get(pi);
1464
60605cbc
AK
1465 /* If mh_info doesn't exist allocate it */
1466 mh_info = e->mh_info;
1467 if (!mh_info)
1468 e->mh_info = mh_info = XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO,
1469 sizeof(struct bgp_path_mh_info));
1470
26c03e43 1471 /* If es_info doesn't exist allocate it */
60605cbc
AK
1472 es_info = mh_info->es_info;
1473 if (!es_info) {
1474 mh_info->es_info = es_info =
1475 XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO,
1476 sizeof(struct bgp_path_es_info));
1477 es_info->vni = vni;
1478 es_info->pi = pi;
26c03e43
AK
1479 }
1480
60605cbc 1481 return es_info;
26c03e43
AK
1482}
1483
60605cbc 1484static void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info)
26c03e43
AK
1485{
1486 struct bgp_evpn_es *es = es_info->es;
1487 struct bgp_path_info *pi;
26c03e43
AK
1488
1489 if (!es)
1490 return;
1491
1492 pi = es_info->pi;
1493 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
229587fb
AK
1494 zlog_debug("vni %u path %pFX unlinked from es %s", es_info->vni,
1495 &pi->net->p, es->esi_str);
26c03e43 1496
58bff4d1
AK
1497 if (es_info->vni)
1498 list_delete_node(es->macip_evi_path_list,
1499 &es_info->es_listnode);
1500 else
1501 list_delete_node(es->macip_global_path_list,
1502 &es_info->es_listnode);
74efb822 1503
26c03e43
AK
1504 es_info->es = NULL;
1505
1506 /* if there are no other references against the ES it
1507 * needs to be freed
1508 */
1509 bgp_evpn_es_free(es, __func__);
1510
1511 /* Note we don't free the path es_info on unlink; it will be freed up
1512 * along with the path.
1513 */
1514}
1515
1516void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi)
1517{
1518 struct bgp_path_es_info *es_info;
1519 struct bgp_evpn_es *es;
58bff4d1 1520 struct bgp *bgp_evpn;
26c03e43 1521
60605cbc
AK
1522 es_info = (pi->extra && pi->extra->mh_info)
1523 ? pi->extra->mh_info->es_info
1524 : NULL;
26c03e43
AK
1525 /* if the esi is zero just unlink the path from the old es */
1526 if (!esi || !memcmp(esi, zero_esi, sizeof(*esi))) {
1527 if (es_info)
1528 bgp_evpn_path_es_unlink(es_info);
1529 return;
1530 }
1531
58bff4d1 1532 bgp_evpn = bgp_get_evpn();
26c03e43
AK
1533 if (!bgp_evpn)
1534 return;
1535
1536 /* setup es_info against the path if it doesn't aleady exist */
1537 if (!es_info)
1538 es_info = bgp_evpn_path_es_info_new(pi, vni);
1539
1540 /* find-create ES */
1541 es = bgp_evpn_es_find(esi);
1542 if (!es)
f61fbf21 1543 es = bgp_evpn_es_new(bgp_evpn, esi);
26c03e43
AK
1544
1545 /* dup check */
1546 if (es_info->es == es)
1547 return;
1548
1549 /* unlink old ES if any */
1550 bgp_evpn_path_es_unlink(es_info);
1551
1552 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
229587fb
AK
1553 zlog_debug("vni %u path %pFX linked to es %s", vni, &pi->net->p,
1554 es->esi_str);
26c03e43
AK
1555
1556 /* link mac-ip path to the new destination ES */
1557 es_info->es = es;
1558 listnode_init(&es_info->es_listnode, es_info);
58bff4d1
AK
1559 if (es_info->vni)
1560 listnode_add(es->macip_evi_path_list, &es_info->es_listnode);
1561 else
1562 listnode_add(es->macip_global_path_list, &es_info->es_listnode);
26c03e43
AK
1563}
1564
74efb822
AK
1565static bool bgp_evpn_is_macip_path(struct bgp_path_info *pi)
1566{
1567 struct prefix_evpn *evp;
1568
1569 /* Only MAC-IP routes need to be linked (MAC-only routes can be
1570 * skipped) as these lists are maintained for managing
1571 * host routes in the tenant VRF
1572 */
1573 evp = (struct prefix_evpn *)&pi->net->p;
1574 return is_evpn_prefix_ipaddr_v4(evp) || is_evpn_prefix_ipaddr_v6(evp);
1575}
1576
58bff4d1
AK
1577/* When a remote ES is added to a VRF, routes using that as
1578 * a destination need to be migrated to a L3NHG or viceversa.
1579 * This is done indirectly by re-attempting an install of the
1580 * route in the associated VRFs. As a part of the VRF install use
1581 * of l3 NHG is evaluated and this results in the
1582 * attr.es_flag ATTR_ES_USE_L3_NHG being set or cleared.
36dd4574
AK
1583 */
1584static void
1585bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf *es_vrf,
58bff4d1 1586 const char *reason)
26c03e43
AK
1587{
1588 struct listnode *node;
1589 struct bgp_path_es_info *es_info;
1590 struct bgp_path_info *pi;
58bff4d1 1591 struct bgp_evpn_es *es = es_vrf->es;
26c03e43 1592
36dd4574
AK
1593 if (!bgp_mh_info->host_routes_use_l3nhg)
1594 return;
1595
26c03e43 1596 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
58bff4d1
AK
1597 zlog_debug("update paths linked to es %s on es-vrf %s %s",
1598 es->esi_str, es_vrf->bgp_vrf->name, reason);
26c03e43 1599
58bff4d1 1600 for (ALL_LIST_ELEMENTS_RO(es->macip_global_path_list, node, es_info)) {
26c03e43 1601 pi = es_info->pi;
26c03e43 1602
74efb822
AK
1603 if (!bgp_evpn_is_macip_path(pi))
1604 continue;
1605
26c03e43 1606 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
2eef4f20 1607 zlog_debug(
58bff4d1
AK
1608 "update path %pFX linked to es %s on vrf chg",
1609 &pi->net->p, es->esi_str);
1610 bgp_evpn_route_entry_install_if_vrf_match(es_vrf->bgp_vrf, pi,
1611 1);
26c03e43
AK
1612 }
1613}
1614
c44ab6f1
AK
1615/* compare ES-IDs for the global ES RB tree */
1616static int bgp_es_rb_cmp(const struct bgp_evpn_es *es1,
1617 const struct bgp_evpn_es *es2)
1618{
1619 return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
1620}
1621RB_GENERATE(bgp_es_rb_head, bgp_evpn_es, rb_node, bgp_es_rb_cmp);
1622
1623struct bgp_evpn_es *bgp_evpn_es_find(const esi_t *esi)
185fb14a 1624{
c44ab6f1 1625 struct bgp_evpn_es tmp;
185fb14a 1626
185fb14a 1627 memcpy(&tmp.esi, esi, sizeof(esi_t));
c44ab6f1 1628 return RB_FIND(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, &tmp);
185fb14a
AK
1629}
1630
c44ab6f1 1631static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
185fb14a 1632{
c44ab6f1 1633 struct bgp_evpn_es *es;
185fb14a
AK
1634
1635 if (!bgp)
1636 return NULL;
1637
c44ab6f1 1638 es = XCALLOC(MTYPE_BGP_EVPN_ES, sizeof(struct bgp_evpn_es));
185fb14a 1639
c44ab6f1 1640 /* set the ESI */
185fb14a 1641 memcpy(&es->esi, esi, sizeof(esi_t));
185fb14a
AK
1642
1643 /* Initialise the VTEP list */
c44ab6f1
AK
1644 es->es_vtep_list = list_new();
1645 listset_app_node_mem(es->es_vtep_list);
1646 es->es_vtep_list->cmp = bgp_evpn_es_vtep_cmp;
185fb14a 1647
c44ab6f1 1648 esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
185fb14a 1649
c44ab6f1 1650 /* Initialize the ES routing table */
185fb14a
AK
1651 es->route_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
1652
c44ab6f1
AK
1653 /* Add to rb_tree */
1654 if (RB_INSERT(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, es)) {
185fb14a
AK
1655 XFREE(MTYPE_BGP_EVPN_ES, es);
1656 return NULL;
1657 }
1658
c44ab6f1
AK
1659 /* Initialise the ES-EVI list */
1660 es->es_evi_list = list_new();
1661 listset_app_node_mem(es->es_evi_list);
1662
c589d847
AK
1663 /* Initialise the ES-VRF list used for L3NHG management */
1664 es->es_vrf_list = list_new();
1665 listset_app_node_mem(es->es_vrf_list);
1666
26c03e43 1667 /* Initialise the route list used for efficient event handling */
d656e0ae
AK
1668 es->macip_evi_path_list = list_new();
1669 listset_app_node_mem(es->macip_evi_path_list);
58bff4d1
AK
1670 es->macip_global_path_list = list_new();
1671 listset_app_node_mem(es->macip_global_path_list);
26c03e43 1672
c44ab6f1
AK
1673 QOBJ_REG(es, bgp_evpn_es);
1674
185fb14a
AK
1675 return es;
1676}
1677
c44ab6f1 1678/* Free a given ES -
185fb14a
AK
1679 * This just frees appropriate memory, caller should have taken other
1680 * needed actions.
1681 */
45a859f1 1682static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
185fb14a 1683{
26c03e43 1684 if ((es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))
58bff4d1
AK
1685 || listcount(es->macip_evi_path_list)
1686 || listcount(es->macip_global_path_list))
c44ab6f1
AK
1687 return;
1688
45a859f1
AK
1689 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1690 zlog_debug("%s: es %s free", caller, es->esi_str);
1691
c44ab6f1
AK
1692 /* cleanup resources maintained against the ES */
1693 list_delete(&es->es_evi_list);
c589d847 1694 list_delete(&es->es_vrf_list);
c44ab6f1 1695 list_delete(&es->es_vtep_list);
d656e0ae 1696 list_delete(&es->macip_evi_path_list);
58bff4d1 1697 list_delete(&es->macip_global_path_list);
185fb14a 1698 bgp_table_unlock(es->route_table);
c44ab6f1
AK
1699
1700 /* remove the entry from various databases */
1701 RB_REMOVE(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, es);
1702 bgp_evpn_es_cons_checks_pend_del(es);
1703
185fb14a
AK
1704 QOBJ_UNREG(es);
1705 XFREE(MTYPE_BGP_EVPN_ES, es);
1706}
1707
74efb822
AK
1708static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es *es)
1709{
1710 return (es->flags & BGP_EVPNES_LOCAL)
1711 && !(es->flags & BGP_EVPNES_BYPASS);
1712}
1713
c44ab6f1
AK
1714/* init local info associated with the ES */
1715static void bgp_evpn_es_local_info_set(struct bgp *bgp, struct bgp_evpn_es *es)
185fb14a 1716{
c44ab6f1 1717 char buf[BGP_EVPN_PREFIX_RD_LEN];
74efb822
AK
1718 bool old_is_local;
1719 bool is_local;
185fb14a 1720
c44ab6f1
AK
1721 if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1722 return;
185fb14a 1723
74efb822 1724 old_is_local = bgp_evpn_is_es_local_and_non_bypass(es);
c44ab6f1 1725 SET_FLAG(es->flags, BGP_EVPNES_LOCAL);
74efb822 1726
c44ab6f1
AK
1727 listnode_init(&es->es_listnode, es);
1728 listnode_add(bgp_mh_info->local_es_list, &es->es_listnode);
185fb14a 1729
c44ab6f1
AK
1730 /* auto derive RD for this es */
1731 bf_assign_index(bm->rd_idspace, es->rd_id);
1732 es->prd.family = AF_UNSPEC;
1733 es->prd.prefixlen = 64;
23d0a753 1734 snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, es->rd_id);
c44ab6f1 1735 (void)str2prefix_rd(buf, &es->prd);
74efb822
AK
1736
1737 is_local = bgp_evpn_is_es_local_and_non_bypass(es);
1738 if (old_is_local != is_local)
1739 bgp_evpn_mac_update_on_es_local_chg(es, is_local);
c44ab6f1
AK
1740}
1741
1742/* clear any local info associated with the ES */
d57e0c05 1743static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es *es, bool finish)
c44ab6f1 1744{
74efb822
AK
1745 bool old_is_local;
1746 bool is_local;
1747
c44ab6f1
AK
1748 if (!CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1749 return;
185fb14a 1750
74efb822 1751 old_is_local = bgp_evpn_is_es_local_and_non_bypass(es);
c44ab6f1 1752 UNSET_FLAG(es->flags, BGP_EVPNES_LOCAL);
185fb14a 1753
74efb822 1754 is_local = bgp_evpn_is_es_local_and_non_bypass(es);
d57e0c05 1755 if (!finish && (old_is_local != is_local))
74efb822
AK
1756 bgp_evpn_mac_update_on_es_local_chg(es, is_local);
1757
c44ab6f1
AK
1758 /* remove from the ES local list */
1759 list_delete_node(bgp_mh_info->local_es_list, &es->es_listnode);
1760
1761 bf_release_index(bm->rd_idspace, es->rd_id);
1762
45a859f1 1763 bgp_evpn_es_free(es, __func__);
185fb14a
AK
1764}
1765
c44ab6f1
AK
1766/* eval remote info associated with the ES */
1767static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es *es)
1768{
1769 if (es->remote_es_evi_cnt) {
1770 SET_FLAG(es->flags, BGP_EVPNES_REMOTE);
1771 } else {
1772 if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE)) {
1773 UNSET_FLAG(es->flags, BGP_EVPNES_REMOTE);
45a859f1 1774 bgp_evpn_es_free(es, __func__);
c44ab6f1
AK
1775 }
1776 }
1777}
1778
70524092
AK
1779/* If ES is present and local it needs to be active/oper-up for
1780 * including L3 EC
1781 */
1782bool bgp_evpn_es_add_l3_ecomm_ok(esi_t *esi)
74be8313 1783{
70524092
AK
1784 struct bgp_evpn_es *es;
1785
1786 if (!esi || !bgp_mh_info->suppress_l3_ecomm_on_inactive_es)
1787 return true;
1788
1789 es = bgp_evpn_es_find(esi);
1790
1791 return (!es || !(es->flags & BGP_EVPNES_LOCAL)
1792 || bgp_evpn_local_es_is_active(es));
1793}
1794
74efb822
AK
1795static bool bgp_evpn_is_valid_local_path(struct bgp_path_info *pi)
1796{
1797 return (CHECK_FLAG(pi->flags, BGP_PATH_VALID)
1798 && pi->type == ZEBRA_ROUTE_BGP
1799 && pi->sub_type == BGP_ROUTE_STATIC);
1800}
1801
d656e0ae
AK
1802/* Update all local MAC-IP routes in the VNI routing table associated
1803 * with the ES. When the ES is down the routes are advertised without
1804 * the L3 extcomm
70524092
AK
1805 */
1806static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es *es)
1807{
1808 struct listnode *node;
1809 struct bgp_path_es_info *es_info;
1810 struct bgp_path_info *pi;
70524092
AK
1811 struct bgp *bgp;
1812 struct bgpevpn *vpn;
1813
1814 if (!bgp_mh_info->suppress_l3_ecomm_on_inactive_es)
1815 return;
1816
1817 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1818 zlog_debug("update paths linked to es %s on oper chg",
1819 es->esi_str);
1820
1821 bgp = bgp_get_evpn();
d656e0ae 1822 for (ALL_LIST_ELEMENTS_RO(es->macip_evi_path_list, node, es_info)) {
70524092 1823 pi = es_info->pi;
74efb822
AK
1824
1825 if (!bgp_evpn_is_valid_local_path(pi))
70524092
AK
1826 continue;
1827
74efb822 1828 if (!bgp_evpn_is_macip_path(pi))
70524092
AK
1829 continue;
1830
1831 vpn = bgp_evpn_lookup_vni(bgp, es_info->vni);
1832 if (!vpn)
1833 continue;
1834
1835 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
58bff4d1 1836 zlog_debug(
70545a29
AK
1837 "update path %d %pFX linked to es %s on oper chg",
1838 es_info->vni, &pi->net->p, es->esi_str);
70524092
AK
1839
1840 bgp_evpn_update_type2_route_entry(bgp, vpn, pi->net, pi,
1841 __func__);
1842 }
74be8313
AK
1843}
1844
74efb822
AK
1845static bool bgp_evpn_is_valid_bgp_path(struct bgp_path_info *pi)
1846{
1847 return (CHECK_FLAG(pi->flags, BGP_PATH_VALID)
1848 && pi->type == ZEBRA_ROUTE_BGP
1849 && pi->sub_type == BGP_ROUTE_NORMAL);
1850}
1851
1852/* If an ES is no longer local (or becomes local) we need to re-install
1853 * paths using that ES as destination. This is needed as the criteria
1854 * for best path selection has changed.
1855 */
1856static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es *es,
1857 bool is_local)
1858{
1859 struct listnode *node;
1860 struct bgp_path_es_info *es_info;
1861 struct bgp_path_info *pi;
74efb822
AK
1862 bool tmp_local;
1863 struct attr *attr_new;
1864 struct attr attr_tmp;
1865
1866 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1867 zlog_debug("update paths linked to es %s on chg to %s",
1868 es->esi_str, is_local ? "local" : "non-local");
1869
1870 for (ALL_LIST_ELEMENTS_RO(es->macip_global_path_list, node, es_info)) {
1871 pi = es_info->pi;
1872
1873 /* Consider "valid" remote routes */
1874 if (!bgp_evpn_is_valid_bgp_path(pi))
1875 continue;
1876
1877 if (!pi->attr)
1878 continue;
1879
1880 tmp_local = !!(pi->attr->es_flags & ATTR_ES_IS_LOCAL);
1881 if (tmp_local == is_local)
1882 continue;
1883
1884 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
1885 zlog_debug(
70545a29
AK
1886 "update path %pFX linked to es %s on chg to %s",
1887 &pi->net->p, es->esi_str,
1888 is_local ? "local" : "non-local");
74efb822
AK
1889
1890 attr_tmp = *pi->attr;
1891 if (is_local)
1892 attr_tmp.es_flags |= ATTR_ES_IS_LOCAL;
1893 else
1894 attr_tmp.es_flags &= ~ATTR_ES_IS_LOCAL;
1895 attr_new = bgp_attr_intern(&attr_tmp);
1896 bgp_attr_unintern(&pi->attr);
1897 pi->attr = attr_new;
1898 bgp_evpn_import_type2_route(pi, 1);
1899 }
1900}
1901
74be8313
AK
1902static void bgp_evpn_local_es_deactivate(struct bgp *bgp,
1903 struct bgp_evpn_es *es)
185fb14a 1904{
185fb14a 1905 struct prefix_evpn p;
c44ab6f1 1906 int ret;
185fb14a 1907
c44ab6f1
AK
1908 /* withdraw ESR */
1909 /* Delete and withdraw locally learnt ES route */
1910 build_evpn_type4_prefix(&p, &es->esi, es->originator_ip);
1911 ret = bgp_evpn_type4_route_delete(bgp, es, &p);
1912 if (ret) {
1913 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
1914 "%u failed to delete type-4 route for ESI %s",
1915 bgp->vrf_id, es->esi_str);
185fb14a
AK
1916 }
1917
c44ab6f1
AK
1918 /* withdraw EAD-EVI */
1919 if (!bgp_mh_info->ead_evi_adv_for_down_links)
1920 bgp_evpn_local_type1_evi_route_del(bgp, es);
185fb14a 1921
c44ab6f1
AK
1922 /* withdraw EAD-ES */
1923 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
1924 &es->esi, es->originator_ip);
1925 ret = bgp_evpn_type1_es_route_delete(bgp, es, &p);
1926 if (ret) {
1927 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
1928 "%u failed to delete type-1 route for ESI %s",
1929 bgp->vrf_id, es->esi_str);
1930 }
70524092
AK
1931
1932 bgp_evpn_mac_update_on_es_oper_chg(es);
c44ab6f1
AK
1933}
1934
74be8313
AK
1935/* Process ES link oper-down by withdrawing ES-EAD and ESR */
1936static void bgp_evpn_local_es_down(struct bgp *bgp, struct bgp_evpn_es *es)
c44ab6f1 1937{
74be8313 1938 bool old_active;
c44ab6f1 1939
74be8313
AK
1940 if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP))
1941 return;
c44ab6f1 1942
74be8313
AK
1943 old_active = bgp_evpn_local_es_is_active(es);
1944 UNSET_FLAG(es->flags, BGP_EVPNES_OPER_UP);
1945
1946 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1947 zlog_debug("local es %s down", es->esi_str);
1948
1949 if (old_active)
1950 bgp_evpn_local_es_deactivate(bgp, es);
1951}
1952
1953static void bgp_evpn_local_es_activate(struct bgp *bgp, struct bgp_evpn_es *es,
1954 bool regen_ead, bool regen_esr)
1955{
1956 struct prefix_evpn p;
c44ab6f1 1957
74e2bd89
AK
1958 if (regen_esr) {
1959 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1960 zlog_debug("local es %s generate ESR", es->esi_str);
1961 /* generate ESR */
1962 build_evpn_type4_prefix(&p, &es->esi, es->originator_ip);
1963 if (bgp_evpn_type4_route_update(bgp, es, &p))
1964 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1965 "%u: Type4 route creation failure for ESI %s",
1966 bgp->vrf_id, es->esi_str);
1967 }
c44ab6f1 1968
74e2bd89
AK
1969 if (regen_ead) {
1970 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1971 zlog_debug("local es %s generate EAD", es->esi_str);
1972 /* generate EAD-EVI */
1973 bgp_evpn_local_type1_evi_route_add(bgp, es);
c44ab6f1 1974
74e2bd89
AK
1975 /* generate EAD-ES */
1976 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG, &es->esi,
1977 es->originator_ip);
d934e491 1978 (void)bgp_evpn_type1_route_update(bgp, es, NULL, &p);
74e2bd89 1979 }
70524092
AK
1980
1981 bgp_evpn_mac_update_on_es_oper_chg(es);
c44ab6f1
AK
1982}
1983
74be8313
AK
1984/* Process ES link oper-up by generating ES-EAD and ESR */
1985static void bgp_evpn_local_es_up(struct bgp *bgp, struct bgp_evpn_es *es,
1986 bool regen_esr)
1987{
1988 bool regen_ead = false;
1989 bool active = false;
1990
1991 if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
1992 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1993 zlog_debug("local es %s up", es->esi_str);
1994
1995 SET_FLAG(es->flags, BGP_EVPNES_OPER_UP);
1996 regen_esr = true;
1997 regen_ead = true;
1998 }
1999
2000 active = bgp_evpn_local_es_is_active(es);
2001 if (active && (regen_ead || regen_esr))
2002 bgp_evpn_local_es_activate(bgp, es, regen_ead, regen_esr);
2003}
2004
2005/* If an ethernet segment is in LACP bypass we cannot advertise
2006 * reachability to it i.e. EAD-per-ES and ESR is not advertised in
2007 * bypass state.
2008 * PS: EAD-per-EVI will continue to be advertised
2009 */
2010static void bgp_evpn_local_es_bypass_update(struct bgp *bgp,
2011 struct bgp_evpn_es *es, bool bypass)
2012{
2013 bool old_bypass = !!(es->flags & BGP_EVPNES_BYPASS);
2014 bool old_active;
2015 bool new_active;
74efb822
AK
2016 bool old_is_local;
2017 bool is_local;
74be8313
AK
2018
2019 if (bypass == old_bypass)
2020 return;
2021
2022 old_active = bgp_evpn_local_es_is_active(es);
74efb822 2023 old_is_local = bgp_evpn_is_es_local_and_non_bypass(es);
74be8313
AK
2024 if (bypass)
2025 SET_FLAG(es->flags, BGP_EVPNES_BYPASS);
2026 else
2027 UNSET_FLAG(es->flags, BGP_EVPNES_BYPASS);
2028
2029 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2030 zlog_debug("local es %s bypass %s", es->esi_str,
2031 bypass ? "set" : "clear");
2032
2033 new_active = bgp_evpn_local_es_is_active(es);
2034 if (old_active != new_active) {
2035 if (new_active)
2036 bgp_evpn_local_es_activate(bgp, es, true, true);
2037 else
2038 bgp_evpn_local_es_deactivate(bgp, es);
2039 }
74efb822
AK
2040
2041 is_local = bgp_evpn_is_es_local_and_non_bypass(es);
2042 if (old_is_local != is_local)
2043 bgp_evpn_mac_update_on_es_local_chg(es, is_local);
74be8313
AK
2044}
2045
c44ab6f1
AK
2046static void bgp_evpn_local_es_do_del(struct bgp *bgp, struct bgp_evpn_es *es)
2047{
2048 struct bgp_evpn_es_evi *es_evi;
2049 struct listnode *evi_node, *evi_next_node;
2050
2051 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2052 zlog_debug("del local es %s", es->esi_str);
2053
2054 /* Delete all local EVPN ES routes from ESI table
2055 * and schedule for processing (to withdraw from peers))
2056 */
2057 bgp_evpn_es_route_del_all(bgp, es);
2058
2059 /* release all local ES EVIs associated with the ES */
2060 for (ALL_LIST_ELEMENTS(es->es_evi_list, evi_node,
2061 evi_next_node, es_evi)) {
2062 bgp_evpn_local_es_evi_do_del(es_evi);
2063 }
2064
2065 /* Clear local info associated with the ES and free it up if there is
2066 * no remote reference
2067 */
d57e0c05 2068 bgp_evpn_es_local_info_clear(es, false);
c44ab6f1
AK
2069}
2070
74efb822 2071bool bgp_evpn_is_esi_local_and_non_bypass(esi_t *esi)
7904e9fd
AK
2072{
2073 struct bgp_evpn_es *es = NULL;
2074
2075 /* Lookup ESI hash - should exist. */
2076 es = bgp_evpn_es_find(esi);
74efb822
AK
2077
2078 return es && bgp_evpn_is_es_local_and_non_bypass(es);
7904e9fd
AK
2079}
2080
c44ab6f1
AK
2081int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi)
2082{
2083 struct bgp_evpn_es *es = NULL;
2084
2085 /* Lookup ESI hash - should exist. */
2086 es = bgp_evpn_es_find(esi);
2087 if (!es) {
eaf80288
DA
2088 flog_warn(EC_BGP_EVPN_ESI, "%u: ES missing at local ES DEL",
2089 bgp->vrf_id);
c44ab6f1
AK
2090 return -1;
2091 }
2092
2093 bgp_evpn_local_es_do_del(bgp, es);
2094 return 0;
2095}
2096
2097/* Handle device to ES id association. Results in the creation of a local
2098 * ES.
2099 */
2100int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi,
74e2bd89 2101 struct in_addr originator_ip, bool oper_up,
74be8313 2102 uint16_t df_pref, bool bypass)
c44ab6f1
AK
2103{
2104 char buf[ESI_STR_LEN];
2105 struct bgp_evpn_es *es;
2106 bool new_es = true;
74e2bd89 2107 bool regen_esr = false;
c44ab6f1
AK
2108
2109 /* create the new es */
2110 es = bgp_evpn_es_find(esi);
2111 if (es) {
2112 if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
2113 new_es = false;
2114 } else {
2115 es = bgp_evpn_es_new(bgp, esi);
2116 if (!es) {
2117 flog_err(EC_BGP_ES_CREATE,
2118 "%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
2119 bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
2120 return -1;
2121 }
2122 }
2123
2124 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
74be8313
AK
2125 zlog_debug("add local es %s orig-ip %pI4 df_pref %u %s",
2126 es->esi_str, &originator_ip, df_pref,
2127 bypass ? "bypass" : "");
c44ab6f1
AK
2128
2129 es->originator_ip = originator_ip;
74e2bd89
AK
2130 if (df_pref != es->df_pref) {
2131 es->df_pref = df_pref;
2132 regen_esr = true;
2133 }
c44ab6f1
AK
2134 bgp_evpn_es_local_info_set(bgp, es);
2135
2136 /* import all remote Type-4 routes in the ES table */
2137 if (new_es)
2138 bgp_evpn_type4_remote_routes_import(bgp, es,
2139 true /* install */);
2140
2141 /* create and advertise EAD-EVI routes for the ES -
2142 * XXX - till an ES-EVI reference is created there is really nothing to
2143 * advertise
2144 */
2145 if (bgp_mh_info->ead_evi_adv_for_down_links)
2146 bgp_evpn_local_type1_evi_route_add(bgp, es);
2147
74be8313
AK
2148 bgp_evpn_local_es_bypass_update(bgp, es, bypass);
2149
c44ab6f1
AK
2150 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
2151 * can be generated even if the link is inactive.
2152 */
2153 if (oper_up)
74e2bd89 2154 bgp_evpn_local_es_up(bgp, es, regen_esr);
c44ab6f1
AK
2155 else
2156 bgp_evpn_local_es_down(bgp, es);
2157
2158 return 0;
2159}
2160
9e0c2fd1
AK
2161static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es,
2162 uint8_t vtep_str_size)
c44ab6f1
AK
2163{
2164 char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
2165 struct listnode *node;
2166 struct bgp_evpn_es_vtep *es_vtep;
2167 bool first = true;
ec779825 2168 char ip_buf[INET6_ADDRSTRLEN];
c44ab6f1
AK
2169
2170 vtep_str[0] = '\0';
2171 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
2172 vtep_flag_str[0] = '\0';
23d0a753 2173
c44ab6f1 2174 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
9e0c2fd1 2175 strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
c44ab6f1 2176 if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
9e0c2fd1 2177 strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
c44ab6f1
AK
2178
2179 if (!strlen(vtep_flag_str))
9e0c2fd1
AK
2180 strlcat(vtep_flag_str, "-", sizeof(vtep_flag_str));
2181 if (first)
c44ab6f1 2182 first = false;
9e0c2fd1
AK
2183 else
2184 strlcat(vtep_str, ",", vtep_str_size);
23d0a753 2185 strlcat(vtep_str,
ec779825
AK
2186 inet_ntop(AF_INET, &es_vtep->vtep_ip, ip_buf,
2187 sizeof(ip_buf)),
23d0a753 2188 vtep_str_size);
9e0c2fd1
AK
2189 strlcat(vtep_str, "(", vtep_str_size);
2190 strlcat(vtep_str, vtep_flag_str, vtep_str_size);
2191 strlcat(vtep_str, ")", vtep_str_size);
c44ab6f1
AK
2192 }
2193
2194 return vtep_str;
2195}
2196
c44ab6f1
AK
2197static void bgp_evpn_es_json_vtep_fill(json_object *json_vteps,
2198 struct bgp_evpn_es_vtep *es_vtep)
2199{
2200 json_object *json_vtep_entry;
2201 json_object *json_flags;
2202
2203 json_vtep_entry = json_object_new_object();
2204
c949c771
DA
2205 json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4",
2206 &es_vtep->vtep_ip);
c44ab6f1
AK
2207 if (es_vtep->flags & (BGP_EVPNES_VTEP_ESR |
2208 BGP_EVPNES_VTEP_ACTIVE)) {
2209 json_flags = json_object_new_array();
2210 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
2211 json_array_string_add(json_flags, "esr");
2212 if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
2213 json_array_string_add(json_flags, "active");
2214 json_object_object_add(json_vtep_entry, "flags", json_flags);
74e2bd89
AK
2215 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) {
2216 json_object_int_add(json_vtep_entry, "dfPreference",
2217 es_vtep->df_pref);
2218 json_object_int_add(json_vtep_entry, "dfAlgorithm",
2219 es_vtep->df_pref);
2220 }
c44ab6f1
AK
2221 }
2222
2223 json_object_array_add(json_vteps,
2224 json_vtep_entry);
2225}
2226
74e2bd89
AK
2227static void bgp_evpn_es_vteps_show_detail(struct vty *vty,
2228 struct bgp_evpn_es *es)
2229{
2230 char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
2231 struct listnode *node;
2232 struct bgp_evpn_es_vtep *es_vtep;
2233 char alg_buf[EVPN_DF_ALG_STR_LEN];
2234
2235 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
2236 vtep_flag_str[0] = '\0';
2237 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
2238 strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
2239 if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
2240 strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
2241
2242 if (!strlen(vtep_flag_str))
2243 strlcat(vtep_flag_str, "-", sizeof(vtep_flag_str));
2244
ec779825 2245 vty_out(vty, " %pI4 flags: %s", &es_vtep->vtep_ip,
74e2bd89
AK
2246 vtep_flag_str);
2247
2248 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
2249 vty_out(vty, " df_alg: %s df_pref: %u\n",
2250 evpn_es_df_alg2str(es_vtep->df_alg, alg_buf,
2251 sizeof(alg_buf)),
2252 es_vtep->df_pref);
2253 else
2254 vty_out(vty, "\n");
2255 }
2256}
2257
c44ab6f1
AK
2258static void bgp_evpn_es_show_entry(struct vty *vty,
2259 struct bgp_evpn_es *es, json_object *json)
2260{
2261 char buf1[RD_ADDRSTRLEN];
2262 struct listnode *node;
2263 struct bgp_evpn_es_vtep *es_vtep;
2264
2265 if (json) {
2266 json_object *json_vteps;
2267 json_object *json_types;
2268
2269 json_object_string_add(json, "esi", es->esi_str);
2270 json_object_string_add(json, "rd",
2271 prefix_rd2str(&es->prd, buf1,
2272 sizeof(buf1)));
2273
2274 if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) {
2275 json_types = json_object_new_array();
2276 if (es->flags & BGP_EVPNES_LOCAL)
2277 json_array_string_add(json_types, "local");
2278 if (es->flags & BGP_EVPNES_REMOTE)
2279 json_array_string_add(json_types, "remote");
2280 json_object_object_add(json, "type", json_types);
2281 }
2282
2283 if (listcount(es->es_vtep_list)) {
2284 json_vteps = json_object_new_array();
2285 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list,
2286 node, es_vtep)) {
2287 bgp_evpn_es_json_vtep_fill(json_vteps, es_vtep);
2288 }
2289 json_object_object_add(json, "vteps", json_vteps);
2290 }
2291 json_object_int_add(json, "vniCount",
2292 listcount(es->es_evi_list));
2293 } else {
2294 char type_str[4];
2295 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
2296
2297 type_str[0] = '\0';
74be8313
AK
2298 if (es->flags & BGP_EVPNES_BYPASS)
2299 strlcat(type_str, "B", sizeof(type_str));
c44ab6f1 2300 if (es->flags & BGP_EVPNES_LOCAL)
9e0c2fd1 2301 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 2302 if (es->flags & BGP_EVPNES_REMOTE)
9e0c2fd1 2303 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 2304 if (es->inconsistencies)
9e0c2fd1 2305 strlcat(type_str, "I", sizeof(type_str));
c44ab6f1 2306
9e0c2fd1 2307 bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
c44ab6f1
AK
2308
2309 if (es->flags & BGP_EVPNES_LOCAL)
2310 prefix_rd2str(&es->prd, buf1, sizeof(buf1));
2311 else
9e0c2fd1 2312 strlcpy(buf1, "-", sizeof(buf1));
c44ab6f1
AK
2313
2314 vty_out(vty, "%-30s %-5s %-21s %-8d %s\n",
2315 es->esi_str, type_str, buf1,
2316 listcount(es->es_evi_list), vtep_str);
2317 }
2318}
2319
2320static void bgp_evpn_es_show_entry_detail(struct vty *vty,
2321 struct bgp_evpn_es *es, json_object *json)
2322{
2323 if (json) {
2324 json_object *json_flags;
2325 json_object *json_incons;
74e2bd89
AK
2326 json_object *json_vteps;
2327 struct listnode *node;
2328 struct bgp_evpn_es_vtep *es_vtep;
c44ab6f1
AK
2329
2330 /* Add the "brief" info first */
2331 bgp_evpn_es_show_entry(vty, es, json);
74be8313
AK
2332 if (es->flags
2333 & (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI
2334 | BGP_EVPNES_BYPASS)) {
c44ab6f1
AK
2335 json_flags = json_object_new_array();
2336 if (es->flags & BGP_EVPNES_OPER_UP)
2337 json_array_string_add(json_flags, "up");
2338 if (es->flags & BGP_EVPNES_ADV_EVI)
2339 json_array_string_add(json_flags,
2340 "advertiseEVI");
74be8313
AK
2341 if (es->flags & BGP_EVPNES_BYPASS)
2342 json_array_string_add(json_flags, "bypass");
c44ab6f1
AK
2343 json_object_object_add(json, "flags", json_flags);
2344 }
c949c771
DA
2345 json_object_string_addf(json, "originator_ip", "%pI4",
2346 &es->originator_ip);
c44ab6f1
AK
2347 json_object_int_add(json, "remoteVniCount",
2348 es->remote_es_evi_cnt);
229587fb
AK
2349 json_object_int_add(json, "vrfCount",
2350 listcount(es->es_vrf_list));
2351 json_object_int_add(json, "macipPathCount",
d656e0ae 2352 listcount(es->macip_evi_path_list));
58bff4d1
AK
2353 json_object_int_add(json, "macipGlobalPathCount",
2354 listcount(es->macip_global_path_list));
c44ab6f1
AK
2355 json_object_int_add(json, "inconsistentVniVtepCount",
2356 es->incons_evi_vtep_cnt);
74e2bd89
AK
2357 if (listcount(es->es_vtep_list)) {
2358 json_vteps = json_object_new_array();
2359 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node,
2360 es_vtep)) {
2361 bgp_evpn_es_json_vtep_fill(json_vteps, es_vtep);
2362 }
2363 json_object_object_add(json, "vteps", json_vteps);
2364 }
c44ab6f1
AK
2365 if (es->inconsistencies) {
2366 json_incons = json_object_new_array();
2367 if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
2368 json_array_string_add(json_incons,
2369 "vni-vtep-mismatch");
2370 json_object_object_add(json, "inconsistencies",
2371 json_incons);
2372 }
2373 } else {
2374 char incons_str[BGP_EVPNES_INCONS_STR_SZ];
2375 char type_str[4];
c44ab6f1
AK
2376 char buf1[RD_ADDRSTRLEN];
2377
2378 type_str[0] = '\0';
2379 if (es->flags & BGP_EVPNES_LOCAL)
9e0c2fd1 2380 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 2381 if (es->flags & BGP_EVPNES_REMOTE)
9e0c2fd1 2382 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 2383
c44ab6f1
AK
2384 if (es->flags & BGP_EVPNES_LOCAL)
2385 prefix_rd2str(&es->prd, buf1, sizeof(buf1));
2386 else
9e0c2fd1 2387 strlcpy(buf1, "-", sizeof(buf1));
c44ab6f1
AK
2388
2389 vty_out(vty, "ESI: %s\n", es->esi_str);
2390 vty_out(vty, " Type: %s\n", type_str);
2391 vty_out(vty, " RD: %s\n", buf1);
23d0a753 2392 vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip);
74e2bd89
AK
2393 if (es->flags & BGP_EVPNES_LOCAL)
2394 vty_out(vty, " Local ES DF preference: %u\n",
2395 es->df_pref);
74be8313
AK
2396 if (es->flags & BGP_EVPNES_BYPASS)
2397 vty_out(vty, " LACP bypass: on\n");
c44ab6f1
AK
2398 vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
2399 vty_out(vty, " Remote VNI Count: %d\n",
2400 es->remote_es_evi_cnt);
229587fb 2401 vty_out(vty, " VRF Count: %d\n", listcount(es->es_vrf_list));
58bff4d1 2402 vty_out(vty, " MACIP EVI Path Count: %d\n",
d656e0ae 2403 listcount(es->macip_evi_path_list));
58bff4d1
AK
2404 vty_out(vty, " MACIP Global Path Count: %d\n",
2405 listcount(es->macip_global_path_list));
c44ab6f1
AK
2406 vty_out(vty, " Inconsistent VNI VTEP Count: %d\n",
2407 es->incons_evi_vtep_cnt);
2408 if (es->inconsistencies) {
2409 incons_str[0] = '\0';
2410 if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
9e0c2fd1
AK
2411 strlcat(incons_str, "vni-vtep-mismatch",
2412 sizeof(incons_str));
c44ab6f1 2413 } else {
9e0c2fd1 2414 strlcpy(incons_str, "-", sizeof(incons_str));
c44ab6f1
AK
2415 }
2416 vty_out(vty, " Inconsistencies: %s\n",
2417 incons_str);
74e2bd89
AK
2418 if (listcount(es->es_vtep_list)) {
2419 vty_out(vty, " VTEPs:\n");
2420 bgp_evpn_es_vteps_show_detail(vty, es);
2421 }
c44ab6f1
AK
2422 vty_out(vty, "\n");
2423 }
2424}
2425
2426/* Display all ESs */
2427void bgp_evpn_es_show(struct vty *vty, bool uj, bool detail)
2428{
2429 struct bgp_evpn_es *es;
9c7edc03 2430 json_object *json_array = NULL;
c44ab6f1
AK
2431 json_object *json = NULL;
2432
2433 if (uj) {
2434 /* create an array of ESs */
2435 json_array = json_object_new_array();
2436 } else {
2437 if (!detail) {
2438 vty_out(vty,
74be8313 2439 "ES Flags: B - bypass, L local, R remote, I inconsistent\n");
c44ab6f1
AK
2440 vty_out(vty,
2441 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
2442 vty_out(vty,
2443 "%-30s %-5s %-21s %-8s %s\n",
2444 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
2445 }
2446 }
2447
2448 RB_FOREACH(es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
2449 if (uj)
2450 /* create a separate json object for each ES */
2451 json = json_object_new_object();
2452 if (detail)
2453 bgp_evpn_es_show_entry_detail(vty, es, json);
2454 else
2455 bgp_evpn_es_show_entry(vty, es, json);
2456 /* add ES to the json array */
2457 if (uj)
2458 json_object_array_add(json_array, json);
2459 }
2460
2461 /* print the array of json-ESs */
c48349e3 2462 if (uj)
75eeda93 2463 vty_json(vty, json_array);
c44ab6f1
AK
2464}
2465
2466/* Display specific ES */
2467void bgp_evpn_es_show_esi(struct vty *vty, esi_t *esi, bool uj)
2468{
2469 struct bgp_evpn_es *es;
2470 json_object *json = NULL;
2471
2472 if (uj)
2473 json = json_object_new_object();
2474
2475 es = bgp_evpn_es_find(esi);
2476 if (es) {
2477 bgp_evpn_es_show_entry_detail(vty, es, json);
2478 } else {
2479 if (!uj)
2480 vty_out(vty, "ESI not found\n");
2481 }
2482
c48349e3 2483 if (uj)
75eeda93 2484 vty_json(vty, json);
c44ab6f1
AK
2485}
2486
c589d847
AK
2487/*****************************************************************************/
2488/* Ethernet Segment to VRF association -
2489 * 1. Each ES-EVI entry is associated with a tenant VRF. This associaton
2490 * triggers the creation of an ES-VRF entry.
2491 * 2. The ES-VRF entry is maintained for the purpose of L3-NHG creation
2492 * 3. Type-2/MAC-IP routes are imported into a tenant VRF and programmed as
2493 * a /32 or host route entry in the dataplane. If the destination of
2494 * the host route is a remote-ES the route is programmed with the
2495 * corresponding (keyed in by {vrf,ES-id}) L3-NHG.
2496 * 4. The reason for this indirection (route->L3-NHG, L3-NHG->list-of-VTEPs)
2497 * is to avoid route updates to the dplane when a remote-ES link flaps i.e.
2498 * instead of updating all the dependent routes the NHG's contents are updated.
2499 * This reduces the amount of datplane updates (nhg updates vs. route updates)
2500 * allowing for a faster failover.
2501 *
2502 * XXX - can the L3 SVI index change without change in vpn->bgp_vrf
2503 * association? If yes we need to handle that by updating all the L3 NHGs
2504 * in that VRF.
2505 */
2506/******************************** L3 NHG management *************************/
8bcb09a1
AK
2507static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf,
2508 bool v4_nhg)
c589d847 2509{
8bcb09a1
AK
2510 uint32_t nhg_id = v4_nhg ? es_vrf->nhg_id : es_vrf->v6_nhg_id;
2511 struct bgp_evpn_es *es = es_vrf->es;
c589d847
AK
2512 struct listnode *node;
2513 struct bgp_evpn_es_vtep *es_vtep;
8bcb09a1
AK
2514 struct nexthop nh;
2515 struct zapi_nexthop *api_nh;
2516 struct zapi_nhg api_nhg = {};
2517
2518 /* Skip installation of L3-NHG if host routes used */
2519 if (!nhg_id)
2520 return;
c589d847
AK
2521
2522 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1
AK
2523 zlog_debug("es %s vrf %u %s nhg %u to zebra", es->esi_str,
2524 es_vrf->bgp_vrf->vrf_id,
2525 v4_nhg ? "v4_nhg" : "v6_nhg", nhg_id);
2526
23aa35ad
AK
2527 frrtrace(4, frr_bgp, evpn_mh_nhg_zsend, true, v4_nhg, nhg_id, es_vrf);
2528
8bcb09a1
AK
2529 /* only the gateway ip changes for each NH. rest of the params
2530 * are constant
2531 */
2532 memset(&nh, 0, sizeof(nh));
2533 nh.vrf_id = es_vrf->bgp_vrf->vrf_id;
2534 nh.flags = NEXTHOP_FLAG_ONLINK;
2535 nh.ifindex = es_vrf->bgp_vrf->l3vni_svi_ifindex;
2536 nh.weight = 1;
2537 nh.type =
2538 v4_nhg ? NEXTHOP_TYPE_IPV4_IFINDEX : NEXTHOP_TYPE_IPV6_IFINDEX;
2539
2540 api_nhg.id = nhg_id;
c589d847 2541 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
8bcb09a1
AK
2542 if (!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
2543 continue;
2544
719b209c
MS
2545 /* Don't overrun the zapi buffer. */
2546 if (api_nhg.nexthop_num == MULTIPATH_NUM)
2547 break;
2548
8bcb09a1
AK
2549 /* overwrite the gw */
2550 if (v4_nhg)
2551 nh.gate.ipv4 = es_vtep->vtep_ip;
2552 else
2553 ipv4_to_ipv4_mapped_ipv6(&nh.gate.ipv6,
2554 es_vtep->vtep_ip);
2555
2556 /* convert to zapi format */
2557 api_nh = &api_nhg.nexthops[api_nhg.nexthop_num];
2558 zapi_nexthop_from_nexthop(api_nh, &nh);
2559
2560 ++api_nhg.nexthop_num;
2561 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2562 zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg.id,
2563 &es_vtep->vtep_ip,
2564 es_vrf->bgp_vrf->l3vni_svi_ifindex);
23aa35ad
AK
2565
2566 frrtrace(3, frr_bgp, evpn_mh_nh_zsend, nhg_id, es_vtep, es_vrf);
c589d847
AK
2567 }
2568
8bcb09a1
AK
2569 if (!api_nhg.nexthop_num)
2570 return;
2571
8bcb09a1 2572 zclient_nhg_send(zclient, ZEBRA_NHG_ADD, &api_nhg);
c589d847
AK
2573}
2574
8bcb09a1
AK
2575static bool bgp_evpn_l3nhg_zebra_ok(struct bgp_evpn_es_vrf *es_vrf)
2576{
2577 if (!bgp_mh_info->host_routes_use_l3nhg && !bgp_mh_info->install_l3nhg)
2578 return false;
2579
2580 /* Check socket. */
2581 if (!zclient || zclient->sock < 0)
2582 return false;
2583
2584 return true;
2585}
2586
2587static void bgp_evpn_l3nhg_zebra_add(struct bgp_evpn_es_vrf *es_vrf)
c589d847 2588{
8bcb09a1
AK
2589 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf))
2590 return;
2591
2592 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf, true /*v4_nhg*/);
2593 bgp_evpn_l3nhg_zebra_add_v4_or_v6(es_vrf, false /*v4_nhg*/);
2594}
2595
2596static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf,
2597 bool v4_nhg)
2598{
2599 struct zapi_nhg api_nhg = {};
2600
2601 api_nhg.id = v4_nhg ? es_vrf->nhg_id : es_vrf->v6_nhg_id;
2602
2603 /* Skip installation of L3-NHG if host routes used */
2604 if (!api_nhg.id)
2605 return;
2606
c589d847 2607 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1 2608 zlog_debug("es %s vrf %u %s nhg %u to zebra",
c589d847 2609 es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
8bcb09a1
AK
2610 v4_nhg ? "v4_nhg" : "v6_nhg", api_nhg.id);
2611
23aa35ad
AK
2612
2613 frrtrace(4, frr_bgp, evpn_mh_nhg_zsend, false, v4_nhg, api_nhg.id,
2614 es_vrf);
2615
8bcb09a1
AK
2616 zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg);
2617}
c589d847 2618
8bcb09a1
AK
2619static void bgp_evpn_l3nhg_zebra_del(struct bgp_evpn_es_vrf *es_vrf)
2620{
2621 if (!bgp_evpn_l3nhg_zebra_ok(es_vrf))
2622 return;
2623
2624 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf, true /*v4_nhg*/);
2625 bgp_evpn_l3nhg_zebra_del_v4_or_v6(es_vrf, false /*v4_nhg*/);
c589d847
AK
2626}
2627
2628static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf)
2629{
2630 if (!(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE))
2631 return;
2632
2633 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1 2634 zlog_debug("es %s vrf %u nhg %u de-activate",
c589d847
AK
2635 es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
2636 es_vrf->nhg_id);
2637 bgp_evpn_l3nhg_zebra_del(es_vrf);
2638 es_vrf->flags &= ~BGP_EVPNES_VRF_NHG_ACTIVE;
58bff4d1
AK
2639 /* MAC-IPs can now be installed via the L3NHG */
2640 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg-deactivate");
c589d847
AK
2641}
2642
2643static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update)
2644{
2645 if (!bgp_evpn_es_get_active_vtep_cnt(es_vrf->es)) {
2646 bgp_evpn_l3nhg_deactivate(es_vrf);
2647 return;
2648 }
2649
2650 if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) {
2651 if (!update)
2652 return;
2653 } else {
2654 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1 2655 zlog_debug("es %s vrf %u nhg %u activate",
c589d847
AK
2656 es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
2657 es_vrf->nhg_id);
2658 es_vrf->flags |= BGP_EVPNES_VRF_NHG_ACTIVE;
58bff4d1
AK
2659 /* MAC-IPs can now be installed via the L3NHG */
2660 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg_activate");
c589d847
AK
2661 }
2662
2663 bgp_evpn_l3nhg_zebra_add(es_vrf);
2664}
2665
2666/* when a VTEP is activated or de-activated against an ES associated
2667 * VRFs' NHG needs to be updated
2668 */
2669static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es)
2670{
2671 struct bgp_evpn_es_vrf *es_vrf;
2672 struct listnode *es_vrf_node;
2673
2674 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2675 zlog_debug("es %s nhg update on vtep chg", es->esi_str);
2676
2677 for (ALL_LIST_ELEMENTS_RO(es->es_vrf_list, es_vrf_node, es_vrf))
2678 bgp_evpn_l3nhg_activate(es_vrf, true /* update */);
2679}
2680
2681/* compare ES-IDs for the ES-VRF RB tree maintained per-VRF */
2682static int bgp_es_vrf_rb_cmp(const struct bgp_evpn_es_vrf *es_vrf1,
2683 const struct bgp_evpn_es_vrf *es_vrf2)
2684{
2685 return memcmp(&es_vrf1->es->esi, &es_vrf2->es->esi, ESI_BYTES);
2686}
2687RB_GENERATE(bgp_es_vrf_rb_head, bgp_evpn_es_vrf, rb_node, bgp_es_vrf_rb_cmp);
2688
2689/* Initialize the ES tables maintained per-tenant vrf */
2690void bgp_evpn_vrf_es_init(struct bgp *bgp_vrf)
2691{
2692 /* Initialize the ES-VRF RB tree */
2693 RB_INIT(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree);
2694}
2695
2696/* find the ES-VRF in the per-VRF RB tree */
2697static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_find(struct bgp_evpn_es *es,
2698 struct bgp *bgp_vrf)
2699{
2700 struct bgp_evpn_es_vrf es_vrf;
2701
2702 es_vrf.es = es;
2703
2704 return RB_FIND(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, &es_vrf);
2705}
2706
2707/* allocate a new ES-VRF and setup L3NHG for it */
2708static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es,
2709 struct bgp *bgp_vrf)
2710{
2711 struct bgp_evpn_es_vrf *es_vrf;
2712
2713 es_vrf = XCALLOC(MTYPE_BGP_EVPN_ES_VRF, sizeof(*es_vrf));
2714
2715 es_vrf->es = es;
2716 es_vrf->bgp_vrf = bgp_vrf;
2717
2718 /* insert into the VRF-ESI rb tree */
2719 if (RB_INSERT(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, es_vrf)) {
2720 XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf);
2721 return NULL;
2722 }
2723
2724 /* add to the ES's VRF list */
2725 listnode_init(&es_vrf->es_listnode, es_vrf);
2726 listnode_add(es->es_vrf_list, &es_vrf->es_listnode);
2727
2728 /* setup the L3 NHG id for the ES */
2729 es_vrf->nhg_id = bgp_l3nhg_id_alloc();
8bcb09a1
AK
2730 es_vrf->v6_nhg_id = bgp_l3nhg_id_alloc();
2731
c589d847 2732 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1
AK
2733 zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es->esi_str,
2734 bgp_vrf->vrf_id, es_vrf->nhg_id, es_vrf->v6_nhg_id);
c589d847
AK
2735 bgp_evpn_l3nhg_activate(es_vrf, false /* update */);
2736
36dd4574
AK
2737 /* update paths in the VRF that may already be associated with
2738 * this destination ES
2739 */
58bff4d1 2740 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "es-vrf-create");
36dd4574 2741
c589d847
AK
2742 return es_vrf;
2743}
2744
2745/* remove the L3-NHG associated with the ES-VRF and free it */
2746static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf)
2747{
2748 struct bgp_evpn_es *es = es_vrf->es;
2749 struct bgp *bgp_vrf = es_vrf->bgp_vrf;
2750
2751 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
8bcb09a1 2752 zlog_debug("es %s vrf %u nhg %u delete", es->esi_str,
c589d847
AK
2753 bgp_vrf->vrf_id, es_vrf->nhg_id);
2754
2755 /* Remove the NHG resources */
2756 bgp_evpn_l3nhg_deactivate(es_vrf);
2757 if (es_vrf->nhg_id)
2758 bgp_l3nhg_id_free(es_vrf->nhg_id);
2759 es_vrf->nhg_id = 0;
8bcb09a1
AK
2760 if (es_vrf->v6_nhg_id)
2761 bgp_l3nhg_id_free(es_vrf->v6_nhg_id);
2762 es_vrf->v6_nhg_id = 0;
c589d847
AK
2763
2764 /* remove from the ES's VRF list */
2765 list_delete_node(es->es_vrf_list, &es_vrf->es_listnode);
2766
2767 /* remove from the VRF-ESI rb tree */
2768 RB_REMOVE(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, es_vrf);
2769
d656e0ae
AK
2770 /* update paths in the VRF that may already be associated with
2771 * this destination ES
2772 */
58bff4d1 2773 bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "es-vrf-delete");
d656e0ae 2774
c589d847
AK
2775 XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf);
2776}
2777
2778/* deref and delete if there are no references */
2779void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi *es_evi)
2780{
2781 struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf;
2782
2783 if (!es_vrf)
2784 return;
2785
2786 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2787 zlog_debug("es-evi %s vni %u vrf %u de-ref",
2788 es_evi->es->esi_str, es_evi->vpn->vni,
2789 es_vrf->bgp_vrf->vrf_id);
2790
2791 es_evi->es_vrf = NULL;
2792 if (es_vrf->ref_cnt)
2793 --es_vrf->ref_cnt;
2794
2795 if (!es_vrf->ref_cnt)
2796 bgp_evpn_es_vrf_delete(es_vrf);
2797}
2798
2799/* find or create and reference */
2800void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi *es_evi, struct bgp *bgp_vrf)
2801{
2802 struct bgp_evpn_es *es = es_evi->es;
2803 struct bgp_evpn_es_vrf *es_vrf = es_evi->es_vrf;
2804 struct bgp *old_bgp_vrf = NULL;
2805
2806 if (es_vrf)
2807 old_bgp_vrf = es_vrf->bgp_vrf;
2808
2809 if (old_bgp_vrf == bgp_vrf)
2810 return;
2811
2812 /* deref the old ES-VRF */
2813 bgp_evpn_es_vrf_deref(es_evi);
2814
2815 if (!bgp_vrf)
2816 return;
2817
2818 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2819 zlog_debug("es-evi %s vni %u vrf %u ref", es_evi->es->esi_str,
2820 es_evi->vpn->vni, bgp_vrf->vrf_id);
2821
2822 /* find-create the new ES-VRF */
2823 es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
2824 if (!es_vrf)
2825 es_vrf = bgp_evpn_es_vrf_create(es, bgp_vrf);
2826 if (!es_vrf)
2827 return;
2828
2829 es_evi->es_vrf = es_vrf;
2830 ++es_vrf->ref_cnt;
2831}
2832
2833/* When the L2-VNI is associated with a L3-VNI/VRF update all the
2834 * associated ES-EVI entries
2835 */
2836void bgp_evpn_es_evi_vrf_deref(struct bgpevpn *vpn)
2837{
2838 struct bgp_evpn_es_evi *es_evi;
2839
2840 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2841 zlog_debug("es-vrf de-ref for vni %u", vpn->vni);
2842
2843 RB_FOREACH (es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree)
2844 bgp_evpn_es_vrf_deref(es_evi);
2845}
2846void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn)
2847{
2848 struct bgp_evpn_es_evi *es_evi;
2849
2850 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2851 zlog_debug("es-vrf ref for vni %u", vpn->vni);
2852
2853 RB_FOREACH (es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree)
2854 bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
2855}
2856
58bff4d1
AK
2857/* 1. If ES-VRF is not present install the host route with the exploded/flat
2858 * multi-path list.
2859 * 2. If ES-VRF is present -
2860 * - if L3NHG has not been activated for the ES-VRF (this could be because
2861 * all the PEs attached to the VRF are down) do not install the route
2862 * in zebra.
2863 * - if L3NHG has been activated install the route via that L3NHG
2864 */
2865void bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi, bool *use_l3nhg,
2866 bool *is_l3nhg_active,
2867 struct bgp_evpn_es_vrf **es_vrf_p)
36dd4574
AK
2868{
2869 struct bgp_evpn_es *es;
2870 struct bgp_evpn_es_vrf *es_vrf;
2871
2872 if (!bgp_mh_info->host_routes_use_l3nhg)
58bff4d1 2873 return;
36dd4574
AK
2874
2875 es = bgp_evpn_es_find(esi);
2876 if (!es)
58bff4d1 2877 return;
36dd4574
AK
2878
2879 es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf);
2880 if (!es_vrf)
58bff4d1
AK
2881 return;
2882
2883 *use_l3nhg = true;
2884 if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
2885 *is_l3nhg_active = true;
36dd4574
AK
2886 if (es_vrf_p)
2887 *es_vrf_p = es_vrf;
36dd4574
AK
2888}
2889
6348981a
AK
2890/* returns false if legacy-exploded mp needs to be used for route install */
2891bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi,
2892 uint32_t *nhg_p)
2893{
2894 esi_t *esi;
36dd4574 2895 struct bgp_evpn_es_vrf *es_vrf = NULL;
6348981a
AK
2896 struct bgp_path_info *parent_pi;
2897 struct bgp_node *rn;
2898 struct prefix_evpn *evp;
2899 struct bgp_path_info *mpinfo;
58bff4d1
AK
2900 bool use_l3nhg = false;
2901 bool is_l3nhg_active = false;
6348981a
AK
2902
2903 *nhg_p = 0;
2904
9f570418
AK
2905 /* we don't support NHG for routes leaked from another VRF yet */
2906 if (pi->extra && pi->extra->bgp_orig)
2907 return false;
2908
6348981a
AK
2909 parent_pi = get_route_parent_evpn(pi);
2910 if (!parent_pi)
2911 return false;
2912
2913 rn = parent_pi->net;
2914 if (!rn)
2915 return false;
2916
2917 evp = (struct prefix_evpn *)&rn->p;
2918 if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
2919 return false;
2920
6348981a
AK
2921 /* non-es path, use legacy-exploded multipath */
2922 esi = bgp_evpn_attr_get_esi(parent_pi->attr);
2923 if (!memcmp(esi, zero_esi, sizeof(*esi)))
2924 return false;
2925
58bff4d1
AK
2926 bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, &use_l3nhg, &is_l3nhg_active,
2927 &es_vrf);
2928
36dd4574 2929 /* L3NHG support is disabled, use legacy-exploded multipath */
58bff4d1 2930 if (!use_l3nhg)
36dd4574
AK
2931 return false;
2932
2933 /* if the NHG has not been installed we cannot install the route yet,
2934 * return a 0-NHG to indicate that
6348981a 2935 */
58bff4d1 2936 if (!is_l3nhg_active)
6348981a
AK
2937 return true;
2938
2939 /* this needs to be set the v6NHG if v6route */
8bcb09a1 2940 if (is_evpn_prefix_ipaddr_v6(evp))
6348981a
AK
2941 *nhg_p = es_vrf->v6_nhg_id;
2942 else
2943 *nhg_p = es_vrf->nhg_id;
2944
2945 for (mpinfo = bgp_path_info_mpath_next(pi); mpinfo;
2946 mpinfo = bgp_path_info_mpath_next(mpinfo)) {
36dd4574 2947 /* if any of the paths have a different ESI we can't use
6348981a
AK
2948 * the NHG associated with the ES. fallback to legacy-exploded
2949 * multipath
2950 */
2951 if (memcmp(esi, bgp_evpn_attr_get_esi(mpinfo->attr),
2952 sizeof(*esi)))
2953 return false;
2954 }
2955
2956 return true;
2957}
2958
229587fb
AK
2959static void bgp_evpn_es_vrf_show_entry(struct vty *vty,
2960 struct bgp_evpn_es_vrf *es_vrf,
2961 json_object *json)
2962{
2963 struct bgp_evpn_es *es = es_vrf->es;
2964 struct bgp *bgp_vrf = es_vrf->bgp_vrf;
2965
2966 if (json) {
2967 json_object *json_types;
2968
2969 json_object_string_add(json, "esi", es->esi_str);
2970 json_object_string_add(json, "vrf", bgp_vrf->name);
2971
2972 if (es_vrf->flags & (BGP_EVPNES_VRF_NHG_ACTIVE)) {
2973 json_types = json_object_new_array();
2974 if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
2975 json_array_string_add(json_types, "active");
2976 json_object_object_add(json, "flags", json_types);
2977 }
2978
2979 json_object_int_add(json, "ipv4NHG", es_vrf->nhg_id);
2980 json_object_int_add(json, "ipv6NHG", es_vrf->v6_nhg_id);
2981 json_object_int_add(json, "refCount", es_vrf->ref_cnt);
2982 } else {
2983 char flags_str[4];
2984
2985 flags_str[0] = '\0';
2986 if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)
2987 strlcat(flags_str, "A", sizeof(flags_str));
2988
2989 vty_out(vty, "%-30s %-15s %-5s %-8u %-8u %u\n", es->esi_str,
2990 bgp_vrf->name, flags_str, es_vrf->nhg_id,
2991 es_vrf->v6_nhg_id, es_vrf->ref_cnt);
2992 }
2993}
2994
2995static void bgp_evpn_es_vrf_show_es(struct vty *vty, json_object *json_array,
2996 struct bgp_evpn_es *es)
2997{
2998 json_object *json = NULL;
2999 struct listnode *es_vrf_node;
3000 struct bgp_evpn_es_vrf *es_vrf;
3001
3002 for (ALL_LIST_ELEMENTS_RO(es->es_vrf_list, es_vrf_node, es_vrf)) {
3003 /* create a separate json object for each ES-VRF */
3004 if (json_array)
3005 json = json_object_new_object();
3006 bgp_evpn_es_vrf_show_entry(vty, es_vrf, json);
3007 /* add ES-VRF to the json array */
3008 if (json_array)
3009 json_object_array_add(json_array, json);
3010 }
3011}
3012
3013/* Display all ES VRFs */
3014void bgp_evpn_es_vrf_show(struct vty *vty, bool uj, struct bgp_evpn_es *es)
3015{
3016 json_object *json_array = NULL;
3017
3018 if (uj) {
3019 /* create an array of ESs */
3020 json_array = json_object_new_array();
3021 } else {
3022 vty_out(vty, "ES-VRF Flags: A Active\n");
3023 vty_out(vty, "%-30s %-15s %-5s %-8s %-8s %s\n", "ESI", "VRF",
3024 "Flags", "IPv4-NHG", "IPv6-NHG", "Ref");
3025 }
3026
3027 if (es) {
3028 bgp_evpn_es_vrf_show_es(vty, json_array, es);
3029 } else {
3030 RB_FOREACH (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree)
3031 bgp_evpn_es_vrf_show_es(vty, json_array, es);
3032 }
3033
3034 /* print the array of json-ESs */
c48349e3 3035 if (uj)
75eeda93 3036 vty_json(vty, json_array);
229587fb
AK
3037}
3038
3039/* Display specific ES VRF */
3040void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj)
3041{
3042 struct bgp_evpn_es *es;
3043
3044 es = bgp_evpn_es_find(esi);
3045 if (es) {
3046 bgp_evpn_es_vrf_show(vty, uj, es);
3047 } else {
3048 if (!uj)
3049 vty_out(vty, "ESI not found\n");
3050 }
3051}
3052
c44ab6f1
AK
3053/*****************************************************************************/
3054/* Ethernet Segment to EVI association -
3055 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
3056 * (bgpevpn->es_evi_rb_tree).
3057 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
3058 * advertises an EAD-EVI (Type-1 EVPN) route
3059 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
3060 * it.
3061 */
3062
3063/* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
3064 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
3065 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
3066 * VTEPs for which both routes have been rxed are activated. Activation
3067 * creates a NHG in the parent ES.
3068 */
3069static int bgp_evpn_es_evi_vtep_cmp(void *p1, void *p2)
3070{
3071 const struct bgp_evpn_es_evi_vtep *evi_vtep1 = p1;
3072 const struct bgp_evpn_es_evi_vtep *evi_vtep2 = p2;
3073
3074 return evi_vtep1->vtep_ip.s_addr - evi_vtep2->vtep_ip.s_addr;
3075}
3076
3077static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_new(
3078 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip)
3079{
3080 struct bgp_evpn_es_evi_vtep *evi_vtep;
3081
3082 evi_vtep = XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP, sizeof(*evi_vtep));
3083
3084 evi_vtep->es_evi = es_evi;
3085 evi_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
3086 listnode_init(&evi_vtep->es_evi_listnode, evi_vtep);
3087 listnode_add_sort(es_evi->es_evi_vtep_list, &evi_vtep->es_evi_listnode);
3088
3089 return evi_vtep;
3090}
3091
3092static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep *evi_vtep)
3093{
3094 struct bgp_evpn_es_evi *es_evi = evi_vtep->es_evi;
3095
3096 if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD))
3097 /* as long as there is some reference we can't free it */
3098 return;
3099
3100 list_delete_node(es_evi->es_evi_vtep_list, &evi_vtep->es_evi_listnode);
3101 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP, evi_vtep);
3102}
3103
3104/* check if VTEP is already part of the list */
3105static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_find(
3106 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip)
3107{
3108 struct listnode *node = NULL;
3109 struct bgp_evpn_es_evi_vtep *evi_vtep;
3110
3111 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
3112 if (evi_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
3113 return evi_vtep;
3114 }
3115 return NULL;
3116}
3117
3118/* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
3119 * EAD-per-EVI routes are rxed from it.
3120 */
3121static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
3122 struct bgp_evpn_es_evi_vtep *evi_vtep)
3123{
3124 bool old_active;
3125 bool new_active;
fe8293c3 3126 uint32_t ead_activity_flags;
c44ab6f1 3127
d4980edf 3128 old_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
c44ab6f1 3129
fe8293c3
AK
3130 if (bgp_mh_info->ead_evi_rx)
3131 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
3132 * before it can be activated.
3133 */
3134 ead_activity_flags = BGP_EVPN_EVI_VTEP_EAD;
3135 else
3136 /* EAD-per-ES is sufficent to activate the PE */
3137 ead_activity_flags = BGP_EVPN_EVI_VTEP_EAD_PER_ES;
3138
3139 if ((evi_vtep->flags & ead_activity_flags) == ead_activity_flags)
c44ab6f1
AK
3140 SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
3141 else
3142 UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
3143
d4980edf 3144 new_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
c44ab6f1
AK
3145
3146 if (old_active == new_active)
3147 return;
3148
3149 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
3150 zlog_debug("es %s evi %u vtep %pI4 %s",
3151 evi_vtep->es_evi->es->esi_str,
3152 evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip,
3153 new_active ? "active" : "inactive");
c44ab6f1
AK
3154
3155 /* add VTEP to parent es */
3156 if (new_active) {
3157 struct bgp_evpn_es_vtep *es_vtep;
3158
3159 es_vtep = bgp_evpn_es_vtep_add(bgp, evi_vtep->es_evi->es,
74e2bd89
AK
3160 evi_vtep->vtep_ip, false /*esr*/,
3161 0, 0);
c44ab6f1
AK
3162 evi_vtep->es_vtep = es_vtep;
3163 } else {
3164 if (evi_vtep->es_vtep) {
3165 bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep,
3166 false /*esr*/);
3167 evi_vtep->es_vtep = NULL;
3168 }
3169 }
3170 /* queue up the parent es for background consistency checks */
3171 bgp_evpn_es_cons_checks_pend_add(evi_vtep->es_evi->es);
3172}
3173
3174static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp,
3175 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
3176 bool ead_es)
3177{
3178 struct bgp_evpn_es_evi_vtep *evi_vtep;
3179
3180 evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip);
3181
3182 if (!evi_vtep)
3183 evi_vtep = bgp_evpn_es_evi_vtep_new(es_evi, vtep_ip);
3184
3185 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
3186 zlog_debug("add es %s evi %u vtep %pI4 %s",
3187 evi_vtep->es_evi->es->esi_str,
3188 evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip,
3189 ead_es ? "ead_es" : "ead_evi");
c44ab6f1
AK
3190
3191 if (ead_es)
3192 SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES);
3193 else
3194 SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
3195
3196 bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
3197}
3198
3199static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp,
3200 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
3201 bool ead_es)
3202{
3203 struct bgp_evpn_es_evi_vtep *evi_vtep;
3204
3205 evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip);
3206 if (!evi_vtep)
3207 return;
3208
3209 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
3210 zlog_debug("del es %s evi %u vtep %pI4 %s",
3211 evi_vtep->es_evi->es->esi_str,
3212 evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip,
3213 ead_es ? "ead_es" : "ead_evi");
c44ab6f1
AK
3214
3215 if (ead_es)
3216 UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES);
3217 else
3218 UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
3219
3220 bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
3221 bgp_evpn_es_evi_vtep_free(evi_vtep);
3222}
3223
3224/* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
3225static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi *es_evi1,
3226 const struct bgp_evpn_es_evi *es_evi2)
3227{
3228 return memcmp(&es_evi1->es->esi, &es_evi2->es->esi, ESI_BYTES);
3229}
3230RB_GENERATE(bgp_es_evi_rb_head, bgp_evpn_es_evi, rb_node, bgp_es_evi_rb_cmp);
3231
3232/* find the ES-EVI in the per-L2-VNI RB tree */
3233static struct bgp_evpn_es_evi *bgp_evpn_es_evi_find(struct bgp_evpn_es *es,
3234 struct bgpevpn *vpn)
3235{
3236 struct bgp_evpn_es_evi es_evi;
3237
3238 es_evi.es = es;
3239
3240 return RB_FIND(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, &es_evi);
3241}
3242
3243/* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
3244 * tables.
3245 */
3246static struct bgp_evpn_es_evi *bgp_evpn_es_evi_new(struct bgp_evpn_es *es,
3247 struct bgpevpn *vpn)
3248{
3249 struct bgp_evpn_es_evi *es_evi;
3250
3251 es_evi = XCALLOC(MTYPE_BGP_EVPN_ES_EVI, sizeof(*es_evi));
3252
3253 es_evi->es = es;
3254 es_evi->vpn = vpn;
3255
3256 /* Initialise the VTEP list */
3257 es_evi->es_evi_vtep_list = list_new();
3258 listset_app_node_mem(es_evi->es_evi_vtep_list);
3259 es_evi->es_evi_vtep_list->cmp = bgp_evpn_es_evi_vtep_cmp;
3260
3261 /* insert into the VNI-ESI rb tree */
3262 if (RB_INSERT(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, es_evi)) {
3263 XFREE(MTYPE_BGP_EVPN_ES_EVI, es_evi);
3264 return NULL;
3265 }
3266
3267 /* add to the ES's VNI list */
3268 listnode_init(&es_evi->es_listnode, es_evi);
3269 listnode_add(es->es_evi_list, &es_evi->es_listnode);
3270
c589d847
AK
3271 bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf);
3272
c44ab6f1
AK
3273 return es_evi;
3274}
3275
3276/* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
3277 * up the memory.
3278 */
333ad64b
AK
3279static struct bgp_evpn_es_evi *
3280bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi)
c44ab6f1
AK
3281{
3282 struct bgp_evpn_es *es = es_evi->es;
3283 struct bgpevpn *vpn = es_evi->vpn;
3284
3285 /* cannot free the element as long as there is a local or remote
3286 * reference
3287 */
3288 if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE))
333ad64b 3289 return es_evi;
c44ab6f1 3290
c589d847
AK
3291 bgp_evpn_es_vrf_deref(es_evi);
3292
c44ab6f1
AK
3293 /* remove from the ES's VNI list */
3294 list_delete_node(es->es_evi_list, &es_evi->es_listnode);
3295
3296 /* remove from the VNI-ESI rb tree */
3297 RB_REMOVE(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, es_evi);
3298
3299 /* free the VTEP list */
3300 list_delete(&es_evi->es_evi_vtep_list);
3301
3302 /* remove from the VNI-ESI rb tree */
3303 XFREE(MTYPE_BGP_EVPN_ES_EVI, es_evi);
333ad64b
AK
3304
3305 return NULL;
c44ab6f1
AK
3306}
3307
3308/* init local info associated with the ES-EVI */
3309static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi *es_evi)
3310{
3311 struct bgpevpn *vpn = es_evi->vpn;
3312
3313 if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
3314 return;
3315
3316 SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
3317 listnode_init(&es_evi->l2vni_listnode, es_evi);
3318 listnode_add(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
3319}
3320
3321/* clear any local info associated with the ES-EVI */
333ad64b
AK
3322static struct bgp_evpn_es_evi *
3323bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi *es_evi)
c44ab6f1
AK
3324{
3325 struct bgpevpn *vpn = es_evi->vpn;
3326
c44ab6f1
AK
3327 UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
3328 list_delete_node(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
3329
333ad64b 3330 return bgp_evpn_es_evi_free(es_evi);
c44ab6f1
AK
3331}
3332
3333/* eval remote info associated with the ES */
3334static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi *es_evi)
3335{
3336 struct bgp_evpn_es *es = es_evi->es;
3337
3338 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
3339 if (listcount(es_evi->es_evi_vtep_list)) {
3340 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) {
3341 SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE);
3342 ++es->remote_es_evi_cnt;
3343 /* set remote on the parent es */
3344 bgp_evpn_es_remote_info_re_eval(es);
3345 }
3346 } else {
3347 if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) {
3348 UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE);
3349 if (es->remote_es_evi_cnt)
3350 --es->remote_es_evi_cnt;
3351 bgp_evpn_es_evi_free(es_evi);
3352 /* check if "remote" can be cleared from the
3353 * parent es.
3354 */
3355 bgp_evpn_es_remote_info_re_eval(es);
3356 }
3357 }
3358}
3359
333ad64b
AK
3360static struct bgp_evpn_es_evi *
3361bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi)
c44ab6f1
AK
3362{
3363 struct prefix_evpn p;
3364 struct bgp_evpn_es *es = es_evi->es;
3365 struct bgp *bgp;
3366
3367 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
333ad64b 3368 return es_evi;
c44ab6f1
AK
3369
3370 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
3371 zlog_debug("del local es %s evi %u",
3372 es_evi->es->esi_str,
3373 es_evi->vpn->vni);
3374
3375 bgp = bgp_get_evpn();
3376
3377 if (bgp) {
3378 /* update EAD-ES with new list of VNIs */
74be8313 3379 if (bgp_evpn_local_es_is_active(es)) {
c44ab6f1
AK
3380 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
3381 &es->esi, es->originator_ip);
3382 if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
3383 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
3384 "%u: EAD-ES route update failure for ESI %s VNI %u",
3385 bgp->vrf_id, es->esi_str,
3386 es_evi->vpn->vni);
3387 }
3388
3389 /* withdraw and delete EAD-EVI */
3390 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
3391 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
3392 &es->esi, es->originator_ip);
3393 if (bgp_evpn_type1_evi_route_delete(bgp,
3394 es, es_evi->vpn, &p))
3395 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
3396 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
3397 bgp->vrf_id, es->esi_str,
3398 es_evi->vpn->vni);
3399 }
3400 }
3401
333ad64b 3402 return bgp_evpn_es_evi_local_info_clear(es_evi);
c44ab6f1
AK
3403}
3404
3405int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni)
3406{
3407 struct bgpevpn *vpn;
3408 struct bgp_evpn_es *es;
3409 struct bgp_evpn_es_evi *es_evi;
3410 char buf[ESI_STR_LEN];
3411
3412 es = bgp_evpn_es_find(esi);
3413 if (!es) {
3414 flog_err(
3415 EC_BGP_ES_CREATE,
3416 "%u: Failed to deref VNI %d from ESI %s; ES not present",
3417 bgp->vrf_id, vni,
3418 esi_to_str(esi, buf, sizeof(buf)));
3419 return -1;
3420 }
3421
3422 vpn = bgp_evpn_lookup_vni(bgp, vni);
3423 if (!vpn) {
3424 flog_err(
3425 EC_BGP_ES_CREATE,
3426 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
3427 bgp->vrf_id, vni, es->esi_str);
3428 return -1;
3429 }
3430
3431 es_evi = bgp_evpn_es_evi_find(es, vpn);
3432 if (!es_evi) {
3433 flog_err(
3434 EC_BGP_ES_CREATE,
3435 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
3436 bgp->vrf_id, vni, es->esi_str);
3437 return -1;
3438 }
3439
3440 bgp_evpn_local_es_evi_do_del(es_evi);
3441 return 0;
3442}
3443
3444/* Create ES-EVI and advertise the corresponding EAD routes */
3445int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni)
3446{
3447 struct bgpevpn *vpn;
3448 struct prefix_evpn p;
3449 struct bgp_evpn_es *es;
3450 struct bgp_evpn_es_evi *es_evi;
3451 char buf[ESI_STR_LEN];
3452
3453 es = bgp_evpn_es_find(esi);
3454 if (!es) {
3455 flog_err(
3456 EC_BGP_ES_CREATE,
3457 "%u: Failed to associate VNI %d with ESI %s; ES not present",
3458 bgp->vrf_id, vni,
3459 esi_to_str(esi, buf, sizeof(buf)));
3460 return -1;
3461 }
3462
3463 vpn = bgp_evpn_lookup_vni(bgp, vni);
3464 if (!vpn) {
3465 flog_err(
3466 EC_BGP_ES_CREATE,
3467 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
3468 bgp->vrf_id, vni, es->esi_str);
3469 return -1;
3470 }
3471
3472 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
3473 zlog_debug("add local es %s evi %u",
3474 es->esi_str, vni);
3475
3476 es_evi = bgp_evpn_es_evi_find(es, vpn);
3477
3478 if (es_evi) {
3479 if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
3480 /* dup */
3481 return 0;
3482 } else {
3483 es_evi = bgp_evpn_es_evi_new(es, vpn);
3484 if (!es_evi)
3485 return -1;
3486 }
3487
3488 bgp_evpn_es_evi_local_info_set(es_evi);
3489
3490 /* generate an EAD-EVI for this new VNI */
c44ab6f1 3491 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
fe8293c3
AK
3492 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG, &es->esi,
3493 es->originator_ip);
c44ab6f1
AK
3494 if (bgp_evpn_type1_route_update(bgp, es, vpn, &p))
3495 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
3496 "%u: EAD-EVI route creation failure for ESI %s VNI %u",
3497 bgp->vrf_id, es->esi_str, vni);
3498 }
3499
3500 /* update EAD-ES */
3501 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
3502 &es->esi, es->originator_ip);
74be8313 3503 if (bgp_evpn_local_es_is_active(es)) {
c44ab6f1
AK
3504 if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
3505 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
3506 "%u: EAD-ES route creation failure for ESI %s VNI %u",
3507 bgp->vrf_id, es->esi_str, vni);
3508 }
3509
3510 return 0;
3511}
3512
3513/* Add remote ES-EVI entry. This is actually the remote VTEP add and the
3514 * ES-EVI is implicity created on first VTEP's reference.
3515 */
3516int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
3517 const struct prefix_evpn *p)
3518{
3519 char buf[ESI_STR_LEN];
3520 struct bgp_evpn_es *es;
3521 struct bgp_evpn_es_evi *es_evi;
3522 bool ead_es;
3523 const esi_t *esi = &p->prefix.ead_addr.esi;
3524
3525 if (!vpn)
3526 /* local EAD-ES need not be sent back to zebra */
3527 return 0;
3528
3529 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
3530 zlog_debug("add remote %s es %s evi %u vtep %pI4",
3531 p->prefix.ead_addr.eth_tag ? "ead-es" : "ead-evi",
3532 esi_to_str(esi, buf, sizeof(buf)), vpn->vni,
3533 &p->prefix.ead_addr.ip.ipaddr_v4);
c44ab6f1
AK
3534
3535 es = bgp_evpn_es_find(esi);
3536 if (!es) {
3537 es = bgp_evpn_es_new(bgp, esi);
3538 if (!es) {
3539 flog_err(EC_BGP_ES_CREATE,
3540 "%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
3541 bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
3542 return -1;
3543 }
3544 }
3545
3546 es_evi = bgp_evpn_es_evi_find(es, vpn);
3547 if (!es_evi) {
3548 es_evi = bgp_evpn_es_evi_new(es, vpn);
3549 if (!es_evi) {
45a859f1 3550 bgp_evpn_es_free(es, __func__);
c44ab6f1
AK
3551 return -1;
3552 }
3553 }
3554
3555 ead_es = !!p->prefix.ead_addr.eth_tag;
3556 bgp_evpn_es_evi_vtep_add(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
3557 ead_es);
3558
3559 bgp_evpn_es_evi_remote_info_re_eval(es_evi);
3560 return 0;
3561}
3562
3563/* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
3564 * parent es-evi freed up implicitly in last VTEP's deref.
3565 */
3566int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
3567 const struct prefix_evpn *p)
3568{
3569 char buf[ESI_STR_LEN];
3570 struct bgp_evpn_es *es;
3571 struct bgp_evpn_es_evi *es_evi;
3572 bool ead_es;
3573
3574 if (!vpn)
3575 /* local EAD-ES need not be sent back to zebra */
3576 return 0;
3577
3578 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
3579 zlog_debug(
3580 "del remote %s es %s evi %u vtep %pI4",
3581 p->prefix.ead_addr.eth_tag ? "ead-es" : "ead-evi",
3582 esi_to_str(&p->prefix.ead_addr.esi, buf, sizeof(buf)),
3583 vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4);
c44ab6f1
AK
3584
3585 es = bgp_evpn_es_find(&p->prefix.ead_addr.esi);
2eef4f20
AK
3586 if (!es) {
3587 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
3588 zlog_debug("del remote %s es %s evi %u vtep %pI4, NO es",
3589 p->prefix.ead_addr.eth_tag ? "ead-es"
3590 : "ead-evi",
3591 esi_to_str(&p->prefix.ead_addr.esi, buf,
3592 sizeof(buf)),
3593 vpn->vni,
3594 &p->prefix.ead_addr.ip.ipaddr_v4);
c44ab6f1 3595 return 0;
2eef4f20 3596 }
c44ab6f1 3597 es_evi = bgp_evpn_es_evi_find(es, vpn);
2eef4f20
AK
3598 if (!es_evi) {
3599 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
3600 zlog_debug(
3601 "del remote %s es %s evi %u vtep %pI4, NO es-evi",
3602 p->prefix.ead_addr.eth_tag ? "ead-es"
3603 : "ead-evi",
3604 esi_to_str(&p->prefix.ead_addr.esi, buf,
3605 sizeof(buf)),
3606 vpn->vni,
3607 &p->prefix.ead_addr.ip.ipaddr_v4);
c44ab6f1 3608 return 0;
2eef4f20 3609 }
c44ab6f1
AK
3610
3611 ead_es = !!p->prefix.ead_addr.eth_tag;
3612 bgp_evpn_es_evi_vtep_del(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
3613 ead_es);
3614 bgp_evpn_es_evi_remote_info_re_eval(es_evi);
3615 return 0;
3616}
3617
333ad64b
AK
3618/* If a VNI is being deleted we need to force del all remote VTEPs */
3619static void bgp_evpn_remote_es_evi_flush(struct bgp_evpn_es_evi *es_evi)
3620{
3621 struct listnode *node = NULL;
3622 struct listnode *nnode = NULL;
3623 struct bgp_evpn_es_evi_vtep *evi_vtep;
3624 struct bgp *bgp;
3625
3626 bgp = bgp_get_evpn();
3627 if (!bgp)
3628 return;
3629
3630 /* delete all VTEPs */
3631 for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list, node, nnode,
3632 evi_vtep)) {
3633 evi_vtep->flags &= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES
3634 | BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
3635 bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
3636 bgp_evpn_es_evi_vtep_free(evi_vtep);
3637 }
3638 /* delete the EVI */
3639 bgp_evpn_es_evi_remote_info_re_eval(es_evi);
3640}
3641
c44ab6f1
AK
3642/* Initialize the ES tables maintained per-L2_VNI */
3643void bgp_evpn_vni_es_init(struct bgpevpn *vpn)
3644{
3645 /* Initialize the ES-EVI RB tree */
3646 RB_INIT(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree);
3647
3648 /* Initialize the local list maintained for quick walks by type */
3649 vpn->local_es_evi_list = list_new();
3650 listset_app_node_mem(vpn->local_es_evi_list);
3651}
3652
3653/* Cleanup the ES info maintained per-L2_VNI */
3654void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn)
3655{
3656 struct bgp_evpn_es_evi *es_evi;
3657 struct bgp_evpn_es_evi *es_evi_next;
3658
3659 RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head,
3660 &vpn->es_evi_rb_tree, es_evi_next) {
333ad64b
AK
3661 es_evi = bgp_evpn_local_es_evi_do_del(es_evi);
3662 if (es_evi)
3663 bgp_evpn_remote_es_evi_flush(es_evi);
c44ab6f1
AK
3664 }
3665
3666 list_delete(&vpn->local_es_evi_list);
3667}
3668
3669static char *bgp_evpn_es_evi_vteps_str(char *vtep_str,
9e0c2fd1
AK
3670 struct bgp_evpn_es_evi *es_evi,
3671 uint8_t vtep_str_size)
c44ab6f1
AK
3672{
3673 char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
3674 struct listnode *node;
3675 struct bgp_evpn_es_evi_vtep *evi_vtep;
3676 bool first = true;
ec779825 3677 char ip_buf[INET6_ADDRSTRLEN];
c44ab6f1
AK
3678
3679 vtep_str[0] = '\0';
3680 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
3681 vtep_flag_str[0] = '\0';
3682 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
9e0c2fd1 3683 strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
c44ab6f1 3684 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
9e0c2fd1 3685 strlcat(vtep_flag_str, "V", sizeof(vtep_flag_str));
c44ab6f1 3686
9e0c2fd1
AK
3687 if (!strnlen(vtep_flag_str, sizeof(vtep_flag_str)))
3688 strlcpy(vtep_flag_str, "-", sizeof(vtep_flag_str));
3689 if (first)
c44ab6f1 3690 first = false;
9e0c2fd1
AK
3691 else
3692 strlcat(vtep_str, ",", vtep_str_size);
23d0a753 3693 strlcat(vtep_str,
ec779825
AK
3694 inet_ntop(AF_INET, &evi_vtep->vtep_ip, ip_buf,
3695 sizeof(ip_buf)),
23d0a753 3696 vtep_str_size);
9e0c2fd1
AK
3697 strlcat(vtep_str, "(", vtep_str_size);
3698 strlcat(vtep_str, vtep_flag_str, vtep_str_size);
3699 strlcat(vtep_str, ")", vtep_str_size);
c44ab6f1
AK
3700 }
3701
3702 return vtep_str;
3703}
3704
3705static void bgp_evpn_es_evi_json_vtep_fill(json_object *json_vteps,
3706 struct bgp_evpn_es_evi_vtep *evi_vtep)
3707{
3708 json_object *json_vtep_entry;
3709 json_object *json_flags;
3710
3711 json_vtep_entry = json_object_new_object();
3712
c949c771
DA
3713 json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4",
3714 &evi_vtep->vtep_ip);
c44ab6f1
AK
3715 if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
3716 BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) {
3717 json_flags = json_object_new_array();
3718 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
3719 json_array_string_add(json_flags, "ead-per-es");
3720 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
b37ff319 3721 json_array_string_add(json_flags, "ead-per-evi");
c44ab6f1
AK
3722 json_object_object_add(json_vtep_entry,
3723 "flags", json_flags);
3724 }
3725
3726 json_object_array_add(json_vteps,
3727 json_vtep_entry);
3728}
3729
3730static void bgp_evpn_es_evi_show_entry(struct vty *vty,
3731 struct bgp_evpn_es_evi *es_evi, json_object *json)
3732{
3733 struct listnode *node;
3734 struct bgp_evpn_es_evi_vtep *evi_vtep;
3735
3736 if (json) {
3737 json_object *json_vteps;
3738 json_object *json_types;
3739
3740 json_object_string_add(json, "esi", es_evi->es->esi_str);
3741 json_object_int_add(json, "vni", es_evi->vpn->vni);
3742
3743 if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL |
3744 BGP_EVPNES_EVI_REMOTE)) {
3745 json_types = json_object_new_array();
3746 if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
3747 json_array_string_add(json_types, "local");
3748 if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
3749 json_array_string_add(json_types, "remote");
3750 json_object_object_add(json, "type", json_types);
3751 }
3752
3753 if (listcount(es_evi->es_evi_vtep_list)) {
3754 json_vteps = json_object_new_array();
3755 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list,
3756 node, evi_vtep)) {
3757 bgp_evpn_es_evi_json_vtep_fill(json_vteps,
3758 evi_vtep);
3759 }
3760 json_object_object_add(json, "vteps", json_vteps);
3761 }
3762 } else {
3763 char type_str[4];
3764 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
3765
3766 type_str[0] = '\0';
3767 if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
9e0c2fd1 3768 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 3769 if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
9e0c2fd1 3770 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 3771 if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST)
9e0c2fd1 3772 strlcat(type_str, "I", sizeof(type_str));
c44ab6f1 3773
9e0c2fd1 3774 bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
c44ab6f1
AK
3775
3776 vty_out(vty, "%-8d %-30s %-5s %s\n",
3777 es_evi->vpn->vni, es_evi->es->esi_str,
3778 type_str, vtep_str);
3779 }
3780}
3781
3782static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
3783 struct bgp_evpn_es_evi *es_evi, json_object *json)
3784{
3785 if (json) {
3786 json_object *json_flags;
3787
3788 /* Add the "brief" info first */
3789 bgp_evpn_es_evi_show_entry(vty, es_evi, json);
3790 if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) {
3791 json_flags = json_object_new_array();
3792 json_array_string_add(json_flags, "es-vtep-mismatch");
3793 json_object_object_add(json, "flags", json_flags);
3794 }
3795 } else {
3796 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
3797 char type_str[4];
3798
3799 type_str[0] = '\0';
3800 if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
9e0c2fd1 3801 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 3802 if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
9e0c2fd1 3803 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 3804
9e0c2fd1 3805 bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
c44ab6f1 3806 if (!strlen(vtep_str))
9e0c2fd1 3807 strlcpy(vtep_str, "-", sizeof(type_str));
c44ab6f1
AK
3808
3809 vty_out(vty, "VNI: %d ESI: %s\n",
3810 es_evi->vpn->vni, es_evi->es->esi_str);
3811 vty_out(vty, " Type: %s\n", type_str);
3812 vty_out(vty, " Inconsistencies: %s\n",
3813 (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
3814 "es-vtep-mismatch":"-");
3815 vty_out(vty, " VTEPs: %s\n", vtep_str);
3816 vty_out(vty, "\n");
3817 }
3818}
3819
3820static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn *vpn, struct vty *vty,
3821 json_object *json_array, bool detail)
3822{
3823 struct bgp_evpn_es_evi *es_evi;
3824 json_object *json = NULL;
3825
3826 RB_FOREACH(es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree) {
3827 if (json_array)
3828 /* create a separate json object for each ES */
3829 json = json_object_new_object();
3830 if (detail)
3831 bgp_evpn_es_evi_show_entry_detail(vty, es_evi, json);
3832 else
3833 bgp_evpn_es_evi_show_entry(vty, es_evi, json);
3834 /* add ES to the json array */
3835 if (json_array)
3836 json_object_array_add(json_array, json);
3837 }
3838}
3839
3840struct es_evi_show_ctx {
3841 struct vty *vty;
3842 json_object *json;
3843 int detail;
3844};
3845
3846static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket *bucket,
3847 void *ctxt)
3848{
3849 struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
3850 struct es_evi_show_ctx *wctx = (struct es_evi_show_ctx *)ctxt;
3851
3852 bgp_evpn_es_evi_show_one_vni(vpn, wctx->vty, wctx->json, wctx->detail);
3853}
3854
3855/* Display all ES EVIs */
3856void bgp_evpn_es_evi_show(struct vty *vty, bool uj, bool detail)
3857{
3858 json_object *json_array = NULL;
3859 struct es_evi_show_ctx wctx;
3860 struct bgp *bgp;
3861
3862 if (uj) {
3863 /* create an array of ES-EVIs */
3864 json_array = json_object_new_array();
3865 }
3866
3867 wctx.vty = vty;
3868 wctx.json = json_array;
3869 wctx.detail = detail;
3870
3871 bgp = bgp_get_evpn();
3872
3873 if (!json_array && !detail) {
3874 vty_out(vty, "Flags: L local, R remote, I inconsistent\n");
3875 vty_out(vty, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3876 vty_out(vty, "%-8s %-30s %-5s %s\n",
3877 "VNI", "ESI", "Flags", "VTEPs");
3878 }
3879
3880 if (bgp)
3881 hash_iterate(bgp->vnihash,
3882 (void (*)(struct hash_bucket *,
3883 void *))bgp_evpn_es_evi_show_one_vni_hash_cb,
3884 &wctx);
c48349e3 3885 if (uj)
75eeda93 3886 vty_json(vty, json_array);
c44ab6f1
AK
3887}
3888
3889/* Display specific ES EVI */
3890void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni,
3891 bool uj, bool detail)
3892{
3893 struct bgpevpn *vpn = NULL;
3894 json_object *json_array = NULL;
3895 struct bgp *bgp;
3896
3897 if (uj) {
3898 /* create an array of ES-EVIs */
3899 json_array = json_object_new_array();
3900 }
3901
3902 bgp = bgp_get_evpn();
3903 if (bgp)
3904 vpn = bgp_evpn_lookup_vni(bgp, vni);
3905
3906 if (vpn) {
3907 if (!json_array && !detail) {
3908 vty_out(vty, "Flags: L local, R remote, I inconsistent\n");
3909 vty_out(vty, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
3910 vty_out(vty, "%-8s %-30s %-5s %s\n",
3911 "VNI", "ESI", "Flags", "VTEPs");
3912 }
3913
3914 bgp_evpn_es_evi_show_one_vni(vpn, vty, json_array, detail);
3915 } else {
3916 if (!uj)
3917 vty_out(vty, "VNI not found\n");
3918 }
3919
c48349e3 3920 if (uj)
75eeda93 3921 vty_json(vty, json_array);
c44ab6f1
AK
3922}
3923
3924/*****************************************************************************
3925 * Ethernet Segment Consistency checks
3926 * Consistency checking is done to detect misconfig or mis-cabling. When
3927 * an inconsistency is detected it is simply logged (and displayed via
3928 * show commands) at this point. A more drastic action can be executed (based
3929 * on user config) in the future.
3930 */
8fc2ffb3
AK
3931static void bgp_evpn_es_cons_checks_timer_start(void)
3932{
3933 if (!bgp_mh_info->consistency_checking || bgp_mh_info->t_cons_check)
3934 return;
3935
3936 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
3937 zlog_debug("periodic consistency checking started");
3938
3939 thread_add_timer(bm->master, bgp_evpn_run_consistency_checks, NULL,
3940 BGP_EVPN_CONS_CHECK_INTERVAL,
3941 &bgp_mh_info->t_cons_check);
3942}
3943
c44ab6f1
AK
3944/* queue up the es for background consistency checks */
3945static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es)
3946{
3947 if (!bgp_mh_info->consistency_checking)
3948 /* consistency checking is not enabled */
3949 return;
3950
3951 if (CHECK_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND))
3952 /* already queued for consistency checking */
3953 return;
3954
8fc2ffb3
AK
3955 /* start the periodic timer for consistency checks if it is not
3956 * already running */
3957 bgp_evpn_es_cons_checks_timer_start();
3958
c44ab6f1
AK
3959 SET_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND);
3960 listnode_init(&es->pend_es_listnode, es);
3961 listnode_add_after(bgp_mh_info->pend_es_list,
3962 listtail_unchecked(bgp_mh_info->pend_es_list),
3963 &es->pend_es_listnode);
3964}
3965
3966/* pull the ES from the consistency check list */
3967static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es)
3968{
3969 if (!CHECK_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND))
3970 return;
3971
3972 UNSET_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND);
3973 list_delete_node(bgp_mh_info->pend_es_list,
3974 &es->pend_es_listnode);
3975}
3976
3977/* Number of active VTEPs associated with the ES-per-EVI */
3978static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
3979 struct bgp_evpn_es_evi *es_evi)
3980{
3981 struct bgp_evpn_es_evi_vtep *evi_vtep;
3982 struct listnode *node;
3983 uint32_t vtep_cnt = 0;
3984
3985 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
3986 if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE))
3987 ++vtep_cnt;
3988 }
3989
3990 return vtep_cnt;
3991}
3992
3993/* Number of active VTEPs associated with the ES */
3994static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es)
3995{
3996 struct listnode *node;
3997 uint32_t vtep_cnt = 0;
3998 struct bgp_evpn_es_vtep *es_vtep;
3999
4000 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
4001 if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
4002 ++vtep_cnt;
4003 }
4004
4005 return vtep_cnt;
4006}
4007
4008static struct bgp_evpn_es_vtep *bgp_evpn_es_get_next_active_vtep(
4009 struct bgp_evpn_es *es, struct bgp_evpn_es_vtep *es_vtep)
4010{
4011 struct listnode *node;
4012 struct bgp_evpn_es_vtep *next_es_vtep;
4013
4014 if (es_vtep)
4015 node = listnextnode_unchecked(&es_vtep->es_listnode);
4016 else
4017 node = listhead(es->es_vtep_list);
4018
4019 for (; node; node = listnextnode_unchecked(node)) {
4020 next_es_vtep = listgetdata(node);
4021 if (CHECK_FLAG(next_es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
4022 return next_es_vtep;
4023 }
4024
4025 return NULL;
4026}
4027
4028static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_get_next_active_vtep(
4029 struct bgp_evpn_es_evi *es_evi,
4030 struct bgp_evpn_es_evi_vtep *evi_vtep)
4031{
4032 struct listnode *node;
4033 struct bgp_evpn_es_evi_vtep *next_evi_vtep;
4034
4035 if (evi_vtep)
4036 node = listnextnode_unchecked(&evi_vtep->es_evi_listnode);
4037 else
4038 node = listhead(es_evi->es_evi_vtep_list);
4039
4040 for (; node; node = listnextnode_unchecked(node)) {
4041 next_evi_vtep = listgetdata(node);
4042 if (CHECK_FLAG(next_evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE))
4043 return next_evi_vtep;
4044 }
4045
4046 return NULL;
4047}
4048
4049static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi *es_evi)
4050{
4051 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST)) {
4052 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4053 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
4054 es_evi->es->esi_str,
4055 es_evi->vpn->vni);
4056 SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST);
4057
4058 /* update parent ES with the incosistency setting */
4059 if (!es_evi->es->incons_evi_vtep_cnt &&
4060 BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4061 zlog_debug("inconsistency detected - es %s vtep list mismatch",
4062 es_evi->es->esi_str);
4063 ++es_evi->es->incons_evi_vtep_cnt;
4064 SET_FLAG(es_evi->es->inconsistencies,
4065 BGP_EVPNES_INCONS_VTEP_LIST);
4066 }
4067}
4068
4069static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es *es)
4070{
4071 int proc_cnt = 0;
4072 int es_active_vtep_cnt;
4073 int evi_active_vtep_cnt;
4074 struct bgp_evpn_es_evi *es_evi;
4075 struct listnode *evi_node;
4076 struct bgp_evpn_es_vtep *es_vtep;
4077 struct bgp_evpn_es_evi_vtep *evi_vtep;
4078
4079 /* reset the inconsistencies and re-evaluate */
4080 es->incons_evi_vtep_cnt = 0;
4081 es->inconsistencies = 0;
4082
4083 es_active_vtep_cnt = bgp_evpn_es_get_active_vtep_cnt(es);
4084 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
4085 evi_node, es_evi)) {
4086 ++proc_cnt;
4087
4088 /* reset the inconsistencies on the EVI and re-evaluate*/
4089 UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST);
4090
4091 evi_active_vtep_cnt =
4092 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi);
4093 if (es_active_vtep_cnt != evi_active_vtep_cnt) {
4094 bgp_evpn_es_evi_set_inconsistent(es_evi);
4095 continue;
4096 }
4097
4098 if (!es_active_vtep_cnt)
4099 continue;
4100
4101 es_vtep = NULL;
4102 evi_vtep = NULL;
4103 while ((es_vtep = bgp_evpn_es_get_next_active_vtep(
4104 es, es_vtep))) {
4105 evi_vtep = bgp_evpn_es_evi_get_next_active_vtep(es_evi,
4106 evi_vtep);
4107 if (!evi_vtep) {
4108 bgp_evpn_es_evi_set_inconsistent(es_evi);
4109 break;
4110 }
4111 if (es_vtep->vtep_ip.s_addr !=
4112 evi_vtep->vtep_ip.s_addr) {
4113 /* inconsistency detected; set it and move
4114 * to the next evi
4115 */
4116 bgp_evpn_es_evi_set_inconsistent(es_evi);
4117 break;
4118 }
4119 }
4120 }
4121
4122 return proc_cnt;
4123}
4124
cc9f21da 4125static void bgp_evpn_run_consistency_checks(struct thread *t)
c44ab6f1
AK
4126{
4127 int proc_cnt = 0;
4128 int es_cnt = 0;
4129 struct listnode *node;
4130 struct listnode *nextnode;
4131 struct bgp_evpn_es *es;
4132
4133 for (ALL_LIST_ELEMENTS(bgp_mh_info->pend_es_list,
4134 node, nextnode, es)) {
4135 ++es_cnt;
4136 ++proc_cnt;
4137 /* run consistency checks on the ES and remove it from the
4138 * pending list
4139 */
4140 proc_cnt += bgp_evpn_es_run_consistency_checks(es);
4141 bgp_evpn_es_cons_checks_pend_del(es);
4142 if (proc_cnt > 500)
4143 break;
4144 }
4145
4146 /* restart the timer */
4147 thread_add_timer(bm->master, bgp_evpn_run_consistency_checks, NULL,
4148 BGP_EVPN_CONS_CHECK_INTERVAL,
4149 &bgp_mh_info->t_cons_check);
c44ab6f1
AK
4150}
4151
090efa2f
AK
4152/*****************************************************************************
4153 * EVPN-Nexthop and RMAC management: nexthops associated with Type-2 routes
4154 * that have an ES as destination are consolidated by BGP into a per-VRF
4155 * nh->rmac mapping which is sent to zebra. Zebra installs the nexthop
4156 * as a remote neigh/fdb entry with a dummy (type-1) prefix referencing it.
4157 *
4158 * This handling is needed because Type-2 routes with ES as dest use NHG
4159 * that is setup using EAD routes (i.e. such NHGs do not include the
4160 * RMAC info).
4161 ****************************************************************************/
4162static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add)
4163{
4164 struct stream *s;
4165 struct bgp *bgp_vrf = nh->bgp_vrf;
4166
4167 /* Check socket. */
4168 if (!zclient || zclient->sock < 0)
4169 return;
4170
4171 /* Don't try to register if Zebra doesn't know of this instance. */
4172 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp_vrf)) {
4173 if (BGP_DEBUG(zebra, ZEBRA))
4174 zlog_debug("No zebra instance, not %s remote nh %s",
4175 add ? "adding" : "deleting", nh->nh_str);
4176 return;
4177 }
4178
4179 s = zclient->obuf;
4180 stream_reset(s);
4181
4182 zclient_create_header(
4183 s, add ? ZEBRA_EVPN_REMOTE_NH_ADD : ZEBRA_EVPN_REMOTE_NH_DEL,
4184 bgp_vrf->vrf_id);
4185 stream_putl(s, bgp_vrf->vrf_id);
4186 stream_put(s, &nh->ip, sizeof(nh->ip));
4187 if (add)
4188 stream_put(s, &nh->rmac, sizeof(nh->rmac));
4189
4190 stream_putw_at(s, 0, stream_get_endp(s));
4191
4192 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) {
4193 if (add)
4194 zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra",
4195 nh->bgp_vrf->name, nh->nh_str, &nh->rmac);
4196 else if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4197 zlog_debug("evpn vrf %s nh %s del to zebra",
4198 nh->bgp_vrf->name, nh->nh_str);
4199 }
4200
23aa35ad
AK
4201 frrtrace(2, frr_bgp, evpn_mh_nh_rmac_zsend, add, nh);
4202
090efa2f
AK
4203 zclient_send_message(zclient);
4204}
4205
4206static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh *nh, bool add)
4207{
4208 if (add && !is_zero_mac(&nh->rmac)) {
4209 nh->flags |= BGP_EVPN_NH_READY_FOR_ZEBRA;
4210 bgp_evpn_nh_zebra_update_send(nh, true);
4211 } else {
4212 if (!(nh->flags & BGP_EVPN_NH_READY_FOR_ZEBRA))
4213 return;
4214 nh->flags &= ~BGP_EVPN_NH_READY_FOR_ZEBRA;
4215 bgp_evpn_nh_zebra_update_send(nh, false);
4216 }
4217}
4218
4219static void *bgp_evpn_nh_alloc(void *p)
4220{
4221 struct bgp_evpn_nh *tmp_n = p;
4222 struct bgp_evpn_nh *n;
4223
4224 n = XCALLOC(MTYPE_BGP_EVPN_NH, sizeof(struct bgp_evpn_nh));
4225 *n = *tmp_n;
4226
4227 return ((void *)n);
4228}
4229
4230static struct bgp_evpn_nh *bgp_evpn_nh_find(struct bgp *bgp_vrf,
4231 struct ipaddr *ip)
4232{
4233 struct bgp_evpn_nh tmp;
4234 struct bgp_evpn_nh *n;
4235
4236 memset(&tmp, 0, sizeof(tmp));
4237 memcpy(&tmp.ip, ip, sizeof(struct ipaddr));
4238 n = hash_lookup(bgp_vrf->evpn_nh_table, &tmp);
4239
4240 return n;
4241}
4242
4243/* Add nexthop entry - implicitly created on first path reference */
4244static struct bgp_evpn_nh *bgp_evpn_nh_add(struct bgp *bgp_vrf,
4245 struct ipaddr *ip,
4246 struct bgp_path_info *pi)
4247{
4248 struct bgp_evpn_nh tmp_n;
4249 struct bgp_evpn_nh *n = NULL;
4250
4251 memset(&tmp_n, 0, sizeof(struct bgp_evpn_nh));
4252 memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr));
4253 n = hash_get(bgp_vrf->evpn_nh_table, &tmp_n, bgp_evpn_nh_alloc);
4254 ipaddr2str(ip, n->nh_str, sizeof(n->nh_str));
4255 n->bgp_vrf = bgp_vrf;
4256
4257 n->pi_list = list_new();
4258 listset_app_node_mem(n->pi_list);
4259
4260 /* Setup ref_pi when the nh is created */
4261 if (CHECK_FLAG(pi->flags, BGP_PATH_VALID) && pi->attr) {
4262 n->ref_pi = pi;
4263 memcpy(&n->rmac, &pi->attr->rmac, ETH_ALEN);
4264 }
4265
4266 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4267 zlog_debug("evpn vrf %s nh %s rmac %pEA add", n->bgp_vrf->name,
4268 n->nh_str, &n->rmac);
4269 bgp_evpn_nh_zebra_update(n, true);
4270 return n;
4271}
4272
4273/* Delete nexthop entry if there are no paths referencing it */
4274static void bgp_evpn_nh_del(struct bgp_evpn_nh *n)
4275{
4276 struct bgp_evpn_nh *tmp_n;
4277 struct bgp *bgp_vrf = n->bgp_vrf;
4278
4279 if (listcount(n->pi_list))
4280 return;
4281
4282 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4283 zlog_debug("evpn vrf %s nh %s del to zebra", bgp_vrf->name,
4284 n->nh_str);
4285
4286 bgp_evpn_nh_zebra_update(n, false);
4287 list_delete(&n->pi_list);
4288 tmp_n = hash_release(bgp_vrf->evpn_nh_table, n);
4289 XFREE(MTYPE_BGP_EVPN_NH, tmp_n);
4290}
4291
4292static unsigned int bgp_evpn_nh_hash_keymake(const void *p)
4293{
4294 const struct bgp_evpn_nh *n = p;
4295 const struct ipaddr *ip = &n->ip;
4296
4297 if (IS_IPADDR_V4(ip))
4298 return jhash_1word(ip->ipaddr_v4.s_addr, 0);
4299
4300 return jhash2(ip->ipaddr_v6.s6_addr32,
4301 array_size(ip->ipaddr_v6.s6_addr32), 0);
4302}
4303
4304static bool bgp_evpn_nh_cmp(const void *p1, const void *p2)
4305{
4306 const struct bgp_evpn_nh *n1 = p1;
4307 const struct bgp_evpn_nh *n2 = p2;
4308
4309 if (n1 == NULL && n2 == NULL)
4310 return true;
4311
4312 if (n1 == NULL || n2 == NULL)
4313 return false;
4314
60cda04d 4315 return (ipaddr_cmp(&n1->ip, &n2->ip) == 0);
090efa2f
AK
4316}
4317
4318void bgp_evpn_nh_init(struct bgp *bgp_vrf)
4319{
4320 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4321 zlog_debug("evpn vrf %s nh init", bgp_vrf->name);
4322 bgp_vrf->evpn_nh_table = hash_create(
4323 bgp_evpn_nh_hash_keymake, bgp_evpn_nh_cmp, "BGP EVPN NH table");
4324}
4325
4326static void bgp_evpn_nh_flush_entry(struct bgp_evpn_nh *nh)
4327{
4328 struct listnode *node;
4329 struct listnode *nnode;
4330 struct bgp_path_evpn_nh_info *nh_info;
4331
4332 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4333 zlog_debug("evpn vrf %s nh %s flush", nh->bgp_vrf->name,
4334 nh->nh_str);
4335
4336 /* force flush paths */
4337 for (ALL_LIST_ELEMENTS(nh->pi_list, node, nnode, nh_info))
4338 bgp_evpn_path_nh_del(nh->bgp_vrf, nh_info->pi);
4339}
4340
4341static void bgp_evpn_nh_flush_cb(struct hash_bucket *bucket, void *ctxt)
4342{
4343 struct bgp_evpn_nh *nh = (struct bgp_evpn_nh *)bucket->data;
4344
4345 bgp_evpn_nh_flush_entry(nh);
4346}
4347
4348void bgp_evpn_nh_finish(struct bgp *bgp_vrf)
4349{
4350 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4351 zlog_debug("evpn vrf %s nh finish", bgp_vrf->name);
4352 hash_iterate(
4353 bgp_vrf->evpn_nh_table,
4354 (void (*)(struct hash_bucket *, void *))bgp_evpn_nh_flush_cb,
4355 NULL);
4356 hash_free(bgp_vrf->evpn_nh_table);
4357 bgp_vrf->evpn_nh_table = NULL;
4358}
4359
4360static void bgp_evpn_nh_update_ref_pi(struct bgp_evpn_nh *nh)
4361{
4362 struct listnode *node;
4363 struct bgp_path_info *pi;
4364 struct bgp_path_evpn_nh_info *nh_info;
4365
4366 if (nh->ref_pi)
4367 return;
4368
4369 for (ALL_LIST_ELEMENTS_RO(nh->pi_list, node, nh_info)) {
4370 pi = nh_info->pi;
4371 if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID) || !pi->attr)
4372 continue;
4373
4374 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4375 zlog_debug("evpn vrf %s nh %s ref_pi update",
4376 nh->bgp_vrf->name, nh->nh_str);
4377 nh->ref_pi = pi;
4378 /* If we have a new pi copy rmac from it and update
4379 * zebra if the new rmac is different
4380 */
4381 if (memcmp(&nh->rmac, &nh->ref_pi->attr->rmac, ETH_ALEN)) {
4382 memcpy(&nh->rmac, &nh->ref_pi->attr->rmac, ETH_ALEN);
4383 bgp_evpn_nh_zebra_update(nh, true);
4384 }
4385 break;
4386 }
4387}
4388
4389static void bgp_evpn_nh_clear_ref_pi(struct bgp_evpn_nh *nh,
4390 struct bgp_path_info *pi)
4391{
4392 if (nh->ref_pi != pi)
4393 return;
4394
4395 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
4396 zlog_debug("evpn vrf %s nh %s ref_pi clear", nh->bgp_vrf->name,
4397 nh->nh_str);
4398 nh->ref_pi = NULL;
4399 /* try to find another ref_pi */
4400 bgp_evpn_nh_update_ref_pi(nh);
4401 /* couldn't find one - clear the old rmac and notify zebra */
4402 if (!nh->ref_pi) {
4403 memset(&nh->rmac, 0, ETH_ALEN);
4404 bgp_evpn_nh_zebra_update(nh, true);
4405 }
4406}
4407
4408static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info *nh_info)
4409{
4410 bgp_evpn_path_nh_unlink(nh_info);
4411 XFREE(MTYPE_BGP_EVPN_PATH_NH_INFO, nh_info);
4412}
4413
4414static struct bgp_path_evpn_nh_info *
4415bgp_evpn_path_nh_info_new(struct bgp_path_info *pi)
4416{
4417 struct bgp_path_info_extra *e;
4418 struct bgp_path_mh_info *mh_info;
4419 struct bgp_path_evpn_nh_info *nh_info;
4420
4421 e = bgp_path_info_extra_get(pi);
4422
4423 /* If mh_info doesn't exist allocate it */
4424 mh_info = e->mh_info;
4425 if (!mh_info)
4426 e->mh_info = mh_info = XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO,
4427 sizeof(struct bgp_path_mh_info));
4428
4429 /* If nh_info doesn't exist allocate it */
4430 nh_info = mh_info->nh_info;
4431 if (!nh_info) {
4432 mh_info->nh_info = nh_info =
4433 XCALLOC(MTYPE_BGP_EVPN_PATH_NH_INFO,
4434 sizeof(struct bgp_path_evpn_nh_info));
4435 nh_info->pi = pi;
4436 }
4437
4438 return nh_info;
4439}
4440
4441static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info)
4442{
4443 struct bgp_evpn_nh *nh = nh_info->nh;
4444 struct bgp_path_info *pi;
4445 char prefix_buf[PREFIX_STRLEN];
4446
4447 if (!nh)
4448 return;
4449
4450 pi = nh_info->pi;
4451 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
4452 zlog_debug("path %s unlinked from nh %s %s",
4453 pi->net ? prefix2str(&pi->net->p, prefix_buf,
4454 sizeof(prefix_buf))
4455 : "",
4456 nh->bgp_vrf->name, nh->nh_str);
4457
4458 list_delete_node(nh->pi_list, &nh_info->nh_listnode);
4459
4460 nh_info->nh = NULL;
4461
4462 /* check if the ref_pi need to be updated */
4463 bgp_evpn_nh_clear_ref_pi(nh, pi);
4464
4465 /* if there are no other references against the nh it
4466 * needs to be freed
4467 */
4468 bgp_evpn_nh_del(nh);
4469
4470 /* Note we don't free the path nh_info on unlink; it will be freed up
4471 * along with the path.
4472 */
4473}
4474
4475static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi)
4476{
4477 struct bgp_path_evpn_nh_info *nh_info;
4478 struct bgp_evpn_nh *nh;
090efa2f
AK
4479 struct ipaddr ip;
4480
4481 /* EVPN nexthop setup in bgp has been turned off */
4482 if (!bgp_mh_info->bgp_evpn_nh_setup)
4483 return;
4484
4485 if (!bgp_vrf->evpn_nh_table) {
4486 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
70545a29
AK
4487 zlog_debug("path %pFX linked to vrf %s failed",
4488 &pi->net->p, bgp_vrf->name);
090efa2f
AK
4489 return;
4490 }
4491
4492 nh_info = (pi->extra && pi->extra->mh_info)
4493 ? pi->extra->mh_info->nh_info
4494 : NULL;
4495
4496 /* if NHG is not being used for this path we don't need to manage the
4497 * nexthops in bgp (they are managed by zebra instead)
4498 */
4499 if (!(pi->attr->es_flags & ATTR_ES_L3_NHG_USE)) {
4500 if (nh_info)
4501 bgp_evpn_path_nh_unlink(nh_info);
4502 return;
4503 }
4504
4505 /* setup nh_info against the path if it doesn't aleady exist */
4506 if (!nh_info)
4507 nh_info = bgp_evpn_path_nh_info_new(pi);
4508
4509 /* find-create nh */
4510 memset(&ip, 0, sizeof(ip));
4511 if (pi->net->p.family == AF_INET6) {
4512 SET_IPADDR_V6(&ip);
4513 memcpy(&ip.ipaddr_v6, &pi->attr->mp_nexthop_global,
4514 sizeof(ip.ipaddr_v6));
4515 } else {
4516 SET_IPADDR_V4(&ip);
4517 memcpy(&ip.ipaddr_v4, &pi->attr->nexthop, sizeof(ip.ipaddr_v4));
4518 }
4519
4520 nh = bgp_evpn_nh_find(bgp_vrf, &ip);
4521 if (!nh)
4522 nh = bgp_evpn_nh_add(bgp_vrf, &ip, pi);
4523
4524 /* dup check */
4525 if (nh_info->nh == nh) {
4526 /* Check if any of the paths are now valid */
4527 bgp_evpn_nh_update_ref_pi(nh);
4528 return;
4529 }
4530
4531 /* unlink old nh if any */
4532 bgp_evpn_path_nh_unlink(nh_info);
4533
4534 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
70545a29
AK
4535 zlog_debug("path %pFX linked to nh %s %s", &pi->net->p,
4536 nh->bgp_vrf->name, nh->nh_str);
090efa2f
AK
4537
4538 /* link mac-ip path to the new nh */
4539 nh_info->nh = nh;
4540 listnode_init(&nh_info->nh_listnode, nh_info);
4541 listnode_add(nh->pi_list, &nh_info->nh_listnode);
4542 /* If a new valid path got linked to the nh see if can get the rmac
4543 * from it
4544 */
4545 bgp_evpn_nh_update_ref_pi(nh);
4546 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) {
4547 if (!nh->ref_pi)
4548 zlog_debug(
70545a29
AK
4549 "path %pFX linked to nh %s %s with no valid pi",
4550 &pi->net->p, nh->bgp_vrf->name, nh->nh_str);
090efa2f
AK
4551 }
4552}
4553
4554void bgp_evpn_path_nh_del(struct bgp *bgp_vrf, struct bgp_path_info *pi)
4555{
4556 struct bgp_path_evpn_nh_info *nh_info;
4557
4558 nh_info = (pi->extra && pi->extra->mh_info)
4559 ? pi->extra->mh_info->nh_info
4560 : NULL;
4561
4562 if (!nh_info)
4563 return;
4564
4565 bgp_evpn_path_nh_unlink(nh_info);
4566}
4567
4568void bgp_evpn_path_nh_add(struct bgp *bgp_vrf, struct bgp_path_info *pi)
4569{
4570 bgp_evpn_path_nh_link(bgp_vrf, pi);
4571}
4572
4573static void bgp_evpn_nh_show_entry(struct bgp_evpn_nh *nh, struct vty *vty,
4574 json_object *json_array)
4575{
4576 json_object *json = NULL;
4577 char mac_buf[ETHER_ADDR_STRLEN];
4578 char prefix_buf[PREFIX_STRLEN];
4579
4580 if (json_array)
4581 /* create a separate json object for each ES */
4582 json = json_object_new_object();
4583
4584 prefix_mac2str(&nh->rmac, mac_buf, sizeof(mac_buf));
4585 if (nh->ref_pi && nh->ref_pi->net)
4586 prefix2str(&nh->ref_pi->net->p, prefix_buf, sizeof(prefix_buf));
4587 else
4588 prefix_buf[0] = '\0';
4589 if (json) {
4590 json_object_string_add(json, "vrf", nh->bgp_vrf->name);
4591 json_object_string_add(json, "ip", nh->nh_str);
4592 json_object_string_add(json, "rmac", mac_buf);
4593 json_object_string_add(json, "basePath", prefix_buf);
4594 json_object_int_add(json, "pathCount", listcount(nh->pi_list));
4595 } else {
4596 vty_out(vty, "%-15s %-15s %-17s %-10d %s\n", nh->bgp_vrf->name,
4597 nh->nh_str, mac_buf, listcount(nh->pi_list),
4598 prefix_buf);
4599 }
4600
4601 /* add ES to the json array */
4602 if (json_array)
4603 json_object_array_add(json_array, json);
4604}
4605
4606struct nh_show_ctx {
4607 struct vty *vty;
4608 json_object *json;
4609};
4610
4611static void bgp_evpn_nh_show_hash_cb(struct hash_bucket *bucket, void *ctxt)
4612{
4613 struct bgp_evpn_nh *nh = (struct bgp_evpn_nh *)bucket->data;
4614 struct nh_show_ctx *wctx = (struct nh_show_ctx *)ctxt;
4615
4616 bgp_evpn_nh_show_entry(nh, wctx->vty, wctx->json);
4617}
4618
4619/* Display all evpn nexthops */
4620void bgp_evpn_nh_show(struct vty *vty, bool uj)
4621{
4622 json_object *json_array = NULL;
4623 struct bgp *bgp_vrf;
4624 struct listnode *node;
4625 struct nh_show_ctx wctx;
4626
4627 if (uj) {
4628 /* create an array of nexthops */
4629 json_array = json_object_new_array();
4630 } else {
4631 vty_out(vty, "%-15s %-15s %-17s %-10s %s\n", "VRF", "IP",
4632 "RMAC", "#Paths", "Base Path");
4633 }
4634
4635 wctx.vty = vty;
4636 wctx.json = json_array;
4637
4638 /* walk through all vrfs */
4639 for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
4640 hash_iterate(bgp_vrf->evpn_nh_table,
4641 (void (*)(struct hash_bucket *,
4642 void *))bgp_evpn_nh_show_hash_cb,
4643 &wctx);
4644 }
4645
4646 /* print the array of json-ESs */
c48349e3 4647 if (uj)
75eeda93 4648 vty_json(vty, json_array);
090efa2f
AK
4649}
4650
c44ab6f1
AK
4651/*****************************************************************************/
4652void bgp_evpn_mh_init(void)
4653{
4654 bm->mh_info = XCALLOC(MTYPE_BGP_EVPN_MH_INFO, sizeof(*bm->mh_info));
4655
4656 /* setup ES tables */
4657 RB_INIT(bgp_es_rb_head, &bgp_mh_info->es_rb_tree);
4658 /* local ES list */
4659 bgp_mh_info->local_es_list = list_new();
4660 listset_app_node_mem(bgp_mh_info->local_es_list);
4661 /* list of ESs with pending processing */
4662 bgp_mh_info->pend_es_list = list_new();
4663 listset_app_node_mem(bgp_mh_info->pend_es_list);
4664
fe8293c3
AK
4665 bgp_mh_info->ead_evi_rx = BGP_EVPN_MH_EAD_EVI_RX_DEF;
4666 bgp_mh_info->ead_evi_tx = BGP_EVPN_MH_EAD_EVI_TX_DEF;
4667
c44ab6f1
AK
4668 /* config knobs - XXX add cli to control it */
4669 bgp_mh_info->ead_evi_adv_for_down_links = true;
4670 bgp_mh_info->consistency_checking = true;
2867823e
AK
4671 bgp_mh_info->install_l3nhg = false;
4672 bgp_mh_info->host_routes_use_l3nhg = BGP_EVPN_MH_USE_ES_L3NHG_DEF;
70524092 4673 bgp_mh_info->suppress_l3_ecomm_on_inactive_es = true;
090efa2f 4674 bgp_mh_info->bgp_evpn_nh_setup = true;
c44ab6f1 4675
c44ab6f1
AK
4676 memset(&zero_esi_buf, 0, sizeof(esi_t));
4677}
4678
4679void bgp_evpn_mh_finish(void)
4680{
4681 struct bgp_evpn_es *es;
4682 struct bgp_evpn_es *es_next;
c44ab6f1 4683
45a859f1
AK
4684 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
4685 zlog_debug("evpn mh finish");
4686
4687 RB_FOREACH_SAFE (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree,
4688 es_next) {
d57e0c05 4689 bgp_evpn_es_local_info_clear(es, true);
c44ab6f1 4690 }
8fc2ffb3
AK
4691 if (bgp_mh_info->t_cons_check)
4692 thread_cancel(&bgp_mh_info->t_cons_check);
c44ab6f1
AK
4693 list_delete(&bgp_mh_info->local_es_list);
4694 list_delete(&bgp_mh_info->pend_es_list);
4695
4696 XFREE(MTYPE_BGP_EVPN_MH_INFO, bgp_mh_info);
4697}
acd1d9bc
AD
4698
4699/* This function is called when disable-ead-evi-rx knob flaps */
4700void bgp_evpn_switch_ead_evi_rx(void)
4701{
4702 struct bgp *bgp;
4703 struct bgp_evpn_es *es;
4704 struct bgp_evpn_es_evi *es_evi;
4705 struct listnode *evi_node = NULL;
4706 struct listnode *evi_next = NULL;
4707 struct bgp_evpn_es_evi_vtep *vtep;
4708 struct listnode *vtep_node = NULL;
4709 struct listnode *vtep_next = NULL;
4710
4711 bgp = bgp_get_evpn();
4712 if (!bgp)
4713 return;
4714
4715 /*
4716 * Process all the remote es_evi_vteps and reevaluate if the es_evi_vtep
4717 * is active.
4718 */
4719 RB_FOREACH(es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
4720 if (!CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
4721 continue;
4722
4723 for (ALL_LIST_ELEMENTS(es->es_evi_list, evi_node, evi_next,
4724 es_evi)) {
4725 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE))
4726 continue;
4727
4728 for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list,
4729 vtep_node, vtep_next, vtep))
4730 bgp_evpn_es_evi_vtep_re_eval_active(bgp, vtep);
4731 }
4732 }
4733}