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