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