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