]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_evpn_mh.c
Merge pull request #7353 from AnuradhaKaruppiah/mh-cleanup-fix-1
[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
AK
50#include "bgpd/bgp_label.h"
51
52static void bgp_evpn_local_es_down(struct bgp *bgp,
53 struct bgp_evpn_es *es);
54static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp,
55 struct bgp_evpn_es *es);
56static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
57 struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr);
58static void bgp_evpn_es_vtep_del(struct bgp *bgp,
59 struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr);
60static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es);
61static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es);
62static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi);
63
64esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
65
66/******************************************************************************
67 * per-ES (Ethernet Segment) routing table
68 *
69 * Following routes are added to the ES's routing table -
70 * 1. Local and remote ESR (Type-4)
71 * 2. Local EAD-per-ES (Type-1).
72 *
73 * Key for these routes is {ESI, VTEP-IP} so the path selection is practically
74 * a no-op i.e. all paths lead to same VTEP-IP (i.e. result in the same VTEP
75 * being added to same ES).
76 *
77 * Note the following routes go into the VNI routing table (instead of the
78 * ES routing table) -
79 * 1. Remote EAD-per-ES
80 * 2. Local and remote EAD-per-EVI
185fb14a 81 */
185fb14a 82
c44ab6f1
AK
83/* Calculate the best path for a multi-homing (Type-1 or Type-4) route
84 * installed in the ES's routing table.
185fb14a 85 */
c44ab6f1 86static int bgp_evpn_es_route_select_install(struct bgp *bgp,
09319b4e
DS
87 struct bgp_evpn_es *es,
88 struct bgp_dest *dest)
185fb14a
AK
89{
90 int ret = 0;
91 afi_t afi = AFI_L2VPN;
92 safi_t safi = SAFI_EVPN;
93 struct bgp_path_info *old_select; /* old best */
94 struct bgp_path_info *new_select; /* new best */
95 struct bgp_path_info_pair old_and_new;
96
97 /* Compute the best path. */
09319b4e
DS
98 bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new,
99 afi, safi);
185fb14a
AK
100 old_select = old_and_new.old;
101 new_select = old_and_new.new;
102
103 /*
104 * If the best path hasn't changed - see if something needs to be
105 * updated
106 */
107 if (old_select && old_select == new_select
09319b4e
DS
108 && old_select->type == ZEBRA_ROUTE_BGP
109 && old_select->sub_type == BGP_ROUTE_IMPORTED
110 && !CHECK_FLAG(dest->flags, BGP_NODE_USER_CLEAR)
111 && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
112 && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
185fb14a 113 if (bgp_zebra_has_route_changed(old_select)) {
c44ab6f1
AK
114 bgp_evpn_es_vtep_add(bgp, es,
115 old_select->attr->nexthop,
116 true /*esr*/);
185fb14a
AK
117 }
118 UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
09319b4e 119 bgp_zebra_clear_route_change_flags(dest);
185fb14a
AK
120 return ret;
121 }
122
123 /* If the user did a "clear" this flag will be set */
09319b4e 124 UNSET_FLAG(dest->flags, BGP_NODE_USER_CLEAR);
185fb14a 125
c44ab6f1 126 /* bestpath has changed; update relevant fields and install or uninstall
185fb14a
AK
127 * into the zebra RIB.
128 */
129 if (old_select || new_select)
09319b4e 130 bgp_bump_version(dest);
185fb14a
AK
131
132 if (old_select)
09319b4e 133 bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED);
185fb14a 134 if (new_select) {
09319b4e
DS
135 bgp_path_info_set_flag(dest, new_select, BGP_PATH_SELECTED);
136 bgp_path_info_unset_flag(dest, new_select,
137 BGP_PATH_ATTR_CHANGED);
185fb14a
AK
138 UNSET_FLAG(new_select->flags, BGP_PATH_MULTIPATH_CHG);
139 }
140
141 if (new_select && new_select->type == ZEBRA_ROUTE_BGP
c44ab6f1
AK
142 && new_select->sub_type == BGP_ROUTE_IMPORTED) {
143 bgp_evpn_es_vtep_add(bgp, es,
144 new_select->attr->nexthop, true /*esr */);
185fb14a
AK
145 } else {
146 if (old_select && old_select->type == ZEBRA_ROUTE_BGP
c44ab6f1
AK
147 && old_select->sub_type == BGP_ROUTE_IMPORTED)
148 bgp_evpn_es_vtep_del(
149 bgp, es, old_select->attr->nexthop,
150 true /*esr*/);
185fb14a
AK
151 }
152
153 /* Clear any route change flags. */
09319b4e 154 bgp_zebra_clear_route_change_flags(dest);
185fb14a
AK
155
156 /* Reap old select bgp_path_info, if it has been removed */
157 if (old_select && CHECK_FLAG(old_select->flags, BGP_PATH_REMOVED))
09319b4e 158 bgp_path_info_reap(dest, old_select);
185fb14a
AK
159
160 return ret;
161}
162
c44ab6f1
AK
163/* Install Type-1/Type-4 route entry in the per-ES routing table */
164static int bgp_evpn_es_route_install(struct bgp *bgp,
165 struct bgp_evpn_es *es, struct prefix_evpn *p,
166 struct bgp_path_info *parent_pi)
167{
168 int ret = 0;
09319b4e 169 struct bgp_dest *dest = NULL;
c44ab6f1
AK
170 struct bgp_path_info *pi = NULL;
171 struct attr *attr_new = NULL;
172
173 /* Create (or fetch) route within the VNI.
174 * NOTE: There is no RD here.
175 */
09319b4e 176 dest = bgp_node_get(es->route_table, (struct prefix *)p);
c44ab6f1
AK
177
178 /* Check if route entry is already present. */
09319b4e 179 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
c44ab6f1
AK
180 if (pi->extra
181 && (struct bgp_path_info *)pi->extra->parent ==
182 parent_pi)
183 break;
184
185 if (!pi) {
186 /* Add (or update) attribute to hash. */
187 attr_new = bgp_attr_intern(parent_pi->attr);
188
189 /* Create new route with its attribute. */
190 pi = info_make(parent_pi->type, BGP_ROUTE_IMPORTED, 0,
09319b4e 191 parent_pi->peer, attr_new, dest);
c44ab6f1
AK
192 SET_FLAG(pi->flags, BGP_PATH_VALID);
193 bgp_path_info_extra_get(pi);
194 pi->extra->parent = bgp_path_info_lock(parent_pi);
09319b4e
DS
195 bgp_dest_lock_node((struct bgp_dest *)parent_pi->net);
196 bgp_path_info_add(dest, pi);
c44ab6f1
AK
197 } else {
198 if (attrhash_cmp(pi->attr, parent_pi->attr)
199 && !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
09319b4e 200 bgp_dest_unlock_node(dest);
c44ab6f1
AK
201 return 0;
202 }
203 /* The attribute has changed. */
204 /* Add (or update) attribute to hash. */
205 attr_new = bgp_attr_intern(parent_pi->attr);
206
207 /* Restore route, if needed. */
208 if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED))
09319b4e 209 bgp_path_info_restore(dest, pi);
c44ab6f1
AK
210
211 /* Mark if nexthop has changed. */
212 if (!IPV4_ADDR_SAME(&pi->attr->nexthop, &attr_new->nexthop))
213 SET_FLAG(pi->flags, BGP_PATH_IGP_CHANGED);
214
215 /* Unintern existing, set to new. */
216 bgp_attr_unintern(&pi->attr);
217 pi->attr = attr_new;
218 pi->uptime = bgp_clock();
219 }
220
221 /* Perform route selection and update zebra, if required. */
09319b4e 222 ret = bgp_evpn_es_route_select_install(bgp, es, dest);
c44ab6f1 223
09319b4e 224 bgp_dest_unlock_node(dest);
c44ab6f1
AK
225
226 return ret;
227}
228
229/* Uninstall Type-1/Type-4 route entry from the ES routing table */
230static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
231 struct prefix_evpn *p, struct bgp_path_info *parent_pi)
232{
233 int ret;
09319b4e 234 struct bgp_dest *dest;
c44ab6f1
AK
235 struct bgp_path_info *pi;
236
237 if (!es->route_table)
238 return 0;
239
240 /* Locate route within the ESI.
241 * NOTE: There is no RD here.
242 */
09319b4e
DS
243 dest = bgp_node_lookup(es->route_table, (struct prefix *)p);
244 if (!dest)
c44ab6f1
AK
245 return 0;
246
247 /* Find matching route entry. */
09319b4e 248 for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
c44ab6f1
AK
249 if (pi->extra
250 && (struct bgp_path_info *)pi->extra->parent ==
251 parent_pi)
252 break;
253
254 if (!pi)
255 return 0;
256
257 /* Mark entry for deletion */
09319b4e 258 bgp_path_info_delete(dest, pi);
c44ab6f1
AK
259
260 /* Perform route selection and update zebra, if required. */
09319b4e 261 ret = bgp_evpn_es_route_select_install(bgp, es, dest);
c44ab6f1
AK
262
263 /* Unlock route node. */
09319b4e 264 bgp_dest_unlock_node(dest);
c44ab6f1
AK
265
266 return ret;
267}
268
269/* Install or unistall a Tyoe-4 route in the per-ES routing table */
270int bgp_evpn_es_route_install_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
271 afi_t afi, safi_t safi, struct prefix_evpn *evp,
272 struct bgp_path_info *pi, int install)
273{
274 int ret = 0;
275
276 if (install)
277 ret = bgp_evpn_es_route_install(bgp, es, evp, pi);
278 else
279 ret = bgp_evpn_es_route_uninstall(bgp, es, evp, pi);
280
281 if (ret) {
282 flog_err(
283 EC_BGP_EVPN_FAIL,
284 "%u: Failed to %s EVPN %s route in ESI %s",
285 bgp->vrf_id,
286 install ? "install" : "uninstall",
287 "ES", es->esi_str);
288 return ret;
289 }
290 return 0;
291}
292
293/* Delete (and withdraw) local routes for specified ES from global and ES table.
294 * Also remove all remote routes from the per ES table. Invoked when ES
295 * is deleted.
185fb14a 296 */
c44ab6f1
AK
297static void bgp_evpn_es_route_del_all(struct bgp *bgp, struct bgp_evpn_es *es)
298{
09319b4e 299 struct bgp_dest *dest;
c44ab6f1
AK
300 struct bgp_path_info *pi, *nextpi;
301
302 /* de-activate the ES */
303 bgp_evpn_local_es_down(bgp, es);
304 bgp_evpn_local_type1_evi_route_del(bgp, es);
305
306 /* Walk this ES's routing table and delete all routes. */
09319b4e
DS
307 for (dest = bgp_table_top(es->route_table); dest;
308 dest = bgp_route_next(dest)) {
309 for (pi = bgp_dest_get_bgp_path_info(dest);
310 (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
311 bgp_path_info_delete(dest, pi);
312 bgp_path_info_reap(dest, pi);
c44ab6f1
AK
313 }
314 }
315}
316
317/*****************************************************************************
318 * Base APIs for creating MH routes (Type-1 or Type-4) on local ethernet
319 * segment updates.
320 */
321
322/* create or update local EVPN type1/type4 route entry.
323 *
324 * This could be in -
325 * the ES table if ESR/EAD-ES (or)
326 * the VNI table if EAD-EVI (or)
327 * the global table if ESR/EAD-ES/EAD-EVI
328 *
329 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
330 * ESR).
331 */
09319b4e
DS
332static int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
333 struct bgpevpn *vpn, afi_t afi, safi_t safi,
334 struct bgp_dest *dest, struct attr *attr,
335 int add, struct bgp_path_info **ri,
336 int *route_changed)
185fb14a 337{
185fb14a
AK
338 struct bgp_path_info *tmp_pi = NULL;
339 struct bgp_path_info *local_pi = NULL; /* local route entry if any */
340 struct bgp_path_info *remote_pi = NULL; /* remote route entry if any */
341 struct attr *attr_new = NULL;
c44ab6f1 342 struct prefix_evpn *evp;
185fb14a
AK
343
344 *ri = NULL;
752eed47 345 evp = (struct prefix_evpn *)bgp_dest_get_prefix(dest);
c44ab6f1 346 *route_changed = 1;
185fb14a
AK
347
348 /* locate the local and remote entries if any */
09319b4e 349 for (tmp_pi = bgp_dest_get_bgp_path_info(dest); tmp_pi;
185fb14a
AK
350 tmp_pi = tmp_pi->next) {
351 if (tmp_pi->peer == bgp->peer_self
c44ab6f1
AK
352 && tmp_pi->type == ZEBRA_ROUTE_BGP
353 && tmp_pi->sub_type == BGP_ROUTE_STATIC)
185fb14a
AK
354 local_pi = tmp_pi;
355 if (tmp_pi->type == ZEBRA_ROUTE_BGP
c44ab6f1
AK
356 && tmp_pi->sub_type == BGP_ROUTE_IMPORTED
357 && CHECK_FLAG(tmp_pi->flags, BGP_PATH_VALID))
185fb14a
AK
358 remote_pi = tmp_pi;
359 }
360
c44ab6f1
AK
361 /* we don't expect to see a remote_ri at this point as
362 * an ES route has {esi, vtep_ip} as the key in the ES-rt-table
363 * in the VNI-rt-table.
185fb14a
AK
364 */
365 if (remote_pi) {
366 flog_err(
23d0a753
DA
367 EC_BGP_ES_INVALID,
368 "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
369 bgp->vrf_id, es->esi_str, &es->originator_ip);
185fb14a
AK
370 return -1;
371 }
372
373 if (!local_pi && !add)
374 return 0;
375
376 /* create or update the entry */
377 if (!local_pi) {
378
379 /* Add or update attribute to hash */
380 attr_new = bgp_attr_intern(attr);
381
382 /* Create new route with its attribute. */
383 tmp_pi = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_STATIC, 0,
09319b4e 384 bgp->peer_self, attr_new, dest);
185fb14a
AK
385 SET_FLAG(tmp_pi->flags, BGP_PATH_VALID);
386
c44ab6f1
AK
387 if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) {
388 bgp_path_info_extra_get(tmp_pi);
389 tmp_pi->extra->num_labels = 1;
390 if (vpn)
391 vni2label(vpn->vni, &tmp_pi->extra->label[0]);
392 else
393 tmp_pi->extra->label[0] = 0;
394 }
395
185fb14a 396 /* add the newly created path to the route-node */
09319b4e 397 bgp_path_info_add(dest, tmp_pi);
185fb14a
AK
398 } else {
399 tmp_pi = local_pi;
400 if (attrhash_cmp(tmp_pi->attr, attr)
c44ab6f1 401 && !CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
185fb14a
AK
402 *route_changed = 0;
403 else {
404 /* The attribute has changed.
405 * Add (or update) attribute to hash.
406 */
407 attr_new = bgp_attr_intern(attr);
09319b4e
DS
408 bgp_path_info_set_flag(dest, tmp_pi,
409 BGP_PATH_ATTR_CHANGED);
185fb14a
AK
410
411 /* Restore route, if needed. */
412 if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_REMOVED))
09319b4e 413 bgp_path_info_restore(dest, tmp_pi);
185fb14a
AK
414
415 /* Unintern existing, set to new. */
416 bgp_attr_unintern(&tmp_pi->attr);
417 tmp_pi->attr = attr_new;
418 tmp_pi->uptime = bgp_clock();
419 }
420 }
421
c44ab6f1
AK
422 if (*route_changed) {
423 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
23d0a753
DA
424 zlog_debug(
425 "local ES %s vni %u route-type %s nexthop %pI4 updated",
426 es->esi_str, vpn ? vpn->vni : 0,
427 evp->prefix.route_type == BGP_EVPN_ES_ROUTE
428 ? "esr"
429 : (vpn ? "ead-evi" : "ead-es"),
430 &attr->mp_nexthop_global_in);
c44ab6f1
AK
431 }
432
185fb14a
AK
433 /* Return back the route entry. */
434 *ri = tmp_pi;
435 return 0;
436}
437
c44ab6f1
AK
438/* Delete local EVPN ESR (type-4) and EAD (type-1) route
439 *
440 * Note: vpn is applicable only to EAD-EVI routes (NULL for EAD-ES and
441 * ESR).
442 */
443static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es,
444 struct bgpevpn *vpn, struct prefix_evpn *p)
185fb14a 445{
185fb14a
AK
446 afi_t afi = AFI_L2VPN;
447 safi_t safi = SAFI_EVPN;
c44ab6f1 448 struct bgp_path_info *pi;
09319b4e
DS
449 struct bgp_dest *dest = NULL; /* dest in esi table */
450 struct bgp_dest *global_dest = NULL; /* dest in global table */
c44ab6f1
AK
451 struct bgp_table *rt_table;
452 struct prefix_rd *prd;
185fb14a 453
c44ab6f1
AK
454 if (vpn) {
455 rt_table = vpn->route_table;
456 prd = &vpn->prd;
457 } else {
458 rt_table = es->route_table;
459 prd = &es->prd;
460 }
185fb14a 461
c44ab6f1
AK
462 /* First, locate the route node within the ESI or VNI.
463 * If it doesn't exist, ther is nothing to do.
464 * Note: there is no RD here.
465 */
09319b4e
DS
466 dest = bgp_node_lookup(rt_table, (struct prefix *)p);
467 if (!dest)
c44ab6f1 468 return 0;
185fb14a 469
c44ab6f1 470 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
23d0a753
DA
471 zlog_debug(
472 "local ES %s vni %u route-type %s nexthop %pI4 delete",
473 es->esi_str, vpn ? vpn->vni : 0,
474 p->prefix.route_type == BGP_EVPN_ES_ROUTE
475 ? "esr"
476 : (vpn ? "ead-evi" : "ead-es"),
477 &es->originator_ip);
185fb14a 478
c44ab6f1
AK
479 /* Next, locate route node in the global EVPN routing table.
480 * Note that this table is a 2-level tree (RD-level + Prefix-level)
481 */
09319b4e
DS
482 global_dest =
483 bgp_global_evpn_node_lookup(bgp->rib[afi][safi], afi, safi,
484 (const struct prefix_evpn *)p, prd);
485 if (global_dest) {
185fb14a 486
c44ab6f1 487 /* Delete route entry in the global EVPN table. */
09319b4e 488 delete_evpn_route_entry(bgp, afi, safi, global_dest, &pi);
185fb14a
AK
489
490 /* Schedule for processing - withdraws to peers happen from
491 * this table.
492 */
493 if (pi)
09319b4e
DS
494 bgp_process(bgp, global_dest, afi, safi);
495 bgp_dest_unlock_node(global_dest);
185fb14a
AK
496 }
497
498 /*
c44ab6f1 499 * Delete route entry in the ESI or VNI routing table.
185fb14a
AK
500 * This can just be removed.
501 */
09319b4e 502 delete_evpn_route_entry(bgp, afi, safi, dest, &pi);
185fb14a 503 if (pi)
09319b4e
DS
504 bgp_path_info_reap(dest, pi);
505 bgp_dest_unlock_node(dest);
185fb14a
AK
506 return 0;
507}
508
c44ab6f1
AK
509/*****************************************************************************
510 * Ethernet Segment (Type-4) Routes
511 * ESRs are used for BUM handling. XXX - BUM support is planned for phase-2 i.e.
512 * this code is just a place holder for now
185fb14a 513 */
c44ab6f1
AK
514/* Build extended community for EVPN ES (type-4) route */
515static void bgp_evpn_type4_route_extcomm_build(struct bgp_evpn_es *es,
516 struct attr *attr)
185fb14a 517{
c44ab6f1
AK
518 struct ecommunity ecom_encap;
519 struct ecommunity ecom_es_rt;
520 struct ecommunity_val eval;
521 struct ecommunity_val eval_es_rt;
522 bgp_encap_types tnl_type;
523 struct ethaddr mac;
185fb14a 524
c44ab6f1
AK
525 /* Encap */
526 tnl_type = BGP_ENCAP_TYPE_VXLAN;
527 memset(&ecom_encap, 0, sizeof(ecom_encap));
528 encode_encap_extcomm(tnl_type, &eval);
529 ecom_encap.size = 1;
34540b0d 530 ecom_encap.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
531 ecom_encap.val = (uint8_t *)eval.val;
532 attr->ecommunity = ecommunity_dup(&ecom_encap);
185fb14a 533
c44ab6f1
AK
534 /* ES import RT */
535 memset(&mac, 0, sizeof(struct ethaddr));
536 memset(&ecom_es_rt, 0, sizeof(ecom_es_rt));
537 es_get_system_mac(&es->esi, &mac);
538 encode_es_rt_extcomm(&eval_es_rt, &mac);
539 ecom_es_rt.size = 1;
34540b0d 540 ecom_es_rt.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
541 ecom_es_rt.val = (uint8_t *)eval_es_rt.val;
542 attr->ecommunity =
543 ecommunity_merge(attr->ecommunity, &ecom_es_rt);
185fb14a 544
c44ab6f1 545 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
185fb14a
AK
546}
547
c44ab6f1
AK
548/* Create or update local type-4 route */
549static int bgp_evpn_type4_route_update(struct bgp *bgp,
550 struct bgp_evpn_es *es, struct prefix_evpn *p)
185fb14a
AK
551{
552 int ret = 0;
c44ab6f1
AK
553 int route_changed = 0;
554 afi_t afi = AFI_L2VPN;
555 safi_t safi = SAFI_EVPN;
556 struct attr attr;
557 struct attr *attr_new = NULL;
09319b4e 558 struct bgp_dest *dest = NULL;
185fb14a 559 struct bgp_path_info *pi = NULL;
185fb14a 560
c44ab6f1
AK
561 memset(&attr, 0, sizeof(struct attr));
562
563 /* Build path-attribute for this route. */
564 bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
565 attr.nexthop = es->originator_ip;
566 attr.mp_nexthop_global_in = es->originator_ip;
567 attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
568
569 /* Set up extended community. */
570 bgp_evpn_type4_route_extcomm_build(es, &attr);
571
572 /* First, create (or fetch) route node within the ESI. */
573 /* NOTE: There is no RD here. */
09319b4e 574 dest = bgp_node_get(es->route_table, (struct prefix *)p);
185fb14a 575
c44ab6f1 576 /* Create or update route entry. */
09319b4e
DS
577 ret = bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest, &attr, 1,
578 &pi, &route_changed);
c44ab6f1 579 if (ret != 0) {
23d0a753
DA
580 flog_err(
581 EC_BGP_ES_INVALID,
582 "%u ERROR: Failed to updated ES route ESI: %s VTEP %pI4",
583 bgp->vrf_id, es->esi_str, &es->originator_ip);
c44ab6f1 584 }
185fb14a 585
c44ab6f1
AK
586 assert(pi);
587 attr_new = pi->attr;
185fb14a 588
c44ab6f1
AK
589 /* Perform route selection;
590 * this is just to set the flags correctly
591 * as local route in the ES always wins.
592 */
09319b4e
DS
593 bgp_evpn_es_route_select_install(bgp, es, dest);
594 bgp_dest_unlock_node(dest);
185fb14a 595
c44ab6f1
AK
596 /* If this is a new route or some attribute has changed, export the
597 * route to the global table. The route will be advertised to peers
598 * from there. Note that this table is a 2-level tree (RD-level +
599 * Prefix-level) similar to L3VPN routes.
600 */
601 if (route_changed) {
602 struct bgp_path_info *global_pi;
185fb14a 603
09319b4e
DS
604 dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
605 p, &es->prd);
606 bgp_evpn_mh_route_update(bgp, es, NULL, afi, safi, dest,
607 attr_new, 1, &global_pi,
608 &route_changed);
185fb14a 609
c44ab6f1 610 /* Schedule for processing and unlock node. */
09319b4e
DS
611 bgp_process(bgp, dest, afi, safi);
612 bgp_dest_unlock_node(dest);
185fb14a
AK
613 }
614
c44ab6f1
AK
615 /* Unintern temporary. */
616 aspath_unintern(&attr.aspath);
617 return 0;
185fb14a
AK
618}
619
c44ab6f1
AK
620/* Delete local type-4 route */
621static int bgp_evpn_type4_route_delete(struct bgp *bgp,
622 struct bgp_evpn_es *es, struct prefix_evpn *p)
185fb14a 623{
c44ab6f1
AK
624 return bgp_evpn_mh_route_delete(bgp, es, NULL /* l2vni */, p);
625}
185fb14a 626
c44ab6f1
AK
627/* Process remote/received EVPN type-4 route (advertise or withdraw) */
628int bgp_evpn_type4_route_process(struct peer *peer, afi_t afi, safi_t safi,
629 struct attr *attr, uint8_t *pfx, int psize,
630 uint32_t addpath_id)
631{
632 int ret;
633 esi_t esi;
634 uint8_t ipaddr_len;
635 struct in_addr vtep_ip;
636 struct prefix_rd prd;
637 struct prefix_evpn p;
185fb14a 638
c44ab6f1
AK
639 /* Type-4 route should be either 23 or 35 bytes
640 * RD (8), ESI (10), ip-len (1), ip (4 or 16)
185fb14a 641 */
c44ab6f1
AK
642 if (psize != BGP_EVPN_TYPE4_V4_PSIZE &&
643 psize != BGP_EVPN_TYPE4_V6_PSIZE) {
644 flog_err(EC_BGP_EVPN_ROUTE_INVALID,
645 "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
646 peer->bgp->vrf_id, peer->host, psize);
647 return -1;
648 }
185fb14a 649
c44ab6f1
AK
650 /* Make prefix_rd */
651 prd.family = AF_UNSPEC;
652 prd.prefixlen = 64;
653 memcpy(&prd.val, pfx, RD_BYTES);
654 pfx += RD_BYTES;
185fb14a 655
c44ab6f1
AK
656 /* get the ESI */
657 memcpy(&esi, pfx, ESI_BYTES);
658 pfx += ESI_BYTES;
185fb14a 659
185fb14a 660
c44ab6f1
AK
661 /* Get the IP. */
662 ipaddr_len = *pfx++;
663 if (ipaddr_len == IPV4_MAX_BITLEN) {
664 memcpy(&vtep_ip, pfx, IPV4_MAX_BYTELEN);
665 } else {
666 flog_err(
667 EC_BGP_EVPN_ROUTE_INVALID,
668 "%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
669 peer->bgp->vrf_id, peer->host, ipaddr_len);
670 return -1;
671 }
185fb14a 672
c44ab6f1
AK
673 build_evpn_type4_prefix(&p, &esi, vtep_ip);
674 /* Process the route. */
675 if (attr) {
676 ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
677 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
678 &prd, NULL, 0, 0, NULL);
679 } else {
680 ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
681 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
682 &prd, NULL, 0, NULL);
683 }
185fb14a
AK
684 return ret;
685}
686
c44ab6f1
AK
687/* Check if a prefix belongs to the local ES */
688static bool bgp_evpn_type4_prefix_match(struct prefix_evpn *p,
689 struct bgp_evpn_es *es)
185fb14a 690{
c44ab6f1
AK
691 return (p->prefix.route_type == BGP_EVPN_ES_ROUTE) &&
692 !memcmp(&p->prefix.es_addr.esi, &es->esi, sizeof(esi_t));
185fb14a
AK
693}
694
c44ab6f1
AK
695/* Import remote ESRs on local ethernet segment add */
696static int bgp_evpn_type4_remote_routes_import(struct bgp *bgp,
697 struct bgp_evpn_es *es, bool install)
185fb14a
AK
698{
699 int ret;
700 afi_t afi;
701 safi_t safi;
702 char buf[PREFIX_STRLEN];
09319b4e 703 struct bgp_dest *rd_dest, *dest;
185fb14a
AK
704 struct bgp_table *table;
705 struct bgp_path_info *pi;
706
707 afi = AFI_L2VPN;
708 safi = SAFI_EVPN;
709
c44ab6f1
AK
710 /* Walk entire global routing table and evaluate routes which could be
711 * imported into this Ethernet Segment.
185fb14a 712 */
09319b4e
DS
713 for (rd_dest = bgp_table_top(bgp->rib[afi][safi]); rd_dest;
714 rd_dest = bgp_route_next(rd_dest)) {
715 table = bgp_dest_get_bgp_table_info(rd_dest);
185fb14a
AK
716 if (!table)
717 continue;
718
09319b4e
DS
719 for (dest = bgp_table_top(table); dest;
720 dest = bgp_route_next(dest)) {
721 struct prefix_evpn *evp =
752eed47 722 (struct prefix_evpn *)bgp_dest_get_prefix(dest);
185fb14a 723
09319b4e
DS
724 for (pi = bgp_dest_get_bgp_path_info(dest); pi;
725 pi = pi->next) {
185fb14a
AK
726 /*
727 * Consider "valid" remote routes applicable for
728 * this ES.
729 */
730 if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID)
c44ab6f1
AK
731 && pi->type == ZEBRA_ROUTE_BGP
732 && pi->sub_type == BGP_ROUTE_NORMAL))
185fb14a
AK
733 continue;
734
c44ab6f1 735 if (!bgp_evpn_type4_prefix_match(evp, es))
185fb14a
AK
736 continue;
737
738 if (install)
c44ab6f1
AK
739 ret = bgp_evpn_es_route_install(
740 bgp, es, evp, pi);
185fb14a 741 else
c44ab6f1
AK
742 ret = bgp_evpn_es_route_uninstall(
743 bgp, es, evp, pi);
185fb14a
AK
744
745 if (ret) {
746 flog_err(
c44ab6f1
AK
747 EC_BGP_EVPN_FAIL,
748 "Failed to %s EVPN %s route in ESI %s",
749 install ? "install"
185fb14a 750 : "uninstall",
c44ab6f1
AK
751 prefix2str(evp, buf,
752 sizeof(buf)),
753 es->esi_str);
185fb14a
AK
754 return ret;
755 }
756 }
757 }
758 }
759 return 0;
760}
761
c44ab6f1
AK
762/*****************************************************************************
763 * Ethernet Auto Discovery (EAD/Type-1) route handling
764 * There are two types of EAD routes -
765 * 1. EAD-per-ES - Key: {ESI, ET=0xffffffff}
766 * 2. EAD-per-EVI - Key: {ESI, ET=0}
185fb14a 767 */
185fb14a 768
c44ab6f1
AK
769/* Extended communities associated with EAD-per-ES */
770static void bgp_evpn_type1_es_route_extcomm_build(struct bgp_evpn_es *es,
771 struct attr *attr)
185fb14a 772{
c44ab6f1
AK
773 struct ecommunity ecom_encap;
774 struct ecommunity ecom_esi_label;
775 struct ecommunity_val eval;
776 struct ecommunity_val eval_esi_label;
777 bgp_encap_types tnl_type;
778 struct listnode *evi_node, *rt_node;
779 struct ecommunity *ecom;
780 struct bgp_evpn_es_evi *es_evi;
185fb14a 781
c44ab6f1
AK
782 /* Encap */
783 tnl_type = BGP_ENCAP_TYPE_VXLAN;
784 memset(&ecom_encap, 0, sizeof(ecom_encap));
785 encode_encap_extcomm(tnl_type, &eval);
786 ecom_encap.size = 1;
34540b0d 787 ecom_encap.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
788 ecom_encap.val = (uint8_t *)eval.val;
789 attr->ecommunity = ecommunity_dup(&ecom_encap);
185fb14a 790
c44ab6f1
AK
791 /* ESI label */
792 encode_esi_label_extcomm(&eval_esi_label,
793 false /*single_active*/);
794 ecom_esi_label.size = 1;
34540b0d 795 ecom_esi_label.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
796 ecom_esi_label.val = (uint8_t *)eval_esi_label.val;
797 attr->ecommunity =
798 ecommunity_merge(attr->ecommunity, &ecom_esi_label);
799
800 /* Add export RTs for all L2-VNIs associated with this ES */
801 /* XXX - suppress EAD-ES advertisment if there are no EVIs associated
802 * with it.
803 */
804 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
805 evi_node, es_evi)) {
806 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
807 continue;
808 for (ALL_LIST_ELEMENTS_RO(es_evi->vpn->export_rtl,
809 rt_node, ecom))
810 attr->ecommunity = ecommunity_merge(attr->ecommunity,
811 ecom);
812 }
813
814 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
815}
816
817/* Extended communities associated with EAD-per-EVI */
818static void bgp_evpn_type1_evi_route_extcomm_build(struct bgp_evpn_es *es,
819 struct bgpevpn *vpn, struct attr *attr)
820{
821 struct ecommunity ecom_encap;
822 struct ecommunity_val eval;
823 bgp_encap_types tnl_type;
824 struct listnode *rt_node;
825 struct ecommunity *ecom;
826
827 /* Encap */
828 tnl_type = BGP_ENCAP_TYPE_VXLAN;
829 memset(&ecom_encap, 0, sizeof(ecom_encap));
830 encode_encap_extcomm(tnl_type, &eval);
831 ecom_encap.size = 1;
7659ad68 832 ecom_encap.unit_size = ECOMMUNITY_SIZE;
c44ab6f1
AK
833 ecom_encap.val = (uint8_t *)eval.val;
834 attr->ecommunity = ecommunity_dup(&ecom_encap);
835
836 /* Add export RTs for the L2-VNI */
837 for (ALL_LIST_ELEMENTS_RO(vpn->export_rtl, rt_node, ecom))
838 attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
839
840 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
841}
842
843/* Update EVPN EAD (type-1) route -
844 * vpn - valid for EAD-EVI routes and NULL for EAD-ES routes
845 */
846static int bgp_evpn_type1_route_update(struct bgp *bgp,
847 struct bgp_evpn_es *es, struct bgpevpn *vpn,
848 struct prefix_evpn *p)
849{
850 int ret = 0;
851 afi_t afi = AFI_L2VPN;
852 safi_t safi = SAFI_EVPN;
853 struct attr attr;
854 struct attr *attr_new = NULL;
09319b4e 855 struct bgp_dest *dest = NULL;
c44ab6f1
AK
856 struct bgp_path_info *pi = NULL;
857 int route_changed = 0;
858 struct prefix_rd *global_rd;
859
860 memset(&attr, 0, sizeof(struct attr));
861
862 /* Build path-attribute for this route. */
863 bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
864 attr.nexthop = es->originator_ip;
865 attr.mp_nexthop_global_in = es->originator_ip;
866 attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
867
868 if (vpn) {
869 /* EAD-EVI route update */
870 /* MPLS label */
871 vni2label(vpn->vni, &(attr.label));
872
873 /* Set up extended community */
874 bgp_evpn_type1_evi_route_extcomm_build(es, vpn, &attr);
875
876 /* First, create (or fetch) route node within the VNI. */
09319b4e 877 dest = bgp_node_get(vpn->route_table, (struct prefix *)p);
c44ab6f1
AK
878
879 /* Create or update route entry. */
09319b4e
DS
880 ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
881 &attr, 1, &pi, &route_changed);
c44ab6f1 882 if (ret != 0) {
23d0a753
DA
883 flog_err(
884 EC_BGP_ES_INVALID,
885 "%u Failed to update EAD-EVI route ESI: %s VNI %u VTEP %pI4",
886 bgp->vrf_id, es->esi_str, vpn->vni,
887 &es->originator_ip);
c44ab6f1
AK
888 }
889 global_rd = &vpn->prd;
890 } else {
891 /* EAD-ES route update */
892 /* MPLS label is 0 for EAD-ES route */
893
894 /* Set up extended community */
895 bgp_evpn_type1_es_route_extcomm_build(es, &attr);
896
897 /* First, create (or fetch) route node within the ES. */
898 /* NOTE: There is no RD here. */
899 /* XXX: fragment ID must be included as a part of the prefix. */
09319b4e 900 dest = bgp_node_get(es->route_table, (struct prefix *)p);
c44ab6f1
AK
901
902 /* Create or update route entry. */
09319b4e
DS
903 ret = bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
904 &attr, 1, &pi, &route_changed);
c44ab6f1 905 if (ret != 0) {
23d0a753
DA
906 flog_err(
907 EC_BGP_ES_INVALID,
908 "%u ERROR: Failed to updated EAD-EVI route ESI: %s VTEP %pI4",
909 bgp->vrf_id, es->esi_str, &es->originator_ip);
c44ab6f1
AK
910 }
911 global_rd = &es->prd;
912 }
913
914
915 assert(pi);
916 attr_new = pi->attr;
917
918 /* Perform route selection;
919 * this is just to set the flags correctly as local route in
920 * the ES always wins.
921 */
09319b4e
DS
922 evpn_route_select_install(bgp, vpn, dest);
923 bgp_dest_unlock_node(dest);
c44ab6f1
AK
924
925 /* If this is a new route or some attribute has changed, export the
926 * route to the global table. The route will be advertised to peers
927 * from there. Note that this table is a 2-level tree (RD-level +
928 * Prefix-level) similar to L3VPN routes.
929 */
930 if (route_changed) {
931 struct bgp_path_info *global_pi;
932
09319b4e
DS
933 dest = bgp_global_evpn_node_get(bgp->rib[afi][safi], afi, safi,
934 p, global_rd);
935 bgp_evpn_mh_route_update(bgp, es, vpn, afi, safi, dest,
936 attr_new, 1, &global_pi,
937 &route_changed);
c44ab6f1
AK
938
939 /* Schedule for processing and unlock node. */
09319b4e
DS
940 bgp_process(bgp, dest, afi, safi);
941 bgp_dest_unlock_node(dest);
c44ab6f1
AK
942 }
943
944 /* Unintern temporary. */
945 aspath_unintern(&attr.aspath);
946 return 0;
947}
948
949/* Delete local Type-1 route */
950static int bgp_evpn_type1_es_route_delete(struct bgp *bgp,
951 struct bgp_evpn_es *es, struct prefix_evpn *p)
952{
953 return bgp_evpn_mh_route_delete(bgp, es, NULL /* l2vni */, p);
954}
955
956static int bgp_evpn_type1_evi_route_delete(struct bgp *bgp,
957 struct bgp_evpn_es *es, struct bgpevpn *vpn,
958 struct prefix_evpn *p)
959{
960 return bgp_evpn_mh_route_delete(bgp, es, vpn, p);
961}
962
963/* Generate EAD-EVI for all VNIs */
964static void bgp_evpn_local_type1_evi_route_add(struct bgp *bgp,
965 struct bgp_evpn_es *es)
966{
967 struct listnode *evi_node;
968 struct prefix_evpn p;
969 struct bgp_evpn_es_evi *es_evi;
970
971 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
972 /* EAD-EVI route add for this ES is already done */
973 return;
974
975 SET_FLAG(es->flags, BGP_EVPNES_ADV_EVI);
976 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
977 &es->esi, es->originator_ip);
978
979 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, evi_node, es_evi)) {
980 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
981 continue;
982 if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn, &p))
983 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
984 "%u: Type4 route creation failure for ESI %s",
985 bgp->vrf_id, es->esi_str);
986 }
987}
988
989/*
990 * Withdraw EAD-EVI for all VNIs
991 */
992static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp,
993 struct bgp_evpn_es *es)
994{
995 struct listnode *evi_node;
996 struct prefix_evpn p;
997 struct bgp_evpn_es_evi *es_evi;
998
999 /* Delete and withdraw locally learnt EAD-EVI route */
1000 if (!CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI))
1001 /* EAD-EVI route has not been advertised for this ES */
1002 return;
1003
1004 UNSET_FLAG(es->flags, BGP_EVPNES_ADV_EVI);
1005 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
1006 &es->esi, es->originator_ip);
1007 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, evi_node, es_evi)) {
1008 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
1009 continue;
1010 if (bgp_evpn_mh_route_delete(bgp, es, es_evi->vpn, &p))
1011 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1012 "%u: Type4 route creation failure for ESI %s",
1013 bgp->vrf_id, es->esi_str);
1014 }
1015}
185fb14a
AK
1016
1017/*
c44ab6f1 1018 * Process received EVPN type-1 route (advertise or withdraw).
185fb14a 1019 */
c44ab6f1
AK
1020int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
1021 struct attr *attr, uint8_t *pfx, int psize,
1022 uint32_t addpath_id)
185fb14a
AK
1023{
1024 int ret;
c44ab6f1 1025 struct prefix_rd prd;
185fb14a 1026 esi_t esi;
c44ab6f1
AK
1027 uint32_t eth_tag;
1028 mpls_label_t label;
185fb14a 1029 struct in_addr vtep_ip;
185fb14a
AK
1030 struct prefix_evpn p;
1031
c44ab6f1 1032 if (psize != BGP_EVPN_TYPE1_PSIZE) {
185fb14a 1033 flog_err(EC_BGP_EVPN_ROUTE_INVALID,
c44ab6f1
AK
1034 "%u:%s - Rx EVPN Type-1 NLRI with invalid length %d",
1035 peer->bgp->vrf_id, peer->host, psize);
185fb14a
AK
1036 return -1;
1037 }
1038
1039 /* Make prefix_rd */
1040 prd.family = AF_UNSPEC;
1041 prd.prefixlen = 64;
c44ab6f1
AK
1042 memcpy(&prd.val, pfx, RD_BYTES);
1043 pfx += RD_BYTES;
185fb14a
AK
1044
1045 /* get the ESI */
1046 memcpy(&esi, pfx, ESI_BYTES);
1047 pfx += ESI_BYTES;
1048
c44ab6f1
AK
1049 /* Copy Ethernet Tag */
1050 memcpy(&eth_tag, pfx, EVPN_ETH_TAG_BYTES);
1051 eth_tag = ntohl(eth_tag);
1052 pfx += EVPN_ETH_TAG_BYTES;
185fb14a 1053
c44ab6f1 1054 memcpy(&label, pfx, BGP_LABEL_BYTES);
185fb14a 1055
c44ab6f1
AK
1056 /* EAD route prefix doesn't include the nexthop in the global
1057 * table
1058 */
1059 vtep_ip.s_addr = 0;
1060 build_evpn_type1_prefix(&p, eth_tag, &esi, vtep_ip);
185fb14a
AK
1061 /* Process the route. */
1062 if (attr) {
1063 ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
c44ab6f1
AK
1064 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
1065 &prd, NULL, 0, 0, NULL);
185fb14a
AK
1066 } else {
1067 ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
c44ab6f1
AK
1068 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
1069 &prd, NULL, 0, NULL);
185fb14a
AK
1070 }
1071 return ret;
1072}
1073
c44ab6f1
AK
1074/*****************************************************************************/
1075/* Ethernet Segment Management
1076 * 1. Ethernet Segment is a collection of links attached to the same
1077 * server (MHD) or switch (MHN)
1078 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1079 * 10-byte ES-ID.
1080 * 3. Local ESs are configured in zebra and sent to BGP
1081 * 4. Remote ESs are created by BGP when one or more ES-EVIs reference it i.e.
1082 * created on first reference and release on last de-reference
1083 * 5. An ES can be both local and remote. Infact most local ESs are expected
1084 * to have an ES peer.
1085 */
1086
1087/* A list of remote VTEPs is maintained for each ES. This list includes -
1088 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1089 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1090 * have been imported into one or more VNIs
185fb14a 1091 */
c44ab6f1
AK
1092static int bgp_evpn_es_vtep_cmp(void *p1, void *p2)
1093{
1094 const struct bgp_evpn_es_vtep *es_vtep1 = p1;
1095 const struct bgp_evpn_es_vtep *es_vtep2 = p2;
1096
1097 return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
1098}
1099
1100static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_new(struct bgp_evpn_es *es,
1101 struct in_addr vtep_ip)
1102{
1103 struct bgp_evpn_es_vtep *es_vtep;
1104
1105 es_vtep = XCALLOC(MTYPE_BGP_EVPN_ES_VTEP, sizeof(*es_vtep));
1106
1107 es_vtep->es = es;
1108 es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
1109 listnode_init(&es_vtep->es_listnode, es_vtep);
1110 listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
1111
1112 return es_vtep;
1113}
1114
1115static void bgp_evpn_es_vtep_free(struct bgp_evpn_es_vtep *es_vtep)
1116{
1117 struct bgp_evpn_es *es = es_vtep->es;
1118
1119 if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR) ||
1120 es_vtep->evi_cnt)
1121 /* as long as there is some reference we can't free it */
1122 return;
1123
1124 list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
1125 XFREE(MTYPE_BGP_EVPN_ES_VTEP, es_vtep);
1126}
1127
1128/* check if VTEP is already part of the list */
1129static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_find(struct bgp_evpn_es *es,
1130 struct in_addr vtep_ip)
1131{
1132 struct listnode *node = NULL;
1133 struct bgp_evpn_es_vtep *es_vtep;
1134
1135 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1136 if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1137 return es_vtep;
1138 }
1139 return NULL;
1140}
1141
1142/* Send the remote ES to zebra for NHG programming */
1143static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp,
1144 struct bgp_evpn_es_vtep *es_vtep, bool add)
1145{
1146 struct bgp_evpn_es *es = es_vtep->es;
1147 struct stream *s;
1148
1149 /* Check socket. */
1150 if (!zclient || zclient->sock < 0)
1151 return 0;
1152
1153 /* Don't try to register if Zebra doesn't know of this instance. */
1154 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
1155 if (BGP_DEBUG(zebra, ZEBRA))
1156 zlog_debug("No zebra instance, not installing remote es %s",
1157 es->esi_str);
1158 return 0;
1159 }
1160
1161 s = zclient->obuf;
1162 stream_reset(s);
1163
1164 zclient_create_header(s,
1165 add ? ZEBRA_REMOTE_ES_VTEP_ADD : ZEBRA_REMOTE_ES_VTEP_DEL,
1166 bgp->vrf_id);
1167 stream_put(s, &es->esi, sizeof(esi_t));
1168 stream_put_ipv4(s, es_vtep->vtep_ip.s_addr);
1169
1170 stream_putw_at(s, 0, stream_get_endp(s));
1171
1172 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1173 zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add ? "ADD" : "DEL",
1174 es->esi_str, &es_vtep->vtep_ip);
c44ab6f1
AK
1175
1176 return zclient_send_message(zclient);
1177}
1178
1179static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp,
1180 struct bgp_evpn_es_vtep *es_vtep)
1181{
1182 bool old_active;
1183 bool new_active;
1184
1185 old_active = !!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1186 /* currently we need an active EVI reference to use the VTEP as
1187 * a nexthop. this may change...
1188 */
1189 if (es_vtep->evi_cnt)
1190 SET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1191 else
1192 UNSET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1193
1194 new_active = !!CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE);
1195
1196 if (old_active == new_active)
1197 return;
1198
1199 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1200 zlog_debug("es %s vtep %pI4 %s", es_vtep->es->esi_str,
1201 &es_vtep->vtep_ip,
1202 new_active ? "active" : "inactive");
c44ab6f1
AK
1203
1204 /* send remote ES to zebra */
1205 bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active);
1206
1207 /* queue up the es for background consistency checks */
1208 bgp_evpn_es_cons_checks_pend_add(es_vtep->es);
1209}
1210
1211static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp,
1212 struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr)
1213{
1214 struct bgp_evpn_es_vtep *es_vtep;
1215
1216 es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip);
1217
1218 if (!es_vtep)
1219 es_vtep = bgp_evpn_es_vtep_new(es, vtep_ip);
1220
1221 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1222 zlog_debug("es %s vtep %pI4 add %s", es_vtep->es->esi_str,
1223 &es_vtep->vtep_ip, esr ? "esr" : "ead");
c44ab6f1
AK
1224
1225 if (esr)
1226 SET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR);
1227 else
1228 ++es_vtep->evi_cnt;
1229
1230 bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep);
1231
1232 return es_vtep;
1233}
1234
1235static void bgp_evpn_es_vtep_do_del(struct bgp *bgp,
1236 struct bgp_evpn_es_vtep *es_vtep, bool esr)
1237{
1238 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1239 zlog_debug("es %s vtep %pI4 del %s", es_vtep->es->esi_str,
1240 &es_vtep->vtep_ip, esr ? "esr" : "ead");
c44ab6f1
AK
1241 if (esr) {
1242 UNSET_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ESR);
1243 } else {
1244 if (es_vtep->evi_cnt)
1245 --es_vtep->evi_cnt;
1246 }
1247
1248 bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep);
1249 bgp_evpn_es_vtep_free(es_vtep);
1250}
1251
1252static void bgp_evpn_es_vtep_del(struct bgp *bgp,
1253 struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr)
1254{
1255 struct bgp_evpn_es_vtep *es_vtep;
1256
1257 es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip);
1258 if (es_vtep)
1259 bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr);
1260}
1261
1262/* compare ES-IDs for the global ES RB tree */
1263static int bgp_es_rb_cmp(const struct bgp_evpn_es *es1,
1264 const struct bgp_evpn_es *es2)
1265{
1266 return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
1267}
1268RB_GENERATE(bgp_es_rb_head, bgp_evpn_es, rb_node, bgp_es_rb_cmp);
1269
1270struct bgp_evpn_es *bgp_evpn_es_find(const esi_t *esi)
185fb14a 1271{
c44ab6f1 1272 struct bgp_evpn_es tmp;
185fb14a 1273
185fb14a 1274 memcpy(&tmp.esi, esi, sizeof(esi_t));
c44ab6f1 1275 return RB_FIND(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, &tmp);
185fb14a
AK
1276}
1277
c44ab6f1 1278static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi)
185fb14a 1279{
c44ab6f1 1280 struct bgp_evpn_es *es;
185fb14a
AK
1281
1282 if (!bgp)
1283 return NULL;
1284
c44ab6f1 1285 es = XCALLOC(MTYPE_BGP_EVPN_ES, sizeof(struct bgp_evpn_es));
185fb14a 1286
c44ab6f1 1287 /* set the ESI */
185fb14a 1288 memcpy(&es->esi, esi, sizeof(esi_t));
185fb14a
AK
1289
1290 /* Initialise the VTEP list */
c44ab6f1
AK
1291 es->es_vtep_list = list_new();
1292 listset_app_node_mem(es->es_vtep_list);
1293 es->es_vtep_list->cmp = bgp_evpn_es_vtep_cmp;
185fb14a 1294
c44ab6f1 1295 esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
185fb14a 1296
c44ab6f1 1297 /* Initialize the ES routing table */
185fb14a
AK
1298 es->route_table = bgp_table_init(bgp, AFI_L2VPN, SAFI_EVPN);
1299
c44ab6f1
AK
1300 /* Add to rb_tree */
1301 if (RB_INSERT(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, es)) {
185fb14a
AK
1302 XFREE(MTYPE_BGP_EVPN_ES, es);
1303 return NULL;
1304 }
1305
c44ab6f1
AK
1306 /* Initialise the ES-EVI list */
1307 es->es_evi_list = list_new();
1308 listset_app_node_mem(es->es_evi_list);
1309
1310 QOBJ_REG(es, bgp_evpn_es);
1311
185fb14a
AK
1312 return es;
1313}
1314
c44ab6f1 1315/* Free a given ES -
185fb14a
AK
1316 * This just frees appropriate memory, caller should have taken other
1317 * needed actions.
1318 */
45a859f1 1319static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller)
185fb14a 1320{
c44ab6f1
AK
1321 if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE))
1322 return;
1323
45a859f1
AK
1324 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1325 zlog_debug("%s: es %s free", caller, es->esi_str);
1326
c44ab6f1
AK
1327 /* cleanup resources maintained against the ES */
1328 list_delete(&es->es_evi_list);
1329 list_delete(&es->es_vtep_list);
185fb14a 1330 bgp_table_unlock(es->route_table);
c44ab6f1
AK
1331
1332 /* remove the entry from various databases */
1333 RB_REMOVE(bgp_es_rb_head, &bgp_mh_info->es_rb_tree, es);
1334 bgp_evpn_es_cons_checks_pend_del(es);
1335
185fb14a
AK
1336 QOBJ_UNREG(es);
1337 XFREE(MTYPE_BGP_EVPN_ES, es);
1338}
1339
c44ab6f1
AK
1340/* init local info associated with the ES */
1341static void bgp_evpn_es_local_info_set(struct bgp *bgp, struct bgp_evpn_es *es)
185fb14a 1342{
c44ab6f1 1343 char buf[BGP_EVPN_PREFIX_RD_LEN];
185fb14a 1344
c44ab6f1
AK
1345 if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1346 return;
185fb14a 1347
c44ab6f1
AK
1348 SET_FLAG(es->flags, BGP_EVPNES_LOCAL);
1349 listnode_init(&es->es_listnode, es);
1350 listnode_add(bgp_mh_info->local_es_list, &es->es_listnode);
185fb14a 1351
c44ab6f1
AK
1352 /* auto derive RD for this es */
1353 bf_assign_index(bm->rd_idspace, es->rd_id);
1354 es->prd.family = AF_UNSPEC;
1355 es->prd.prefixlen = 64;
23d0a753 1356 snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, es->rd_id);
c44ab6f1
AK
1357 (void)str2prefix_rd(buf, &es->prd);
1358}
1359
1360/* clear any local info associated with the ES */
1361static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es *es)
1362{
1363 if (!CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1364 return;
185fb14a 1365
c44ab6f1 1366 UNSET_FLAG(es->flags, BGP_EVPNES_LOCAL);
185fb14a 1367
c44ab6f1
AK
1368 /* remove from the ES local list */
1369 list_delete_node(bgp_mh_info->local_es_list, &es->es_listnode);
1370
1371 bf_release_index(bm->rd_idspace, es->rd_id);
1372
45a859f1 1373 bgp_evpn_es_free(es, __func__);
185fb14a
AK
1374}
1375
c44ab6f1
AK
1376/* eval remote info associated with the ES */
1377static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es *es)
1378{
1379 if (es->remote_es_evi_cnt) {
1380 SET_FLAG(es->flags, BGP_EVPNES_REMOTE);
1381 } else {
1382 if (CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE)) {
1383 UNSET_FLAG(es->flags, BGP_EVPNES_REMOTE);
45a859f1 1384 bgp_evpn_es_free(es, __func__);
c44ab6f1
AK
1385 }
1386 }
1387}
1388
1389/* Process ES link oper-down by withdrawing ES-EAD and ESR */
1390static void bgp_evpn_local_es_down(struct bgp *bgp,
1391 struct bgp_evpn_es *es)
185fb14a 1392{
185fb14a 1393 struct prefix_evpn p;
c44ab6f1 1394 int ret;
185fb14a 1395
c44ab6f1
AK
1396 if (!CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP))
1397 return;
185fb14a 1398
c44ab6f1 1399 UNSET_FLAG(es->flags, BGP_EVPNES_OPER_UP);
185fb14a 1400
c44ab6f1
AK
1401 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1402 zlog_debug("local es %s down", es->esi_str);
1403
1404 /* withdraw ESR */
1405 /* Delete and withdraw locally learnt ES route */
1406 build_evpn_type4_prefix(&p, &es->esi, es->originator_ip);
1407 ret = bgp_evpn_type4_route_delete(bgp, es, &p);
1408 if (ret) {
1409 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
1410 "%u failed to delete type-4 route for ESI %s",
1411 bgp->vrf_id, es->esi_str);
185fb14a
AK
1412 }
1413
c44ab6f1
AK
1414 /* withdraw EAD-EVI */
1415 if (!bgp_mh_info->ead_evi_adv_for_down_links)
1416 bgp_evpn_local_type1_evi_route_del(bgp, es);
185fb14a 1417
c44ab6f1
AK
1418 /* withdraw EAD-ES */
1419 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
1420 &es->esi, es->originator_ip);
1421 ret = bgp_evpn_type1_es_route_delete(bgp, es, &p);
1422 if (ret) {
1423 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
1424 "%u failed to delete type-1 route for ESI %s",
1425 bgp->vrf_id, es->esi_str);
1426 }
1427}
1428
1429/* Process ES link oper-up by generating ES-EAD and ESR */
1430static void bgp_evpn_local_es_up(struct bgp *bgp, struct bgp_evpn_es *es)
1431{
1432 struct prefix_evpn p;
1433
1434 if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP))
1435 return;
1436
1437 SET_FLAG(es->flags, BGP_EVPNES_OPER_UP);
1438
1439 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1440 zlog_debug("local es %s up", es->esi_str);
1441
1442 /* generate ESR */
1443 build_evpn_type4_prefix(&p, &es->esi, es->originator_ip);
1444 if (bgp_evpn_type4_route_update(bgp, es, &p))
1445 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
1446 "%u: Type4 route creation failure for ESI %s",
1447 bgp->vrf_id, es->esi_str);
1448
1449 /* generate EAD-EVI */
1450 bgp_evpn_local_type1_evi_route_add(bgp, es);
1451
1452 /* generate EAD-ES */
1453 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
1454 &es->esi, es->originator_ip);
1455 bgp_evpn_type1_route_update(bgp, es, NULL, &p);
1456}
1457
1458static void bgp_evpn_local_es_do_del(struct bgp *bgp, struct bgp_evpn_es *es)
1459{
1460 struct bgp_evpn_es_evi *es_evi;
1461 struct listnode *evi_node, *evi_next_node;
1462
1463 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1464 zlog_debug("del local es %s", es->esi_str);
1465
1466 /* Delete all local EVPN ES routes from ESI table
1467 * and schedule for processing (to withdraw from peers))
1468 */
1469 bgp_evpn_es_route_del_all(bgp, es);
1470
1471 /* release all local ES EVIs associated with the ES */
1472 for (ALL_LIST_ELEMENTS(es->es_evi_list, evi_node,
1473 evi_next_node, es_evi)) {
1474 bgp_evpn_local_es_evi_do_del(es_evi);
1475 }
1476
1477 /* Clear local info associated with the ES and free it up if there is
1478 * no remote reference
1479 */
1480 bgp_evpn_es_local_info_clear(es);
1481}
1482
7904e9fd
AK
1483bool bgp_evpn_is_esi_local(esi_t *esi)
1484{
1485 struct bgp_evpn_es *es = NULL;
1486
1487 /* Lookup ESI hash - should exist. */
1488 es = bgp_evpn_es_find(esi);
1489 return es ? !!(es->flags & BGP_EVPNES_LOCAL) : false;
1490}
1491
c44ab6f1
AK
1492int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi)
1493{
1494 struct bgp_evpn_es *es = NULL;
1495
1496 /* Lookup ESI hash - should exist. */
1497 es = bgp_evpn_es_find(esi);
1498 if (!es) {
1499 flog_warn(EC_BGP_EVPN_ESI,
1500 "%u: ES %s missing at local ES DEL",
1501 bgp->vrf_id, es->esi_str);
1502 return -1;
1503 }
1504
1505 bgp_evpn_local_es_do_del(bgp, es);
1506 return 0;
1507}
1508
1509/* Handle device to ES id association. Results in the creation of a local
1510 * ES.
1511 */
1512int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi,
1513 struct in_addr originator_ip, bool oper_up)
1514{
1515 char buf[ESI_STR_LEN];
1516 struct bgp_evpn_es *es;
1517 bool new_es = true;
1518
1519 /* create the new es */
1520 es = bgp_evpn_es_find(esi);
1521 if (es) {
1522 if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL))
1523 new_es = false;
1524 } else {
1525 es = bgp_evpn_es_new(bgp, esi);
1526 if (!es) {
1527 flog_err(EC_BGP_ES_CREATE,
1528 "%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
1529 bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
1530 return -1;
1531 }
1532 }
1533
1534 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1535 zlog_debug("add local es %s orig-ip %pI4", es->esi_str,
1536 &originator_ip);
c44ab6f1
AK
1537
1538 es->originator_ip = originator_ip;
1539 bgp_evpn_es_local_info_set(bgp, es);
1540
1541 /* import all remote Type-4 routes in the ES table */
1542 if (new_es)
1543 bgp_evpn_type4_remote_routes_import(bgp, es,
1544 true /* install */);
1545
1546 /* create and advertise EAD-EVI routes for the ES -
1547 * XXX - till an ES-EVI reference is created there is really nothing to
1548 * advertise
1549 */
1550 if (bgp_mh_info->ead_evi_adv_for_down_links)
1551 bgp_evpn_local_type1_evi_route_add(bgp, es);
1552
1553 /* If the ES link is operationally up generate EAD-ES. EAD-EVI
1554 * can be generated even if the link is inactive.
1555 */
1556 if (oper_up)
1557 bgp_evpn_local_es_up(bgp, es);
1558 else
1559 bgp_evpn_local_es_down(bgp, es);
1560
1561 return 0;
1562}
1563
9e0c2fd1
AK
1564static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es,
1565 uint8_t vtep_str_size)
c44ab6f1
AK
1566{
1567 char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
1568 struct listnode *node;
1569 struct bgp_evpn_es_vtep *es_vtep;
1570 bool first = true;
23d0a753 1571 char vtep_ip[BUFSIZ] = {0};
c44ab6f1
AK
1572
1573 vtep_str[0] = '\0';
1574 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1575 vtep_flag_str[0] = '\0';
23d0a753 1576
c44ab6f1 1577 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
9e0c2fd1 1578 strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
c44ab6f1 1579 if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
9e0c2fd1 1580 strlcat(vtep_flag_str, "A", sizeof(vtep_flag_str));
c44ab6f1
AK
1581
1582 if (!strlen(vtep_flag_str))
9e0c2fd1
AK
1583 strlcat(vtep_flag_str, "-", sizeof(vtep_flag_str));
1584 if (first)
c44ab6f1 1585 first = false;
9e0c2fd1
AK
1586 else
1587 strlcat(vtep_str, ",", vtep_str_size);
23d0a753
DA
1588
1589 strlcat(vtep_str,
1590 inet_ntop(AF_INET, &es_vtep->vtep_ip, vtep_ip,
1591 sizeof(vtep_ip)),
1592 vtep_str_size);
9e0c2fd1
AK
1593 strlcat(vtep_str, "(", vtep_str_size);
1594 strlcat(vtep_str, vtep_flag_str, vtep_str_size);
1595 strlcat(vtep_str, ")", vtep_str_size);
c44ab6f1
AK
1596 }
1597
1598 return vtep_str;
1599}
1600
1601static inline void json_array_string_add(json_object *json, const char *str)
1602{
1603 json_object_array_add(json, json_object_new_string(str));
1604}
1605
1606static void bgp_evpn_es_json_vtep_fill(json_object *json_vteps,
1607 struct bgp_evpn_es_vtep *es_vtep)
1608{
1609 json_object *json_vtep_entry;
1610 json_object *json_flags;
23d0a753 1611 char vtep_ip[BUFSIZ] = {0};
c44ab6f1
AK
1612
1613 json_vtep_entry = json_object_new_object();
1614
1615 json_object_string_add(json_vtep_entry, "vtep_ip",
23d0a753
DA
1616 inet_ntop(AF_INET, &es_vtep->vtep_ip, vtep_ip,
1617 sizeof(vtep_ip)));
1618
c44ab6f1
AK
1619 if (es_vtep->flags & (BGP_EVPNES_VTEP_ESR |
1620 BGP_EVPNES_VTEP_ACTIVE)) {
1621 json_flags = json_object_new_array();
1622 if (es_vtep->flags & BGP_EVPNES_VTEP_ESR)
1623 json_array_string_add(json_flags, "esr");
1624 if (es_vtep->flags & BGP_EVPNES_VTEP_ACTIVE)
1625 json_array_string_add(json_flags, "active");
1626 json_object_object_add(json_vtep_entry, "flags", json_flags);
1627 }
1628
1629 json_object_array_add(json_vteps,
1630 json_vtep_entry);
1631}
1632
1633static void bgp_evpn_es_show_entry(struct vty *vty,
1634 struct bgp_evpn_es *es, json_object *json)
1635{
1636 char buf1[RD_ADDRSTRLEN];
1637 struct listnode *node;
1638 struct bgp_evpn_es_vtep *es_vtep;
1639
1640 if (json) {
1641 json_object *json_vteps;
1642 json_object *json_types;
1643
1644 json_object_string_add(json, "esi", es->esi_str);
1645 json_object_string_add(json, "rd",
1646 prefix_rd2str(&es->prd, buf1,
1647 sizeof(buf1)));
1648
1649 if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) {
1650 json_types = json_object_new_array();
1651 if (es->flags & BGP_EVPNES_LOCAL)
1652 json_array_string_add(json_types, "local");
1653 if (es->flags & BGP_EVPNES_REMOTE)
1654 json_array_string_add(json_types, "remote");
1655 json_object_object_add(json, "type", json_types);
1656 }
1657
1658 if (listcount(es->es_vtep_list)) {
1659 json_vteps = json_object_new_array();
1660 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list,
1661 node, es_vtep)) {
1662 bgp_evpn_es_json_vtep_fill(json_vteps, es_vtep);
1663 }
1664 json_object_object_add(json, "vteps", json_vteps);
1665 }
1666 json_object_int_add(json, "vniCount",
1667 listcount(es->es_evi_list));
1668 } else {
1669 char type_str[4];
1670 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
1671
1672 type_str[0] = '\0';
1673 if (es->flags & BGP_EVPNES_LOCAL)
9e0c2fd1 1674 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 1675 if (es->flags & BGP_EVPNES_REMOTE)
9e0c2fd1 1676 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 1677 if (es->inconsistencies)
9e0c2fd1 1678 strlcat(type_str, "I", sizeof(type_str));
c44ab6f1 1679
9e0c2fd1 1680 bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
c44ab6f1
AK
1681
1682 if (es->flags & BGP_EVPNES_LOCAL)
1683 prefix_rd2str(&es->prd, buf1, sizeof(buf1));
1684 else
9e0c2fd1 1685 strlcpy(buf1, "-", sizeof(buf1));
c44ab6f1
AK
1686
1687 vty_out(vty, "%-30s %-5s %-21s %-8d %s\n",
1688 es->esi_str, type_str, buf1,
1689 listcount(es->es_evi_list), vtep_str);
1690 }
1691}
1692
1693static void bgp_evpn_es_show_entry_detail(struct vty *vty,
1694 struct bgp_evpn_es *es, json_object *json)
1695{
23d0a753
DA
1696 char originator_ip[BUFSIZ] = {0};
1697
c44ab6f1
AK
1698 if (json) {
1699 json_object *json_flags;
1700 json_object *json_incons;
1701
1702 /* Add the "brief" info first */
1703 bgp_evpn_es_show_entry(vty, es, json);
1704 if (es->flags & (BGP_EVPNES_OPER_UP | BGP_EVPNES_ADV_EVI)) {
1705 json_flags = json_object_new_array();
1706 if (es->flags & BGP_EVPNES_OPER_UP)
1707 json_array_string_add(json_flags, "up");
1708 if (es->flags & BGP_EVPNES_ADV_EVI)
1709 json_array_string_add(json_flags,
1710 "advertiseEVI");
1711 json_object_object_add(json, "flags", json_flags);
1712 }
1713 json_object_string_add(json, "originator_ip",
23d0a753
DA
1714 inet_ntop(AF_INET, &es->originator_ip,
1715 originator_ip,
1716 sizeof(originator_ip)));
c44ab6f1
AK
1717 json_object_int_add(json, "remoteVniCount",
1718 es->remote_es_evi_cnt);
1719 json_object_int_add(json, "inconsistentVniVtepCount",
1720 es->incons_evi_vtep_cnt);
1721 if (es->inconsistencies) {
1722 json_incons = json_object_new_array();
1723 if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
1724 json_array_string_add(json_incons,
1725 "vni-vtep-mismatch");
1726 json_object_object_add(json, "inconsistencies",
1727 json_incons);
1728 }
1729 } else {
1730 char incons_str[BGP_EVPNES_INCONS_STR_SZ];
1731 char type_str[4];
1732 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
1733 char buf1[RD_ADDRSTRLEN];
1734
1735 type_str[0] = '\0';
1736 if (es->flags & BGP_EVPNES_LOCAL)
9e0c2fd1 1737 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 1738 if (es->flags & BGP_EVPNES_REMOTE)
9e0c2fd1 1739 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 1740
9e0c2fd1 1741 bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
c44ab6f1 1742 if (!strlen(vtep_str))
9e0c2fd1 1743 strlcpy(buf1, "-", sizeof(buf1));
c44ab6f1
AK
1744
1745 if (es->flags & BGP_EVPNES_LOCAL)
1746 prefix_rd2str(&es->prd, buf1, sizeof(buf1));
1747 else
9e0c2fd1 1748 strlcpy(buf1, "-", sizeof(buf1));
c44ab6f1
AK
1749
1750 vty_out(vty, "ESI: %s\n", es->esi_str);
1751 vty_out(vty, " Type: %s\n", type_str);
1752 vty_out(vty, " RD: %s\n", buf1);
23d0a753 1753 vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip);
c44ab6f1
AK
1754 vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
1755 vty_out(vty, " Remote VNI Count: %d\n",
1756 es->remote_es_evi_cnt);
1757 vty_out(vty, " Inconsistent VNI VTEP Count: %d\n",
1758 es->incons_evi_vtep_cnt);
1759 if (es->inconsistencies) {
1760 incons_str[0] = '\0';
1761 if (es->inconsistencies & BGP_EVPNES_INCONS_VTEP_LIST)
9e0c2fd1
AK
1762 strlcat(incons_str, "vni-vtep-mismatch",
1763 sizeof(incons_str));
c44ab6f1 1764 } else {
9e0c2fd1 1765 strlcpy(incons_str, "-", sizeof(incons_str));
c44ab6f1
AK
1766 }
1767 vty_out(vty, " Inconsistencies: %s\n",
1768 incons_str);
1769 vty_out(vty, " VTEPs: %s\n", vtep_str);
1770 vty_out(vty, "\n");
1771 }
1772}
1773
1774/* Display all ESs */
1775void bgp_evpn_es_show(struct vty *vty, bool uj, bool detail)
1776{
1777 struct bgp_evpn_es *es;
9c7edc03 1778 json_object *json_array = NULL;
c44ab6f1
AK
1779 json_object *json = NULL;
1780
1781 if (uj) {
1782 /* create an array of ESs */
1783 json_array = json_object_new_array();
1784 } else {
1785 if (!detail) {
1786 vty_out(vty,
1787 "ES Flags: L local, R remote, I inconsistent\n");
1788 vty_out(vty,
1789 "VTEP Flags: E ESR/Type-4, A active nexthop\n");
1790 vty_out(vty,
1791 "%-30s %-5s %-21s %-8s %s\n",
1792 "ESI", "Flags", "RD", "#VNIs", "VTEPs");
1793 }
1794 }
1795
1796 RB_FOREACH(es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
1797 if (uj)
1798 /* create a separate json object for each ES */
1799 json = json_object_new_object();
1800 if (detail)
1801 bgp_evpn_es_show_entry_detail(vty, es, json);
1802 else
1803 bgp_evpn_es_show_entry(vty, es, json);
1804 /* add ES to the json array */
1805 if (uj)
1806 json_object_array_add(json_array, json);
1807 }
1808
1809 /* print the array of json-ESs */
1810 if (uj) {
1811 vty_out(vty, "%s\n", json_object_to_json_string_ext(
1812 json_array, JSON_C_TO_STRING_PRETTY));
1813 json_object_free(json_array);
1814 }
1815}
1816
1817/* Display specific ES */
1818void bgp_evpn_es_show_esi(struct vty *vty, esi_t *esi, bool uj)
1819{
1820 struct bgp_evpn_es *es;
1821 json_object *json = NULL;
1822
1823 if (uj)
1824 json = json_object_new_object();
1825
1826 es = bgp_evpn_es_find(esi);
1827 if (es) {
1828 bgp_evpn_es_show_entry_detail(vty, es, json);
1829 } else {
1830 if (!uj)
1831 vty_out(vty, "ESI not found\n");
1832 }
1833
1834 if (uj) {
1835 vty_out(vty, "%s\n", json_object_to_json_string_ext(
1836 json, JSON_C_TO_STRING_PRETTY));
1837 json_object_free(json);
1838 }
1839}
1840
1841/*****************************************************************************/
1842/* Ethernet Segment to EVI association -
1843 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
1844 * (bgpevpn->es_evi_rb_tree).
1845 * 2. Each local ES-EVI entry is rxed from zebra and then used by BGP to
1846 * advertises an EAD-EVI (Type-1 EVPN) route
1847 * 3. The remote ES-EVI is created when a bgp_evpn_es_evi_vtep references
1848 * it.
1849 */
1850
1851/* A list of remote VTEPs is maintained for each ES-EVI. This list includes -
1852 * 1. VTEPs for which we have imported the EAD-per-ES Type1 route
1853 * 2. VTEPs for which we have imported the EAD-per-EVI Type1 route
1854 * VTEPs for which both routes have been rxed are activated. Activation
1855 * creates a NHG in the parent ES.
1856 */
1857static int bgp_evpn_es_evi_vtep_cmp(void *p1, void *p2)
1858{
1859 const struct bgp_evpn_es_evi_vtep *evi_vtep1 = p1;
1860 const struct bgp_evpn_es_evi_vtep *evi_vtep2 = p2;
1861
1862 return evi_vtep1->vtep_ip.s_addr - evi_vtep2->vtep_ip.s_addr;
1863}
1864
1865static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_new(
1866 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip)
1867{
1868 struct bgp_evpn_es_evi_vtep *evi_vtep;
1869
1870 evi_vtep = XCALLOC(MTYPE_BGP_EVPN_ES_EVI_VTEP, sizeof(*evi_vtep));
1871
1872 evi_vtep->es_evi = es_evi;
1873 evi_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
1874 listnode_init(&evi_vtep->es_evi_listnode, evi_vtep);
1875 listnode_add_sort(es_evi->es_evi_vtep_list, &evi_vtep->es_evi_listnode);
1876
1877 return evi_vtep;
1878}
1879
1880static void bgp_evpn_es_evi_vtep_free(struct bgp_evpn_es_evi_vtep *evi_vtep)
1881{
1882 struct bgp_evpn_es_evi *es_evi = evi_vtep->es_evi;
1883
1884 if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD))
1885 /* as long as there is some reference we can't free it */
1886 return;
1887
1888 list_delete_node(es_evi->es_evi_vtep_list, &evi_vtep->es_evi_listnode);
1889 XFREE(MTYPE_BGP_EVPN_ES_EVI_VTEP, evi_vtep);
1890}
1891
1892/* check if VTEP is already part of the list */
1893static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_find(
1894 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip)
1895{
1896 struct listnode *node = NULL;
1897 struct bgp_evpn_es_evi_vtep *evi_vtep;
1898
1899 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
1900 if (evi_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1901 return evi_vtep;
1902 }
1903 return NULL;
1904}
1905
1906/* A VTEP can be added as "active" attach to an ES if EAD-per-ES and
1907 * EAD-per-EVI routes are rxed from it.
1908 */
1909static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp,
1910 struct bgp_evpn_es_evi_vtep *evi_vtep)
1911{
1912 bool old_active;
1913 bool new_active;
1914
1915 old_active = !!CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
1916
1917 /* Both EAD-per-ES and EAD-per-EVI routes must be rxed from a PE
1918 * before it can be activated.
1919 */
1920 if ((evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD) ==
1921 BGP_EVPN_EVI_VTEP_EAD)
1922 SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
1923 else
1924 UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
1925
1926 new_active = !!CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE);
1927
1928 if (old_active == new_active)
1929 return;
1930
1931 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1932 zlog_debug("es %s evi %u vtep %pI4 %s",
1933 evi_vtep->es_evi->es->esi_str,
1934 evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip,
1935 new_active ? "active" : "inactive");
c44ab6f1
AK
1936
1937 /* add VTEP to parent es */
1938 if (new_active) {
1939 struct bgp_evpn_es_vtep *es_vtep;
1940
1941 es_vtep = bgp_evpn_es_vtep_add(bgp, evi_vtep->es_evi->es,
1942 evi_vtep->vtep_ip, false /*esr*/);
1943 evi_vtep->es_vtep = es_vtep;
1944 } else {
1945 if (evi_vtep->es_vtep) {
1946 bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep,
1947 false /*esr*/);
1948 evi_vtep->es_vtep = NULL;
1949 }
1950 }
1951 /* queue up the parent es for background consistency checks */
1952 bgp_evpn_es_cons_checks_pend_add(evi_vtep->es_evi->es);
1953}
1954
1955static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp,
1956 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
1957 bool ead_es)
1958{
1959 struct bgp_evpn_es_evi_vtep *evi_vtep;
1960
1961 evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip);
1962
1963 if (!evi_vtep)
1964 evi_vtep = bgp_evpn_es_evi_vtep_new(es_evi, vtep_ip);
1965
1966 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1967 zlog_debug("add es %s evi %u vtep %pI4 %s",
1968 evi_vtep->es_evi->es->esi_str,
1969 evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip,
1970 ead_es ? "ead_es" : "ead_evi");
c44ab6f1
AK
1971
1972 if (ead_es)
1973 SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES);
1974 else
1975 SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
1976
1977 bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
1978}
1979
1980static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp,
1981 struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip,
1982 bool ead_es)
1983{
1984 struct bgp_evpn_es_evi_vtep *evi_vtep;
1985
1986 evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip);
1987 if (!evi_vtep)
1988 return;
1989
1990 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
1991 zlog_debug("del es %s evi %u vtep %pI4 %s",
1992 evi_vtep->es_evi->es->esi_str,
1993 evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip,
1994 ead_es ? "ead_es" : "ead_evi");
c44ab6f1
AK
1995
1996 if (ead_es)
1997 UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES);
1998 else
1999 UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI);
2000
2001 bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep);
2002 bgp_evpn_es_evi_vtep_free(evi_vtep);
2003}
2004
2005/* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */
2006static int bgp_es_evi_rb_cmp(const struct bgp_evpn_es_evi *es_evi1,
2007 const struct bgp_evpn_es_evi *es_evi2)
2008{
2009 return memcmp(&es_evi1->es->esi, &es_evi2->es->esi, ESI_BYTES);
2010}
2011RB_GENERATE(bgp_es_evi_rb_head, bgp_evpn_es_evi, rb_node, bgp_es_evi_rb_cmp);
2012
2013/* find the ES-EVI in the per-L2-VNI RB tree */
2014static struct bgp_evpn_es_evi *bgp_evpn_es_evi_find(struct bgp_evpn_es *es,
2015 struct bgpevpn *vpn)
2016{
2017 struct bgp_evpn_es_evi es_evi;
2018
2019 es_evi.es = es;
2020
2021 return RB_FIND(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, &es_evi);
2022}
2023
2024/* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
2025 * tables.
2026 */
2027static struct bgp_evpn_es_evi *bgp_evpn_es_evi_new(struct bgp_evpn_es *es,
2028 struct bgpevpn *vpn)
2029{
2030 struct bgp_evpn_es_evi *es_evi;
2031
2032 es_evi = XCALLOC(MTYPE_BGP_EVPN_ES_EVI, sizeof(*es_evi));
2033
2034 es_evi->es = es;
2035 es_evi->vpn = vpn;
2036
2037 /* Initialise the VTEP list */
2038 es_evi->es_evi_vtep_list = list_new();
2039 listset_app_node_mem(es_evi->es_evi_vtep_list);
2040 es_evi->es_evi_vtep_list->cmp = bgp_evpn_es_evi_vtep_cmp;
2041
2042 /* insert into the VNI-ESI rb tree */
2043 if (RB_INSERT(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, es_evi)) {
2044 XFREE(MTYPE_BGP_EVPN_ES_EVI, es_evi);
2045 return NULL;
2046 }
2047
2048 /* add to the ES's VNI list */
2049 listnode_init(&es_evi->es_listnode, es_evi);
2050 listnode_add(es->es_evi_list, &es_evi->es_listnode);
2051
2052 return es_evi;
2053}
2054
2055/* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
2056 * up the memory.
2057 */
2058static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi)
2059{
2060 struct bgp_evpn_es *es = es_evi->es;
2061 struct bgpevpn *vpn = es_evi->vpn;
2062
2063 /* cannot free the element as long as there is a local or remote
2064 * reference
2065 */
2066 if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE))
2067 return;
2068
2069 /* remove from the ES's VNI list */
2070 list_delete_node(es->es_evi_list, &es_evi->es_listnode);
2071
2072 /* remove from the VNI-ESI rb tree */
2073 RB_REMOVE(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, es_evi);
2074
2075 /* free the VTEP list */
2076 list_delete(&es_evi->es_evi_vtep_list);
2077
2078 /* remove from the VNI-ESI rb tree */
2079 XFREE(MTYPE_BGP_EVPN_ES_EVI, es_evi);
2080}
2081
2082/* init local info associated with the ES-EVI */
2083static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi *es_evi)
2084{
2085 struct bgpevpn *vpn = es_evi->vpn;
2086
2087 if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2088 return;
2089
2090 SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
2091 listnode_init(&es_evi->l2vni_listnode, es_evi);
2092 listnode_add(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
2093}
2094
2095/* clear any local info associated with the ES-EVI */
2096static void bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi *es_evi)
2097{
2098 struct bgpevpn *vpn = es_evi->vpn;
2099
2100 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2101 return;
2102
2103 UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
2104 list_delete_node(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
2105
2106 bgp_evpn_es_evi_free(es_evi);
2107}
2108
2109/* eval remote info associated with the ES */
2110static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi *es_evi)
2111{
2112 struct bgp_evpn_es *es = es_evi->es;
2113
2114 /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2115 if (listcount(es_evi->es_evi_vtep_list)) {
2116 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) {
2117 SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE);
2118 ++es->remote_es_evi_cnt;
2119 /* set remote on the parent es */
2120 bgp_evpn_es_remote_info_re_eval(es);
2121 }
2122 } else {
2123 if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE)) {
2124 UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE);
2125 if (es->remote_es_evi_cnt)
2126 --es->remote_es_evi_cnt;
2127 bgp_evpn_es_evi_free(es_evi);
2128 /* check if "remote" can be cleared from the
2129 * parent es.
2130 */
2131 bgp_evpn_es_remote_info_re_eval(es);
2132 }
2133 }
2134}
2135
2136static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi)
2137{
2138 struct prefix_evpn p;
2139 struct bgp_evpn_es *es = es_evi->es;
2140 struct bgp *bgp;
2141
2142 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2143 return;
2144
2145 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2146 zlog_debug("del local es %s evi %u",
2147 es_evi->es->esi_str,
2148 es_evi->vpn->vni);
2149
2150 bgp = bgp_get_evpn();
2151
2152 if (bgp) {
2153 /* update EAD-ES with new list of VNIs */
2154 if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
2155 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
2156 &es->esi, es->originator_ip);
2157 if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
2158 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
2159 "%u: EAD-ES route update failure for ESI %s VNI %u",
2160 bgp->vrf_id, es->esi_str,
2161 es_evi->vpn->vni);
2162 }
2163
2164 /* withdraw and delete EAD-EVI */
2165 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
2166 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
2167 &es->esi, es->originator_ip);
2168 if (bgp_evpn_type1_evi_route_delete(bgp,
2169 es, es_evi->vpn, &p))
2170 flog_err(EC_BGP_EVPN_ROUTE_DELETE,
2171 "%u: EAD-EVI route deletion failure for ESI %s VNI %u",
2172 bgp->vrf_id, es->esi_str,
2173 es_evi->vpn->vni);
2174 }
2175 }
2176
2177 bgp_evpn_es_evi_local_info_clear(es_evi);
185fb14a 2178
c44ab6f1
AK
2179}
2180
2181int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni)
2182{
2183 struct bgpevpn *vpn;
2184 struct bgp_evpn_es *es;
2185 struct bgp_evpn_es_evi *es_evi;
2186 char buf[ESI_STR_LEN];
2187
2188 es = bgp_evpn_es_find(esi);
2189 if (!es) {
2190 flog_err(
2191 EC_BGP_ES_CREATE,
2192 "%u: Failed to deref VNI %d from ESI %s; ES not present",
2193 bgp->vrf_id, vni,
2194 esi_to_str(esi, buf, sizeof(buf)));
2195 return -1;
2196 }
2197
2198 vpn = bgp_evpn_lookup_vni(bgp, vni);
2199 if (!vpn) {
2200 flog_err(
2201 EC_BGP_ES_CREATE,
2202 "%u: Failed to deref VNI %d from ESI %s; VNI not present",
2203 bgp->vrf_id, vni, es->esi_str);
2204 return -1;
2205 }
2206
2207 es_evi = bgp_evpn_es_evi_find(es, vpn);
2208 if (!es_evi) {
2209 flog_err(
2210 EC_BGP_ES_CREATE,
2211 "%u: Failed to deref VNI %d from ESI %s; ES-VNI not present",
2212 bgp->vrf_id, vni, es->esi_str);
2213 return -1;
2214 }
2215
2216 bgp_evpn_local_es_evi_do_del(es_evi);
2217 return 0;
2218}
2219
2220/* Create ES-EVI and advertise the corresponding EAD routes */
2221int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni)
2222{
2223 struct bgpevpn *vpn;
2224 struct prefix_evpn p;
2225 struct bgp_evpn_es *es;
2226 struct bgp_evpn_es_evi *es_evi;
2227 char buf[ESI_STR_LEN];
2228
2229 es = bgp_evpn_es_find(esi);
2230 if (!es) {
2231 flog_err(
2232 EC_BGP_ES_CREATE,
2233 "%u: Failed to associate VNI %d with ESI %s; ES not present",
2234 bgp->vrf_id, vni,
2235 esi_to_str(esi, buf, sizeof(buf)));
2236 return -1;
2237 }
2238
2239 vpn = bgp_evpn_lookup_vni(bgp, vni);
2240 if (!vpn) {
2241 flog_err(
2242 EC_BGP_ES_CREATE,
2243 "%u: Failed to associate VNI %d with ESI %s; VNI not present",
2244 bgp->vrf_id, vni, es->esi_str);
2245 return -1;
2246 }
2247
2248 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2249 zlog_debug("add local es %s evi %u",
2250 es->esi_str, vni);
2251
2252 es_evi = bgp_evpn_es_evi_find(es, vpn);
2253
2254 if (es_evi) {
2255 if (CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
2256 /* dup */
2257 return 0;
2258 } else {
2259 es_evi = bgp_evpn_es_evi_new(es, vpn);
2260 if (!es_evi)
2261 return -1;
2262 }
2263
2264 bgp_evpn_es_evi_local_info_set(es_evi);
2265
2266 /* generate an EAD-EVI for this new VNI */
2267 build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
2268 &es->esi, es->originator_ip);
2269 if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
2270 if (bgp_evpn_type1_route_update(bgp, es, vpn, &p))
2271 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
2272 "%u: EAD-EVI route creation failure for ESI %s VNI %u",
2273 bgp->vrf_id, es->esi_str, vni);
2274 }
2275
2276 /* update EAD-ES */
2277 build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
2278 &es->esi, es->originator_ip);
2279 if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
2280 if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
2281 flog_err(EC_BGP_EVPN_ROUTE_CREATE,
2282 "%u: EAD-ES route creation failure for ESI %s VNI %u",
2283 bgp->vrf_id, es->esi_str, vni);
2284 }
2285
2286 return 0;
2287}
2288
2289/* Add remote ES-EVI entry. This is actually the remote VTEP add and the
2290 * ES-EVI is implicity created on first VTEP's reference.
2291 */
2292int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn,
2293 const struct prefix_evpn *p)
2294{
2295 char buf[ESI_STR_LEN];
2296 struct bgp_evpn_es *es;
2297 struct bgp_evpn_es_evi *es_evi;
2298 bool ead_es;
2299 const esi_t *esi = &p->prefix.ead_addr.esi;
2300
2301 if (!vpn)
2302 /* local EAD-ES need not be sent back to zebra */
2303 return 0;
2304
2305 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
2306 zlog_debug("add remote %s es %s evi %u vtep %pI4",
2307 p->prefix.ead_addr.eth_tag ? "ead-es" : "ead-evi",
2308 esi_to_str(esi, buf, sizeof(buf)), vpn->vni,
2309 &p->prefix.ead_addr.ip.ipaddr_v4);
c44ab6f1
AK
2310
2311 es = bgp_evpn_es_find(esi);
2312 if (!es) {
2313 es = bgp_evpn_es_new(bgp, esi);
2314 if (!es) {
2315 flog_err(EC_BGP_ES_CREATE,
2316 "%u: Failed to allocate ES entry for ESI %s - at remote ES Add",
2317 bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
2318 return -1;
2319 }
2320 }
2321
2322 es_evi = bgp_evpn_es_evi_find(es, vpn);
2323 if (!es_evi) {
2324 es_evi = bgp_evpn_es_evi_new(es, vpn);
2325 if (!es_evi) {
45a859f1 2326 bgp_evpn_es_free(es, __func__);
c44ab6f1
AK
2327 return -1;
2328 }
2329 }
2330
2331 ead_es = !!p->prefix.ead_addr.eth_tag;
2332 bgp_evpn_es_evi_vtep_add(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
2333 ead_es);
2334
2335 bgp_evpn_es_evi_remote_info_re_eval(es_evi);
2336 return 0;
2337}
2338
2339/* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the
2340 * parent es-evi freed up implicitly in last VTEP's deref.
2341 */
2342int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn,
2343 const struct prefix_evpn *p)
2344{
2345 char buf[ESI_STR_LEN];
2346 struct bgp_evpn_es *es;
2347 struct bgp_evpn_es_evi *es_evi;
2348 bool ead_es;
2349
2350 if (!vpn)
2351 /* local EAD-ES need not be sent back to zebra */
2352 return 0;
2353
2354 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
23d0a753
DA
2355 zlog_debug(
2356 "del remote %s es %s evi %u vtep %pI4",
2357 p->prefix.ead_addr.eth_tag ? "ead-es" : "ead-evi",
2358 esi_to_str(&p->prefix.ead_addr.esi, buf, sizeof(buf)),
2359 vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4);
c44ab6f1
AK
2360
2361 es = bgp_evpn_es_find(&p->prefix.ead_addr.esi);
2362 if (!es)
2363 /* XXX - error logs */
2364 return 0;
2365 es_evi = bgp_evpn_es_evi_find(es, vpn);
2366 if (!es_evi)
2367 /* XXX - error logs */
2368 return 0;
2369
2370 ead_es = !!p->prefix.ead_addr.eth_tag;
2371 bgp_evpn_es_evi_vtep_del(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4,
2372 ead_es);
2373 bgp_evpn_es_evi_remote_info_re_eval(es_evi);
2374 return 0;
2375}
2376
2377/* Initialize the ES tables maintained per-L2_VNI */
2378void bgp_evpn_vni_es_init(struct bgpevpn *vpn)
2379{
2380 /* Initialize the ES-EVI RB tree */
2381 RB_INIT(bgp_es_evi_rb_head, &vpn->es_evi_rb_tree);
2382
2383 /* Initialize the local list maintained for quick walks by type */
2384 vpn->local_es_evi_list = list_new();
2385 listset_app_node_mem(vpn->local_es_evi_list);
2386}
2387
2388/* Cleanup the ES info maintained per-L2_VNI */
2389void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn)
2390{
2391 struct bgp_evpn_es_evi *es_evi;
2392 struct bgp_evpn_es_evi *es_evi_next;
2393
2394 RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head,
2395 &vpn->es_evi_rb_tree, es_evi_next) {
2396 bgp_evpn_local_es_evi_do_del(es_evi);
2397 }
2398
2399 list_delete(&vpn->local_es_evi_list);
2400}
2401
2402static char *bgp_evpn_es_evi_vteps_str(char *vtep_str,
9e0c2fd1
AK
2403 struct bgp_evpn_es_evi *es_evi,
2404 uint8_t vtep_str_size)
c44ab6f1
AK
2405{
2406 char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ];
2407 struct listnode *node;
2408 struct bgp_evpn_es_evi_vtep *evi_vtep;
2409 bool first = true;
23d0a753 2410 char vtep_ip[BUFSIZ] = {0};
c44ab6f1
AK
2411
2412 vtep_str[0] = '\0';
2413 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
2414 vtep_flag_str[0] = '\0';
2415 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
9e0c2fd1 2416 strlcat(vtep_flag_str, "E", sizeof(vtep_flag_str));
c44ab6f1 2417 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
9e0c2fd1 2418 strlcat(vtep_flag_str, "V", sizeof(vtep_flag_str));
c44ab6f1 2419
9e0c2fd1
AK
2420 if (!strnlen(vtep_flag_str, sizeof(vtep_flag_str)))
2421 strlcpy(vtep_flag_str, "-", sizeof(vtep_flag_str));
2422 if (first)
c44ab6f1 2423 first = false;
9e0c2fd1
AK
2424 else
2425 strlcat(vtep_str, ",", vtep_str_size);
23d0a753
DA
2426 strlcat(vtep_str,
2427 inet_ntop(AF_INET, &evi_vtep->vtep_ip, vtep_ip,
2428 sizeof(vtep_ip)),
2429 vtep_str_size);
9e0c2fd1
AK
2430 strlcat(vtep_str, "(", vtep_str_size);
2431 strlcat(vtep_str, vtep_flag_str, vtep_str_size);
2432 strlcat(vtep_str, ")", vtep_str_size);
c44ab6f1
AK
2433 }
2434
2435 return vtep_str;
2436}
2437
2438static void bgp_evpn_es_evi_json_vtep_fill(json_object *json_vteps,
2439 struct bgp_evpn_es_evi_vtep *evi_vtep)
2440{
2441 json_object *json_vtep_entry;
2442 json_object *json_flags;
23d0a753 2443 char vtep_ip[BUFSIZ] = {0};
c44ab6f1
AK
2444
2445 json_vtep_entry = json_object_new_object();
2446
23d0a753
DA
2447 json_object_string_add(json_vtep_entry, "vtep_ip",
2448 inet_ntop(AF_INET, &evi_vtep->vtep_ip, vtep_ip,
2449 sizeof(vtep_ip)));
2450
c44ab6f1
AK
2451 if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD_PER_ES |
2452 BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) {
2453 json_flags = json_object_new_array();
2454 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_ES)
2455 json_array_string_add(json_flags, "ead-per-es");
2456 if (evi_vtep->flags & BGP_EVPN_EVI_VTEP_EAD_PER_EVI)
2457 json_array_string_add(json_flags, "ed-per-evi");
2458 json_object_object_add(json_vtep_entry,
2459 "flags", json_flags);
2460 }
2461
2462 json_object_array_add(json_vteps,
2463 json_vtep_entry);
2464}
2465
2466static void bgp_evpn_es_evi_show_entry(struct vty *vty,
2467 struct bgp_evpn_es_evi *es_evi, json_object *json)
2468{
2469 struct listnode *node;
2470 struct bgp_evpn_es_evi_vtep *evi_vtep;
2471
2472 if (json) {
2473 json_object *json_vteps;
2474 json_object *json_types;
2475
2476 json_object_string_add(json, "esi", es_evi->es->esi_str);
2477 json_object_int_add(json, "vni", es_evi->vpn->vni);
2478
2479 if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL |
2480 BGP_EVPNES_EVI_REMOTE)) {
2481 json_types = json_object_new_array();
2482 if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
2483 json_array_string_add(json_types, "local");
2484 if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
2485 json_array_string_add(json_types, "remote");
2486 json_object_object_add(json, "type", json_types);
2487 }
2488
2489 if (listcount(es_evi->es_evi_vtep_list)) {
2490 json_vteps = json_object_new_array();
2491 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list,
2492 node, evi_vtep)) {
2493 bgp_evpn_es_evi_json_vtep_fill(json_vteps,
2494 evi_vtep);
2495 }
2496 json_object_object_add(json, "vteps", json_vteps);
2497 }
2498 } else {
2499 char type_str[4];
2500 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
2501
2502 type_str[0] = '\0';
2503 if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
9e0c2fd1 2504 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 2505 if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
9e0c2fd1 2506 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 2507 if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST)
9e0c2fd1 2508 strlcat(type_str, "I", sizeof(type_str));
c44ab6f1 2509
9e0c2fd1 2510 bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
c44ab6f1
AK
2511
2512 vty_out(vty, "%-8d %-30s %-5s %s\n",
2513 es_evi->vpn->vni, es_evi->es->esi_str,
2514 type_str, vtep_str);
2515 }
2516}
2517
2518static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
2519 struct bgp_evpn_es_evi *es_evi, json_object *json)
2520{
2521 if (json) {
2522 json_object *json_flags;
2523
2524 /* Add the "brief" info first */
2525 bgp_evpn_es_evi_show_entry(vty, es_evi, json);
2526 if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) {
2527 json_flags = json_object_new_array();
2528 json_array_string_add(json_flags, "es-vtep-mismatch");
2529 json_object_object_add(json, "flags", json_flags);
2530 }
2531 } else {
2532 char vtep_str[ES_VTEP_LIST_STR_SZ + BGP_EVPN_VTEPS_FLAG_STR_SZ];
2533 char type_str[4];
2534
2535 type_str[0] = '\0';
2536 if (es_evi->flags & BGP_EVPNES_EVI_LOCAL)
9e0c2fd1 2537 strlcat(type_str, "L", sizeof(type_str));
c44ab6f1 2538 if (es_evi->flags & BGP_EVPNES_EVI_REMOTE)
9e0c2fd1 2539 strlcat(type_str, "R", sizeof(type_str));
c44ab6f1 2540
9e0c2fd1 2541 bgp_evpn_es_evi_vteps_str(vtep_str, es_evi, sizeof(vtep_str));
c44ab6f1 2542 if (!strlen(vtep_str))
9e0c2fd1 2543 strlcpy(vtep_str, "-", sizeof(type_str));
c44ab6f1
AK
2544
2545 vty_out(vty, "VNI: %d ESI: %s\n",
2546 es_evi->vpn->vni, es_evi->es->esi_str);
2547 vty_out(vty, " Type: %s\n", type_str);
2548 vty_out(vty, " Inconsistencies: %s\n",
2549 (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
2550 "es-vtep-mismatch":"-");
2551 vty_out(vty, " VTEPs: %s\n", vtep_str);
2552 vty_out(vty, "\n");
2553 }
2554}
2555
2556static void bgp_evpn_es_evi_show_one_vni(struct bgpevpn *vpn, struct vty *vty,
2557 json_object *json_array, bool detail)
2558{
2559 struct bgp_evpn_es_evi *es_evi;
2560 json_object *json = NULL;
2561
2562 RB_FOREACH(es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree) {
2563 if (json_array)
2564 /* create a separate json object for each ES */
2565 json = json_object_new_object();
2566 if (detail)
2567 bgp_evpn_es_evi_show_entry_detail(vty, es_evi, json);
2568 else
2569 bgp_evpn_es_evi_show_entry(vty, es_evi, json);
2570 /* add ES to the json array */
2571 if (json_array)
2572 json_object_array_add(json_array, json);
2573 }
2574}
2575
2576struct es_evi_show_ctx {
2577 struct vty *vty;
2578 json_object *json;
2579 int detail;
2580};
2581
2582static void bgp_evpn_es_evi_show_one_vni_hash_cb(struct hash_bucket *bucket,
2583 void *ctxt)
2584{
2585 struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
2586 struct es_evi_show_ctx *wctx = (struct es_evi_show_ctx *)ctxt;
2587
2588 bgp_evpn_es_evi_show_one_vni(vpn, wctx->vty, wctx->json, wctx->detail);
2589}
2590
2591/* Display all ES EVIs */
2592void bgp_evpn_es_evi_show(struct vty *vty, bool uj, bool detail)
2593{
2594 json_object *json_array = NULL;
2595 struct es_evi_show_ctx wctx;
2596 struct bgp *bgp;
2597
2598 if (uj) {
2599 /* create an array of ES-EVIs */
2600 json_array = json_object_new_array();
2601 }
2602
2603 wctx.vty = vty;
2604 wctx.json = json_array;
2605 wctx.detail = detail;
2606
2607 bgp = bgp_get_evpn();
2608
2609 if (!json_array && !detail) {
2610 vty_out(vty, "Flags: L local, R remote, I inconsistent\n");
2611 vty_out(vty, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
2612 vty_out(vty, "%-8s %-30s %-5s %s\n",
2613 "VNI", "ESI", "Flags", "VTEPs");
2614 }
2615
2616 if (bgp)
2617 hash_iterate(bgp->vnihash,
2618 (void (*)(struct hash_bucket *,
2619 void *))bgp_evpn_es_evi_show_one_vni_hash_cb,
2620 &wctx);
2621 if (uj) {
2622 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2623 json_array, JSON_C_TO_STRING_PRETTY));
2624 json_object_free(json_array);
2625 }
2626}
2627
2628/* Display specific ES EVI */
2629void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni,
2630 bool uj, bool detail)
2631{
2632 struct bgpevpn *vpn = NULL;
2633 json_object *json_array = NULL;
2634 struct bgp *bgp;
2635
2636 if (uj) {
2637 /* create an array of ES-EVIs */
2638 json_array = json_object_new_array();
2639 }
2640
2641 bgp = bgp_get_evpn();
2642 if (bgp)
2643 vpn = bgp_evpn_lookup_vni(bgp, vni);
2644
2645 if (vpn) {
2646 if (!json_array && !detail) {
2647 vty_out(vty, "Flags: L local, R remote, I inconsistent\n");
2648 vty_out(vty, "VTEP-Flags: E EAD-per-ES, V EAD-per-EVI\n");
2649 vty_out(vty, "%-8s %-30s %-5s %s\n",
2650 "VNI", "ESI", "Flags", "VTEPs");
2651 }
2652
2653 bgp_evpn_es_evi_show_one_vni(vpn, vty, json_array, detail);
2654 } else {
2655 if (!uj)
2656 vty_out(vty, "VNI not found\n");
2657 }
2658
2659 if (uj) {
2660 vty_out(vty, "%s\n", json_object_to_json_string_ext(
2661 json_array, JSON_C_TO_STRING_PRETTY));
2662 json_object_free(json_array);
2663 }
2664}
2665
2666/*****************************************************************************
2667 * Ethernet Segment Consistency checks
2668 * Consistency checking is done to detect misconfig or mis-cabling. When
2669 * an inconsistency is detected it is simply logged (and displayed via
2670 * show commands) at this point. A more drastic action can be executed (based
2671 * on user config) in the future.
2672 */
2673/* queue up the es for background consistency checks */
2674static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es)
2675{
2676 if (!bgp_mh_info->consistency_checking)
2677 /* consistency checking is not enabled */
2678 return;
2679
2680 if (CHECK_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND))
2681 /* already queued for consistency checking */
2682 return;
2683
2684 SET_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND);
2685 listnode_init(&es->pend_es_listnode, es);
2686 listnode_add_after(bgp_mh_info->pend_es_list,
2687 listtail_unchecked(bgp_mh_info->pend_es_list),
2688 &es->pend_es_listnode);
2689}
2690
2691/* pull the ES from the consistency check list */
2692static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es)
2693{
2694 if (!CHECK_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND))
2695 return;
2696
2697 UNSET_FLAG(es->flags, BGP_EVPNES_CONS_CHECK_PEND);
2698 list_delete_node(bgp_mh_info->pend_es_list,
2699 &es->pend_es_listnode);
2700}
2701
2702/* Number of active VTEPs associated with the ES-per-EVI */
2703static uint32_t bgp_evpn_es_evi_get_active_vtep_cnt(
2704 struct bgp_evpn_es_evi *es_evi)
2705{
2706 struct bgp_evpn_es_evi_vtep *evi_vtep;
2707 struct listnode *node;
2708 uint32_t vtep_cnt = 0;
2709
2710 for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
2711 if (CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE))
2712 ++vtep_cnt;
2713 }
2714
2715 return vtep_cnt;
2716}
2717
2718/* Number of active VTEPs associated with the ES */
2719static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es)
2720{
2721 struct listnode *node;
2722 uint32_t vtep_cnt = 0;
2723 struct bgp_evpn_es_vtep *es_vtep;
2724
2725 for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
2726 if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
2727 ++vtep_cnt;
2728 }
2729
2730 return vtep_cnt;
2731}
2732
2733static struct bgp_evpn_es_vtep *bgp_evpn_es_get_next_active_vtep(
2734 struct bgp_evpn_es *es, struct bgp_evpn_es_vtep *es_vtep)
2735{
2736 struct listnode *node;
2737 struct bgp_evpn_es_vtep *next_es_vtep;
2738
2739 if (es_vtep)
2740 node = listnextnode_unchecked(&es_vtep->es_listnode);
2741 else
2742 node = listhead(es->es_vtep_list);
2743
2744 for (; node; node = listnextnode_unchecked(node)) {
2745 next_es_vtep = listgetdata(node);
2746 if (CHECK_FLAG(next_es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE))
2747 return next_es_vtep;
2748 }
2749
2750 return NULL;
2751}
2752
2753static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_get_next_active_vtep(
2754 struct bgp_evpn_es_evi *es_evi,
2755 struct bgp_evpn_es_evi_vtep *evi_vtep)
2756{
2757 struct listnode *node;
2758 struct bgp_evpn_es_evi_vtep *next_evi_vtep;
2759
2760 if (evi_vtep)
2761 node = listnextnode_unchecked(&evi_vtep->es_evi_listnode);
2762 else
2763 node = listhead(es_evi->es_evi_vtep_list);
2764
2765 for (; node; node = listnextnode_unchecked(node)) {
2766 next_evi_vtep = listgetdata(node);
2767 if (CHECK_FLAG(next_evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE))
2768 return next_evi_vtep;
2769 }
2770
2771 return NULL;
2772}
2773
2774static void bgp_evpn_es_evi_set_inconsistent(struct bgp_evpn_es_evi *es_evi)
2775{
2776 if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST)) {
2777 if (BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2778 zlog_debug("inconsistency detected - es %s evi %u vtep list mismatch",
2779 es_evi->es->esi_str,
2780 es_evi->vpn->vni);
2781 SET_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST);
2782
2783 /* update parent ES with the incosistency setting */
2784 if (!es_evi->es->incons_evi_vtep_cnt &&
2785 BGP_DEBUG(evpn_mh, EVPN_MH_ES))
2786 zlog_debug("inconsistency detected - es %s vtep list mismatch",
2787 es_evi->es->esi_str);
2788 ++es_evi->es->incons_evi_vtep_cnt;
2789 SET_FLAG(es_evi->es->inconsistencies,
2790 BGP_EVPNES_INCONS_VTEP_LIST);
2791 }
2792}
2793
2794static uint32_t bgp_evpn_es_run_consistency_checks(struct bgp_evpn_es *es)
2795{
2796 int proc_cnt = 0;
2797 int es_active_vtep_cnt;
2798 int evi_active_vtep_cnt;
2799 struct bgp_evpn_es_evi *es_evi;
2800 struct listnode *evi_node;
2801 struct bgp_evpn_es_vtep *es_vtep;
2802 struct bgp_evpn_es_evi_vtep *evi_vtep;
2803
2804 /* reset the inconsistencies and re-evaluate */
2805 es->incons_evi_vtep_cnt = 0;
2806 es->inconsistencies = 0;
2807
2808 es_active_vtep_cnt = bgp_evpn_es_get_active_vtep_cnt(es);
2809 for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
2810 evi_node, es_evi)) {
2811 ++proc_cnt;
2812
2813 /* reset the inconsistencies on the EVI and re-evaluate*/
2814 UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_INCONS_VTEP_LIST);
2815
2816 evi_active_vtep_cnt =
2817 bgp_evpn_es_evi_get_active_vtep_cnt(es_evi);
2818 if (es_active_vtep_cnt != evi_active_vtep_cnt) {
2819 bgp_evpn_es_evi_set_inconsistent(es_evi);
2820 continue;
2821 }
2822
2823 if (!es_active_vtep_cnt)
2824 continue;
2825
2826 es_vtep = NULL;
2827 evi_vtep = NULL;
2828 while ((es_vtep = bgp_evpn_es_get_next_active_vtep(
2829 es, es_vtep))) {
2830 evi_vtep = bgp_evpn_es_evi_get_next_active_vtep(es_evi,
2831 evi_vtep);
2832 if (!evi_vtep) {
2833 bgp_evpn_es_evi_set_inconsistent(es_evi);
2834 break;
2835 }
2836 if (es_vtep->vtep_ip.s_addr !=
2837 evi_vtep->vtep_ip.s_addr) {
2838 /* inconsistency detected; set it and move
2839 * to the next evi
2840 */
2841 bgp_evpn_es_evi_set_inconsistent(es_evi);
2842 break;
2843 }
2844 }
2845 }
2846
2847 return proc_cnt;
2848}
2849
2850static int bgp_evpn_run_consistency_checks(struct thread *t)
2851{
2852 int proc_cnt = 0;
2853 int es_cnt = 0;
2854 struct listnode *node;
2855 struct listnode *nextnode;
2856 struct bgp_evpn_es *es;
2857
2858 for (ALL_LIST_ELEMENTS(bgp_mh_info->pend_es_list,
2859 node, nextnode, es)) {
2860 ++es_cnt;
2861 ++proc_cnt;
2862 /* run consistency checks on the ES and remove it from the
2863 * pending list
2864 */
2865 proc_cnt += bgp_evpn_es_run_consistency_checks(es);
2866 bgp_evpn_es_cons_checks_pend_del(es);
2867 if (proc_cnt > 500)
2868 break;
2869 }
2870
2871 /* restart the timer */
2872 thread_add_timer(bm->master, bgp_evpn_run_consistency_checks, NULL,
2873 BGP_EVPN_CONS_CHECK_INTERVAL,
2874 &bgp_mh_info->t_cons_check);
2875
2876 return 0;
2877}
2878
2879/*****************************************************************************/
2880void bgp_evpn_mh_init(void)
2881{
2882 bm->mh_info = XCALLOC(MTYPE_BGP_EVPN_MH_INFO, sizeof(*bm->mh_info));
2883
2884 /* setup ES tables */
2885 RB_INIT(bgp_es_rb_head, &bgp_mh_info->es_rb_tree);
2886 /* local ES list */
2887 bgp_mh_info->local_es_list = list_new();
2888 listset_app_node_mem(bgp_mh_info->local_es_list);
2889 /* list of ESs with pending processing */
2890 bgp_mh_info->pend_es_list = list_new();
2891 listset_app_node_mem(bgp_mh_info->pend_es_list);
2892
2893 /* config knobs - XXX add cli to control it */
2894 bgp_mh_info->ead_evi_adv_for_down_links = true;
2895 bgp_mh_info->consistency_checking = true;
2896
2897 if (bgp_mh_info->consistency_checking)
2898 thread_add_timer(bm->master, bgp_evpn_run_consistency_checks,
2899 NULL, BGP_EVPN_CONS_CHECK_INTERVAL,
2900 &bgp_mh_info->t_cons_check);
2901
2902 memset(&zero_esi_buf, 0, sizeof(esi_t));
2903}
2904
2905void bgp_evpn_mh_finish(void)
2906{
2907 struct bgp_evpn_es *es;
2908 struct bgp_evpn_es *es_next;
c44ab6f1 2909
45a859f1
AK
2910 if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
2911 zlog_debug("evpn mh finish");
2912
2913 RB_FOREACH_SAFE (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree,
2914 es_next) {
2915 bgp_evpn_es_local_info_clear(es);
c44ab6f1
AK
2916 }
2917 thread_cancel(bgp_mh_info->t_cons_check);
2918 list_delete(&bgp_mh_info->local_es_list);
2919 list_delete(&bgp_mh_info->pend_es_list);
2920
2921 XFREE(MTYPE_BGP_EVPN_MH_INFO, bgp_mh_info);
2922}