Line data Source code
1 : /*
2 : * Zebra EVPN for VxLAN code
3 : * Copyright (C) 2016, 2017 Cumulus Networks, Inc.
4 : *
5 : * This file is part of FRR.
6 : *
7 : * FRR is free software; you can redistribute it and/or modify it
8 : * under the terms of the GNU General Public License as published by the
9 : * Free Software Foundation; either version 2, or (at your option) any
10 : * later version.
11 : *
12 : * FRR is distributed in the hope that it will be useful, but
13 : * WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with FRR; see the file COPYING. If not, write to the Free
19 : * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 : * 02111-1307, USA.
21 : */
22 :
23 : #include <zebra.h>
24 :
25 : #include "hash.h"
26 : #include "interface.h"
27 : #include "jhash.h"
28 : #include "memory.h"
29 : #include "prefix.h"
30 : #include "vlan.h"
31 : #include "json.h"
32 : #include "printfrr.h"
33 :
34 : #include "zebra/zserv.h"
35 : #include "zebra/debug.h"
36 : #include "zebra/zebra_router.h"
37 : #include "zebra/zebra_errors.h"
38 : #include "zebra/zebra_vrf.h"
39 : #include "zebra/zebra_evpn.h"
40 : #include "zebra/zebra_evpn_mh.h"
41 : #include "zebra/zebra_evpn_mac.h"
42 : #include "zebra/zebra_evpn_neigh.h"
43 :
44 6 : DEFINE_MTYPE_STATIC(ZEBRA, MAC, "EVPN MAC");
45 :
46 : /*
47 : * Return number of valid MACs in an EVPN's MAC hash table - all
48 : * remote MACs and non-internal (auto) local MACs count.
49 : */
50 0 : uint32_t num_valid_macs(struct zebra_evpn *zevpn)
51 : {
52 0 : unsigned int i;
53 0 : uint32_t num_macs = 0;
54 0 : struct hash *hash;
55 0 : struct hash_bucket *hb;
56 0 : struct zebra_mac *mac;
57 :
58 0 : hash = zevpn->mac_table;
59 0 : if (!hash)
60 : return num_macs;
61 0 : for (i = 0; i < hash->size; i++) {
62 0 : for (hb = hash->index[i]; hb; hb = hb->next) {
63 0 : mac = (struct zebra_mac *)hb->data;
64 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
65 : || CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
66 0 : || !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
67 0 : num_macs++;
68 : }
69 : }
70 :
71 : return num_macs;
72 : }
73 :
74 0 : uint32_t num_dup_detected_macs(struct zebra_evpn *zevpn)
75 : {
76 0 : unsigned int i;
77 0 : uint32_t num_macs = 0;
78 0 : struct hash *hash;
79 0 : struct hash_bucket *hb;
80 0 : struct zebra_mac *mac;
81 :
82 0 : hash = zevpn->mac_table;
83 0 : if (!hash)
84 : return num_macs;
85 0 : for (i = 0; i < hash->size; i++) {
86 0 : for (hb = hash->index[i]; hb; hb = hb->next) {
87 0 : mac = (struct zebra_mac *)hb->data;
88 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
89 0 : num_macs++;
90 : }
91 : }
92 :
93 : return num_macs;
94 : }
95 :
96 : /* Setup mac_list against the access port. This is done when a mac uses
97 : * the ifp as destination for the first time
98 : */
99 0 : static void zebra_evpn_mac_ifp_new(struct zebra_if *zif)
100 : {
101 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
102 0 : zlog_debug("MAC list created for ifp %s (%u)", zif->ifp->name,
103 : zif->ifp->ifindex);
104 :
105 0 : zif->mac_list = list_new();
106 0 : listset_app_node_mem(zif->mac_list);
107 0 : }
108 :
109 : /* Unlink local mac from a destination access port */
110 0 : static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac)
111 : {
112 0 : struct zebra_if *zif;
113 0 : struct interface *ifp = zmac->ifp;
114 :
115 0 : if (!ifp)
116 : return;
117 :
118 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
119 0 : zlog_debug("VNI %d MAC %pEA unlinked from ifp %s (%u)",
120 : zmac->zevpn->vni,
121 : &zmac->macaddr,
122 : ifp->name, ifp->ifindex);
123 :
124 0 : zif = ifp->info;
125 0 : list_delete_node(zif->mac_list, &zmac->ifp_listnode);
126 0 : zmac->ifp = NULL;
127 : }
128 :
129 : /* Free up the mac_list if any as a part of the interface del/cleanup */
130 4 : void zebra_evpn_mac_ifp_del(struct interface *ifp)
131 : {
132 4 : struct zebra_if *zif = ifp->info;
133 4 : struct listnode *node;
134 4 : struct zebra_mac *zmac;
135 :
136 4 : if (zif->mac_list) {
137 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
138 0 : zlog_debug("MAC list deleted for ifp %s (%u)",
139 : zif->ifp->name, zif->ifp->ifindex);
140 :
141 0 : for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) {
142 0 : zebra_evpn_mac_ifp_unlink(zmac);
143 : }
144 0 : list_delete(&zif->mac_list);
145 : }
146 4 : }
147 :
148 : /* Link local mac to destination access port. This is done only if the
149 : * local mac is associated with a zero ESI i.e. single attach or lacp-bypass
150 : * bridge port member
151 : */
152 0 : static void zebra_evpn_mac_ifp_link(struct zebra_mac *zmac,
153 : struct interface *ifp)
154 : {
155 0 : struct zebra_if *zif;
156 :
157 0 : if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
158 : return;
159 :
160 : /* already linked to the destination */
161 0 : if (zmac->ifp == ifp)
162 : return;
163 :
164 : /* unlink the mac from any old destination */
165 0 : if (zmac->ifp)
166 0 : zebra_evpn_mac_ifp_unlink(zmac);
167 :
168 0 : if (!ifp)
169 : return;
170 :
171 0 : zif = ifp->info;
172 : /* the interface mac_list is created on first mac link attempt */
173 0 : if (!zif->mac_list)
174 0 : zebra_evpn_mac_ifp_new(zif);
175 :
176 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
177 0 : zlog_debug("VNI %d MAC %pEA linked to ifp %s (%u)",
178 : zmac->zevpn->vni,
179 : &zmac->macaddr,
180 : ifp->name, ifp->ifindex);
181 :
182 0 : zmac->ifp = ifp;
183 0 : listnode_init(&zmac->ifp_listnode, zmac);
184 0 : listnode_add(zif->mac_list, &zmac->ifp_listnode);
185 : }
186 :
187 : /* If the mac is a local mac clear links to destination access port */
188 0 : void zebra_evpn_mac_clear_fwd_info(struct zebra_mac *zmac)
189 : {
190 0 : zebra_evpn_mac_ifp_unlink(zmac);
191 0 : memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info));
192 0 : }
193 :
194 : /*
195 : * Install remote MAC into the forwarding plane.
196 : */
197 0 : int zebra_evpn_rem_mac_install(struct zebra_evpn *zevpn, struct zebra_mac *mac,
198 : bool was_static)
199 : {
200 0 : const struct zebra_if *zif, *br_zif;
201 0 : const struct zebra_l2info_vxlan *vxl;
202 0 : bool sticky;
203 0 : enum zebra_dplane_result res;
204 0 : const struct interface *br_ifp;
205 0 : vlanid_t vid;
206 0 : uint32_t nhg_id;
207 0 : struct in_addr vtep_ip;
208 :
209 0 : zif = zevpn->vxlan_if->info;
210 0 : if (!zif)
211 : return -1;
212 :
213 0 : br_ifp = zif->brslave_info.br_if;
214 0 : if (br_ifp == NULL)
215 : return -1;
216 :
217 0 : vxl = &zif->l2info.vxl;
218 :
219 0 : sticky = !!CHECK_FLAG(mac->flags,
220 : (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW));
221 :
222 : /* If nexthop group for the FDB entry is inactive (not programmed in
223 : * the dataplane) the MAC entry cannot be installed
224 : */
225 0 : if (mac->es) {
226 0 : if (!(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
227 : return -1;
228 0 : nhg_id = mac->es->nhg_id;
229 0 : vtep_ip.s_addr = 0;
230 : } else {
231 0 : nhg_id = 0;
232 0 : vtep_ip = mac->fwd_info.r_vtep_ip;
233 : }
234 :
235 0 : br_zif = (const struct zebra_if *)(br_ifp->info);
236 :
237 0 : if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
238 0 : vid = vxl->access_vlan;
239 : else
240 : vid = 0;
241 :
242 0 : res = dplane_rem_mac_add(zevpn->vxlan_if, br_ifp, vid, &mac->macaddr,
243 : vtep_ip, sticky, nhg_id, was_static);
244 0 : if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
245 : return 0;
246 : else
247 : return -1;
248 : }
249 :
250 : /*
251 : * Uninstall remote MAC from the forwarding plane.
252 : */
253 0 : int zebra_evpn_rem_mac_uninstall(struct zebra_evpn *zevpn,
254 : struct zebra_mac *mac, bool force)
255 : {
256 0 : const struct zebra_if *zif, *br_zif;
257 0 : const struct zebra_l2info_vxlan *vxl;
258 0 : struct in_addr vtep_ip;
259 0 : const struct interface *ifp, *br_ifp;
260 0 : vlanid_t vid;
261 0 : enum zebra_dplane_result res;
262 :
263 : /* If the MAC was not installed there is no need to uninstall it */
264 0 : if (!force && mac->es && !(mac->es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
265 : return -1;
266 :
267 0 : if (!zevpn->vxlan_if) {
268 0 : if (IS_ZEBRA_DEBUG_VXLAN)
269 0 : zlog_debug(
270 : "VNI %u hash %p couldn't be uninstalled - no intf",
271 : zevpn->vni, zevpn);
272 0 : return -1;
273 : }
274 :
275 0 : zif = zevpn->vxlan_if->info;
276 0 : if (!zif)
277 : return -1;
278 :
279 0 : br_ifp = zif->brslave_info.br_if;
280 0 : if (br_ifp == NULL)
281 : return -1;
282 :
283 0 : vxl = &zif->l2info.vxl;
284 :
285 0 : br_zif = (const struct zebra_if *)br_ifp->info;
286 :
287 0 : if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
288 0 : vid = vxl->access_vlan;
289 : else
290 : vid = 0;
291 :
292 0 : ifp = zevpn->vxlan_if;
293 0 : vtep_ip = mac->fwd_info.r_vtep_ip;
294 :
295 0 : res = dplane_rem_mac_del(ifp, br_ifp, vid, &mac->macaddr, vtep_ip);
296 0 : if (res != ZEBRA_DPLANE_REQUEST_FAILURE)
297 : return 0;
298 : else
299 : return -1;
300 : }
301 :
302 : /*
303 : * Decrement neighbor refcount of MAC; uninstall and free it if
304 : * appropriate.
305 : */
306 0 : void zebra_evpn_deref_ip2mac(struct zebra_evpn *zevpn, struct zebra_mac *mac)
307 : {
308 0 : if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
309 : return;
310 :
311 : /* If all remote neighbors referencing a remote MAC go away,
312 : * we need to uninstall the MAC.
313 : */
314 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
315 0 : && remote_neigh_count(mac) == 0) {
316 0 : zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
317 0 : zebra_evpn_es_mac_deref_entry(mac);
318 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
319 : }
320 :
321 : /* If no references, delete the MAC. */
322 0 : if (!zebra_evpn_mac_in_use(mac))
323 0 : zebra_evpn_mac_del(zevpn, mac);
324 : }
325 :
326 0 : static void zebra_evpn_mac_get_access_info(struct zebra_mac *mac,
327 : struct interface **p_ifp,
328 : vlanid_t *vid)
329 : {
330 : /* if the mac is associated with an ES we must get the access
331 : * info from the ES
332 : */
333 0 : if (mac->es) {
334 0 : struct zebra_if *zif;
335 :
336 : /* get the access port from the es */
337 0 : *p_ifp = mac->es->zif ? mac->es->zif->ifp : NULL;
338 : /* get the vlan from the EVPN */
339 0 : if (mac->zevpn->vxlan_if) {
340 0 : zif = mac->zevpn->vxlan_if->info;
341 0 : *vid = zif->l2info.vxl.access_vlan;
342 : } else {
343 0 : *vid = 0;
344 : }
345 : } else {
346 0 : struct zebra_ns *zns;
347 :
348 0 : *vid = mac->fwd_info.local.vid;
349 0 : zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
350 0 : *p_ifp = if_lookup_by_index_per_ns(zns,
351 0 : mac->fwd_info.local.ifindex);
352 : }
353 0 : }
354 :
355 : #define MAC_BUF_SIZE 256
356 0 : static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac *mac, char *buf,
357 : size_t len)
358 : {
359 0 : if (mac->flags == 0) {
360 0 : snprintfrr(buf, len, "None ");
361 0 : return buf;
362 : }
363 :
364 0 : snprintfrr(
365 : buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s",
366 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ? "LOC " : "",
367 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ? "REM " : "",
368 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) ? "AUTO " : "",
369 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? "STICKY " : "",
370 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router "
371 : : "",
372 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) ? "Default GW " : "",
373 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW "
374 : : "",
375 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "",
376 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "",
377 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE)
378 : ? "PEER Active "
379 : : "",
380 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "",
381 0 : CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)
382 : ? "LOC Inactive "
383 : : "");
384 0 : return buf;
385 : }
386 :
387 0 : static void zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
388 : {
389 0 : struct zebra_vrf *zvrf = NULL;
390 0 : struct zebra_mac *mac = NULL;
391 0 : struct zebra_evpn *zevpn = NULL;
392 0 : struct listnode *node = NULL;
393 0 : struct zebra_neigh *nbr = NULL;
394 :
395 0 : mac = THREAD_ARG(t);
396 :
397 : /* since this is asynchronous we need sanity checks*/
398 0 : zvrf = vrf_info_lookup(mac->zevpn->vrf_id);
399 0 : if (!zvrf)
400 : return;
401 :
402 0 : zevpn = zebra_evpn_lookup(mac->zevpn->vni);
403 0 : if (!zevpn)
404 : return;
405 :
406 0 : mac = zebra_evpn_mac_lookup(zevpn, &mac->macaddr);
407 0 : if (!mac)
408 : return;
409 :
410 0 : if (IS_ZEBRA_DEBUG_VXLAN) {
411 0 : char mac_buf[MAC_BUF_SIZE];
412 :
413 0 : zlog_debug(
414 : "%s: duplicate addr mac %pEA flags %slearn count %u host count %u auto recovery expired",
415 : __func__, &mac->macaddr,
416 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
417 : sizeof(mac_buf)),
418 : mac->dad_count, listcount(mac->neigh_list));
419 : }
420 :
421 : /* Remove all IPs as duplicate associcated with this MAC */
422 0 : for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
423 0 : if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) {
424 0 : if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
425 0 : ZEBRA_NEIGH_SET_INACTIVE(nbr);
426 0 : else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE))
427 0 : zebra_evpn_rem_neigh_install(
428 : zevpn, nbr, false /*was_static*/);
429 : }
430 :
431 0 : UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
432 0 : nbr->dad_count = 0;
433 0 : nbr->detect_start_time.tv_sec = 0;
434 0 : nbr->dad_dup_detect_time = 0;
435 : }
436 :
437 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
438 0 : mac->dad_count = 0;
439 0 : mac->detect_start_time.tv_sec = 0;
440 0 : mac->detect_start_time.tv_usec = 0;
441 0 : mac->dad_dup_detect_time = 0;
442 0 : mac->dad_mac_auto_recovery_timer = NULL;
443 :
444 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
445 : /* Inform to BGP */
446 0 : if (zebra_evpn_mac_send_add_to_client(zevpn->vni, &mac->macaddr,
447 : mac->flags, mac->loc_seq,
448 : mac->es))
449 : return;
450 :
451 : /* Process all neighbors associated with this MAC. */
452 0 : zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
453 : 0 /*es_change*/);
454 :
455 0 : } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
456 0 : zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
457 :
458 : /* Install the entry. */
459 0 : zebra_evpn_rem_mac_install(zevpn, mac, false /* was_static */);
460 : }
461 : }
462 :
463 0 : static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
464 : struct zebra_mac *mac,
465 : struct in_addr vtep_ip,
466 : bool do_dad, bool *is_dup_detect,
467 : bool is_local)
468 : {
469 0 : struct zebra_neigh *nbr;
470 0 : struct listnode *node = NULL;
471 0 : struct timeval elapsed = {0, 0};
472 0 : bool reset_params = false;
473 :
474 0 : if (!(zebra_evpn_do_dup_addr_detect(zvrf) && do_dad))
475 0 : return;
476 :
477 : /* MAC is detected as duplicate,
478 : * Local MAC event -> hold on advertising to BGP.
479 : * Remote MAC event -> hold on installing it.
480 : */
481 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
482 0 : if (IS_ZEBRA_DEBUG_VXLAN) {
483 0 : char mac_buf[MAC_BUF_SIZE];
484 :
485 0 : zlog_debug(
486 : "%s: duplicate addr MAC %pEA flags %sskip update to client, learn count %u recover time %u",
487 : __func__, &mac->macaddr,
488 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
489 : sizeof(mac_buf)),
490 : mac->dad_count, zvrf->dad_freeze_time);
491 : }
492 : /* For duplicate MAC do not update
493 : * client but update neigh due to
494 : * this MAC update.
495 : */
496 0 : if (zvrf->dad_freeze)
497 0 : *is_dup_detect = true;
498 :
499 0 : return;
500 : }
501 :
502 : /* Check if detection time (M-secs) expired.
503 : * Reset learn count and detection start time.
504 : */
505 0 : monotime_since(&mac->detect_start_time, &elapsed);
506 0 : reset_params = (elapsed.tv_sec > zvrf->dad_time);
507 0 : if (is_local && !reset_params) {
508 : /* RFC-7432: A PE/VTEP that detects a MAC mobility
509 : * event via LOCAL learning starts an M-second timer.
510 : *
511 : * NOTE: This is the START of the probe with count is
512 : * 0 during LOCAL learn event.
513 : * (mac->dad_count == 0 || elapsed.tv_sec >= zvrf->dad_time)
514 : */
515 0 : reset_params = !mac->dad_count;
516 : }
517 :
518 0 : if (reset_params) {
519 0 : if (IS_ZEBRA_DEBUG_VXLAN) {
520 0 : char mac_buf[MAC_BUF_SIZE];
521 :
522 0 : zlog_debug(
523 : "%s: duplicate addr MAC %pEA flags %sdetection time passed, reset learn count %u",
524 : __func__, &mac->macaddr,
525 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
526 : sizeof(mac_buf)),
527 : mac->dad_count);
528 : }
529 :
530 0 : mac->dad_count = 0;
531 : /* Start dup. addr detection (DAD) start time,
532 : * ONLY during LOCAL learn.
533 : */
534 0 : if (is_local)
535 0 : monotime(&mac->detect_start_time);
536 :
537 0 : } else if (!is_local) {
538 : /* For REMOTE MAC, increment detection count
539 : * ONLY while in probe window, once window passed,
540 : * next local learn event should trigger DAD.
541 : */
542 0 : mac->dad_count++;
543 : }
544 :
545 : /* For LOCAL MAC learn event, once count is reset above via either
546 : * initial/start detection time or passed the probe time, the count
547 : * needs to be incremented.
548 : */
549 0 : if (is_local)
550 0 : mac->dad_count++;
551 :
552 0 : if (mac->dad_count >= zvrf->dad_max_moves) {
553 0 : flog_warn(EC_ZEBRA_DUP_MAC_DETECTED,
554 : "VNI %u: MAC %pEA detected as duplicate during %s VTEP %pI4",
555 : mac->zevpn->vni, &mac->macaddr,
556 : is_local ? "local update, last" :
557 : "remote update, from", &vtep_ip);
558 :
559 0 : SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE);
560 :
561 : /* Capture Duplicate detection time */
562 0 : mac->dad_dup_detect_time = monotime(NULL);
563 :
564 : /* Mark all IPs/Neighs as duplicate
565 : * associcated with this MAC
566 : */
567 0 : for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
568 :
569 : /* Ony Mark IPs which are Local */
570 0 : if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL))
571 0 : continue;
572 :
573 0 : SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE);
574 :
575 0 : nbr->dad_dup_detect_time = monotime(NULL);
576 :
577 0 : flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED,
578 : "VNI %u: MAC %pEA IP %pIA detected as duplicate during %s update, inherit duplicate from MAC",
579 : mac->zevpn->vni, &mac->macaddr, &nbr->ip,
580 : is_local ? "local" : "remote");
581 : }
582 :
583 : /* Start auto recovery timer for this MAC */
584 0 : THREAD_OFF(mac->dad_mac_auto_recovery_timer);
585 0 : if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
586 0 : if (IS_ZEBRA_DEBUG_VXLAN) {
587 0 : char mac_buf[MAC_BUF_SIZE];
588 :
589 0 : zlog_debug(
590 : "%s: duplicate addr MAC %pEA flags %sauto recovery time %u start",
591 : __func__, &mac->macaddr,
592 : zebra_evpn_zebra_mac_flag_dump(
593 : mac, mac_buf, sizeof(mac_buf)),
594 : zvrf->dad_freeze_time);
595 : }
596 :
597 0 : thread_add_timer(zrouter.master,
598 : zebra_evpn_dad_mac_auto_recovery_exp,
599 : mac, zvrf->dad_freeze_time,
600 : &mac->dad_mac_auto_recovery_timer);
601 : }
602 :
603 : /* In case of local update, do not inform to client (BGPd),
604 : * upd_neigh for neigh sequence change.
605 : */
606 0 : if (zvrf->dad_freeze)
607 0 : *is_dup_detect = true;
608 : }
609 : }
610 :
611 : /*
612 : * Print a specific MAC entry.
613 : */
614 0 : void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json)
615 : {
616 0 : struct vty *vty;
617 0 : struct zebra_neigh *n = NULL;
618 0 : struct listnode *node = NULL;
619 0 : char buf1[ETHER_ADDR_STRLEN];
620 0 : char buf2[INET6_ADDRSTRLEN];
621 0 : struct zebra_vrf *zvrf;
622 0 : struct timeval detect_start_time = {0, 0};
623 0 : char timebuf[MONOTIME_STRLEN];
624 0 : char thread_buf[THREAD_TIMER_STRLEN];
625 0 : time_t uptime;
626 0 : char up_str[MONOTIME_STRLEN];
627 :
628 0 : zvrf = zebra_vrf_get_evpn();
629 0 : vty = (struct vty *)ctxt;
630 0 : prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
631 :
632 0 : uptime = monotime(NULL);
633 0 : uptime -= mac->uptime;
634 :
635 0 : frrtime_to_interval(uptime, up_str, sizeof(up_str));
636 :
637 0 : if (json) {
638 0 : json_object *json_mac = json_object_new_object();
639 :
640 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
641 0 : struct interface *ifp;
642 0 : vlanid_t vid;
643 :
644 0 : zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
645 0 : json_object_string_add(json_mac, "type", "local");
646 0 : if (ifp) {
647 0 : json_object_string_add(json_mac, "intf",
648 0 : ifp->name);
649 0 : json_object_int_add(json_mac, "ifindex",
650 0 : ifp->ifindex);
651 : }
652 0 : if (vid)
653 0 : json_object_int_add(json_mac, "vlan", vid);
654 0 : } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
655 0 : json_object_string_add(json_mac, "type", "remote");
656 0 : if (mac->es)
657 0 : json_object_string_add(json_mac, "remoteEs",
658 0 : mac->es->esi_str);
659 : else
660 0 : json_object_string_addf(
661 : json_mac, "remoteVtep", "%pI4",
662 : &mac->fwd_info.r_vtep_ip);
663 0 : } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO))
664 0 : json_object_string_add(json_mac, "type", "auto");
665 :
666 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
667 0 : json_object_boolean_true_add(json_mac, "stickyMac");
668 :
669 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
670 0 : json_object_boolean_true_add(json_mac, "sviMac");
671 :
672 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
673 0 : json_object_boolean_true_add(json_mac,
674 : "defaultGateway");
675 :
676 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
677 0 : json_object_boolean_true_add(json_mac,
678 : "remoteGatewayMac");
679 :
680 0 : json_object_string_add(json_mac, "uptime", up_str);
681 0 : json_object_int_add(json_mac, "localSequence", mac->loc_seq);
682 0 : json_object_int_add(json_mac, "remoteSequence", mac->rem_seq);
683 :
684 0 : json_object_int_add(json_mac, "detectionCount", mac->dad_count);
685 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
686 0 : json_object_boolean_true_add(json_mac, "isDuplicate");
687 : else
688 0 : json_object_boolean_false_add(json_mac, "isDuplicate");
689 :
690 0 : json_object_int_add(json_mac, "syncNeighCount",
691 0 : mac->sync_neigh_cnt);
692 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
693 0 : json_object_boolean_true_add(json_mac, "localInactive");
694 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
695 0 : json_object_boolean_true_add(json_mac, "peerProxy");
696 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
697 0 : json_object_boolean_true_add(json_mac, "peerActive");
698 0 : if (mac->hold_timer)
699 0 : json_object_string_add(
700 : json_mac, "peerActiveHold",
701 0 : thread_timer_to_hhmmss(thread_buf,
702 : sizeof(thread_buf),
703 : mac->hold_timer));
704 0 : if (mac->es)
705 0 : json_object_string_add(json_mac, "esi",
706 0 : mac->es->esi_str);
707 : /* print all the associated neigh */
708 0 : if (!listcount(mac->neigh_list))
709 0 : json_object_string_add(json_mac, "neighbors", "none");
710 : else {
711 0 : json_object *json_active_nbrs = json_object_new_array();
712 0 : json_object *json_inactive_nbrs =
713 0 : json_object_new_array();
714 0 : json_object *json_nbrs = json_object_new_object();
715 :
716 0 : for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
717 0 : if (IS_ZEBRA_NEIGH_ACTIVE(n))
718 0 : json_object_array_add(
719 : json_active_nbrs,
720 : json_object_new_string(
721 0 : ipaddr2str(
722 0 : &n->ip, buf2,
723 : sizeof(buf2))));
724 : else
725 0 : json_object_array_add(
726 : json_inactive_nbrs,
727 : json_object_new_string(
728 0 : ipaddr2str(
729 0 : &n->ip, buf2,
730 : sizeof(buf2))));
731 : }
732 :
733 0 : json_object_object_add(json_nbrs, "active",
734 : json_active_nbrs);
735 0 : json_object_object_add(json_nbrs, "inactive",
736 : json_inactive_nbrs);
737 0 : json_object_object_add(json_mac, "neighbors",
738 : json_nbrs);
739 : }
740 :
741 0 : json_object_object_add(json, buf1, json_mac);
742 : } else {
743 0 : vty_out(vty, "MAC: %s\n", buf1);
744 :
745 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
746 0 : struct interface *ifp;
747 0 : vlanid_t vid;
748 :
749 0 : zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
750 :
751 0 : if (mac->es)
752 0 : vty_out(vty, " ESI: %s\n", mac->es->esi_str);
753 :
754 0 : if (ifp)
755 0 : vty_out(vty, " Intf: %s(%u)", ifp->name,
756 : ifp->ifindex);
757 : else
758 0 : vty_out(vty, " Intf: -");
759 0 : vty_out(vty, " VLAN: %u", vid);
760 0 : } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
761 0 : if (mac->es)
762 0 : vty_out(vty, " Remote ES: %s",
763 0 : mac->es->esi_str);
764 : else
765 0 : vty_out(vty, " Remote VTEP: %pI4",
766 : &mac->fwd_info.r_vtep_ip);
767 0 : } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
768 0 : vty_out(vty, " Auto Mac ");
769 : }
770 :
771 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
772 0 : vty_out(vty, " Sticky Mac ");
773 :
774 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
775 0 : vty_out(vty, " SVI-Mac ");
776 :
777 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW))
778 0 : vty_out(vty, " Default-gateway Mac ");
779 :
780 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW))
781 0 : vty_out(vty, " Remote-gateway Mac ");
782 :
783 0 : vty_out(vty, "\n");
784 0 : vty_out(vty, " Sync-info: neigh#: %u", mac->sync_neigh_cnt);
785 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE))
786 0 : vty_out(vty, " local-inactive");
787 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY))
788 0 : vty_out(vty, " peer-proxy");
789 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
790 0 : vty_out(vty, " peer-active");
791 0 : if (mac->hold_timer)
792 0 : vty_out(vty, " (ht: %s)",
793 : thread_timer_to_hhmmss(thread_buf,
794 : sizeof(thread_buf),
795 : mac->hold_timer));
796 0 : vty_out(vty, "\n");
797 0 : vty_out(vty, " Local Seq: %u Remote Seq: %u\n", mac->loc_seq,
798 : mac->rem_seq);
799 0 : vty_out(vty, " Uptime: %s\n", up_str);
800 :
801 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
802 0 : vty_out(vty, " Duplicate, detected at %s",
803 : time_to_string(mac->dad_dup_detect_time,
804 : timebuf));
805 0 : } else if (mac->dad_count) {
806 0 : monotime_since(&mac->detect_start_time,
807 : &detect_start_time);
808 0 : if (detect_start_time.tv_sec <= zvrf->dad_time) {
809 0 : time_to_string(mac->detect_start_time.tv_sec,
810 : timebuf);
811 0 : vty_out(vty,
812 : " Duplicate detection started at %s, detection count %u\n",
813 : timebuf, mac->dad_count);
814 : }
815 : }
816 :
817 : /* print all the associated neigh */
818 0 : vty_out(vty, " Neighbors:\n");
819 0 : if (!listcount(mac->neigh_list))
820 0 : vty_out(vty, " No Neighbors\n");
821 : else {
822 0 : for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) {
823 0 : vty_out(vty, " %s %s\n",
824 0 : ipaddr2str(&n->ip, buf2, sizeof(buf2)),
825 0 : (IS_ZEBRA_NEIGH_ACTIVE(n)
826 : ? "Active"
827 : : "Inactive"));
828 : }
829 : }
830 :
831 0 : vty_out(vty, "\n");
832 : }
833 0 : }
834 :
835 0 : static char *zebra_evpn_print_mac_flags(struct zebra_mac *mac, char *flags_buf,
836 : size_t flags_buf_sz)
837 : {
838 0 : snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
839 0 : mac->sync_neigh_cnt ? "N" : "",
840 0 : (mac->flags & ZEBRA_MAC_ES_PEER_ACTIVE) ? "P" : "",
841 0 : (mac->flags & ZEBRA_MAC_ES_PEER_PROXY) ? "X" : "",
842 0 : (mac->flags & ZEBRA_MAC_LOCAL_INACTIVE) ? "I" : "");
843 :
844 0 : return flags_buf;
845 : }
846 :
847 : /*
848 : * Print MAC hash entry - called for display of all MACs.
849 : */
850 0 : void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
851 : {
852 0 : struct vty *vty;
853 0 : json_object *json_mac_hdr = NULL, *json_mac = NULL;
854 0 : struct zebra_mac *mac;
855 0 : char buf1[ETHER_ADDR_STRLEN];
856 0 : char addr_buf[PREFIX_STRLEN];
857 0 : struct mac_walk_ctx *wctx = ctxt;
858 0 : char flags_buf[6];
859 :
860 0 : vty = wctx->vty;
861 0 : json_mac_hdr = wctx->json;
862 0 : mac = (struct zebra_mac *)bucket->data;
863 :
864 0 : prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
865 :
866 0 : if (json_mac_hdr)
867 0 : json_mac = json_object_new_object();
868 :
869 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
870 0 : struct interface *ifp;
871 0 : vlanid_t vid;
872 :
873 0 : if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
874 0 : return;
875 :
876 0 : zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
877 0 : if (json_mac_hdr == NULL) {
878 0 : vty_out(vty, "%-17s %-6s %-5s %-30s", buf1, "local",
879 : zebra_evpn_print_mac_flags(mac, flags_buf,
880 : sizeof(flags_buf)),
881 0 : ifp ? ifp->name : "-");
882 : } else {
883 0 : json_object_string_add(json_mac, "type", "local");
884 0 : if (ifp)
885 0 : json_object_string_add(json_mac, "intf",
886 0 : ifp->name);
887 : }
888 0 : if (vid) {
889 0 : if (json_mac_hdr == NULL)
890 0 : vty_out(vty, " %-5u", vid);
891 : else
892 0 : json_object_int_add(json_mac, "vlan", vid);
893 : } else /* No vid? fill out the space */
894 0 : if (json_mac_hdr == NULL)
895 0 : vty_out(vty, " %-5s", "");
896 0 : if (json_mac_hdr == NULL) {
897 0 : vty_out(vty, " %u/%u", mac->loc_seq, mac->rem_seq);
898 0 : vty_out(vty, "\n");
899 : } else {
900 0 : json_object_int_add(json_mac, "localSequence",
901 0 : mac->loc_seq);
902 0 : json_object_int_add(json_mac, "remoteSequence",
903 0 : mac->rem_seq);
904 0 : json_object_int_add(json_mac, "detectionCount",
905 0 : mac->dad_count);
906 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
907 0 : json_object_boolean_true_add(json_mac,
908 : "isDuplicate");
909 : else
910 0 : json_object_boolean_false_add(json_mac,
911 : "isDuplicate");
912 0 : json_object_object_add(json_mac_hdr, buf1, json_mac);
913 : }
914 :
915 0 : wctx->count++;
916 :
917 0 : } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
918 :
919 0 : if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
920 0 : && !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip,
921 : &wctx->r_vtep_ip))
922 : return;
923 :
924 0 : if (json_mac_hdr == NULL) {
925 0 : if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
926 0 : && (wctx->count == 0)) {
927 0 : vty_out(vty, "\nVNI %u\n\n", wctx->zevpn->vni);
928 0 : vty_out(vty, "%-17s %-6s %-5s%-30s %-5s %s\n",
929 : "MAC", "Type", "Flags",
930 : "Intf/Remote ES/VTEP", "VLAN",
931 : "Seq #'s");
932 : }
933 0 : if (mac->es == NULL)
934 0 : inet_ntop(AF_INET, &mac->fwd_info.r_vtep_ip,
935 : addr_buf, sizeof(addr_buf));
936 :
937 0 : vty_out(vty, "%-17s %-6s %-5s %-30s %-5s %u/%u\n", buf1,
938 : "remote",
939 : zebra_evpn_print_mac_flags(mac, flags_buf,
940 : sizeof(flags_buf)),
941 0 : mac->es ? mac->es->esi_str : addr_buf,
942 : "", mac->loc_seq, mac->rem_seq);
943 : } else {
944 0 : json_object_string_add(json_mac, "type", "remote");
945 0 : if (mac->es)
946 0 : json_object_string_add(json_mac, "remoteEs",
947 0 : mac->es->esi_str);
948 : else
949 0 : json_object_string_addf(
950 : json_mac, "remoteVtep", "%pI4",
951 : &mac->fwd_info.r_vtep_ip);
952 0 : json_object_object_add(json_mac_hdr, buf1, json_mac);
953 0 : json_object_int_add(json_mac, "localSequence",
954 0 : mac->loc_seq);
955 0 : json_object_int_add(json_mac, "remoteSequence",
956 0 : mac->rem_seq);
957 0 : json_object_int_add(json_mac, "detectionCount",
958 0 : mac->dad_count);
959 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
960 0 : json_object_boolean_true_add(json_mac,
961 : "isDuplicate");
962 : else
963 0 : json_object_boolean_false_add(json_mac,
964 : "isDuplicate");
965 : }
966 :
967 0 : wctx->count++;
968 : }
969 : }
970 :
971 : /*
972 : * Print MAC hash entry in detail - called for display of all MACs.
973 : */
974 0 : void zebra_evpn_print_mac_hash_detail(struct hash_bucket *bucket, void *ctxt)
975 : {
976 0 : struct vty *vty;
977 0 : json_object *json_mac_hdr = NULL;
978 0 : struct zebra_mac *mac;
979 0 : struct mac_walk_ctx *wctx = ctxt;
980 0 : char buf1[ETHER_ADDR_STRLEN];
981 :
982 0 : vty = wctx->vty;
983 0 : json_mac_hdr = wctx->json;
984 0 : mac = (struct zebra_mac *)bucket->data;
985 0 : if (!mac)
986 0 : return;
987 :
988 0 : wctx->count++;
989 0 : prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1));
990 :
991 0 : zebra_evpn_print_mac(mac, vty, json_mac_hdr);
992 : }
993 :
994 : /*
995 : * Inform BGP about local MACIP.
996 : */
997 0 : int zebra_evpn_macip_send_msg_to_client(vni_t vni,
998 : const struct ethaddr *macaddr,
999 : const struct ipaddr *ip, uint8_t flags,
1000 : uint32_t seq, int state,
1001 : struct zebra_evpn_es *es, uint16_t cmd)
1002 : {
1003 0 : int ipa_len;
1004 0 : struct zserv *client = NULL;
1005 0 : struct stream *s = NULL;
1006 0 : esi_t *esi = es ? &es->esi : zero_esi;
1007 :
1008 0 : client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1009 : /* BGP may not be running. */
1010 0 : if (!client)
1011 : return 0;
1012 :
1013 0 : s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1014 :
1015 0 : zclient_create_header(s, cmd, zebra_vrf_get_evpn_id());
1016 0 : stream_putl(s, vni);
1017 0 : stream_put(s, macaddr->octet, ETH_ALEN);
1018 0 : if (ip) {
1019 0 : ipa_len = 0;
1020 0 : if (IS_IPADDR_V4(ip))
1021 : ipa_len = IPV4_MAX_BYTELEN;
1022 0 : else if (IS_IPADDR_V6(ip))
1023 0 : ipa_len = IPV6_MAX_BYTELEN;
1024 :
1025 0 : stream_putl(s, ipa_len); /* IP address length */
1026 0 : if (ipa_len)
1027 0 : stream_put(s, &ip->ip.addr, ipa_len); /* IP address */
1028 : } else
1029 0 : stream_putl(s, 0); /* Just MAC. */
1030 :
1031 0 : if (cmd == ZEBRA_MACIP_ADD) {
1032 0 : stream_putc(s, flags); /* sticky mac/gateway mac */
1033 0 : stream_putl(s, seq); /* sequence number */
1034 0 : stream_put(s, esi, sizeof(esi_t));
1035 : } else {
1036 0 : stream_putl(s, state); /* state - active/inactive */
1037 : }
1038 :
1039 :
1040 : /* Write packet size. */
1041 0 : stream_putw_at(s, 0, stream_get_endp(s));
1042 :
1043 0 : if (IS_ZEBRA_DEBUG_VXLAN) {
1044 0 : char flag_buf[MACIP_BUF_SIZE];
1045 :
1046 0 : zlog_debug(
1047 : "Send MACIP %s f %s MAC %pEA IP %pIA seq %u L2-VNI %u ESI %s to %s",
1048 : (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
1049 : zclient_evpn_dump_macip_flags(flags, flag_buf,
1050 : sizeof(flag_buf)),
1051 : macaddr, ip, seq, vni,
1052 : es ? es->esi_str : "-",
1053 : zebra_route_string(client->proto));
1054 : }
1055 :
1056 0 : if (cmd == ZEBRA_MACIP_ADD)
1057 0 : client->macipadd_cnt++;
1058 : else
1059 0 : client->macipdel_cnt++;
1060 :
1061 0 : return zserv_send_message(client, s);
1062 : }
1063 :
1064 0 : static unsigned int mac_hash_keymake(const void *p)
1065 : {
1066 0 : const struct zebra_mac *pmac = p;
1067 0 : const void *pnt = (void *)pmac->macaddr.octet;
1068 :
1069 0 : return jhash(pnt, ETH_ALEN, 0xa5a5a55a);
1070 : }
1071 :
1072 : /*
1073 : * Compare two MAC addresses.
1074 : */
1075 0 : static bool mac_cmp(const void *p1, const void *p2)
1076 : {
1077 0 : const struct zebra_mac *pmac1 = p1;
1078 0 : const struct zebra_mac *pmac2 = p2;
1079 :
1080 0 : if (pmac1 == NULL && pmac2 == NULL)
1081 : return true;
1082 :
1083 0 : if (pmac1 == NULL || pmac2 == NULL)
1084 : return false;
1085 :
1086 0 : return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN)
1087 0 : == 0);
1088 : }
1089 :
1090 : /*
1091 : * Callback to allocate MAC hash entry.
1092 : */
1093 0 : static void *zebra_evpn_mac_alloc(void *p)
1094 : {
1095 0 : const struct zebra_mac *tmp_mac = p;
1096 0 : struct zebra_mac *mac;
1097 :
1098 0 : mac = XCALLOC(MTYPE_MAC, sizeof(struct zebra_mac));
1099 0 : *mac = *tmp_mac;
1100 :
1101 0 : return ((void *)mac);
1102 : }
1103 :
1104 : /*
1105 : * Add MAC entry.
1106 : */
1107 0 : struct zebra_mac *zebra_evpn_mac_add(struct zebra_evpn *zevpn,
1108 : const struct ethaddr *macaddr)
1109 : {
1110 0 : struct zebra_mac tmp_mac;
1111 0 : struct zebra_mac *mac = NULL;
1112 :
1113 0 : memset(&tmp_mac, 0, sizeof(tmp_mac));
1114 0 : memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN);
1115 0 : mac = hash_get(zevpn->mac_table, &tmp_mac, zebra_evpn_mac_alloc);
1116 :
1117 0 : mac->zevpn = zevpn;
1118 0 : mac->dad_mac_auto_recovery_timer = NULL;
1119 :
1120 0 : mac->neigh_list = list_new();
1121 0 : mac->neigh_list->cmp = neigh_list_cmp;
1122 :
1123 0 : mac->uptime = monotime(NULL);
1124 0 : if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1125 0 : char mac_buf[MAC_BUF_SIZE];
1126 :
1127 0 : zlog_debug("%s: MAC %pEA flags %s", __func__,
1128 : &mac->macaddr,
1129 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1130 : sizeof(mac_buf)));
1131 : }
1132 0 : return mac;
1133 : }
1134 :
1135 : /*
1136 : * Delete MAC entry.
1137 : */
1138 0 : int zebra_evpn_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
1139 : {
1140 0 : struct zebra_mac *tmp_mac;
1141 :
1142 0 : if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1143 0 : char mac_buf[MAC_BUF_SIZE];
1144 :
1145 0 : zlog_debug("%s: MAC %pEA flags %s", __func__,
1146 : &mac->macaddr,
1147 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1148 : sizeof(mac_buf)));
1149 : }
1150 :
1151 : /* force de-ref any ES entry linked to the MAC */
1152 0 : zebra_evpn_es_mac_deref_entry(mac);
1153 :
1154 : /* remove links to the destination access port */
1155 0 : zebra_evpn_mac_clear_fwd_info(mac);
1156 :
1157 : /* Cancel proxy hold timer */
1158 0 : zebra_evpn_mac_stop_hold_timer(mac);
1159 :
1160 : /* Cancel auto recovery */
1161 0 : THREAD_OFF(mac->dad_mac_auto_recovery_timer);
1162 :
1163 : /* If the MAC is freed before the neigh we will end up
1164 : * with a stale pointer against the neigh.
1165 : * The situation can arise when a MAC is in remote state
1166 : * and its associated neigh is local state.
1167 : * zebra_evpn_cfg_cleanup() cleans up remote neighs and MACs.
1168 : * Instead of deleting remote MAC, if its neigh list is non-empty
1169 : * (associated to local neighs), mark the MAC as AUTO.
1170 : */
1171 0 : if (!list_isempty(mac->neigh_list)) {
1172 0 : if (IS_ZEBRA_DEBUG_VXLAN)
1173 0 : zlog_debug(
1174 : "MAC %pEA (flags 0x%x vni %u) has non-empty neigh list "
1175 : "count %u, mark MAC as AUTO",
1176 : &mac->macaddr, mac->flags, zevpn->vni,
1177 : listcount(mac->neigh_list));
1178 :
1179 0 : SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
1180 0 : return 0;
1181 : }
1182 :
1183 0 : list_delete(&mac->neigh_list);
1184 :
1185 : /* Free the VNI hash entry and allocated memory. */
1186 0 : tmp_mac = hash_release(zevpn->mac_table, mac);
1187 0 : XFREE(MTYPE_MAC, tmp_mac);
1188 :
1189 0 : return 0;
1190 : }
1191 :
1192 : /*
1193 : * Add Auto MAC entry.
1194 : */
1195 0 : struct zebra_mac *zebra_evpn_mac_add_auto(struct zebra_evpn *zevpn,
1196 : const struct ethaddr *macaddr)
1197 : {
1198 0 : struct zebra_mac *mac;
1199 :
1200 0 : mac = zebra_evpn_mac_add(zevpn, macaddr);
1201 0 : if (!mac)
1202 : return NULL;
1203 :
1204 0 : zebra_evpn_mac_clear_fwd_info(mac);
1205 0 : memset(&mac->flags, 0, sizeof(uint32_t));
1206 0 : SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
1207 :
1208 0 : return mac;
1209 : }
1210 :
1211 0 : static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
1212 : struct zebra_mac *mac)
1213 : {
1214 0 : if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL))
1215 : return true;
1216 0 : else if ((wctx->flags & DEL_REMOTE_MAC)
1217 0 : && (mac->flags & ZEBRA_MAC_REMOTE))
1218 : return true;
1219 0 : else if ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP)
1220 0 : && (mac->flags & ZEBRA_MAC_REMOTE)
1221 0 : && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip))
1222 : return true;
1223 0 : else if ((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_AUTO)
1224 0 : && !listcount(mac->neigh_list)) {
1225 0 : if (IS_ZEBRA_DEBUG_VXLAN) {
1226 0 : char mac_buf[MAC_BUF_SIZE];
1227 :
1228 0 : zlog_debug(
1229 : "%s: Del MAC %pEA flags %s", __func__,
1230 : &mac->macaddr,
1231 : zebra_evpn_zebra_mac_flag_dump(
1232 : mac, mac_buf, sizeof(mac_buf)));
1233 : }
1234 0 : wctx->uninstall = 0;
1235 :
1236 0 : return true;
1237 : }
1238 :
1239 : return false;
1240 : }
1241 :
1242 : /*
1243 : * Free MAC hash entry (callback)
1244 : */
1245 0 : static void zebra_evpn_mac_del_hash_entry(struct hash_bucket *bucket, void *arg)
1246 : {
1247 0 : struct mac_walk_ctx *wctx = arg;
1248 0 : struct zebra_mac *mac = bucket->data;
1249 :
1250 0 : if (zebra_evpn_check_mac_del_from_db(wctx, mac)) {
1251 0 : if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) {
1252 0 : zebra_evpn_mac_send_del_to_client(wctx->zevpn->vni,
1253 0 : &mac->macaddr,
1254 : mac->flags, false);
1255 : }
1256 0 : if (wctx->uninstall) {
1257 0 : if (zebra_evpn_mac_is_static(mac))
1258 0 : zebra_evpn_sync_mac_dp_install(
1259 : mac, false /* set_inactive */,
1260 : true /* force_clear_static */,
1261 : __func__);
1262 :
1263 0 : if (mac->flags & ZEBRA_MAC_REMOTE)
1264 0 : zebra_evpn_rem_mac_uninstall(wctx->zevpn, mac,
1265 : false /*force*/);
1266 : }
1267 :
1268 0 : zebra_evpn_mac_del(wctx->zevpn, mac);
1269 : }
1270 :
1271 0 : return;
1272 : }
1273 :
1274 : /*
1275 : * Delete all MAC entries for this EVPN.
1276 : */
1277 0 : void zebra_evpn_mac_del_all(struct zebra_evpn *zevpn, int uninstall,
1278 : int upd_client, uint32_t flags)
1279 : {
1280 0 : struct mac_walk_ctx wctx;
1281 :
1282 0 : if (!zevpn->mac_table)
1283 0 : return;
1284 :
1285 0 : memset(&wctx, 0, sizeof(wctx));
1286 0 : wctx.zevpn = zevpn;
1287 0 : wctx.uninstall = uninstall;
1288 0 : wctx.upd_client = upd_client;
1289 0 : wctx.flags = flags;
1290 :
1291 0 : hash_iterate(zevpn->mac_table, zebra_evpn_mac_del_hash_entry, &wctx);
1292 : }
1293 :
1294 : /*
1295 : * Look up MAC hash entry.
1296 : */
1297 0 : struct zebra_mac *zebra_evpn_mac_lookup(struct zebra_evpn *zevpn,
1298 : const struct ethaddr *mac)
1299 : {
1300 0 : struct zebra_mac tmp;
1301 0 : struct zebra_mac *pmac;
1302 :
1303 0 : memset(&tmp, 0, sizeof(tmp));
1304 0 : memcpy(&tmp.macaddr, mac, ETH_ALEN);
1305 0 : pmac = hash_lookup(zevpn->mac_table, &tmp);
1306 :
1307 0 : return pmac;
1308 : }
1309 :
1310 : /*
1311 : * Inform BGP about local MAC addition.
1312 : */
1313 0 : int zebra_evpn_mac_send_add_to_client(vni_t vni, const struct ethaddr *macaddr,
1314 : uint32_t mac_flags, uint32_t seq,
1315 : struct zebra_evpn_es *es)
1316 : {
1317 0 : uint8_t flags = 0;
1318 :
1319 0 : if (CHECK_FLAG(mac_flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
1320 : /* host reachability has not been verified locally */
1321 :
1322 : /* if no ES peer is claiming reachability we can't advertise the
1323 : * entry
1324 : */
1325 0 : if (!CHECK_FLAG(mac_flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1326 : return 0;
1327 :
1328 : /* ES peers are claiming reachability; we will
1329 : * advertise the entry but with a proxy flag
1330 : */
1331 : SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT);
1332 : }
1333 :
1334 0 : if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY))
1335 0 : SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
1336 0 : if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW))
1337 0 : SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
1338 :
1339 0 : return zebra_evpn_macip_send_msg_to_client(vni, macaddr, NULL, flags,
1340 : seq, ZEBRA_NEIGH_ACTIVE, es,
1341 : ZEBRA_MACIP_ADD);
1342 : }
1343 :
1344 : /*
1345 : * Inform BGP about local MAC deletion.
1346 : */
1347 0 : int zebra_evpn_mac_send_del_to_client(vni_t vni, const struct ethaddr *macaddr,
1348 : uint32_t flags, bool force)
1349 : {
1350 0 : if (!force) {
1351 0 : if (CHECK_FLAG(flags, ZEBRA_MAC_LOCAL_INACTIVE)
1352 0 : && !CHECK_FLAG(flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1353 : /* the host was not advertised - nothing to delete */
1354 : return 0;
1355 : }
1356 :
1357 0 : return zebra_evpn_macip_send_msg_to_client(
1358 : vni, macaddr, NULL, 0 /* flags */, 0 /* seq */,
1359 : ZEBRA_NEIGH_ACTIVE, NULL, ZEBRA_MACIP_DEL);
1360 : }
1361 :
1362 : /*
1363 : * wrapper to create a MAC hash table
1364 : */
1365 0 : struct hash *zebra_mac_db_create(const char *desc)
1366 : {
1367 0 : return hash_create_size(8, mac_hash_keymake, mac_cmp, desc);
1368 : }
1369 :
1370 : /* program sync mac flags in the dataplane */
1371 0 : int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive,
1372 : bool force_clear_static, const char *caller)
1373 : {
1374 0 : struct interface *ifp;
1375 0 : bool sticky;
1376 0 : bool set_static;
1377 0 : struct zebra_evpn *zevpn = mac->zevpn;
1378 0 : vlanid_t vid;
1379 0 : struct zebra_if *zif;
1380 0 : struct interface *br_ifp;
1381 :
1382 : /* If the ES-EVI doesn't exist defer install. When the ES-EVI is
1383 : * created we will attempt to install the mac entry again
1384 : */
1385 0 : if (mac->es) {
1386 0 : struct zebra_evpn_es_evi *es_evi;
1387 :
1388 0 : es_evi = zebra_evpn_es_evi_find(mac->es, mac->zevpn);
1389 0 : if (!es_evi) {
1390 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1391 0 : zlog_debug(
1392 : "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi",
1393 : caller, zevpn->vni, &mac->macaddr,
1394 : mac->es ? mac->es->esi_str : "-",
1395 : mac->flags,
1396 : set_inactive ? "inactive " : "");
1397 0 : return -1;
1398 : }
1399 : }
1400 :
1401 : /* get the access vlan from the vxlan_device */
1402 0 : zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
1403 :
1404 0 : if (!ifp) {
1405 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1406 0 : char mac_buf[MAC_BUF_SIZE];
1407 :
1408 0 : zlog_debug(
1409 : "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port",
1410 : caller, zevpn->vni, &mac->macaddr,
1411 : mac->es ? mac->es->esi_str : "-",
1412 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1413 : sizeof(mac_buf)),
1414 : set_inactive ? "inactive " : "");
1415 : }
1416 0 : return -1;
1417 : }
1418 :
1419 0 : zif = ifp->info;
1420 0 : br_ifp = zif->brslave_info.br_if;
1421 0 : if (!br_ifp) {
1422 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1423 0 : char mac_buf[MAC_BUF_SIZE];
1424 :
1425 0 : zlog_debug(
1426 : "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br",
1427 : caller, zevpn->vni, &mac->macaddr,
1428 : mac->es ? mac->es->esi_str : "-",
1429 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1430 : sizeof(mac_buf)),
1431 : set_inactive ? "inactive " : "");
1432 : }
1433 0 : return -1;
1434 : }
1435 :
1436 0 : sticky = !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY);
1437 0 : if (force_clear_static)
1438 : set_static = false;
1439 : else
1440 0 : set_static = zebra_evpn_mac_is_static(mac);
1441 :
1442 : /* We can install a local mac that has been synced from the peer
1443 : * over the VxLAN-overlay/network-port if fast failover is not
1444 : * supported and if the local ES is oper-down.
1445 : */
1446 0 : if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
1447 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1448 0 : char mac_buf[MAC_BUF_SIZE];
1449 :
1450 0 : zlog_debug(
1451 : "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s",
1452 : set_static ? "install" : "uninstall",
1453 : zevpn->vni, &mac->macaddr,
1454 : mac->es ? mac->es->esi_str : "-",
1455 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1456 : sizeof(mac_buf)),
1457 : set_inactive ? "inactive " : "");
1458 : }
1459 0 : if (set_static)
1460 : /* XXX - old_static needs to be computed more
1461 : * accurately
1462 : */
1463 0 : zebra_evpn_rem_mac_install(zevpn, mac,
1464 : true /* old_static */);
1465 : else
1466 0 : zebra_evpn_rem_mac_uninstall(zevpn, mac,
1467 : false /* force */);
1468 :
1469 0 : return 0;
1470 : }
1471 :
1472 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1473 0 : char mac_buf[MAC_BUF_SIZE];
1474 :
1475 0 : zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s",
1476 : zevpn->vni, &mac->macaddr,
1477 : mac->es ? mac->es->esi_str : "-",
1478 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1479 : sizeof(mac_buf)),
1480 : set_static ? "static " : "",
1481 : set_inactive ? "inactive " : "");
1482 : }
1483 :
1484 0 : dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
1485 : set_static, set_inactive);
1486 0 : return 0;
1487 : }
1488 :
1489 0 : void zebra_evpn_mac_send_add_del_to_client(struct zebra_mac *mac,
1490 : bool old_bgp_ready,
1491 : bool new_bgp_ready)
1492 : {
1493 0 : if (new_bgp_ready)
1494 0 : zebra_evpn_mac_send_add_to_client(mac->zevpn->vni,
1495 0 : &mac->macaddr, mac->flags,
1496 : mac->loc_seq, mac->es);
1497 0 : else if (old_bgp_ready)
1498 0 : zebra_evpn_mac_send_del_to_client(mac->zevpn->vni,
1499 0 : &mac->macaddr, mac->flags,
1500 : true /* force */);
1501 0 : }
1502 :
1503 : /* MAC hold timer is used to age out peer-active flag.
1504 : *
1505 : * During this wait time we expect the dataplane component or an
1506 : * external neighmgr daemon to probe existing hosts to independently
1507 : * establish their presence on the ES.
1508 : */
1509 0 : static void zebra_evpn_mac_hold_exp_cb(struct thread *t)
1510 : {
1511 0 : struct zebra_mac *mac;
1512 0 : bool old_bgp_ready;
1513 0 : bool new_bgp_ready;
1514 0 : bool old_static;
1515 0 : bool new_static;
1516 :
1517 0 : mac = THREAD_ARG(t);
1518 : /* the purpose of the hold timer is to age out the peer-active
1519 : * flag
1520 : */
1521 0 : if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1522 : return;
1523 :
1524 0 : old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1525 0 : old_static = zebra_evpn_mac_is_static(mac);
1526 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1527 0 : new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1528 0 : new_static = zebra_evpn_mac_is_static(mac);
1529 :
1530 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1531 0 : char mac_buf[MAC_BUF_SIZE];
1532 :
1533 0 : zlog_debug(
1534 : "sync-mac vni %u mac %pEA es %s %shold expired",
1535 : mac->zevpn->vni, &mac->macaddr,
1536 : mac->es ? mac->es->esi_str : "-",
1537 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1538 : sizeof(mac_buf)));
1539 : }
1540 :
1541 : /* re-program the local mac in the dataplane if the mac is no
1542 : * longer static
1543 : */
1544 0 : if (old_static != new_static)
1545 0 : zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1546 : false /* force_clear_static */,
1547 : __func__);
1548 :
1549 : /* inform bgp if needed */
1550 0 : if (old_bgp_ready != new_bgp_ready)
1551 0 : zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
1552 : new_bgp_ready);
1553 : }
1554 :
1555 0 : static inline void zebra_evpn_mac_start_hold_timer(struct zebra_mac *mac)
1556 : {
1557 0 : if (mac->hold_timer)
1558 : return;
1559 :
1560 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1561 0 : char mac_buf[MAC_BUF_SIZE];
1562 :
1563 0 : zlog_debug(
1564 : "sync-mac vni %u mac %pEA es %s %shold started",
1565 : mac->zevpn->vni, &mac->macaddr,
1566 : mac->es ? mac->es->esi_str : "-",
1567 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1568 : sizeof(mac_buf)));
1569 : }
1570 0 : thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
1571 : zmh_info->mac_hold_time, &mac->hold_timer);
1572 : }
1573 :
1574 0 : void zebra_evpn_mac_stop_hold_timer(struct zebra_mac *mac)
1575 : {
1576 0 : if (!mac->hold_timer)
1577 : return;
1578 :
1579 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1580 0 : char mac_buf[MAC_BUF_SIZE];
1581 :
1582 0 : zlog_debug(
1583 : "sync-mac vni %u mac %pEA es %s %shold stopped",
1584 : mac->zevpn->vni, &mac->macaddr,
1585 : mac->es ? mac->es->esi_str : "-",
1586 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1587 : sizeof(mac_buf)));
1588 : }
1589 :
1590 0 : THREAD_OFF(mac->hold_timer);
1591 : }
1592 :
1593 0 : void zebra_evpn_sync_mac_del(struct zebra_mac *mac)
1594 : {
1595 0 : bool old_static;
1596 0 : bool new_static;
1597 :
1598 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1599 0 : char mac_buf[MAC_BUF_SIZE];
1600 :
1601 0 : zlog_debug(
1602 : "sync-mac del vni %u mac %pEA es %s seq %d f %s",
1603 : mac->zevpn->vni, &mac->macaddr,
1604 : mac->es ? mac->es->esi_str : "-", mac->loc_seq,
1605 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1606 : sizeof(mac_buf)));
1607 : }
1608 :
1609 0 : old_static = zebra_evpn_mac_is_static(mac);
1610 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
1611 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
1612 0 : zebra_evpn_mac_start_hold_timer(mac);
1613 0 : new_static = zebra_evpn_mac_is_static(mac);
1614 :
1615 0 : if (old_static != new_static)
1616 : /* program the local mac in the kernel */
1617 0 : zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1618 : false /* force_clear_static */,
1619 : __func__);
1620 0 : }
1621 :
1622 0 : static inline bool zebra_evpn_mac_is_bgp_seq_ok(struct zebra_evpn *zevpn,
1623 : struct zebra_mac *mac,
1624 : uint32_t seq, bool sync)
1625 : {
1626 0 : char mac_buf[MAC_BUF_SIZE];
1627 0 : uint32_t tmp_seq;
1628 0 : const char *n_type;
1629 0 : bool is_local = false;
1630 :
1631 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
1632 0 : tmp_seq = mac->loc_seq;
1633 0 : n_type = "local";
1634 0 : is_local = true;
1635 : } else {
1636 0 : tmp_seq = mac->rem_seq;
1637 0 : n_type = "remote";
1638 : }
1639 :
1640 0 : if (seq < tmp_seq) {
1641 :
1642 0 : if (is_local && !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
1643 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
1644 0 : zlog_debug(
1645 : "%s-macip not ready vni %u %s-mac %pEA lower seq %u f 0x%x",
1646 : sync ? "sync" : "rem", zevpn->vni,
1647 : n_type, &mac->macaddr, tmp_seq,
1648 : mac->flags);
1649 0 : return true;
1650 : }
1651 :
1652 : /* if the mac was never advertised to bgp we must accept
1653 : * whatever sequence number bgp sends
1654 : */
1655 0 : if (!is_local && zebra_vxlan_get_accept_bgp_seq()) {
1656 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC ||
1657 0 : IS_ZEBRA_DEBUG_VXLAN) {
1658 0 : zlog_debug(
1659 : "%s-macip accept vni %u %s-mac %pEA lower seq %u f %s",
1660 : sync ? "sync" : "rem", zevpn->vni,
1661 : n_type, &mac->macaddr, tmp_seq,
1662 : zebra_evpn_zebra_mac_flag_dump(
1663 : mac, mac_buf, sizeof(mac_buf)));
1664 : }
1665 :
1666 0 : return true;
1667 : }
1668 :
1669 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
1670 0 : zlog_debug(
1671 : "%s-macip ignore vni %u %s-mac %pEA as existing has higher seq %u f %s",
1672 : sync ? "sync" : "rem", zevpn->vni, n_type,
1673 : &mac->macaddr, tmp_seq,
1674 : zebra_evpn_zebra_mac_flag_dump(
1675 : mac, mac_buf, sizeof(mac_buf)));
1676 : }
1677 :
1678 0 : return false;
1679 : }
1680 :
1681 : return true;
1682 : }
1683 :
1684 0 : struct zebra_mac *zebra_evpn_proc_sync_mac_update(struct zebra_evpn *zevpn,
1685 : const struct ethaddr *macaddr,
1686 : uint16_t ipa_len,
1687 : const struct ipaddr *ipaddr,
1688 : uint8_t flags, uint32_t seq,
1689 : const esi_t *esi)
1690 : {
1691 0 : struct zebra_mac *mac;
1692 0 : bool inform_bgp = false;
1693 0 : bool inform_dataplane = false;
1694 0 : bool seq_change = false;
1695 0 : bool es_change = false;
1696 0 : uint32_t tmp_seq;
1697 0 : char ipbuf[INET6_ADDRSTRLEN];
1698 0 : bool old_local = false;
1699 0 : bool old_bgp_ready;
1700 0 : bool new_bgp_ready;
1701 0 : bool created = false;
1702 :
1703 0 : mac = zebra_evpn_mac_lookup(zevpn, macaddr);
1704 0 : if (!mac) {
1705 : /* if it is a new local path we need to inform both
1706 : * the control protocol and the data-plane
1707 : */
1708 0 : inform_bgp = true;
1709 0 : inform_dataplane = true;
1710 :
1711 : /* create the MAC and associate it with the dest ES */
1712 0 : mac = zebra_evpn_mac_add(zevpn, macaddr);
1713 0 : zebra_evpn_es_mac_ref(mac, esi);
1714 :
1715 : /* local mac activated by an ES peer */
1716 0 : SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
1717 : /* if mac-only route setup peer flags */
1718 0 : if (!ipa_len) {
1719 0 : if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT))
1720 0 : SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
1721 : else
1722 0 : SET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1723 : }
1724 0 : SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
1725 0 : old_bgp_ready = false;
1726 0 : new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1727 0 : created = true;
1728 : } else {
1729 0 : uint32_t old_flags;
1730 0 : uint32_t new_flags;
1731 0 : bool old_static;
1732 0 : bool new_static;
1733 0 : bool sticky;
1734 0 : bool remote_gw;
1735 :
1736 0 : mac->uptime = monotime(NULL);
1737 :
1738 0 : old_flags = mac->flags;
1739 0 : sticky = !!CHECK_FLAG(old_flags, ZEBRA_MAC_STICKY);
1740 0 : remote_gw = !!CHECK_FLAG(old_flags, ZEBRA_MAC_REMOTE_DEF_GW);
1741 0 : if (sticky || remote_gw) {
1742 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH)
1743 0 : zlog_debug(
1744 : "Ignore sync-macip vni %u mac %pEA%s%s%s%s",
1745 : zevpn->vni, macaddr,
1746 : ipa_len ? " IP " : "",
1747 : ipa_len ? ipaddr2str(ipaddr, ipbuf,
1748 : sizeof(ipbuf))
1749 : : "",
1750 : sticky ? " sticky" : "",
1751 : remote_gw ? " remote_gw" : "");
1752 0 : return NULL;
1753 : }
1754 0 : if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq, true))
1755 : return NULL;
1756 :
1757 0 : old_local = !!CHECK_FLAG(old_flags, ZEBRA_MAC_LOCAL);
1758 0 : old_static = zebra_evpn_mac_is_static(mac);
1759 :
1760 : /* re-build the mac flags */
1761 0 : new_flags = 0;
1762 0 : SET_FLAG(new_flags, ZEBRA_MAC_LOCAL);
1763 : /* retain old local activity flag */
1764 0 : if (old_flags & ZEBRA_MAC_LOCAL)
1765 0 : new_flags |= (old_flags & ZEBRA_MAC_LOCAL_INACTIVE);
1766 : else
1767 : new_flags |= ZEBRA_MAC_LOCAL_INACTIVE;
1768 :
1769 0 : if (ipa_len) {
1770 : /* if mac-ip route do NOT update the peer flags
1771 : * i.e. retain only flags as is
1772 : */
1773 0 : new_flags |= (old_flags & ZEBRA_MAC_ALL_PEER_FLAGS);
1774 : } else {
1775 : /* if mac-only route update peer flags */
1776 0 : if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) {
1777 0 : SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_PROXY);
1778 : /* if the mac was peer-active previously we
1779 : * need to keep the flag and start the
1780 : * holdtimer on it. the peer-active flag is
1781 : * cleared on holdtimer expiry.
1782 : */
1783 0 : if (CHECK_FLAG(old_flags,
1784 : ZEBRA_MAC_ES_PEER_ACTIVE)) {
1785 0 : SET_FLAG(new_flags,
1786 : ZEBRA_MAC_ES_PEER_ACTIVE);
1787 0 : zebra_evpn_mac_start_hold_timer(mac);
1788 : }
1789 : } else {
1790 0 : SET_FLAG(new_flags, ZEBRA_MAC_ES_PEER_ACTIVE);
1791 : /* stop hold timer if a peer has verified
1792 : * reachability
1793 : */
1794 0 : zebra_evpn_mac_stop_hold_timer(mac);
1795 : }
1796 : }
1797 0 : mac->rem_seq = 0;
1798 0 : zebra_evpn_mac_clear_fwd_info(mac);
1799 0 : mac->flags = new_flags;
1800 :
1801 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) {
1802 0 : char mac_buf[MAC_BUF_SIZE], omac_buf[MAC_BUF_SIZE];
1803 0 : struct zebra_mac omac;
1804 :
1805 0 : omac.flags = old_flags;
1806 0 : zlog_debug(
1807 : "sync-mac vni %u mac %pEA old_f %snew_f %s",
1808 : zevpn->vni, macaddr,
1809 : zebra_evpn_zebra_mac_flag_dump(
1810 : &omac, omac_buf, sizeof(omac_buf)),
1811 : zebra_evpn_zebra_mac_flag_dump(
1812 : mac, mac_buf, sizeof(mac_buf)));
1813 : }
1814 :
1815 : /* update es */
1816 0 : es_change = zebra_evpn_es_mac_ref(mac, esi);
1817 : /* if mac dest change - inform both sides */
1818 0 : if (es_change) {
1819 : inform_bgp = true;
1820 : inform_dataplane = true;
1821 : }
1822 :
1823 : /* if peer-flag is being set notify dataplane that the
1824 : * entry must not be expired because of local inactivity
1825 : */
1826 0 : new_static = zebra_evpn_mac_is_static(mac);
1827 0 : if (old_static != new_static)
1828 0 : inform_dataplane = true;
1829 :
1830 0 : old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(old_flags);
1831 0 : new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
1832 0 : if (old_bgp_ready != new_bgp_ready)
1833 0 : inform_bgp = true;
1834 : }
1835 :
1836 :
1837 : /* update sequence number; if that results in a new local sequence
1838 : * inform bgp
1839 : */
1840 0 : tmp_seq = MAX(mac->loc_seq, seq);
1841 0 : if (tmp_seq != mac->loc_seq) {
1842 0 : mac->loc_seq = tmp_seq;
1843 0 : seq_change = true;
1844 0 : inform_bgp = true;
1845 : }
1846 :
1847 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
1848 0 : char mac_buf[MAC_BUF_SIZE];
1849 :
1850 0 : zlog_debug("sync-mac %s vni %u mac %pEA es %s seq %d f %s%s%s",
1851 : created ? "created" : "updated", zevpn->vni, macaddr,
1852 : mac->es ? mac->es->esi_str : "-", mac->loc_seq,
1853 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
1854 : sizeof(mac_buf)),
1855 : inform_bgp ? "inform_bgp" : "",
1856 : inform_dataplane ? " inform_dp" : "");
1857 : }
1858 :
1859 0 : if (inform_bgp)
1860 0 : zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
1861 : new_bgp_ready);
1862 :
1863 : /* neighs using the mac may need to be re-sent to
1864 : * bgp with updated info
1865 : */
1866 0 : if (seq_change || es_change || !old_local)
1867 0 : zebra_evpn_process_neigh_on_local_mac_change(
1868 : zevpn, mac, seq_change, es_change);
1869 :
1870 0 : if (inform_dataplane && !ipa_len) {
1871 : /* program the local mac in the kernel. when the ES
1872 : * change we need to force the dataplane to reset
1873 : * the activity as we are yet to establish activity
1874 : * locally
1875 : */
1876 0 : zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
1877 : false /* force_clear_static */,
1878 : __func__);
1879 : }
1880 :
1881 : return mac;
1882 : }
1883 :
1884 : /* update local forwarding info. return true if a dest-ES change
1885 : * is detected
1886 : */
1887 0 : static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac *mac,
1888 : struct interface *ifp,
1889 : vlanid_t vid)
1890 : {
1891 0 : struct zebra_if *zif = ifp->info;
1892 0 : bool es_change;
1893 0 : ns_id_t local_ns_id = NS_DEFAULT;
1894 0 : struct zebra_vrf *zvrf;
1895 0 : struct zebra_evpn_es *es;
1896 :
1897 0 : zvrf = ifp->vrf->info;
1898 0 : if (zvrf && zvrf->zns)
1899 0 : local_ns_id = zvrf->zns->ns_id;
1900 :
1901 0 : zebra_evpn_mac_clear_fwd_info(mac);
1902 :
1903 0 : es = zif->es_info.es;
1904 0 : if (es && (es->flags & ZEBRA_EVPNES_BYPASS))
1905 0 : es = NULL;
1906 0 : es_change = zebra_evpn_es_mac_ref_entry(mac, es);
1907 :
1908 0 : if (!mac->es) {
1909 : /* if es is set fwd_info is not-relevant/taped-out */
1910 0 : mac->fwd_info.local.ifindex = ifp->ifindex;
1911 0 : mac->fwd_info.local.ns_id = local_ns_id;
1912 0 : mac->fwd_info.local.vid = vid;
1913 0 : zebra_evpn_mac_ifp_link(mac, ifp);
1914 : }
1915 :
1916 0 : return es_change;
1917 : }
1918 :
1919 : /* Notify Local MACs to the clienti, skips GW MAC */
1920 0 : static void zebra_evpn_send_mac_hash_entry_to_client(struct hash_bucket *bucket,
1921 : void *arg)
1922 : {
1923 0 : struct mac_walk_ctx *wctx = arg;
1924 0 : struct zebra_mac *zmac = bucket->data;
1925 :
1926 0 : if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_DEF_GW))
1927 : return;
1928 :
1929 0 : if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL))
1930 0 : zebra_evpn_mac_send_add_to_client(wctx->zevpn->vni,
1931 0 : &zmac->macaddr, zmac->flags,
1932 : zmac->loc_seq, zmac->es);
1933 : }
1934 :
1935 : /* Iterator to Notify Local MACs of a EVPN */
1936 0 : void zebra_evpn_send_mac_list_to_client(struct zebra_evpn *zevpn)
1937 : {
1938 0 : struct mac_walk_ctx wctx;
1939 :
1940 0 : if (!zevpn->mac_table)
1941 0 : return;
1942 :
1943 0 : memset(&wctx, 0, sizeof(wctx));
1944 0 : wctx.zevpn = zevpn;
1945 :
1946 0 : hash_iterate(zevpn->mac_table, zebra_evpn_send_mac_hash_entry_to_client,
1947 : &wctx);
1948 : }
1949 :
1950 0 : void zebra_evpn_rem_mac_del(struct zebra_evpn *zevpn, struct zebra_mac *mac)
1951 : {
1952 0 : zebra_evpn_process_neigh_on_remote_mac_del(zevpn, mac);
1953 : /* the remote sequence number in the auto mac entry
1954 : * needs to be reset to 0 as the mac entry may have
1955 : * been removed on all VTEPs (including
1956 : * the originating one)
1957 : */
1958 0 : mac->rem_seq = 0;
1959 :
1960 : /* If all remote neighbors referencing a remote MAC
1961 : * go away, we need to uninstall the MAC.
1962 : */
1963 0 : if (remote_neigh_count(mac) == 0) {
1964 0 : zebra_evpn_rem_mac_uninstall(zevpn, mac, false /*force*/);
1965 0 : zebra_evpn_es_mac_deref_entry(mac);
1966 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
1967 : }
1968 :
1969 0 : if (list_isempty(mac->neigh_list))
1970 0 : zebra_evpn_mac_del(zevpn, mac);
1971 : else
1972 0 : SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
1973 0 : }
1974 :
1975 : /* Print Duplicate MAC */
1976 0 : void zebra_evpn_print_dad_mac_hash(struct hash_bucket *bucket, void *ctxt)
1977 : {
1978 0 : struct zebra_mac *mac;
1979 :
1980 0 : mac = (struct zebra_mac *)bucket->data;
1981 0 : if (!mac)
1982 : return;
1983 :
1984 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
1985 0 : zebra_evpn_print_mac_hash(bucket, ctxt);
1986 : }
1987 :
1988 : /* Print Duplicate MAC in detail */
1989 0 : void zebra_evpn_print_dad_mac_hash_detail(struct hash_bucket *bucket,
1990 : void *ctxt)
1991 : {
1992 0 : struct zebra_mac *mac;
1993 :
1994 0 : mac = (struct zebra_mac *)bucket->data;
1995 0 : if (!mac)
1996 : return;
1997 :
1998 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
1999 0 : zebra_evpn_print_mac_hash_detail(bucket, ctxt);
2000 : }
2001 :
2002 0 : int zebra_evpn_mac_remote_macip_add(struct zebra_evpn *zevpn,
2003 : struct zebra_vrf *zvrf,
2004 : const struct ethaddr *macaddr,
2005 : struct in_addr vtep_ip, uint8_t flags,
2006 : uint32_t seq, const esi_t *esi)
2007 : {
2008 0 : bool sticky;
2009 0 : bool remote_gw;
2010 0 : int update_mac = 0;
2011 0 : bool do_dad = false;
2012 0 : bool is_dup_detect = false;
2013 0 : esi_t *old_esi;
2014 0 : bool old_static = false;
2015 0 : struct zebra_mac *mac;
2016 0 : bool old_es_present;
2017 0 : bool new_es_present;
2018 :
2019 0 : sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
2020 0 : remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
2021 :
2022 0 : mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2023 :
2024 : /* Ignore if the mac is already present as a gateway mac */
2025 0 : if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)
2026 0 : && CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) {
2027 0 : if (IS_ZEBRA_DEBUG_VXLAN)
2028 0 : zlog_debug(
2029 : "Ignore remote MACIP ADD VNI %u MAC %pEA as MAC is already configured as gateway MAC",
2030 : zevpn->vni, macaddr);
2031 0 : return -1;
2032 : }
2033 :
2034 0 : old_esi = (mac && mac->es) ? &mac->es->esi : zero_esi;
2035 :
2036 : /* check if the remote MAC is unknown or has a change.
2037 : * If so, that needs to be updated first. Note that client could
2038 : * install MAC and MACIP separately or just install the latter.
2039 : */
2040 0 : if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2041 0 : || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)
2042 0 : || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)
2043 0 : || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)
2044 0 : || memcmp(old_esi, esi, sizeof(esi_t)) || seq != mac->rem_seq)
2045 0 : update_mac = 1;
2046 :
2047 0 : if (update_mac) {
2048 0 : if (!mac) {
2049 0 : mac = zebra_evpn_mac_add(zevpn, macaddr);
2050 0 : zebra_evpn_es_mac_ref(mac, esi);
2051 : } else {
2052 : /* When host moves but changes its (MAC,IP)
2053 : * binding, BGP may install a MACIP entry that
2054 : * corresponds to "older" location of the host
2055 : * in transient situations (because {IP1,M1}
2056 : * is a different route from {IP1,M2}). Check
2057 : * the sequence number and ignore this update
2058 : * if appropriate.
2059 : */
2060 0 : if (!zebra_evpn_mac_is_bgp_seq_ok(zevpn, mac, seq,
2061 : false))
2062 : return -1;
2063 :
2064 0 : old_es_present = !!mac->es;
2065 0 : zebra_evpn_es_mac_ref(mac, esi);
2066 0 : new_es_present = !!mac->es;
2067 : /* XXX - dataplane is curently not able to handle a MAC
2068 : * replace if the destination changes from L2-NHG to
2069 : * single VTEP and vice-versa. So delete the old entry
2070 : * and re-install
2071 : */
2072 0 : if (old_es_present != new_es_present)
2073 0 : zebra_evpn_rem_mac_uninstall(zevpn, mac, false);
2074 : }
2075 :
2076 : /* Check MAC's curent state is local (this is the case
2077 : * where MAC has moved from L->R) and check previous
2078 : * detection started via local learning.
2079 : * RFC-7432: A PE/VTEP that detects a MAC mobility
2080 : * event via local learning starts an M-second timer.
2081 : *
2082 : * VTEP-IP or seq. change alone is not considered
2083 : * for dup. detection.
2084 : *
2085 : * MAC is already marked duplicate set dad, then
2086 : * is_dup_detect will be set to not install the entry.
2087 : */
2088 0 : if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2089 0 : && mac->dad_count)
2090 0 : || CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE))
2091 0 : do_dad = true;
2092 :
2093 : /* Remove local MAC from BGP. */
2094 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
2095 : /* force drop the sync flags */
2096 0 : old_static = zebra_evpn_mac_is_static(mac);
2097 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2098 0 : char mac_buf[MAC_BUF_SIZE];
2099 :
2100 0 : zlog_debug(
2101 : "sync-mac->remote vni %u mac %pEA es %s seq %d f %s",
2102 : zevpn->vni, macaddr,
2103 : mac->es ? mac->es->esi_str : "-",
2104 : mac->loc_seq,
2105 : zebra_evpn_zebra_mac_flag_dump(
2106 : mac, mac_buf, sizeof(mac_buf)));
2107 : }
2108 :
2109 0 : zebra_evpn_mac_clear_sync_info(mac);
2110 0 : zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr,
2111 : mac->flags,
2112 : false /* force */);
2113 : }
2114 :
2115 : /* Set "auto" and "remote" forwarding info. */
2116 0 : zebra_evpn_mac_clear_fwd_info(mac);
2117 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
2118 0 : SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
2119 0 : mac->fwd_info.r_vtep_ip = vtep_ip;
2120 :
2121 0 : if (sticky)
2122 0 : SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2123 : else
2124 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2125 :
2126 0 : if (remote_gw)
2127 0 : SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
2128 : else
2129 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW);
2130 :
2131 0 : zebra_evpn_dup_addr_detect_for_mac(
2132 : zvrf, mac, mac->fwd_info.r_vtep_ip, do_dad,
2133 : &is_dup_detect, false);
2134 :
2135 0 : if (!is_dup_detect) {
2136 0 : zebra_evpn_process_neigh_on_remote_mac_add(zevpn, mac);
2137 : /* Install the entry. */
2138 0 : zebra_evpn_rem_mac_install(zevpn, mac, old_static);
2139 : }
2140 : }
2141 :
2142 : /* Update seq number. */
2143 0 : mac->rem_seq = seq;
2144 :
2145 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2146 0 : return 0;
2147 : }
2148 :
2149 0 : int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf,
2150 : struct zebra_evpn *zevpn,
2151 : struct interface *ifp,
2152 : const struct ethaddr *macaddr, vlanid_t vid,
2153 : bool sticky, bool local_inactive,
2154 : bool dp_static, struct zebra_mac *mac)
2155 : {
2156 0 : bool mac_sticky = false;
2157 0 : bool inform_client = false;
2158 0 : bool upd_neigh = false;
2159 0 : bool is_dup_detect = false;
2160 0 : struct in_addr vtep_ip = {.s_addr = 0};
2161 0 : bool es_change = false;
2162 0 : bool new_bgp_ready;
2163 : /* assume inactive if not present or if not local */
2164 0 : bool old_local_inactive = true;
2165 0 : bool old_bgp_ready = false;
2166 0 : bool inform_dataplane = false;
2167 0 : bool new_static = false;
2168 :
2169 0 : assert(ifp);
2170 : /* Check if we need to create or update or it is a NO-OP. */
2171 0 : if (!mac)
2172 0 : mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2173 0 : if (!mac) {
2174 0 : if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2175 0 : zlog_debug(
2176 : "ADD %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s",
2177 : sticky ? "sticky " : "", macaddr,
2178 : ifp->name, ifp->ifindex, vid, zevpn->vni,
2179 : local_inactive ? " local-inactive" : "");
2180 :
2181 0 : mac = zebra_evpn_mac_add(zevpn, macaddr);
2182 0 : SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2183 0 : es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid);
2184 0 : if (sticky)
2185 0 : SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2186 : inform_client = true;
2187 : } else {
2188 0 : if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2189 0 : char mac_buf[MAC_BUF_SIZE];
2190 :
2191 0 : zlog_debug(
2192 : "UPD %sMAC %pEA intf %s(%u) VID %u -> VNI %u %scurFlags %s",
2193 : sticky ? "sticky " : "", macaddr,
2194 : ifp->name, ifp->ifindex, vid, zevpn->vni,
2195 : local_inactive ? "local-inactive " : "",
2196 : zebra_evpn_zebra_mac_flag_dump(
2197 : mac, mac_buf, sizeof(mac_buf)));
2198 : }
2199 :
2200 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
2201 0 : struct interface *old_ifp;
2202 0 : vlanid_t old_vid;
2203 0 : bool old_static;
2204 :
2205 0 : zebra_evpn_mac_get_access_info(mac, &old_ifp, &old_vid);
2206 0 : old_bgp_ready =
2207 0 : zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2208 0 : old_local_inactive =
2209 0 : !!(mac->flags & ZEBRA_MAC_LOCAL_INACTIVE);
2210 0 : old_static = zebra_evpn_mac_is_static(mac);
2211 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY))
2212 0 : mac_sticky = true;
2213 0 : es_change = zebra_evpn_local_mac_update_fwd_info(
2214 : mac, ifp, vid);
2215 :
2216 : /*
2217 : * Update any changes and if changes are relevant to
2218 : * BGP, note it.
2219 : */
2220 0 : if (mac_sticky == sticky && old_ifp == ifp
2221 0 : && old_vid == vid
2222 0 : && old_local_inactive == local_inactive
2223 0 : && dp_static == old_static && !es_change) {
2224 0 : if (IS_ZEBRA_DEBUG_VXLAN)
2225 0 : zlog_debug(
2226 : " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, "
2227 : "entry exists and has not changed ",
2228 : sticky ? "sticky " : "",
2229 : macaddr, ifp->name,
2230 : ifp->ifindex, vid, zevpn->vni,
2231 : local_inactive
2232 : ? " local_inactive"
2233 : : "");
2234 0 : return 0;
2235 : }
2236 0 : if (mac_sticky != sticky) {
2237 0 : if (sticky)
2238 0 : SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2239 : else
2240 0 : UNSET_FLAG(mac->flags,
2241 : ZEBRA_MAC_STICKY);
2242 : inform_client = true;
2243 : }
2244 :
2245 : /* If an es_change is detected we need to advertise
2246 : * the route with a sequence that is one
2247 : * greater. This is need to indicate a mac-move
2248 : * to the ES peers
2249 : */
2250 0 : if (es_change) {
2251 : /* update the sequence number only if the entry
2252 : * is locally active
2253 : */
2254 0 : if (!local_inactive)
2255 0 : mac->loc_seq = mac->loc_seq + 1;
2256 : /* force drop the peer/sync info as it is
2257 : * simply no longer relevant
2258 : */
2259 0 : if (CHECK_FLAG(mac->flags,
2260 : ZEBRA_MAC_ALL_PEER_FLAGS)) {
2261 0 : zebra_evpn_mac_clear_sync_info(mac);
2262 0 : new_static =
2263 0 : zebra_evpn_mac_is_static(mac);
2264 : /* if we clear peer-flags we
2265 : * also need to notify the dataplane
2266 : * to drop the static flag
2267 : */
2268 0 : if (old_static != new_static)
2269 0 : inform_dataplane = true;
2270 : }
2271 : }
2272 0 : } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
2273 0 : || CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) {
2274 0 : bool do_dad = false;
2275 :
2276 : /*
2277 : * MAC has either moved or was "internally" created due
2278 : * to a neighbor learn and is now actually learnt. If
2279 : * it was learnt as a remote sticky MAC, this is an
2280 : * operator error.
2281 : */
2282 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) {
2283 0 : flog_warn(
2284 : EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT,
2285 : "MAC %pEA already learnt as remote sticky MAC behind VTEP %pI4 VNI %u",
2286 : macaddr,
2287 : &mac->fwd_info.r_vtep_ip,
2288 : zevpn->vni);
2289 0 : return 0;
2290 : }
2291 :
2292 : /* If an actual move, compute MAC's seq number */
2293 0 : if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) {
2294 0 : mac->loc_seq =
2295 0 : MAX(mac->rem_seq + 1, mac->loc_seq);
2296 0 : vtep_ip = mac->fwd_info.r_vtep_ip;
2297 : /* Trigger DAD for remote MAC */
2298 0 : do_dad = true;
2299 : }
2300 :
2301 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE);
2302 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2303 0 : SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2304 0 : es_change = zebra_evpn_local_mac_update_fwd_info(
2305 : mac, ifp, vid);
2306 0 : if (sticky)
2307 0 : SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2308 : else
2309 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2310 : /*
2311 : * We have to inform BGP of this MAC as well as process
2312 : * all neighbors.
2313 : */
2314 0 : inform_client = true;
2315 0 : upd_neigh = true;
2316 :
2317 0 : zebra_evpn_dup_addr_detect_for_mac(
2318 : zvrf, mac, vtep_ip, do_dad, &is_dup_detect,
2319 : true);
2320 0 : if (is_dup_detect) {
2321 0 : inform_client = false;
2322 0 : upd_neigh = false;
2323 0 : es_change = false;
2324 : }
2325 : }
2326 : }
2327 :
2328 : /* if the dataplane thinks the entry is sync but it is
2329 : * not sync in zebra (or vice-versa) we need to re-install
2330 : * to fixup
2331 : */
2332 0 : new_static = zebra_evpn_mac_is_static(mac);
2333 0 : if (dp_static != new_static)
2334 0 : inform_dataplane = true;
2335 :
2336 0 : if (local_inactive)
2337 0 : SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2338 : else
2339 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2340 :
2341 0 : new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2342 : /* if local-activity has changed we need update bgp
2343 : * even if bgp already knows about the mac
2344 : */
2345 0 : if ((old_local_inactive != local_inactive)
2346 0 : || (new_bgp_ready != old_bgp_ready)) {
2347 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2348 0 : char mac_buf[MAC_BUF_SIZE];
2349 :
2350 0 : zlog_debug(
2351 : "local mac vni %u mac %pEA es %s seq %d f %s%s",
2352 : zevpn->vni, macaddr,
2353 : mac->es ? mac->es->esi_str : "", mac->loc_seq,
2354 : zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
2355 : sizeof(mac_buf)),
2356 : local_inactive ? "local-inactive" : "");
2357 : }
2358 :
2359 0 : if (!is_dup_detect)
2360 0 : inform_client = true;
2361 : }
2362 :
2363 0 : if (es_change) {
2364 0 : inform_client = true;
2365 0 : upd_neigh = true;
2366 : }
2367 :
2368 : /* Inform dataplane if required. */
2369 0 : if (inform_dataplane)
2370 0 : zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */,
2371 : false /* force_clear_static */,
2372 : __func__);
2373 :
2374 : /* Inform BGP if required. */
2375 0 : if (inform_client)
2376 0 : zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2377 : new_bgp_ready);
2378 :
2379 : /* Process all neighbors associated with this MAC, if required. */
2380 0 : if (upd_neigh)
2381 0 : zebra_evpn_process_neigh_on_local_mac_change(zevpn, mac, 0,
2382 : es_change);
2383 :
2384 : return 0;
2385 : }
2386 :
2387 0 : int zebra_evpn_del_local_mac(struct zebra_evpn *zevpn, struct zebra_mac *mac,
2388 : bool clear_static)
2389 : {
2390 0 : bool old_bgp_ready;
2391 0 : bool new_bgp_ready;
2392 :
2393 0 : if (IS_ZEBRA_DEBUG_VXLAN)
2394 0 : zlog_debug("DEL MAC %pEA VNI %u seq %u flags 0x%x nbr count %u",
2395 : &mac->macaddr, zevpn->vni, mac->loc_seq, mac->flags,
2396 : listcount(mac->neigh_list));
2397 :
2398 0 : old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2399 0 : if (!clear_static && zebra_evpn_mac_is_static(mac)) {
2400 : /* this is a synced entry and can only be removed when the
2401 : * es-peers stop advertising it.
2402 : */
2403 0 : zebra_evpn_mac_clear_fwd_info(mac);
2404 :
2405 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
2406 0 : char mac_buf[MAC_BUF_SIZE];
2407 :
2408 0 : zlog_debug(
2409 : "re-add sync-mac vni %u mac %pEA es %s seq %d f %s",
2410 : zevpn->vni, &mac->macaddr,
2411 : mac->es ? mac->es->esi_str : "-", mac->loc_seq,
2412 : zebra_evpn_zebra_mac_flag_dump(
2413 : mac, mac_buf, sizeof(mac_buf)));
2414 : }
2415 :
2416 : /* inform-bgp about change in local-activity if any */
2417 0 : if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
2418 0 : SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE);
2419 0 : new_bgp_ready =
2420 0 : zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2421 0 : zebra_evpn_mac_send_add_del_to_client(
2422 : mac, old_bgp_ready, new_bgp_ready);
2423 : }
2424 :
2425 : /* re-install the inactive entry in the kernel */
2426 0 : zebra_evpn_sync_mac_dp_install(mac, true /* set_inactive */,
2427 : false /* force_clear_static */,
2428 : __func__);
2429 :
2430 0 : return 0;
2431 : }
2432 :
2433 : /* flush the peer info */
2434 0 : zebra_evpn_mac_clear_sync_info(mac);
2435 :
2436 : /* Update all the neigh entries associated with this mac */
2437 0 : zebra_evpn_process_neigh_on_local_mac_del(zevpn, mac);
2438 :
2439 : /* Remove MAC from BGP. */
2440 0 : zebra_evpn_mac_send_del_to_client(zevpn->vni, &mac->macaddr, mac->flags,
2441 : false /* force */);
2442 :
2443 0 : zebra_evpn_es_mac_deref_entry(mac);
2444 :
2445 : /* remove links to the destination access port */
2446 0 : zebra_evpn_mac_clear_fwd_info(mac);
2447 :
2448 : /*
2449 : * If there are no neigh associated with the mac delete the mac
2450 : * else mark it as AUTO for forward reference
2451 : */
2452 0 : if (!listcount(mac->neigh_list)) {
2453 0 : zebra_evpn_mac_del(zevpn, mac);
2454 : } else {
2455 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_ALL_LOCAL_FLAGS);
2456 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
2457 0 : SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2458 : }
2459 :
2460 : return 0;
2461 : }
2462 :
2463 0 : void zebra_evpn_mac_gw_macip_add(struct interface *ifp,
2464 : struct zebra_evpn *zevpn,
2465 : const struct ipaddr *ip,
2466 : struct zebra_mac **macp,
2467 : const struct ethaddr *macaddr,
2468 : vlanid_t vlan_id, bool def_gw)
2469 : {
2470 0 : struct zebra_mac *mac;
2471 0 : ns_id_t local_ns_id = NS_DEFAULT;
2472 0 : struct zebra_vrf *zvrf;
2473 :
2474 0 : zvrf = ifp->vrf->info;
2475 0 : if (zvrf && zvrf->zns)
2476 0 : local_ns_id = zvrf->zns->ns_id;
2477 :
2478 0 : if (!*macp) {
2479 0 : mac = zebra_evpn_mac_lookup(zevpn, macaddr);
2480 0 : if (!mac)
2481 0 : mac = zebra_evpn_mac_add(zevpn, macaddr);
2482 0 : *macp = mac;
2483 : } else
2484 : mac = *macp;
2485 :
2486 : /* Set "local" forwarding info. */
2487 0 : zebra_evpn_mac_clear_fwd_info(mac);
2488 0 : SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
2489 0 : SET_FLAG(mac->flags, ZEBRA_MAC_AUTO);
2490 0 : if (def_gw)
2491 0 : SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
2492 : else
2493 0 : SET_FLAG(mac->flags, ZEBRA_MAC_SVI);
2494 0 : mac->fwd_info.local.ifindex = ifp->ifindex;
2495 0 : mac->fwd_info.local.ns_id = local_ns_id;
2496 0 : mac->fwd_info.local.vid = vlan_id;
2497 0 : }
2498 :
2499 0 : void zebra_evpn_mac_svi_del(struct interface *ifp, struct zebra_evpn *zevpn)
2500 : {
2501 0 : struct zebra_mac *mac;
2502 0 : struct ethaddr macaddr;
2503 0 : bool old_bgp_ready;
2504 :
2505 0 : if (!zebra_evpn_mh_do_adv_svi_mac())
2506 0 : return;
2507 :
2508 0 : memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
2509 0 : mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
2510 0 : if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) {
2511 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2512 0 : zlog_debug("SVI %s mac free", ifp->name);
2513 :
2514 0 : old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2515 0 : UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI);
2516 0 : zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2517 : false);
2518 0 : zebra_evpn_deref_ip2mac(mac->zevpn, mac);
2519 : }
2520 : }
2521 :
2522 0 : void zebra_evpn_mac_svi_add(struct interface *ifp, struct zebra_evpn *zevpn)
2523 : {
2524 0 : struct zebra_mac *mac = NULL;
2525 0 : struct ethaddr macaddr;
2526 0 : struct zebra_if *zif = ifp->info;
2527 0 : bool old_bgp_ready;
2528 0 : bool new_bgp_ready;
2529 :
2530 0 : if (!zebra_evpn_mh_do_adv_svi_mac()
2531 0 : || !zebra_evpn_send_to_client_ok(zevpn))
2532 0 : return;
2533 :
2534 0 : memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN);
2535 :
2536 : /* dup check */
2537 0 : mac = zebra_evpn_mac_lookup(zevpn, &macaddr);
2538 0 : if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI))
2539 : return;
2540 :
2541 : /* add/update mac */
2542 0 : if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2543 0 : zlog_debug("SVI %s mac add", zif->ifp->name);
2544 :
2545 0 : old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags))
2546 : ? true
2547 0 : : false;
2548 :
2549 0 : zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false);
2550 :
2551 0 : new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
2552 0 : zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
2553 : new_bgp_ready);
2554 : }
|