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