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