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