Coverage Report

Created: 2025-08-28 06:29

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