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