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