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