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