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