Coverage Report

Created: 2026-04-27 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/zebra/zebra_evpn_mh.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Zebra EVPN multihoming code
4
 *
5
 * Copyright (C) 2019 Cumulus Networks, Inc.
6
 * Anuradha Karuppiah
7
 */
8
9
#include <zebra.h>
10
11
#include "command.h"
12
#include "hash.h"
13
#include "if.h"
14
#include "jhash.h"
15
#include "linklist.h"
16
#include "log.h"
17
#include "memory.h"
18
#include "prefix.h"
19
#include "stream.h"
20
#include "table.h"
21
#include "vlan.h"
22
#include "vxlan.h"
23
24
#include "zebra/zebra_router.h"
25
#include "zebra/debug.h"
26
#include "zebra/interface.h"
27
#include "zebra/rib.h"
28
#include "zebra/rt.h"
29
#include "zebra/rt_netlink.h"
30
#include "zebra/if_netlink.h"
31
#include "zebra/zebra_errors.h"
32
#include "zebra/zebra_l2.h"
33
#include "zebra/zebra_l2_bridge_if.h"
34
#include "zebra/zebra_ns.h"
35
#include "zebra/zebra_vrf.h"
36
#include "zebra/zebra_vxlan.h"
37
#include "zebra/zebra_vxlan_private.h"
38
#include "zebra/zebra_evpn.h"
39
#include "zebra/zebra_evpn_mac.h"
40
#include "zebra/zebra_router.h"
41
#include "zebra/zebra_evpn_mh.h"
42
#include "zebra/zebra_nhg.h"
43
44
2
DEFINE_MTYPE_STATIC(ZEBRA, ZACC_BD, "Access Broadcast Domain");
45
2
DEFINE_MTYPE_STATIC(ZEBRA, ZES, "Ethernet Segment");
46
2
DEFINE_MTYPE_STATIC(ZEBRA, ZES_EVI, "ES info per-EVI");
47
2
DEFINE_MTYPE_STATIC(ZEBRA, ZMH_INFO, "MH global info");
48
2
DEFINE_MTYPE_STATIC(ZEBRA, ZES_VTEP, "VTEP attached to the ES");
49
2
DEFINE_MTYPE_STATIC(ZEBRA, L2_NH, "L2 nexthop");
50
2
51
2
static void zebra_evpn_es_get_one_base_evpn(void);
52
2
static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
53
2
              struct zebra_evpn *zevpn, bool add);
54
2
static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp);
55
2
static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi);
56
2
static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
57
2
            const char *caller);
58
2
static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set);
59
2
static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
60
2
                bool resync_dplane);
61
2
static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es);
62
2
static void zebra_evpn_mh_startup_delay_timer_start(const char *rc);
63
2
64
2
esi_t zero_esi_buf, *zero_esi = &zero_esi_buf;
65
2
66
2
/*****************************************************************************/
67
2
/* Ethernet Segment to EVI association -
68
2
 * 1. The ES-EVI entry is maintained as a RB tree per L2-VNI
69
2
 * (struct zebra_evpn.es_evi_rb_tree).
70
2
 * 2. Each local ES-EVI entry is sent to BGP which advertises it as an
71
2
 * EAD-EVI (Type-1 EVPN) route
72
2
 * 3. Local ES-EVI setup is re-evaluated on the following triggers -
73
2
 *    a. When an ESI is set or cleared on an access port.
74
2
 *    b. When an access port associated with an ESI is deleted.
75
2
 *    c. When VLAN member ship changes on an access port.
76
2
 *    d. When a VXLAN_IF is set or cleared on an access broadcast domain.
77
2
 *    e. When a L2-VNI is added or deleted for a VxLAN_IF.
78
2
 * 4. Currently zebra doesn't remote ES-EVIs. Those are managed and maintained
79
2
 * entirely in BGP which consolidates them into a remote ES. The remote ES
80
2
 * is then sent to zebra which allocates a NHG for it.
81
2
 */
82
2
83
2
/* compare ES-IDs for the ES-EVI RB tree maintained per-EVPN */
84
2
static int zebra_es_evi_rb_cmp(const struct zebra_evpn_es_evi *es_evi1,
85
2
    const struct zebra_evpn_es_evi *es_evi2)
86
2
{
87
0
  return memcmp(&es_evi1->es->esi, &es_evi2->es->esi, ESI_BYTES);
88
0
}
89
RB_GENERATE(zebra_es_evi_rb_head, zebra_evpn_es_evi,
90
    rb_node, zebra_es_evi_rb_cmp);
91
92
/* allocate a new ES-EVI and insert it into the per-L2-VNI and per-ES
93
 * tables.
94
 */
95
static struct zebra_evpn_es_evi *zebra_evpn_es_evi_new(struct zebra_evpn_es *es,
96
                   struct zebra_evpn *zevpn)
97
0
{
98
0
  struct zebra_evpn_es_evi *es_evi;
99
100
0
  es_evi = XCALLOC(MTYPE_ZES_EVI, sizeof(struct zebra_evpn_es_evi));
101
102
0
  es_evi->es = es;
103
0
  es_evi->zevpn = zevpn;
104
105
  /* insert into the EVPN-ESI rb tree */
106
0
  RB_INSERT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi);
107
108
  /* add to the ES's VNI list */
109
0
  listnode_init(&es_evi->es_listnode, es_evi);
110
0
  listnode_add(es->es_evi_list, &es_evi->es_listnode);
111
112
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
113
0
    zlog_debug("es %s evi %d new",
114
0
        es_evi->es->esi_str, es_evi->zevpn->vni);
115
116
0
  return es_evi;
117
0
}
118
119
/* Evaluate if the es_evi is ready to be sent BGP -
120
 * 1. If it is ready an add is sent to BGP
121
 * 2. If it is not ready a del is sent (if the ES had been previously added
122
 *   to BGP).
123
 */
124
static void zebra_evpn_es_evi_re_eval_send_to_client(
125
    struct zebra_evpn_es_evi *es_evi)
126
0
{
127
0
  bool old_ready;
128
0
  bool new_ready;
129
130
0
  old_ready = !!(es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP);
131
132
  /* ES and L2-VNI have to be individually ready for BGP */
133
0
  if ((es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) &&
134
0
      (es_evi->es->flags & ZEBRA_EVPNES_READY_FOR_BGP) &&
135
0
      zebra_evpn_send_to_client_ok(es_evi->zevpn))
136
0
    es_evi->flags |= ZEBRA_EVPNES_EVI_READY_FOR_BGP;
137
0
  else
138
0
    es_evi->flags &= ~ZEBRA_EVPNES_EVI_READY_FOR_BGP;
139
140
0
  new_ready = !!(es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP);
141
142
0
  if (old_ready == new_ready)
143
0
    return;
144
145
0
  if (new_ready)
146
0
    zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
147
0
        true /* add */);
148
0
  else
149
0
    zebra_evpn_es_evi_send_to_client(es_evi->es, es_evi->zevpn,
150
0
        false /* add */);
151
0
}
152
153
/* remove the ES-EVI from the per-L2-VNI and per-ES tables and free
154
 * up the memory.
155
 */
156
static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi *es_evi)
157
0
{
158
0
  struct zebra_evpn_es *es = es_evi->es;
159
0
  struct zebra_evpn *zevpn = es_evi->zevpn;
160
161
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
162
0
    zlog_debug("es %s evi %d free",
163
0
        es_evi->es->esi_str, es_evi->zevpn->vni);
164
165
  /* remove from the ES's VNI list */
166
0
  list_delete_node(es->es_evi_list, &es_evi->es_listnode);
167
168
  /* remove from the VNI-ESI rb tree */
169
0
  RB_REMOVE(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, es_evi);
170
171
  /* remove from the VNI-ESI rb tree */
172
0
  XFREE(MTYPE_ZES_EVI, es_evi);
173
0
}
174
175
/* find the ES-EVI in the per-L2-VNI RB tree */
176
struct zebra_evpn_es_evi *zebra_evpn_es_evi_find(struct zebra_evpn_es *es,
177
             struct zebra_evpn *zevpn)
178
0
{
179
0
  struct zebra_evpn_es_evi es_evi;
180
181
0
  es_evi.es = es;
182
183
0
  return RB_FIND(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree, &es_evi);
184
0
}
185
186
/* Tell BGP about an ES-EVI deletion and then delete it */
187
static void zebra_evpn_local_es_evi_do_del(struct zebra_evpn_es_evi *es_evi)
188
0
{
189
0
  if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
190
0
    return;
191
192
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
193
0
    zlog_debug("local es %s evi %d del",
194
0
        es_evi->es->esi_str, es_evi->zevpn->vni);
195
196
0
  if (es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP) {
197
    /* send a del only if add was sent for it earlier */
198
0
    zebra_evpn_es_evi_send_to_client(es_evi->es,
199
0
        es_evi->zevpn, false /* add */);
200
0
  }
201
202
  /* delete it from the EVPN's local list */
203
0
  list_delete_node(es_evi->zevpn->local_es_evi_list,
204
0
      &es_evi->l2vni_listnode);
205
206
0
  es_evi->flags &= ~ZEBRA_EVPNES_EVI_LOCAL;
207
0
  zebra_evpn_es_evi_free(es_evi);
208
0
}
209
static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es *es,
210
          struct zebra_evpn *zevpn)
211
0
{
212
0
  struct zebra_evpn_es_evi *es_evi;
213
214
0
  es_evi = zebra_evpn_es_evi_find(es, zevpn);
215
0
  if (es_evi)
216
0
    zebra_evpn_local_es_evi_do_del(es_evi);
217
0
}
218
219
/* If there are any existing MAC entries for this es/zevpn we need
220
 * to install it in the dataplane.
221
 *
222
 * Note: primary purpose of this is to handle es del/re-add windows where
223
 * sync MAC entries may be added by bgpd before the es-evi membership is
224
 * created in the dataplane and in zebra
225
 */
226
static void zebra_evpn_es_evi_mac_install(struct zebra_evpn_es_evi *es_evi)
227
0
{
228
0
  struct zebra_mac *mac;
229
0
  struct listnode *node;
230
0
  struct zebra_evpn_es *es = es_evi->es;
231
232
0
  if (listcount(es->mac_list) && IS_ZEBRA_DEBUG_EVPN_MH_ES)
233
0
    zlog_debug("dp-mac install on es %s evi %d add", es->esi_str,
234
0
         es_evi->zevpn->vni);
235
236
0
  for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
237
0
    if (mac->zevpn != es_evi->zevpn)
238
0
      continue;
239
240
0
    if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
241
0
      continue;
242
243
0
    zebra_evpn_sync_mac_dp_install(mac, false, false, __func__);
244
0
  }
245
0
}
246
247
/* Create an ES-EVI if it doesn't already exist and tell BGP */
248
static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es *es,
249
          struct zebra_evpn *zevpn)
250
0
{
251
0
  struct zebra_evpn_es_evi *es_evi;
252
253
0
  es_evi = zebra_evpn_es_evi_find(es, zevpn);
254
0
  if (!es_evi) {
255
0
    es_evi = zebra_evpn_es_evi_new(es, zevpn);
256
0
    if (!es_evi)
257
0
      return;
258
259
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
260
0
      zlog_debug("local es %s evi %d add",
261
0
          es_evi->es->esi_str, es_evi->zevpn->vni);
262
0
    es_evi->flags |= ZEBRA_EVPNES_EVI_LOCAL;
263
    /* add to the EVPN's local list */
264
0
    listnode_init(&es_evi->l2vni_listnode, es_evi);
265
0
    listnode_add(zevpn->local_es_evi_list, &es_evi->l2vni_listnode);
266
267
0
    zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
268
269
0
    zebra_evpn_es_evi_mac_install(es_evi);
270
0
  }
271
0
}
272
273
static void zebra_evpn_es_evi_show_entry(struct vty *vty,
274
           struct zebra_evpn_es_evi *es_evi,
275
           json_object *json_array)
276
0
{
277
0
  char type_str[4];
278
279
0
  if (json_array) {
280
0
    json_object *json;
281
0
    json_object *json_types;
282
283
    /* Separate JSON object for each es-evi entry */
284
0
    json = json_object_new_object();
285
286
0
    json_object_string_add(json, "esi", es_evi->es->esi_str);
287
0
    json_object_int_add(json, "vni", es_evi->zevpn->vni);
288
0
    if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL) {
289
0
      json_types = json_object_new_array();
290
0
      if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
291
0
        json_array_string_add(json_types, "local");
292
0
      json_object_object_add(json, "type", json_types);
293
0
    }
294
295
    /* Add es-evi entry to json array */
296
0
    json_object_array_add(json_array, json);
297
0
  } else {
298
0
    type_str[0] = '\0';
299
0
    if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
300
0
      strlcat(type_str, "L", sizeof(type_str));
301
302
0
    vty_out(vty, "%-8d %-30s %-4s\n",
303
0
        es_evi->zevpn->vni, es_evi->es->esi_str,
304
0
        type_str);
305
0
  }
306
0
}
307
308
static void
309
zebra_evpn_es_evi_show_entry_detail(struct vty *vty,
310
            struct zebra_evpn_es_evi *es_evi,
311
            json_object *json_array)
312
0
{
313
0
  char type_str[4];
314
315
0
  if (json_array) {
316
0
    json_object *json;
317
0
    json_object *json_flags;
318
319
    /* Separate JSON object for each es-evi entry */
320
0
    json = json_object_new_object();
321
322
0
    json_object_string_add(json, "esi", es_evi->es->esi_str);
323
0
    json_object_int_add(json, "vni", es_evi->zevpn->vni);
324
0
    if (es_evi->flags
325
0
        & (ZEBRA_EVPNES_EVI_LOCAL
326
0
           | ZEBRA_EVPNES_EVI_READY_FOR_BGP)) {
327
0
      json_flags = json_object_new_array();
328
0
      if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
329
0
        json_array_string_add(json_flags, "local");
330
0
      if (es_evi->flags & ZEBRA_EVPNES_EVI_READY_FOR_BGP)
331
0
        json_array_string_add(json_flags,
332
0
                  "readyForBgp");
333
0
      json_object_object_add(json, "flags", json_flags);
334
0
    }
335
336
    /* Add es-evi entry to json array */
337
0
    json_object_array_add(json_array, json);
338
0
  } else {
339
0
    type_str[0] = '\0';
340
0
    if (es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL)
341
0
      strlcat(type_str, "L", sizeof(type_str));
342
343
0
    vty_out(vty, "VNI %d ESI: %s\n",
344
0
        es_evi->zevpn->vni, es_evi->es->esi_str);
345
0
    vty_out(vty, " Type: %s\n", type_str);
346
0
    vty_out(vty, " Ready for BGP: %s\n",
347
0
        (es_evi->flags &
348
0
         ZEBRA_EVPNES_EVI_READY_FOR_BGP) ?
349
0
        "yes" : "no");
350
0
    vty_out(vty, "\n");
351
0
  }
352
0
}
353
354
static void zebra_evpn_es_evi_show_one_evpn(struct zebra_evpn *zevpn,
355
              struct vty *vty,
356
              json_object *json_array, int detail)
357
0
{
358
0
  struct zebra_evpn_es_evi *es_evi;
359
360
0
  RB_FOREACH(es_evi, zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree) {
361
0
    if (detail)
362
0
      zebra_evpn_es_evi_show_entry_detail(vty, es_evi,
363
0
                  json_array);
364
0
    else
365
0
      zebra_evpn_es_evi_show_entry(vty, es_evi, json_array);
366
0
  }
367
0
}
368
369
struct evpn_mh_show_ctx {
370
  struct vty *vty;
371
  json_object *json;
372
  int detail;
373
};
374
375
static void zebra_evpn_es_evi_show_one_evpn_hash_cb(struct hash_bucket *bucket,
376
    void *ctxt)
377
0
{
378
0
  struct zebra_evpn *zevpn = (struct zebra_evpn *)bucket->data;
379
0
  struct evpn_mh_show_ctx *wctx = (struct evpn_mh_show_ctx *)ctxt;
380
381
0
  zebra_evpn_es_evi_show_one_evpn(zevpn, wctx->vty,
382
0
      wctx->json, wctx->detail);
383
0
}
384
385
void zebra_evpn_es_evi_show(struct vty *vty, bool uj, int detail)
386
0
{
387
0
  json_object *json_array = NULL;
388
0
  struct zebra_vrf *zvrf;
389
0
  struct evpn_mh_show_ctx wctx;
390
391
0
  zvrf = zebra_vrf_get_evpn();
392
0
  if (uj)
393
0
    json_array = json_object_new_array();
394
395
0
  memset(&wctx, 0, sizeof(wctx));
396
0
  wctx.vty = vty;
397
0
  wctx.json = json_array;
398
0
  wctx.detail = detail;
399
400
0
  if (!detail && !json_array) {
401
0
    vty_out(vty, "Type: L local, R remote\n");
402
0
    vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
403
0
  }
404
  /* Display all L2-VNIs */
405
0
  hash_iterate(zvrf->evpn_table, zebra_evpn_es_evi_show_one_evpn_hash_cb,
406
0
      &wctx);
407
408
0
  if (uj)
409
0
    vty_json(vty, json_array);
410
0
}
411
412
void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
413
0
{
414
0
  json_object *json_array = NULL;
415
0
  struct zebra_evpn *zevpn;
416
417
0
  zevpn = zebra_evpn_lookup(vni);
418
0
  if (uj)
419
0
    json_array = json_object_new_array();
420
421
0
  if (zevpn) {
422
0
    if (!detail && !json_array) {
423
0
      vty_out(vty, "Type: L local, R remote\n");
424
0
      vty_out(vty, "%-8s %-30s %-4s\n", "VNI", "ESI", "Type");
425
0
    }
426
0
    zebra_evpn_es_evi_show_one_evpn(zevpn, vty, json_array, detail);
427
0
  } else {
428
0
    if (!uj)
429
0
      vty_out(vty, "VNI %d doesn't exist\n", vni);
430
0
  }
431
432
0
  if (uj)
433
0
    vty_json(vty, json_array);
434
0
}
435
436
/* Initialize the ES tables maintained per-L2_VNI */
437
void zebra_evpn_es_evi_init(struct zebra_evpn *zevpn)
438
0
{
439
  /* Initialize the ES-EVI RB tree */
440
0
  RB_INIT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree);
441
442
  /* Initialize the local and remote ES lists maintained for quick
443
   * walks by type
444
   */
445
0
  zevpn->local_es_evi_list = list_new();
446
0
  listset_app_node_mem(zevpn->local_es_evi_list);
447
0
}
448
449
/* Cleanup the ES info maintained per- EVPN */
450
void zebra_evpn_es_evi_cleanup(struct zebra_evpn *zevpn)
451
0
{
452
0
  struct zebra_evpn_es_evi *es_evi;
453
0
  struct zebra_evpn_es_evi *es_evi_next;
454
455
0
  RB_FOREACH_SAFE(es_evi, zebra_es_evi_rb_head,
456
0
      &zevpn->es_evi_rb_tree, es_evi_next) {
457
0
    zebra_evpn_local_es_evi_do_del(es_evi);
458
0
  }
459
460
0
  list_delete(&zevpn->local_es_evi_list);
461
0
  zebra_evpn_es_clear_base_evpn(zevpn);
462
0
}
463
464
/* called when the oper state or bridge membership changes for the
465
 * vxlan device
466
 */
467
void zebra_evpn_update_all_es(struct zebra_evpn *zevpn)
468
0
{
469
0
  struct zebra_evpn_es_evi *es_evi;
470
0
  struct listnode *node;
471
0
  struct interface *vlan_if;
472
0
  struct interface *vxlan_if;
473
0
  struct zebra_if *vxlan_zif;
474
0
  struct zebra_vxlan_vni *vni;
475
476
  /* the EVPN is now elgible as a base for EVPN-MH */
477
0
  if (zebra_evpn_send_to_client_ok(zevpn))
478
0
    zebra_evpn_es_set_base_evpn(zevpn);
479
0
  else
480
0
    zebra_evpn_es_clear_base_evpn(zevpn);
481
482
0
  for (ALL_LIST_ELEMENTS_RO(zevpn->local_es_evi_list, node, es_evi))
483
0
    zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
484
485
  /* reinstall SVI MAC */
486
0
  vxlan_if = zevpn->vxlan_if;
487
0
  if (vxlan_if) {
488
0
    vxlan_zif = vxlan_if->info;
489
0
    if (if_is_operative(vxlan_if)
490
0
        && vxlan_zif->brslave_info.br_if) {
491
0
      vni = zebra_vxlan_if_vni_find(vxlan_zif, zevpn->vni);
492
      /* VLAN-VNI mappings may not exist */
493
0
      if (vni) {
494
0
        vlan_if = zvni_map_to_svi(
495
0
          vni->access_vlan,
496
0
          vxlan_zif->brslave_info.br_if);
497
0
        if (vlan_if)
498
0
          zebra_evpn_acc_bd_svi_mac_add(vlan_if);
499
0
      }
500
0
    }
501
0
  }
502
0
}
503
504
/*****************************************************************************/
505
/* Access broadcast domains (BD)
506
 * 1. These broadcast domains can be VLAN aware (in which case
507
 * the key is VID) or VLAN unaware (in which case the key is
508
 * 2. A VID-BD is created when a VLAN is associated with an access port or
509
 *    when the VLAN is associated with VXLAN_IF
510
 * 3. A BD is translated into ES-EVI entries when a VNI is associated
511
 *  with the broadcast domain
512
 */
513
/* Hash key for VLAN based broadcast domains */
514
static unsigned int zebra_evpn_acc_vl_hash_keymake(const void *p)
515
0
{
516
0
  const struct zebra_evpn_access_bd *acc_bd = p;
517
518
0
  return jhash_2words(acc_bd->vid, acc_bd->bridge_ifindex, 0);
519
0
}
520
521
/* Compare two VLAN based broadcast domains */
522
static bool zebra_evpn_acc_vl_cmp(const void *p1, const void *p2)
523
0
{
524
0
  const struct zebra_evpn_access_bd *acc_bd1 = p1;
525
0
  const struct zebra_evpn_access_bd *acc_bd2 = p2;
526
527
0
  if (acc_bd1 == NULL && acc_bd2 == NULL)
528
0
    return true;
529
530
0
  if (acc_bd1 == NULL || acc_bd2 == NULL)
531
0
    return false;
532
533
0
  return ((acc_bd1->vid == acc_bd2->vid) &&
534
0
    (acc_bd1->bridge_ifindex == acc_bd2->bridge_ifindex));
535
0
}
536
537
/* Lookup VLAN based broadcast domain */
538
struct zebra_evpn_access_bd *
539
zebra_evpn_acc_vl_find_index(vlanid_t vid, ifindex_t bridge_ifindex)
540
0
{
541
0
  struct zebra_evpn_access_bd *acc_bd;
542
0
  struct zebra_evpn_access_bd tmp;
543
544
0
  tmp.vid = vid;
545
0
  tmp.bridge_ifindex = bridge_ifindex;
546
0
  acc_bd = hash_lookup(zmh_info->evpn_vlan_table, &tmp);
547
548
0
  return acc_bd;
549
0
}
550
551
/* Lookup VLAN based broadcast domain */
552
struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid,
553
                struct interface *br_if)
554
0
{
555
0
  return zebra_evpn_acc_vl_find_index(vid, br_if->ifindex);
556
0
}
557
558
/* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF
559
 * mapping is added.
560
 */
561
static struct zebra_evpn_access_bd *
562
zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if)
563
0
{
564
0
  struct zebra_evpn_access_bd *acc_bd;
565
0
  struct interface *vlan_if;
566
567
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
568
0
    zlog_debug("access vlan %d bridge %s add", vid, br_if->name);
569
570
0
  acc_bd = XCALLOC(MTYPE_ZACC_BD, sizeof(struct zebra_evpn_access_bd));
571
572
0
  acc_bd->vid = vid;
573
0
  acc_bd->bridge_ifindex = br_if->ifindex;
574
0
  acc_bd->bridge_zif = (struct zebra_if *)br_if->info;
575
576
  /* Initialize the mbr list */
577
0
  acc_bd->mbr_zifs = list_new();
578
579
  /* Add to hash */
580
0
  (void)hash_get(zmh_info->evpn_vlan_table, acc_bd, hash_alloc_intern);
581
582
  /* check if an svi exists for the vlan */
583
0
  vlan_if = zvni_map_to_svi(vid, br_if);
584
0
  if (vlan_if) {
585
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
586
0
      zlog_debug("vlan %d bridge %s SVI %s set", vid,
587
0
           br_if->name, vlan_if->name);
588
0
    acc_bd->vlan_zif = vlan_if->info;
589
0
  }
590
0
  return acc_bd;
591
0
}
592
593
/* Free VLAN based broadcast domain -
594
 * This just frees appropriate memory, caller should have taken other
595
 * needed actions.
596
 */
597
static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd *acc_bd)
598
0
{
599
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
600
0
    zlog_debug("access vlan %d del", acc_bd->vid);
601
602
0
  if (acc_bd->vlan_zif && acc_bd->zevpn && acc_bd->zevpn->mac_table)
603
0
    zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp, acc_bd->zevpn);
604
605
  /* cleanup resources maintained against the ES */
606
0
  list_delete(&acc_bd->mbr_zifs);
607
608
  /* remove EVI from various tables */
609
0
  hash_release(zmh_info->evpn_vlan_table, acc_bd);
610
611
0
  XFREE(MTYPE_ZACC_BD, acc_bd);
612
0
}
613
614
static void zebra_evpn_acc_vl_cleanup_all(struct hash_bucket *bucket, void *arg)
615
0
{
616
0
  struct zebra_evpn_access_bd *acc_bd = bucket->data;
617
618
0
  zebra_evpn_acc_vl_free(acc_bd);
619
0
}
620
621
/* called when a bd mbr is removed or VxLAN_IF is diassociated from the access
622
 * VLAN
623
 */
624
static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd)
625
0
{
626
0
  if (!list_isempty(acc_bd->mbr_zifs) || acc_bd->vxlan_zif)
627
0
    return;
628
629
  /* Remove this access_bd from bridge hash table */
630
0
  zebra_l2_bridge_if_vlan_access_bd_deref(acc_bd);
631
632
  /* if there are no references free the EVI */
633
0
  zebra_evpn_acc_vl_free(acc_bd);
634
0
}
635
636
static struct zebra_evpn_access_bd *
637
zebra_evpn_acc_bd_alloc_on_ref(vlanid_t vid, struct interface *br_if)
638
0
{
639
0
  struct zebra_evpn_access_bd *acc_bd = NULL;
640
641
0
  assert(br_if && br_if->info);
642
0
  acc_bd = zebra_evpn_acc_vl_new(vid, br_if);
643
0
  if (acc_bd)
644
    /* Add this access_bd to bridge hash table */
645
0
    zebra_l2_bridge_if_vlan_access_bd_ref(acc_bd);
646
647
0
  return acc_bd;
648
0
}
649
650
/* called when a SVI is goes up/down */
651
void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif,
652
             struct zebra_if *br_zif, bool is_up)
653
0
{
654
0
  struct zebra_evpn_access_bd *acc_bd;
655
0
  uint16_t vid;
656
0
  struct zebra_if *tmp_br_zif = br_zif;
657
658
0
  if (!tmp_br_zif) {
659
0
    if (!vlan_zif->link || !vlan_zif->link->info)
660
0
      return;
661
662
0
    tmp_br_zif = vlan_zif->link->info;
663
0
  }
664
665
  /* ignore vlan unaware bridges */
666
0
  if (!IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(tmp_br_zif))
667
0
    return;
668
669
0
  vid = vlan_zif->l2info.vl.vid;
670
0
  acc_bd = zebra_evpn_acc_vl_find(vid, tmp_br_zif->ifp);
671
0
  if (!acc_bd)
672
0
    return;
673
674
0
  if (is_up) {
675
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
676
0
      zlog_debug("vlan %d bridge %s SVI %s set", vid,
677
0
           tmp_br_zif->ifp->name, vlan_zif->ifp->name);
678
679
0
    acc_bd->vlan_zif = vlan_zif;
680
0
    if (acc_bd->zevpn)
681
0
      zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp,
682
0
                 acc_bd->zevpn);
683
0
  } else if (acc_bd->vlan_zif) {
684
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
685
0
      zlog_debug("vlan %d bridge %s SVI clear", vid,
686
0
           tmp_br_zif->ifp->name);
687
0
    acc_bd->vlan_zif = NULL;
688
0
    if (acc_bd->zevpn && acc_bd->zevpn->mac_table)
689
0
      zebra_evpn_mac_svi_del(vlan_zif->ifp, acc_bd->zevpn);
690
0
  }
691
0
}
692
693
/* On some events macs are force-flushed. This api can be used to reinstate
694
 * the svi-mac after such cleanup-events.
695
 */
696
void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if)
697
0
{
698
0
  zebra_evpn_acc_bd_svi_set(vlan_if->info, NULL,
699
0
          if_is_operative(vlan_if));
700
0
}
701
702
/* called when a EVPN-L2VNI is set or cleared against a BD */
703
static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd,
704
               struct zebra_evpn *zevpn,
705
               struct zebra_evpn *old_zevpn)
706
0
{
707
0
  struct zebra_if *zif;
708
0
  struct listnode *node;
709
710
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
711
0
    zlog_debug("access vlan %d bridge %s l2-vni %u set",
712
0
         acc_bd->vid, acc_bd->bridge_zif->ifp->name,
713
0
         zevpn ? zevpn->vni : 0);
714
715
0
  for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
716
0
    if (!zif->es_info.es)
717
0
      continue;
718
719
0
    if (zevpn)
720
0
      zebra_evpn_local_es_evi_add(zif->es_info.es, zevpn);
721
0
    else if (old_zevpn)
722
0
      zebra_evpn_local_es_evi_del(zif->es_info.es, old_zevpn);
723
0
  }
724
725
0
  if (acc_bd->vlan_zif) {
726
0
    if (zevpn)
727
0
      zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp,
728
0
                 acc_bd->zevpn);
729
0
    else if (old_zevpn && old_zevpn->mac_table)
730
0
      zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp,
731
0
                 old_zevpn);
732
0
  }
733
0
}
734
735
/* handle VLAN->VxLAN_IF association */
736
void zebra_evpn_vl_vxl_ref(uint16_t vid, vni_t vni_id,
737
         struct zebra_if *vxlan_zif)
738
0
{
739
0
  vni_t old_vni;
740
0
  struct zebra_evpn_access_bd *acc_bd;
741
0
  struct zebra_evpn *old_zevpn;
742
0
  struct interface *br_if;
743
744
0
  if (!vid)
745
0
    return;
746
747
0
  if (!vni_id)
748
0
    return;
749
750
0
  br_if = vxlan_zif->brslave_info.br_if;
751
752
0
  if (!br_if)
753
0
    return;
754
755
0
  acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
756
0
  if (!acc_bd)
757
0
    acc_bd = zebra_evpn_acc_bd_alloc_on_ref(vid, br_if);
758
759
0
  old_vni = acc_bd->vni;
760
761
0
  if (vni_id == old_vni)
762
0
    return;
763
764
0
  acc_bd->vni = vni_id;
765
0
  acc_bd->vxlan_zif = vxlan_zif;
766
767
0
  old_zevpn = acc_bd->zevpn;
768
0
  acc_bd->zevpn = zebra_evpn_lookup(vni_id);
769
0
  if (acc_bd->zevpn == old_zevpn)
770
0
    return;
771
772
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
773
0
    zlog_debug("access vlan %d vni %u ref", acc_bd->vid, vni_id);
774
775
0
  if (old_zevpn)
776
0
    zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
777
778
0
  if (acc_bd->zevpn)
779
0
    zebra_evpn_acc_bd_evpn_set(acc_bd, acc_bd->zevpn, NULL);
780
0
}
781
782
/* handle VLAN->VxLAN_IF deref */
783
void zebra_evpn_vl_vxl_deref(uint16_t vid, vni_t vni_id,
784
           struct zebra_if *vxlan_zif)
785
0
{
786
0
  struct interface *br_if;
787
0
  struct zebra_evpn_access_bd *acc_bd;
788
789
0
  if (!vid)
790
0
    return;
791
792
0
  if (!vni_id)
793
0
    return;
794
795
0
  br_if = vxlan_zif->brslave_info.br_if;
796
0
  if (!br_if)
797
0
    return;
798
799
0
  acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
800
0
  if (!acc_bd)
801
0
    return;
802
803
  /* clear vxlan_if only if it matches */
804
0
  if (acc_bd->vni != vni_id)
805
0
    return;
806
807
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
808
0
    zlog_debug("access vlan %d bridge %s vni %u deref", acc_bd->vid,
809
0
         br_if->name, vni_id);
810
811
0
  if (acc_bd->zevpn)
812
0
    zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, acc_bd->zevpn);
813
814
0
  acc_bd->zevpn = NULL;
815
0
  acc_bd->vxlan_zif = NULL;
816
0
  acc_bd->vni = 0;
817
818
  /* if there are no other references the access_bd can be freed */
819
0
  zebra_evpn_acc_bd_free_on_deref(acc_bd);
820
0
}
821
822
/* handle BridgeIf<->AccessBD cleanup */
823
void zebra_evpn_access_bd_bridge_cleanup(vlanid_t vid, struct interface *br_if,
824
           struct zebra_evpn_access_bd *acc_bd)
825
0
{
826
0
  struct zebra_evpn *zevpn;
827
828
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
829
0
    zlog_debug("access bd vlan %d bridge %s cleanup", acc_bd->vid,
830
0
         br_if->name);
831
832
0
  zevpn = acc_bd->zevpn;
833
0
  if (zevpn)
834
0
    zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, zevpn);
835
836
  /* cleanup resources maintained against the ES */
837
0
  list_delete_all_node(acc_bd->mbr_zifs);
838
839
0
  acc_bd->zevpn = NULL;
840
0
  acc_bd->vxlan_zif = NULL;
841
0
  acc_bd->vni = 0;
842
0
  acc_bd->bridge_zif = NULL;
843
844
  /* if there are no other references the access_bd can be freed */
845
0
  zebra_evpn_acc_bd_free_on_deref(acc_bd);
846
0
}
847
848
/* handle EVPN add/del */
849
void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, struct zebra_evpn *zevpn,
850
           bool set)
851
0
{
852
0
  struct zebra_vxlan_vni *vni;
853
0
  struct zebra_evpn_access_bd *acc_bd;
854
0
  ifindex_t br_ifindex;
855
856
0
  if (!zif)
857
0
    return;
858
859
  /* locate access_bd associated with the vxlan device */
860
0
  vni = zebra_vxlan_if_vni_find(zif, zevpn->vni);
861
0
  if (!vni)
862
0
    return;
863
864
  /* Use the index as the pointer can be stale (deleted) */
865
0
  br_ifindex = zif->brslave_info.bridge_ifindex;
866
0
  if (!zif->brslave_info.br_if || br_ifindex == IFINDEX_INTERNAL)
867
0
    return;
868
869
0
  acc_bd = zebra_evpn_acc_vl_find_index(vni->access_vlan, br_ifindex);
870
0
  if (!acc_bd)
871
0
    return;
872
873
0
  if (set) {
874
0
    zebra_evpn_es_set_base_evpn(zevpn);
875
0
    if (acc_bd->zevpn != zevpn) {
876
0
      acc_bd->zevpn = zevpn;
877
0
      zebra_evpn_acc_bd_evpn_set(acc_bd, zevpn, NULL);
878
0
    }
879
0
  } else {
880
0
    if (acc_bd->zevpn) {
881
0
      struct zebra_evpn *old_zevpn = acc_bd->zevpn;
882
0
      acc_bd->zevpn = NULL;
883
0
      zebra_evpn_acc_bd_evpn_set(acc_bd, NULL, old_zevpn);
884
0
    }
885
0
  }
886
0
}
887
888
/* handle addition of new VLAN members */
889
void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif)
890
0
{
891
0
  struct interface *br_if;
892
0
  struct zebra_evpn_access_bd *acc_bd;
893
894
0
  if (!vid)
895
0
    return;
896
897
0
  br_if = zif->brslave_info.br_if;
898
0
  if (!br_if)
899
0
    return;
900
901
0
  acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
902
0
  if (!acc_bd)
903
0
    acc_bd = zebra_evpn_acc_bd_alloc_on_ref(vid, br_if);
904
905
0
  if (listnode_lookup(acc_bd->mbr_zifs, zif))
906
0
    return;
907
908
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
909
0
    zlog_debug("access vlan %d bridge %s mbr %s ref", vid,
910
0
         br_if->name, zif->ifp->name);
911
912
0
  listnode_add(acc_bd->mbr_zifs, zif);
913
0
  if (acc_bd->zevpn && zif->es_info.es)
914
0
    zebra_evpn_local_es_evi_add(zif->es_info.es, acc_bd->zevpn);
915
0
}
916
917
/* handle deletion of VLAN members */
918
void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif)
919
0
{
920
0
  struct interface *br_if;
921
0
  struct zebra_evpn_access_bd *acc_bd;
922
0
  struct listnode *node;
923
924
0
  if (!vid)
925
0
    return;
926
927
0
  br_if = zif->brslave_info.br_if;
928
0
  if (!br_if)
929
0
    return;
930
931
0
  acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
932
0
  if (!acc_bd)
933
0
    return;
934
935
0
  node = listnode_lookup(acc_bd->mbr_zifs, zif);
936
0
  if (!node)
937
0
    return;
938
939
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
940
0
    zlog_debug("access vlan %d bridge %s mbr %s deref", vid,
941
0
         br_if->name, zif->ifp->name);
942
943
0
  list_delete_node(acc_bd->mbr_zifs, node);
944
945
0
  if (acc_bd->zevpn && zif->es_info.es)
946
0
    zebra_evpn_local_es_evi_del(zif->es_info.es, acc_bd->zevpn);
947
948
  /* if there are no other references the access_bd can be freed */
949
0
  zebra_evpn_acc_bd_free_on_deref(acc_bd);
950
0
}
951
952
static void zebra_evpn_acc_vl_adv_svi_mac_cb(struct hash_bucket *bucket,
953
               void *ctxt)
954
0
{
955
0
  struct zebra_evpn_access_bd *acc_bd = bucket->data;
956
957
0
  if (acc_bd->vlan_zif && acc_bd->zevpn)
958
0
    zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp, acc_bd->zevpn);
959
0
}
960
961
/* called when advertise SVI MAC is enabled on the switch */
962
static void zebra_evpn_acc_vl_adv_svi_mac_all(void)
963
0
{
964
0
  hash_iterate(zmh_info->evpn_vlan_table,
965
0
         zebra_evpn_acc_vl_adv_svi_mac_cb, NULL);
966
0
}
967
968
static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd *acc_bd,
969
          json_object *json, bool detail)
970
0
{
971
0
  json_object_int_add(json, "vlan", acc_bd->vid);
972
0
  if (acc_bd->vxlan_zif)
973
0
    json_object_string_add(json, "vxlanIf",
974
0
               acc_bd->vxlan_zif->ifp->name);
975
0
  if (acc_bd->zevpn)
976
0
    json_object_int_add(json, "vni", acc_bd->zevpn->vni);
977
0
  if (acc_bd->mbr_zifs)
978
0
    json_object_int_add(json, "memberIfCount",
979
0
            listcount(acc_bd->mbr_zifs));
980
981
0
  if (detail) {
982
0
    json_object *json_mbrs;
983
0
    json_object *json_mbr;
984
0
    struct zebra_if *zif;
985
0
    struct listnode *node;
986
987
988
0
    json_mbrs = json_object_new_array();
989
0
    for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif)) {
990
0
      json_mbr = json_object_new_object();
991
0
      json_object_string_add(json_mbr, "ifName",
992
0
                 zif->ifp->name);
993
0
      json_object_array_add(json_mbrs, json_mbr);
994
0
    }
995
0
    json_object_object_add(json, "members", json_mbrs);
996
0
  }
997
0
}
998
999
static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty,
1000
    struct zebra_evpn_access_bd *acc_bd, json_object *json)
1001
0
{
1002
0
  struct zebra_if *zif;
1003
0
  struct listnode *node;
1004
1005
0
  if (json) {
1006
0
    zebra_evpn_acc_vl_json_fill(acc_bd, json, true);
1007
0
  } else {
1008
0
    vty_out(vty, "VLAN: %s.%u\n", acc_bd->bridge_zif->ifp->name,
1009
0
      acc_bd->vid);
1010
0
    vty_out(vty, " VxLAN Interface: %s\n",
1011
0
        acc_bd->vxlan_zif ?
1012
0
        acc_bd->vxlan_zif->ifp->name : "-");
1013
0
    vty_out(vty, " SVI: %s\n",
1014
0
      acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-");
1015
0
    if (acc_bd->zevpn)
1016
0
      vty_out(vty, " L2-VNI: %d\n", acc_bd->zevpn->vni);
1017
0
    else {
1018
0
      vty_out(vty, " L2-VNI: 0\n");
1019
0
      vty_out(vty, " L3-VNI: %d\n", acc_bd->vni);
1020
0
    }
1021
0
    vty_out(vty, " Member Count: %d\n",
1022
0
        listcount(acc_bd->mbr_zifs));
1023
0
    vty_out(vty, " Members: \n");
1024
0
    for (ALL_LIST_ELEMENTS_RO(acc_bd->mbr_zifs, node, zif))
1025
0
      vty_out(vty, "    %s\n", zif->ifp->name);
1026
0
    vty_out(vty, "\n");
1027
0
  }
1028
0
}
1029
1030
static void zebra_evpn_acc_vl_show_entry(struct vty *vty,
1031
    struct zebra_evpn_access_bd *acc_bd, json_object *json)
1032
0
{
1033
0
  if (json) {
1034
0
    zebra_evpn_acc_vl_json_fill(acc_bd, json, false);
1035
0
  } else {
1036
0
    vty_out(vty, "%-5s.%-5u %-15s %-8d %-15s %u\n",
1037
0
      acc_bd->bridge_zif->ifp->name, acc_bd->vid,
1038
0
      acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-",
1039
0
      acc_bd->zevpn ? acc_bd->zevpn->vni : 0,
1040
0
      acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-",
1041
0
      listcount(acc_bd->mbr_zifs));
1042
0
  }
1043
0
}
1044
1045
static void zebra_evpn_acc_vl_show_hash(struct hash_bucket *bucket, void *ctxt)
1046
0
{
1047
0
  struct evpn_mh_show_ctx *wctx = ctxt;
1048
0
  struct zebra_evpn_access_bd *acc_bd = bucket->data;
1049
0
  json_object *json = NULL;
1050
1051
0
  if (wctx->json)
1052
0
    json = json_object_new_object();
1053
0
  if (wctx->detail)
1054
0
    zebra_evpn_acc_vl_show_entry_detail(wctx->vty, acc_bd, json);
1055
0
  else
1056
0
    zebra_evpn_acc_vl_show_entry(wctx->vty, acc_bd, json);
1057
0
  if (json)
1058
0
    json_object_array_add(wctx->json, json);
1059
0
}
1060
1061
void zebra_evpn_acc_vl_show(struct vty *vty, bool uj)
1062
0
{
1063
0
  struct evpn_mh_show_ctx wctx;
1064
0
  json_object *json_array = NULL;
1065
1066
0
  if (uj)
1067
0
    json_array = json_object_new_array();
1068
1069
0
  memset(&wctx, 0, sizeof(wctx));
1070
0
  wctx.vty = vty;
1071
0
  wctx.json = json_array;
1072
0
  wctx.detail = false;
1073
1074
0
  if (!uj)
1075
0
    vty_out(vty, "%-12s %-15s %-8s %-15s %s\n", "VLAN", "SVI",
1076
0
      "L2-VNI", "VXLAN-IF", "# Members");
1077
1078
0
  hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
1079
0
      &wctx);
1080
1081
0
  if (uj)
1082
0
    vty_json(vty, json_array);
1083
0
}
1084
1085
void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj)
1086
0
{
1087
0
  struct evpn_mh_show_ctx wctx;
1088
0
  json_object *json_array = NULL;
1089
1090
0
  if (uj)
1091
0
    json_array = json_object_new_array();
1092
0
  memset(&wctx, 0, sizeof(wctx));
1093
0
  wctx.vty = vty;
1094
0
  wctx.json = json_array;
1095
0
  wctx.detail = true;
1096
1097
0
  hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash,
1098
0
      &wctx);
1099
1100
0
  if (uj)
1101
0
    vty_json(vty, json_array);
1102
0
}
1103
1104
void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid,
1105
        struct interface *br_if)
1106
0
{
1107
0
  json_object *json = NULL;
1108
0
  struct zebra_evpn_access_bd *acc_bd;
1109
1110
0
  if (uj)
1111
0
    json = json_object_new_object();
1112
1113
0
  acc_bd = zebra_evpn_acc_vl_find(vid, br_if);
1114
0
  if (acc_bd) {
1115
0
    zebra_evpn_acc_vl_show_entry_detail(vty, acc_bd, json);
1116
0
  } else {
1117
0
    if (!json)
1118
0
      vty_out(vty, "VLAN %s.%u not present\n", br_if->name,
1119
0
        vid);
1120
0
  }
1121
1122
0
  if (uj)
1123
0
    vty_json(vty, json);
1124
0
}
1125
1126
/* Initialize VLAN member bitmap on an interface. Although VLAN membership
1127
 * is independent of EVPN we only process it if its of interest to EVPN-MH
1128
 * i.e. on access ports that can be setup as Ethernet Segments. And that is
1129
 * intended as an optimization.
1130
 */
1131
void zebra_evpn_if_init(struct zebra_if *zif)
1132
0
{
1133
0
  if (!zebra_evpn_is_if_es_capable(zif))
1134
0
    return;
1135
1136
0
  if (!bf_is_inited(zif->vlan_bitmap))
1137
0
    bf_init(zif->vlan_bitmap, IF_VLAN_BITMAP_MAX);
1138
1139
  /* if an es_id and sysmac are already present against the interface
1140
   * activate it
1141
   */
1142
0
  zebra_evpn_local_es_update(zif, &zif->es_info.esi);
1143
0
}
1144
1145
/* handle deletion of an access port by removing it from all associated
1146
 * broadcast domains.
1147
 */
1148
void zebra_evpn_if_cleanup(struct zebra_if *zif)
1149
0
{
1150
0
  vlanid_t vid;
1151
0
  struct zebra_evpn_es *es;
1152
1153
0
  if (bf_is_inited(zif->vlan_bitmap)) {
1154
0
    bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX)
1155
0
    {
1156
0
      zebra_evpn_vl_mbr_deref(vid, zif);
1157
0
    }
1158
1159
0
    bf_free(zif->vlan_bitmap);
1160
0
  }
1161
1162
  /* Delete associated Ethernet Segment */
1163
0
  es = zif->es_info.es;
1164
0
  if (es)
1165
0
    zebra_evpn_local_es_del(&es);
1166
0
}
1167
1168
/*****************************************************************************
1169
 * L2 NH/NHG Management
1170
 *   A L2 NH entry is programmed in the kernel for every ES-VTEP entry. This
1171
 * NH is then added to the L2-ECMP-NHG associated with the ES.
1172
 */
1173
static uint32_t zebra_evpn_nhid_alloc(struct zebra_evpn_es *es)
1174
0
{
1175
0
  uint32_t id;
1176
0
  uint32_t nh_id;
1177
1178
0
  bf_assign_index(zmh_info->nh_id_bitmap, id);
1179
1180
0
  if (!id)
1181
0
    return 0;
1182
1183
0
  if (es) {
1184
0
    nh_id = id | EVPN_NHG_ID_TYPE_BIT;
1185
    /* Add to NHG hash */
1186
0
    es->nhg_id = nh_id;
1187
0
    (void)hash_get(zmh_info->nhg_table, es, hash_alloc_intern);
1188
0
  } else {
1189
0
    nh_id = id | EVPN_NH_ID_TYPE_BIT;
1190
0
  }
1191
1192
0
  return nh_id;
1193
0
}
1194
1195
static void zebra_evpn_nhid_free(uint32_t nh_id, struct zebra_evpn_es *es)
1196
0
{
1197
0
  uint32_t id = (nh_id & EVPN_NH_ID_VAL_MASK);
1198
1199
0
  if (!id)
1200
0
    return;
1201
1202
0
  if (es) {
1203
0
    hash_release(zmh_info->nhg_table, es);
1204
0
    es->nhg_id = 0;
1205
0
  }
1206
1207
0
  bf_release_index(zmh_info->nh_id_bitmap, id);
1208
0
}
1209
1210
static unsigned int zebra_evpn_nh_ip_hash_keymake(const void *p)
1211
0
{
1212
0
  const struct zebra_evpn_l2_nh *nh = p;
1213
1214
0
  return jhash_1word(nh->vtep_ip.s_addr, 0);
1215
0
}
1216
1217
static bool zebra_evpn_nh_ip_cmp(const void *p1, const void *p2)
1218
0
{
1219
0
  const struct zebra_evpn_l2_nh *nh1 = p1;
1220
0
  const struct zebra_evpn_l2_nh *nh2 = p2;
1221
1222
0
  if (nh1 == NULL && nh2 == NULL)
1223
0
    return true;
1224
1225
0
  if (nh1 == NULL || nh2 == NULL)
1226
0
    return false;
1227
1228
0
  return (nh1->vtep_ip.s_addr == nh2->vtep_ip.s_addr);
1229
0
}
1230
1231
static unsigned int zebra_evpn_nhg_hash_keymake(const void *p)
1232
0
{
1233
0
  const struct zebra_evpn_es *es = p;
1234
1235
0
  return jhash_1word(es->nhg_id, 0);
1236
0
}
1237
1238
static bool zebra_evpn_nhg_cmp(const void *p1, const void *p2)
1239
0
{
1240
0
  const struct zebra_evpn_es *es1 = p1;
1241
0
  const struct zebra_evpn_es *es2 = p2;
1242
1243
0
  if (es1 == NULL && es2 == NULL)
1244
0
    return true;
1245
1246
0
  if (es1 == NULL || es2 == NULL)
1247
0
    return false;
1248
1249
0
  return (es1->nhg_id == es2->nhg_id);
1250
0
}
1251
1252
/* Lookup ES using the NHG id associated with it */
1253
static struct zebra_evpn_es *zebra_evpn_nhg_find(uint32_t nhg_id)
1254
0
{
1255
0
  struct zebra_evpn_es *es;
1256
0
  struct zebra_evpn_es tmp;
1257
1258
0
  tmp.nhg_id = nhg_id;
1259
0
  es = hash_lookup(zmh_info->nhg_table, &tmp);
1260
1261
0
  return es;
1262
0
}
1263
1264
/* Returns TRUE if the NHG is associated with a local ES */
1265
bool zebra_evpn_nhg_is_local_es(uint32_t nhg_id,
1266
        struct zebra_evpn_es **local_es)
1267
0
{
1268
0
  struct zebra_evpn_es *es;
1269
1270
0
  es = zebra_evpn_nhg_find(nhg_id);
1271
0
  if (es && (es->flags & ZEBRA_EVPNES_LOCAL)) {
1272
0
    *local_es = es;
1273
0
    return true;
1274
0
  }
1275
1276
0
  *local_es = NULL;
1277
0
  return false;
1278
0
}
1279
1280
/* update remote macs associated with the ES */
1281
static void zebra_evpn_nhg_mac_update(struct zebra_evpn_es *es)
1282
0
{
1283
0
  struct zebra_mac *mac;
1284
0
  struct listnode *node;
1285
0
  bool local_via_nw;
1286
1287
0
  local_via_nw = zebra_evpn_es_local_mac_via_network_port(es);
1288
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1289
0
    zlog_debug("mac update on es %s nhg %s", es->esi_str,
1290
0
         (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
1291
0
           ? "activate"
1292
0
           : "de-activate");
1293
1294
0
  for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
1295
0
    if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)
1296
0
        || (local_via_nw && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
1297
0
      && zebra_evpn_mac_is_static(mac))) {
1298
0
      if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
1299
0
        if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1300
0
          zlog_debug(
1301
0
            "%smac %pEA install via es %s nhg 0x%x",
1302
0
            (mac->flags & ZEBRA_MAC_REMOTE)
1303
0
              ? "rem"
1304
0
              : "local-nw",
1305
0
            &mac->macaddr, es->esi_str,
1306
0
            es->nhg_id);
1307
0
        zebra_evpn_rem_mac_install(
1308
0
          mac->zevpn, mac, false /*was_static*/);
1309
0
      } else {
1310
0
        if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
1311
0
          zlog_debug(
1312
0
            "%smac %pEA un-install es %s",
1313
0
            (mac->flags & ZEBRA_MAC_REMOTE)
1314
0
              ? "rem"
1315
0
              : "local-nw",
1316
0
            &mac->macaddr, es->esi_str);
1317
0
        zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
1318
0
                   true /*force*/);
1319
0
      }
1320
0
    }
1321
0
  }
1322
0
}
1323
1324
/* The MAC ECMP group is activated on the first VTEP */
1325
static void zebra_evpn_nhg_update(struct zebra_evpn_es *es)
1326
0
{
1327
0
  uint32_t nh_cnt = 0;
1328
0
  struct nh_grp nh_ids[ES_VTEP_MAX_CNT];
1329
0
  struct zebra_evpn_es_vtep *es_vtep;
1330
0
  struct listnode *node;
1331
1332
0
  if (!es->nhg_id)
1333
0
    return;
1334
1335
0
  for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1336
0
    if (!es_vtep->nh)
1337
0
      continue;
1338
1339
0
    if (nh_cnt >= ES_VTEP_MAX_CNT)
1340
0
      break;
1341
1342
0
    memset(&nh_ids[nh_cnt], 0, sizeof(struct nh_grp));
1343
0
    nh_ids[nh_cnt].id = es_vtep->nh->nh_id;
1344
0
    ++nh_cnt;
1345
0
  }
1346
1347
0
  if (nh_cnt) {
1348
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_NH) {
1349
0
      char nh_str[ES_VTEP_LIST_STR_SZ];
1350
0
      uint32_t i;
1351
0
      char nh_buf[16];
1352
1353
0
      nh_str[0] = '\0';
1354
0
      for (i = 0; i < nh_cnt; ++i) {
1355
0
        snprintf(nh_buf, sizeof(nh_buf), "%u ",
1356
0
           nh_ids[i].id);
1357
0
        strlcat(nh_str, nh_buf, sizeof(nh_str));
1358
0
      }
1359
0
      zlog_debug("es %s nhg %u add %s", es->esi_str,
1360
0
           es->nhg_id, nh_str);
1361
0
    }
1362
1363
0
    kernel_upd_mac_nhg(es->nhg_id, nh_cnt, nh_ids);
1364
0
    if (!(es->flags & ZEBRA_EVPNES_NHG_ACTIVE)) {
1365
0
      es->flags |= ZEBRA_EVPNES_NHG_ACTIVE;
1366
      /* add backup NHG to the br-port */
1367
0
      if ((es->flags & ZEBRA_EVPNES_LOCAL))
1368
0
        zebra_evpn_es_br_port_dplane_update(es,
1369
0
                    __func__);
1370
0
      zebra_evpn_nhg_mac_update(es);
1371
0
    }
1372
0
  } else {
1373
0
    if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
1374
0
      if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
1375
0
        zlog_debug("es %s nhg %u del", es->esi_str,
1376
0
             es->nhg_id);
1377
0
      es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
1378
      /* remove backup NHG from the br-port */
1379
0
      if ((es->flags & ZEBRA_EVPNES_LOCAL))
1380
0
        zebra_evpn_es_br_port_dplane_update(es,
1381
0
                    __func__);
1382
0
      zebra_evpn_nhg_mac_update(es);
1383
0
      kernel_del_mac_nhg(es->nhg_id);
1384
0
    }
1385
0
  }
1386
1387
0
}
1388
1389
static void zebra_evpn_es_l2_nh_show_entry(struct zebra_evpn_l2_nh *nh,
1390
             struct vty *vty,
1391
             json_object *json_array)
1392
0
{
1393
0
  if (json_array) {
1394
0
    json_object *json = NULL;
1395
1396
0
    json = json_object_new_object();
1397
0
    json_object_string_addf(json, "vtep", "%pI4", &nh->vtep_ip);
1398
0
    json_object_int_add(json, "nhId", nh->nh_id);
1399
0
    json_object_int_add(json, "refCnt", nh->ref_cnt);
1400
1401
0
    json_object_array_add(json_array, json);
1402
0
  } else {
1403
0
    vty_out(vty, "%-16pI4 %-10u %u\n", &nh->vtep_ip, nh->nh_id,
1404
0
      nh->ref_cnt);
1405
0
  }
1406
0
}
1407
1408
static void zebra_evpn_l2_nh_show_cb(struct hash_bucket *bucket, void *ctxt)
1409
0
{
1410
0
  struct zebra_evpn_l2_nh *nh = (struct zebra_evpn_l2_nh *)bucket->data;
1411
0
  struct evpn_mh_show_ctx *wctx = (struct evpn_mh_show_ctx *)ctxt;
1412
1413
0
  zebra_evpn_es_l2_nh_show_entry(nh, wctx->vty, wctx->json);
1414
0
}
1415
1416
void zebra_evpn_l2_nh_show(struct vty *vty, bool uj)
1417
0
{
1418
0
  struct evpn_mh_show_ctx wctx;
1419
0
  json_object *json_array = NULL;
1420
1421
0
  if (uj) {
1422
0
    json_array = json_object_new_array();
1423
0
  } else {
1424
0
    vty_out(vty, "%-16s %-10s %s\n", "VTEP", "NH id", "#ES");
1425
0
  }
1426
1427
0
  memset(&wctx, 0, sizeof(wctx));
1428
0
  wctx.vty = vty;
1429
0
  wctx.json = json_array;
1430
1431
0
  hash_iterate(zmh_info->nh_ip_table, zebra_evpn_l2_nh_show_cb, &wctx);
1432
1433
0
  if (uj)
1434
0
    vty_json(vty, json_array);
1435
0
}
1436
1437
static struct zebra_evpn_l2_nh *zebra_evpn_l2_nh_find(struct in_addr vtep_ip)
1438
0
{
1439
0
  struct zebra_evpn_l2_nh *nh;
1440
0
  struct zebra_evpn_l2_nh tmp;
1441
1442
0
  tmp.vtep_ip.s_addr = vtep_ip.s_addr;
1443
0
  nh = hash_lookup(zmh_info->nh_ip_table, &tmp);
1444
1445
0
  return nh;
1446
0
}
1447
1448
static struct zebra_evpn_l2_nh *zebra_evpn_l2_nh_alloc(struct in_addr vtep_ip)
1449
0
{
1450
0
  struct zebra_evpn_l2_nh *nh;
1451
1452
0
  nh = XCALLOC(MTYPE_L2_NH, sizeof(*nh));
1453
0
  nh->vtep_ip = vtep_ip;
1454
0
  (void)hash_get(zmh_info->nh_ip_table, nh, hash_alloc_intern);
1455
1456
0
  nh->nh_id = zebra_evpn_nhid_alloc(NULL);
1457
0
  if (!nh->nh_id) {
1458
0
    hash_release(zmh_info->nh_ip_table, nh);
1459
0
    XFREE(MTYPE_L2_NH, nh);
1460
0
    return NULL;
1461
0
  }
1462
1463
  /* install the NH in the dataplane */
1464
0
  kernel_upd_mac_nh(nh->nh_id, nh->vtep_ip);
1465
1466
0
  return nh;
1467
0
}
1468
1469
static void zebra_evpn_l2_nh_free(struct zebra_evpn_l2_nh *nh)
1470
0
{
1471
  /* delete the NH from the dataplane */
1472
0
  kernel_del_mac_nh(nh->nh_id);
1473
1474
0
  zebra_evpn_nhid_free(nh->nh_id, NULL);
1475
0
  hash_release(zmh_info->nh_ip_table, nh);
1476
0
  XFREE(MTYPE_L2_NH, nh);
1477
0
}
1478
1479
static void zebra_evpn_l2_nh_es_vtep_ref(struct zebra_evpn_es_vtep *es_vtep)
1480
0
{
1481
0
  if (es_vtep->nh)
1482
0
    return;
1483
1484
0
  es_vtep->nh = zebra_evpn_l2_nh_find(es_vtep->vtep_ip);
1485
0
  if (!es_vtep->nh)
1486
0
    es_vtep->nh = zebra_evpn_l2_nh_alloc(es_vtep->vtep_ip);
1487
1488
0
  if (!es_vtep->nh) {
1489
0
    zlog_warn("es %s vtep %pI4 nh ref failed", es_vtep->es->esi_str,
1490
0
        &es_vtep->vtep_ip);
1491
0
    return;
1492
0
  }
1493
1494
0
  ++es_vtep->nh->ref_cnt;
1495
1496
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
1497
0
    zlog_debug("es %s vtep %pI4 nh %u ref %u", es_vtep->es->esi_str,
1498
0
         &es_vtep->vtep_ip, es_vtep->nh->nh_id,
1499
0
         es_vtep->nh->ref_cnt);
1500
1501
  /* add the NH to the parent NHG */
1502
0
  zebra_evpn_nhg_update(es_vtep->es);
1503
0
}
1504
1505
static void zebra_evpn_l2_nh_es_vtep_deref(struct zebra_evpn_es_vtep *es_vtep)
1506
0
{
1507
0
  struct zebra_evpn_l2_nh *nh = es_vtep->nh;
1508
1509
0
  if (!nh)
1510
0
    return;
1511
1512
0
  es_vtep->nh = NULL;
1513
0
  if (nh->ref_cnt)
1514
0
    --nh->ref_cnt;
1515
1516
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_NH)
1517
0
    zlog_debug("es %s vtep %pI4 nh %u deref %u",
1518
0
         es_vtep->es->esi_str, &es_vtep->vtep_ip, nh->nh_id,
1519
0
         nh->ref_cnt);
1520
1521
  /* remove the NH from the parent NHG */
1522
0
  zebra_evpn_nhg_update(es_vtep->es);
1523
1524
  /* uninstall the NH */
1525
0
  if (!nh->ref_cnt)
1526
0
    zebra_evpn_l2_nh_free(nh);
1527
0
}
1528
1529
/*****************************************************************************/
1530
/* Ethernet Segment Management
1531
 * 1. Ethernet Segment is a collection of links attached to the same
1532
 *    server (MHD) or switch (MHN)
1533
 * 2. An Ethernet Segment can span multiple PEs and is identified by the
1534
 *    10-byte ES-ID.
1535
 * 3. Zebra manages the local ESI configuration.
1536
 * 4. It also maintains the aliasing that maps an ESI (local or remote)
1537
 *    to one or more PEs/VTEPs.
1538
 * 5. remote ESs are added by BGP (on rxing EAD Type-1 routes)
1539
 */
1540
/* A list of remote VTEPs is maintained for each ES. This list includes -
1541
 * 1. VTEPs for which we have imported the ESR i.e. ES-peers
1542
 * 2. VTEPs that have an "active" ES-EVI VTEP i.e. EAD-per-ES and EAD-per-EVI
1543
 *    have been imported into one or more EVPNs
1544
 */
1545
static int zebra_evpn_es_vtep_cmp(void *p1, void *p2)
1546
0
{
1547
0
  const struct zebra_evpn_es_vtep *es_vtep1 = p1;
1548
0
  const struct zebra_evpn_es_vtep *es_vtep2 = p2;
1549
1550
0
  return es_vtep1->vtep_ip.s_addr - es_vtep2->vtep_ip.s_addr;
1551
0
}
1552
1553
static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_new(
1554
    struct zebra_evpn_es *es, struct in_addr vtep_ip)
1555
0
{
1556
0
  struct zebra_evpn_es_vtep *es_vtep;
1557
1558
0
  es_vtep = XCALLOC(MTYPE_ZES_VTEP, sizeof(*es_vtep));
1559
1560
0
  es_vtep->es = es;
1561
0
  es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
1562
0
  listnode_init(&es_vtep->es_listnode, es_vtep);
1563
0
  listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
1564
1565
0
  return es_vtep;
1566
0
}
1567
1568
static void zebra_evpn_es_vtep_free(struct zebra_evpn_es_vtep *es_vtep)
1569
0
{
1570
0
  struct zebra_evpn_es *es = es_vtep->es;
1571
1572
0
  list_delete_node(es->es_vtep_list, &es_vtep->es_listnode);
1573
  /* update the L2-NHG associated with the ES */
1574
0
  zebra_evpn_l2_nh_es_vtep_deref(es_vtep);
1575
0
  XFREE(MTYPE_ZES_VTEP, es_vtep);
1576
0
}
1577
1578
1579
/* check if VTEP is already part of the list */
1580
static struct zebra_evpn_es_vtep *zebra_evpn_es_vtep_find(
1581
    struct zebra_evpn_es *es, struct in_addr vtep_ip)
1582
0
{
1583
0
  struct listnode *node = NULL;
1584
0
  struct zebra_evpn_es_vtep *es_vtep;
1585
1586
0
  for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1587
0
    if (es_vtep->vtep_ip.s_addr == vtep_ip.s_addr)
1588
0
      return es_vtep;
1589
0
  }
1590
0
  return NULL;
1591
0
}
1592
1593
/* flush all the dataplane br-port info associated with the ES */
1594
static bool zebra_evpn_es_br_port_dplane_clear(struct zebra_evpn_es *es)
1595
0
{
1596
0
  struct in_addr sph_filters[ES_VTEP_MAX_CNT];
1597
1598
0
  if (!(es->flags & ZEBRA_EVPNES_BR_PORT))
1599
0
    return false;
1600
1601
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1602
0
    zlog_debug("es %s br-port dplane clear", es->esi_str);
1603
1604
0
  memset(&sph_filters, 0, sizeof(sph_filters));
1605
0
  dplane_br_port_update(es->zif->ifp, false /* non_df */, 0, sph_filters,
1606
0
            0 /* backup_nhg_id */);
1607
0
  return true;
1608
0
}
1609
1610
static inline bool
1611
zebra_evpn_es_br_port_dplane_update_needed(struct zebra_evpn_es *es)
1612
0
{
1613
0
  return (es->flags & ZEBRA_EVPNES_NON_DF)
1614
0
         || (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
1615
0
         || listcount(es->es_vtep_list);
1616
0
}
1617
1618
/* returns TRUE if dplane entry was updated */
1619
static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
1620
            const char *caller)
1621
0
{
1622
0
  uint32_t backup_nhg_id;
1623
0
  struct in_addr sph_filters[ES_VTEP_MAX_CNT];
1624
0
  struct listnode *node = NULL;
1625
0
  struct zebra_evpn_es_vtep *es_vtep;
1626
0
  uint32_t sph_filter_cnt = 0;
1627
1628
0
  if (!(es->flags & ZEBRA_EVPNES_LOCAL))
1629
0
    return zebra_evpn_es_br_port_dplane_clear(es);
1630
1631
  /* If the ES is not a bridge port there is nothing
1632
   * in the dataplane
1633
   */
1634
0
  if (!(es->flags & ZEBRA_EVPNES_BR_PORT))
1635
0
    return false;
1636
1637
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1638
0
    zlog_debug("es %s br-port dplane update by %s", es->esi_str,
1639
0
         caller);
1640
0
  backup_nhg_id = (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) ? es->nhg_id : 0;
1641
1642
0
  memset(&sph_filters, 0, sizeof(sph_filters));
1643
0
  if (es->flags & ZEBRA_EVPNES_BYPASS) {
1644
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1645
0
      zlog_debug(
1646
0
        "es %s SPH filter disabled as it is in bypass",
1647
0
        es->esi_str);
1648
0
  } else {
1649
0
    if (listcount(es->es_vtep_list) > ES_VTEP_MAX_CNT) {
1650
0
      zlog_warn("es %s vtep count %d exceeds filter cnt %d",
1651
0
          es->esi_str, listcount(es->es_vtep_list),
1652
0
          ES_VTEP_MAX_CNT);
1653
0
    } else {
1654
0
      for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node,
1655
0
              es_vtep)) {
1656
0
        if (es_vtep->flags
1657
0
            & ZEBRA_EVPNES_VTEP_DEL_IN_PROG)
1658
0
          continue;
1659
0
        sph_filters[sph_filter_cnt] = es_vtep->vtep_ip;
1660
0
        ++sph_filter_cnt;
1661
0
      }
1662
0
    }
1663
0
  }
1664
1665
0
  dplane_br_port_update(es->zif->ifp, !!(es->flags & ZEBRA_EVPNES_NON_DF),
1666
0
            sph_filter_cnt, sph_filters, backup_nhg_id);
1667
1668
0
  return true;
1669
0
}
1670
1671
/* returns TRUE if dplane entry was updated */
1672
static bool zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
1673
            const char *caller, const char *reason)
1674
0
{
1675
0
  bool old_non_df;
1676
1677
0
  old_non_df = !!(es->flags & ZEBRA_EVPNES_NON_DF);
1678
1679
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1680
0
    zlog_debug("df-change es %s %s to %s; %s: %s", es->esi_str,
1681
0
         old_non_df ? "non-df" : "df",
1682
0
         new_non_df ? "non-df" : "df", caller, reason);
1683
1684
0
  if (old_non_df == new_non_df)
1685
0
    return false;
1686
1687
0
  if (new_non_df)
1688
0
    es->flags |= ZEBRA_EVPNES_NON_DF;
1689
0
  else
1690
0
    es->flags &= ~ZEBRA_EVPNES_NON_DF;
1691
1692
  /* update non-DF block filter in the dataplane */
1693
0
  return zebra_evpn_es_br_port_dplane_update(es, __func__);
1694
0
}
1695
1696
1697
/* returns TRUE if dplane entry was updated */
1698
static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
1699
            const char *caller)
1700
0
{
1701
0
  struct listnode *node = NULL;
1702
0
  struct zebra_evpn_es_vtep *es_vtep;
1703
0
  bool new_non_df = false;
1704
1705
  /* If the ES is not ready (i.e. not completely configured) there
1706
   * is no need to setup the BUM block filter
1707
   */
1708
0
  if (!(es->flags & ZEBRA_EVPNES_LOCAL)
1709
0
      || (es->flags & ZEBRA_EVPNES_BYPASS)
1710
0
      || !zmh_info->es_originator_ip.s_addr)
1711
0
    return zebra_evpn_es_df_change(es, new_non_df, caller,
1712
0
                 "not-ready");
1713
1714
  /* if oper-state is down DF filtering must be on. when the link comes
1715
   * up again dataplane should block BUM till FRR has had the chance
1716
   * to run DF election again
1717
   */
1718
0
  if (!(es->flags & ZEBRA_EVPNES_OPER_UP)) {
1719
0
    new_non_df = true;
1720
0
    return zebra_evpn_es_df_change(es, new_non_df, caller,
1721
0
                 "oper-down");
1722
0
  }
1723
1724
  /* ES was just created; we need to wait for the peers to rx the
1725
   * our Type-4 routes and for the switch to import the peers' Type-4
1726
   * routes
1727
   */
1728
0
  if (es->df_delay_timer) {
1729
0
    new_non_df = true;
1730
0
    return zebra_evpn_es_df_change(es, new_non_df, caller,
1731
0
                 "df-delay");
1732
0
  }
1733
1734
0
  for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
1735
    /* Only VTEPs that have advertised the ESR can participate
1736
     * in DF election
1737
     */
1738
0
    if (!(es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR))
1739
0
      continue;
1740
1741
    /* If the DF alg is not the same we should fall back to
1742
     * service-carving. But as service-carving is not supported
1743
     * we will stop forwarding BUM
1744
     */
1745
0
    if (es_vtep->df_alg != EVPN_MH_DF_ALG_PREF) {
1746
0
      new_non_df = true;
1747
0
      break;
1748
0
    }
1749
1750
    /* Peer VTEP wins DF election if -
1751
     * the peer-VTEP has higher preference (or)
1752
     * the pref is the same but peer's IP address is lower
1753
     */
1754
0
    if ((es_vtep->df_pref > es->df_pref)
1755
0
        || ((es_vtep->df_pref == es->df_pref)
1756
0
      && (es_vtep->vtep_ip.s_addr
1757
0
          < zmh_info->es_originator_ip.s_addr))) {
1758
0
      new_non_df = true;
1759
0
      break;
1760
0
    }
1761
0
  }
1762
1763
0
  return zebra_evpn_es_df_change(es, new_non_df, caller, "elected");
1764
0
}
1765
1766
static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
1767
           struct in_addr vtep_ip, bool esr_rxed,
1768
           uint8_t df_alg, uint16_t df_pref)
1769
0
{
1770
0
  struct zebra_evpn_es_vtep *es_vtep;
1771
0
  bool old_esr_rxed;
1772
0
  bool dplane_updated = false;
1773
1774
0
  es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1775
1776
0
  if (!es_vtep) {
1777
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1778
0
      zlog_debug("es %s vtep %pI4 add",
1779
0
          es->esi_str, &vtep_ip);
1780
0
    es_vtep = zebra_evpn_es_vtep_new(es, vtep_ip);
1781
    /* update the L2-NHG associated with the ES */
1782
0
    zebra_evpn_l2_nh_es_vtep_ref(es_vtep);
1783
0
  }
1784
1785
0
  old_esr_rxed = !!(es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR);
1786
0
  if ((old_esr_rxed != esr_rxed) || (es_vtep->df_alg != df_alg)
1787
0
      || (es_vtep->df_pref != df_pref)) {
1788
    /* If any of the DF election params changed we need to re-run
1789
     * DF election
1790
     */
1791
0
    if (esr_rxed)
1792
0
      es_vtep->flags |= ZEBRA_EVPNES_VTEP_RXED_ESR;
1793
0
    else
1794
0
      es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
1795
0
    es_vtep->df_alg = df_alg;
1796
0
    es_vtep->df_pref = df_pref;
1797
0
    dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
1798
0
  }
1799
  /* add the vtep to the SPH list */
1800
0
  if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL))
1801
0
    zebra_evpn_es_br_port_dplane_update(es, __func__);
1802
0
}
1803
1804
static void zebra_evpn_es_vtep_del(struct zebra_evpn_es *es,
1805
    struct in_addr vtep_ip)
1806
0
{
1807
0
  struct zebra_evpn_es_vtep *es_vtep;
1808
0
  bool dplane_updated = false;
1809
1810
0
  es_vtep = zebra_evpn_es_vtep_find(es, vtep_ip);
1811
1812
0
  if (es_vtep) {
1813
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1814
0
      zlog_debug("es %s vtep %pI4 del",
1815
0
          es->esi_str, &vtep_ip);
1816
0
    es_vtep->flags |= ZEBRA_EVPNES_VTEP_DEL_IN_PROG;
1817
0
    if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) {
1818
0
      es_vtep->flags &= ~ZEBRA_EVPNES_VTEP_RXED_ESR;
1819
0
      dplane_updated =
1820
0
        zebra_evpn_es_run_df_election(es, __func__);
1821
0
    }
1822
    /* remove the vtep from the SPH list */
1823
0
    if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL))
1824
0
      zebra_evpn_es_br_port_dplane_update(es, __func__);
1825
0
    zebra_evpn_es_vtep_free(es_vtep);
1826
0
  }
1827
0
}
1828
1829
/* compare ES-IDs for the global ES RB tree */
1830
static int zebra_es_rb_cmp(const struct zebra_evpn_es *es1,
1831
    const struct zebra_evpn_es *es2)
1832
0
{
1833
0
  return memcmp(&es1->esi, &es2->esi, ESI_BYTES);
1834
0
}
1835
RB_GENERATE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);
1836
1837
/* Lookup ES */
1838
struct zebra_evpn_es *zebra_evpn_es_find(const esi_t *esi)
1839
0
{
1840
0
  struct zebra_evpn_es tmp;
1841
1842
0
  memcpy(&tmp.esi, esi, sizeof(esi_t));
1843
0
  return RB_FIND(zebra_es_rb_head, &zmh_info->es_rb_tree, &tmp);
1844
0
}
1845
1846
/* A new local es is created when a local-es-id and sysmac is configured
1847
 * against an interface.
1848
 */
1849
static struct zebra_evpn_es *zebra_evpn_es_new(const esi_t *esi)
1850
0
{
1851
0
  struct zebra_evpn_es *es;
1852
1853
0
  if (!memcmp(esi, zero_esi, sizeof(esi_t)))
1854
0
    return NULL;
1855
1856
0
  es = XCALLOC(MTYPE_ZES, sizeof(struct zebra_evpn_es));
1857
1858
  /* fill in ESI */
1859
0
  memcpy(&es->esi, esi, sizeof(esi_t));
1860
0
  esi_to_str(&es->esi, es->esi_str, sizeof(es->esi_str));
1861
1862
  /* Add to rb_tree */
1863
0
  RB_INSERT(zebra_es_rb_head, &zmh_info->es_rb_tree, es);
1864
1865
  /* Initialise the ES-EVI list */
1866
0
  es->es_evi_list = list_new();
1867
0
  listset_app_node_mem(es->es_evi_list);
1868
1869
  /* Initialise the VTEP list */
1870
0
  es->es_vtep_list = list_new();
1871
0
  listset_app_node_mem(es->es_vtep_list);
1872
0
  es->es_vtep_list->cmp = zebra_evpn_es_vtep_cmp;
1873
1874
  /* mac entries associated with the ES */
1875
0
  es->mac_list = list_new();
1876
0
  listset_app_node_mem(es->mac_list);
1877
1878
  /* reserve a NHG  */
1879
0
  es->nhg_id = zebra_evpn_nhid_alloc(es);
1880
1881
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1882
0
    zlog_debug("es %s nhg %u new", es->esi_str, es->nhg_id);
1883
1884
0
  return es;
1885
0
}
1886
1887
/* Free a given ES -
1888
 * This just frees appropriate memory, caller should have taken other
1889
 * needed actions.
1890
 */
1891
static void zebra_evpn_es_free(struct zebra_evpn_es **esp)
1892
0
{
1893
0
  struct zebra_evpn_es *es = *esp;
1894
1895
  /* If the ES has a local or remote reference it cannot be freed.
1896
   * Free is also prevented if there are MAC entries referencing
1897
   * it.
1898
   */
1899
0
  if ((es->flags & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE)) ||
1900
0
      listcount(es->mac_list))
1901
0
    return;
1902
1903
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1904
0
    zlog_debug("es %s free", es->esi_str);
1905
1906
  /* If the NHG is still installed uninstall it and free the id */
1907
0
  if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE) {
1908
0
    es->flags &= ~ZEBRA_EVPNES_NHG_ACTIVE;
1909
0
    kernel_del_mac_nhg(es->nhg_id);
1910
0
  }
1911
0
  zebra_evpn_nhid_free(es->nhg_id, es);
1912
1913
  /* cleanup resources maintained against the ES */
1914
0
  list_delete(&es->es_evi_list);
1915
0
  list_delete(&es->es_vtep_list);
1916
0
  list_delete(&es->mac_list);
1917
1918
  /* remove from the VNI-ESI rb tree */
1919
0
  RB_REMOVE(zebra_es_rb_head, &zmh_info->es_rb_tree, es);
1920
1921
0
  XFREE(MTYPE_ZES, es);
1922
1923
0
  *esp = NULL;
1924
0
}
1925
1926
/* Inform BGP about local ES addition */
1927
static int zebra_evpn_es_send_add_to_client(struct zebra_evpn_es *es)
1928
0
{
1929
0
  struct zserv *client;
1930
0
  struct stream *s;
1931
0
  uint8_t oper_up;
1932
0
  bool bypass;
1933
1934
0
  client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1935
  /* BGP may not be running. */
1936
0
  if (!client)
1937
0
    return 0;
1938
1939
0
  s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1940
1941
0
  zclient_create_header(s, ZEBRA_LOCAL_ES_ADD, zebra_vrf_get_evpn_id());
1942
0
  stream_put(s, &es->esi, sizeof(esi_t));
1943
0
  stream_put_ipv4(s, zmh_info->es_originator_ip.s_addr);
1944
0
  oper_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
1945
0
  stream_putc(s, oper_up);
1946
0
  stream_putw(s, es->df_pref);
1947
0
  bypass = !!(es->flags & ZEBRA_EVPNES_BYPASS);
1948
0
  stream_putc(s, bypass);
1949
1950
  /* Write packet size. */
1951
0
  stream_putw_at(s, 0, stream_get_endp(s));
1952
1953
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1954
0
    zlog_debug(
1955
0
      "send add local es %s %pI4 active %u df_pref %u%s to %s",
1956
0
      es->esi_str, &zmh_info->es_originator_ip, oper_up,
1957
0
      es->df_pref, bypass ? " bypass" : "",
1958
0
      zebra_route_string(client->proto));
1959
1960
0
  client->local_es_add_cnt++;
1961
0
  return zserv_send_message(client, s);
1962
0
}
1963
1964
/* Inform BGP about local ES deletion */
1965
static int zebra_evpn_es_send_del_to_client(struct zebra_evpn_es *es)
1966
0
{
1967
0
  struct zserv *client;
1968
0
  struct stream *s;
1969
1970
0
  client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
1971
  /* BGP may not be running. */
1972
0
  if (!client)
1973
0
    return 0;
1974
1975
0
  s = stream_new(ZEBRA_MAX_PACKET_SIZ);
1976
0
  stream_reset(s);
1977
1978
0
  zclient_create_header(s, ZEBRA_LOCAL_ES_DEL, zebra_vrf_get_evpn_id());
1979
0
  stream_put(s, &es->esi, sizeof(esi_t));
1980
1981
  /* Write packet size. */
1982
0
  stream_putw_at(s, 0, stream_get_endp(s));
1983
1984
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
1985
0
    zlog_debug("send del local es %s to %s", es->esi_str,
1986
0
        zebra_route_string(client->proto));
1987
1988
0
  client->local_es_del_cnt++;
1989
0
  return zserv_send_message(client, s);
1990
0
}
1991
1992
static void zebra_evpn_es_re_eval_send_to_client(struct zebra_evpn_es *es,
1993
    bool es_evi_re_reval)
1994
0
{
1995
0
  bool old_ready;
1996
0
  bool new_ready;
1997
0
  struct listnode *node;
1998
0
  struct zebra_evpn_es_evi *es_evi;
1999
2000
0
  old_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
2001
2002
0
  if ((es->flags & ZEBRA_EVPNES_LOCAL) &&
2003
0
      zmh_info->es_originator_ip.s_addr)
2004
0
    es->flags |= ZEBRA_EVPNES_READY_FOR_BGP;
2005
0
  else
2006
0
    es->flags &= ~ZEBRA_EVPNES_READY_FOR_BGP;
2007
2008
0
  new_ready = !!(es->flags & ZEBRA_EVPNES_READY_FOR_BGP);
2009
0
  if (old_ready == new_ready)
2010
0
    return;
2011
2012
0
  if (new_ready)
2013
0
    zebra_evpn_es_send_add_to_client(es);
2014
0
  else
2015
0
    zebra_evpn_es_send_del_to_client(es);
2016
2017
  /* re-eval associated EVIs */
2018
0
  if (es_evi_re_reval) {
2019
0
    for (ALL_LIST_ELEMENTS_RO(es->es_evi_list, node, es_evi)) {
2020
0
      if (!(es_evi->flags & ZEBRA_EVPNES_EVI_LOCAL))
2021
0
        continue;
2022
0
      zebra_evpn_es_evi_re_eval_send_to_client(es_evi);
2023
0
    }
2024
0
  }
2025
0
}
2026
2027
void zebra_evpn_es_send_all_to_client(bool add)
2028
1
{
2029
1
  struct listnode *es_node;
2030
1
  struct listnode *evi_node;
2031
1
  struct zebra_evpn_es *es;
2032
1
  struct zebra_evpn_es_evi *es_evi;
2033
2034
1
  if (!zmh_info)
2035
0
    return;
2036
2037
1
  for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, es_node, es)) {
2038
0
    if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) {
2039
0
      if (add)
2040
0
        zebra_evpn_es_send_add_to_client(es);
2041
0
      for (ALL_LIST_ELEMENTS_RO(es->es_evi_list,
2042
0
            evi_node, es_evi)) {
2043
0
        if (!(es_evi->flags &
2044
0
          ZEBRA_EVPNES_EVI_READY_FOR_BGP))
2045
0
          continue;
2046
2047
0
        if (add)
2048
0
          zebra_evpn_es_evi_send_to_client(
2049
0
            es, es_evi->zevpn,
2050
0
            true /* add */);
2051
0
        else
2052
0
          zebra_evpn_es_evi_send_to_client(
2053
0
            es, es_evi->zevpn,
2054
0
            false /* add */);
2055
0
      }
2056
0
      if (!add)
2057
0
        zebra_evpn_es_send_del_to_client(es);
2058
0
    }
2059
0
  }
2060
1
}
2061
2062
/* walk the vlan bitmap associated with the zif and create or delete
2063
 * es_evis for all vlans associated with a VNI.
2064
 * XXX: This API is really expensive. optimize later if possible.
2065
 */
2066
static void zebra_evpn_es_setup_evis(struct zebra_evpn_es *es)
2067
0
{
2068
0
  struct zebra_if *zif = es->zif;
2069
0
  uint16_t vid;
2070
0
  struct zebra_evpn_access_bd *acc_bd;
2071
2072
0
  if (!bf_is_inited(zif->vlan_bitmap))
2073
0
    return;
2074
2075
0
  bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) {
2076
0
    acc_bd = zebra_evpn_acc_vl_find(vid, zif->brslave_info.br_if);
2077
0
    if (acc_bd->zevpn)
2078
0
      zebra_evpn_local_es_evi_add(es, acc_bd->zevpn);
2079
0
  }
2080
0
}
2081
2082
static void zebra_evpn_flush_local_mac(struct zebra_mac *mac,
2083
               struct interface *ifp)
2084
0
{
2085
0
  vlanid_t vid;
2086
0
  struct zebra_if *zif;
2087
0
  struct interface *br_ifp;
2088
0
  struct zebra_vxlan_vni *vni;
2089
2090
0
  zif = ifp->info;
2091
0
  br_ifp = zif->brslave_info.br_if;
2092
0
  if (!br_ifp)
2093
0
    return;
2094
2095
0
  if (mac->zevpn->vxlan_if) {
2096
0
    zif = mac->zevpn->vxlan_if->info;
2097
0
    vni = zebra_vxlan_if_vni_find(zif, mac->zevpn->vni);
2098
0
    vid = vni->access_vlan;
2099
0
  } else {
2100
0
    vid = 0;
2101
0
  }
2102
2103
  /* delete the local mac from the dataplane */
2104
0
  dplane_local_mac_del(ifp, br_ifp, vid, &mac->macaddr);
2105
  /* delete the local mac in zebra */
2106
0
  zebra_evpn_del_local_mac(mac->zevpn, mac, true);
2107
0
}
2108
2109
static void zebra_evpn_es_flush_local_macs(struct zebra_evpn_es *es,
2110
             struct interface *ifp, bool add)
2111
0
{
2112
0
  struct zebra_mac *mac;
2113
0
  struct listnode *node;
2114
0
  struct listnode *nnode;
2115
2116
0
  for (ALL_LIST_ELEMENTS(es->mac_list, node, nnode, mac)) {
2117
0
    if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
2118
0
      continue;
2119
2120
    /* If ES is being attached/detached from the access port we
2121
     * need to clear local activity and peer activity and start
2122
     * over */
2123
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2124
0
      zlog_debug("VNI %u mac %pEA update; local ES %s %s",
2125
0
           mac->zevpn->vni,
2126
0
           &mac->macaddr,
2127
0
           es->esi_str, add ? "add" : "del");
2128
0
    zebra_evpn_flush_local_mac(mac, ifp);
2129
0
  }
2130
0
}
2131
2132
void zebra_evpn_es_local_br_port_update(struct zebra_if *zif)
2133
0
{
2134
0
  struct zebra_evpn_es *es = zif->es_info.es;
2135
0
  bool old_br_port = !!(es->flags & ZEBRA_EVPNES_BR_PORT);
2136
0
  bool new_br_port;
2137
2138
0
  if (zif->brslave_info.bridge_ifindex != IFINDEX_INTERNAL)
2139
0
    es->flags |= ZEBRA_EVPNES_BR_PORT;
2140
0
  else
2141
0
    es->flags &= ~ZEBRA_EVPNES_BR_PORT;
2142
2143
0
  new_br_port = !!(es->flags & ZEBRA_EVPNES_BR_PORT);
2144
0
  if (old_br_port == new_br_port)
2145
0
    return;
2146
2147
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2148
0
    zlog_debug("es %s br_port change old %u new %u", es->esi_str,
2149
0
         old_br_port, new_br_port);
2150
2151
  /* update the dataplane br_port attrs */
2152
0
  if (new_br_port && zebra_evpn_es_br_port_dplane_update_needed(es))
2153
0
    zebra_evpn_es_br_port_dplane_update(es, __func__);
2154
0
}
2155
2156
/* On config of first local-ES turn off DAD */
2157
static void zebra_evpn_mh_dup_addr_detect_off(void)
2158
0
{
2159
0
  struct zebra_vrf *zvrf;
2160
0
  bool old_detect;
2161
0
  bool new_detect;
2162
2163
0
  if (zmh_info->flags & ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF)
2164
0
    return;
2165
2166
0
  zvrf = zebra_vrf_get_evpn();
2167
0
  old_detect = zebra_evpn_do_dup_addr_detect(zvrf);
2168
0
  zmh_info->flags |= ZEBRA_EVPN_MH_DUP_ADDR_DETECT_OFF;
2169
0
  new_detect = zebra_evpn_do_dup_addr_detect(zvrf);
2170
2171
0
  if (old_detect && !new_detect) {
2172
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2173
0
      zlog_debug(
2174
0
        "evpn-mh config caused DAD addr detect chg from %s to %s",
2175
0
        old_detect ? "on" : "off",
2176
0
        new_detect ? "on" : "off");
2177
0
    zebra_vxlan_clear_dup_detect_vni_all(zvrf);
2178
0
  }
2179
0
}
2180
2181
/* On config of first local-ES turn off advertisement of STALE/DELAY/PROBE
2182
 * neighbors
2183
 */
2184
static void zebra_evpn_mh_advertise_reach_neigh_only(void)
2185
0
{
2186
0
  if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY)
2187
0
    return;
2188
2189
0
  zmh_info->flags |= ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY;
2190
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2191
0
    zlog_debug("evpn-mh: only REACHABLE neigh advertised");
2192
2193
  /* XXX - if STALE/DELAY/PROBE neighs were previously advertised we
2194
   * need to withdraw them
2195
   */
2196
0
}
2197
2198
/* On config of first local-ES turn on advertisement of local SVI-MAC */
2199
static void zebra_evpn_mh_advertise_svi_mac(void)
2200
0
{
2201
0
  if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_SVI_MAC)
2202
0
    return;
2203
2204
0
  zmh_info->flags |= ZEBRA_EVPN_MH_ADV_SVI_MAC;
2205
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2206
0
    zlog_debug("evpn-mh: advertise SVI MAC");
2207
2208
  /* walk through all SVIs and see if we need to advertise the MAC */
2209
0
  zebra_evpn_acc_vl_adv_svi_mac_all();
2210
0
}
2211
2212
static void zebra_evpn_es_df_delay_exp_cb(struct event *t)
2213
0
{
2214
0
  struct zebra_evpn_es *es;
2215
0
2216
0
  es = EVENT_ARG(t);
2217
0
2218
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2219
0
    zlog_debug("es %s df-delay expired", es->esi_str);
2220
0
2221
0
  zebra_evpn_es_run_df_election(es, __func__);
2222
0
}
2223
2224
/* currently there is no global config to turn on MH instead we use
2225
 * the addition of the first local Ethernet Segment as the trigger to
2226
 * init MH specific processing
2227
 */
2228
static void zebra_evpn_mh_on_first_local_es(void)
2229
0
{
2230
0
  zebra_evpn_mh_dup_addr_detect_off();
2231
0
  zebra_evpn_mh_advertise_reach_neigh_only();
2232
0
  zebra_evpn_mh_advertise_svi_mac();
2233
0
}
2234
2235
static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
2236
    struct zebra_if *zif)
2237
0
{
2238
0
  if (es->flags & ZEBRA_EVPNES_LOCAL)
2239
0
    return;
2240
2241
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2242
0
    zlog_debug("local es %s add; nhg %u if %s", es->esi_str,
2243
0
         es->nhg_id, zif->ifp->name);
2244
2245
0
  zebra_evpn_mh_on_first_local_es();
2246
2247
0
  es->flags |= ZEBRA_EVPNES_LOCAL;
2248
0
  listnode_init(&es->local_es_listnode, es);
2249
0
  listnode_add(zmh_info->local_es_list, &es->local_es_listnode);
2250
2251
  /* attach es to interface */
2252
0
  zif->es_info.es = es;
2253
0
  es->df_pref = zif->es_info.df_pref ? zif->es_info.df_pref
2254
0
             : EVPN_MH_DF_PREF_DEFAULT;
2255
2256
  /* attach interface to es */
2257
0
  es->zif = zif;
2258
0
  if (if_is_operative(zif->ifp))
2259
0
    es->flags |= ZEBRA_EVPNES_OPER_UP;
2260
2261
0
  if (zif->brslave_info.bridge_ifindex != IFINDEX_INTERNAL)
2262
0
    es->flags |= ZEBRA_EVPNES_BR_PORT;
2263
2264
  /* inherit the bypass flag from the interface */
2265
0
  if (zif->flags & ZIF_FLAG_LACP_BYPASS)
2266
0
    es->flags |= ZEBRA_EVPNES_BYPASS;
2267
2268
  /* setup base-vni if one doesn't already exist; the ES will get sent
2269
   * to BGP as a part of that process
2270
   */
2271
0
  if (!zmh_info->es_base_evpn)
2272
0
    zebra_evpn_es_get_one_base_evpn();
2273
0
  else
2274
    /* send notification to bgp */
2275
0
    zebra_evpn_es_re_eval_send_to_client(es,
2276
0
      false /* es_evi_re_reval */);
2277
2278
  /* Start the DF delay timer on the local ES */
2279
0
  if (!es->df_delay_timer)
2280
0
    event_add_timer(zrouter.master, zebra_evpn_es_df_delay_exp_cb,
2281
0
        es, ZEBRA_EVPN_MH_DF_DELAY_TIME,
2282
0
        &es->df_delay_timer);
2283
2284
  /* See if the local VTEP can function as DF on the ES */
2285
0
  if (!zebra_evpn_es_run_df_election(es, __func__)) {
2286
    /* check if the dplane entry needs to be re-programmed as a
2287
     * result of some thing other than DF status change
2288
     */
2289
0
    if (zebra_evpn_es_br_port_dplane_update_needed(es))
2290
0
      zebra_evpn_es_br_port_dplane_update(es, __func__);
2291
0
  }
2292
2293
2294
  /* Setup ES-EVIs for all VxLAN stretched VLANs associated with
2295
   * the zif
2296
   */
2297
0
  zebra_evpn_es_setup_evis(es);
2298
  /* if there any local macs referring to the ES as dest we
2299
   * need to clear the contents and start over
2300
   */
2301
0
  zebra_evpn_es_flush_local_macs(es, zif->ifp, true);
2302
2303
  /* inherit EVPN protodown flags on the access port */
2304
0
  zebra_evpn_mh_update_protodown_es(es, true /*resync_dplane*/);
2305
0
}
2306
2307
static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
2308
0
{
2309
0
  struct zebra_if *zif;
2310
0
  struct zebra_evpn_es *es = *esp;
2311
0
  bool dplane_updated = false;
2312
2313
0
  if (!(es->flags & ZEBRA_EVPNES_LOCAL))
2314
0
    return;
2315
2316
0
  zif = es->zif;
2317
2318
  /* if there any local macs referring to the ES as dest we
2319
   * need to clear the contents and start over
2320
   */
2321
0
  zebra_evpn_es_flush_local_macs(es, zif->ifp, false);
2322
2323
0
  es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
2324
2325
0
  EVENT_OFF(es->df_delay_timer);
2326
2327
  /* clear EVPN protodown flags on the access port */
2328
0
  zebra_evpn_mh_clear_protodown_es(es);
2329
2330
  /* remove the DF filter */
2331
0
  dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
2332
2333
  /* flush the BUM filters and backup NHG */
2334
0
  if (!dplane_updated)
2335
0
    zebra_evpn_es_br_port_dplane_clear(es);
2336
2337
  /* clear the es from the parent interface */
2338
0
  zif->es_info.es = NULL;
2339
0
  es->zif = NULL;
2340
2341
  /* clear all local flags associated with the ES */
2342
0
  es->flags &= ~(ZEBRA_EVPNES_OPER_UP | ZEBRA_EVPNES_BR_PORT
2343
0
           | ZEBRA_EVPNES_BYPASS);
2344
2345
  /* remove from the ES list */
2346
0
  list_delete_node(zmh_info->local_es_list, &es->local_es_listnode);
2347
2348
  /* free up the ES if there is no remote reference */
2349
0
  zebra_evpn_es_free(esp);
2350
0
}
2351
2352
/* Delete an ethernet segment and inform BGP */
2353
static void zebra_evpn_local_es_del(struct zebra_evpn_es **esp)
2354
0
{
2355
0
  struct zebra_evpn_es_evi *es_evi;
2356
0
  struct listnode *node = NULL;
2357
0
  struct listnode *nnode = NULL;
2358
0
  struct zebra_if *zif;
2359
0
  struct zebra_evpn_es *es = *esp;
2360
2361
0
  if (!CHECK_FLAG(es->flags, ZEBRA_EVPNES_LOCAL))
2362
0
    return;
2363
2364
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES) {
2365
0
    zif = es->zif;
2366
0
    zlog_debug("local es %s del; nhg %u if %s", es->esi_str,
2367
0
         es->nhg_id, zif ? zif->ifp->name : "-");
2368
0
  }
2369
2370
  /* remove all ES-EVIs associated with the ES */
2371
0
  for (ALL_LIST_ELEMENTS(es->es_evi_list, node, nnode, es_evi))
2372
0
    zebra_evpn_local_es_evi_do_del(es_evi);
2373
2374
  /* send a del if the ES had been sent to BGP earlier */
2375
0
  if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2376
0
    zebra_evpn_es_send_del_to_client(es);
2377
2378
0
  zebra_evpn_es_local_info_clear(esp);
2379
0
}
2380
2381
/* eval remote info associated with the ES */
2382
static void zebra_evpn_es_remote_info_re_eval(struct zebra_evpn_es **esp)
2383
0
{
2384
0
  struct zebra_evpn_es *es = *esp;
2385
2386
  /* if there are remote VTEPs the ES-EVI is classified as "remote" */
2387
0
  if (listcount(es->es_vtep_list)) {
2388
0
    if (!(es->flags & ZEBRA_EVPNES_REMOTE)) {
2389
0
      es->flags |= ZEBRA_EVPNES_REMOTE;
2390
0
      if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2391
0
        zlog_debug("remote es %s add; nhg %u",
2392
0
             es->esi_str, es->nhg_id);
2393
0
    }
2394
0
  } else {
2395
0
    if (es->flags & ZEBRA_EVPNES_REMOTE) {
2396
0
      es->flags &= ~ZEBRA_EVPNES_REMOTE;
2397
0
      if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2398
0
        zlog_debug("remote es %s del; nhg %u",
2399
0
             es->esi_str, es->nhg_id);
2400
0
      zebra_evpn_es_free(esp);
2401
0
    }
2402
0
  }
2403
0
}
2404
2405
/* A new local es is created when a local-es-id and sysmac is configured
2406
 * against an interface.
2407
 */
2408
static int zebra_evpn_local_es_update(struct zebra_if *zif, esi_t *esi)
2409
0
{
2410
0
  struct zebra_evpn_es *old_es = zif->es_info.es;
2411
0
  struct zebra_evpn_es *es;
2412
2413
0
  if (old_es && !memcmp(&old_es->esi, esi, sizeof(*esi)))
2414
    /* dup - nothing to be done */
2415
0
    return 0;
2416
2417
  /* release the old_es against the zif */
2418
0
  if (old_es)
2419
0
    zebra_evpn_local_es_del(&old_es);
2420
2421
0
  es = zebra_evpn_es_find(esi);
2422
0
  if (es) {
2423
    /* if it exists against another interface flag an error */
2424
0
    if (es->zif && es->zif != zif)
2425
0
      return -1;
2426
0
  } else {
2427
    /* create new es */
2428
0
    es = zebra_evpn_es_new(esi);
2429
0
  }
2430
2431
0
  memcpy(&zif->es_info.esi, esi, sizeof(*esi));
2432
0
  if (es)
2433
0
    zebra_evpn_es_local_info_set(es, zif);
2434
2435
0
  return 0;
2436
0
}
2437
2438
static int zebra_evpn_type3_esi_update(struct zebra_if *zif, uint32_t lid,
2439
               struct ethaddr *sysmac)
2440
0
{
2441
0
  struct zebra_evpn_es *old_es = zif->es_info.es;
2442
0
  esi_t esi;
2443
0
  int offset = 0;
2444
0
  int field_bytes = 0;
2445
2446
  /* Complete config of the ES-ID bootstraps the ES */
2447
0
  if (!lid || is_zero_mac(sysmac)) {
2448
    /* clear old esi */
2449
0
    memset(&zif->es_info.esi, 0, sizeof(zif->es_info.esi));
2450
    /* if in ES is attached to zif delete it */
2451
0
    if (old_es)
2452
0
      zebra_evpn_local_es_del(&old_es);
2453
0
    return 0;
2454
0
  }
2455
2456
  /* build 10-byte type-3-ESI -
2457
   * Type(1-byte), MAC(6-bytes), ES-LID (3-bytes)
2458
   */
2459
0
  field_bytes = 1;
2460
0
  esi.val[offset] = ESI_TYPE_MAC;
2461
0
  offset += field_bytes;
2462
2463
0
  field_bytes = ETH_ALEN;
2464
0
  memcpy(&esi.val[offset], (uint8_t *)sysmac, field_bytes);
2465
0
  offset += field_bytes;
2466
2467
0
  esi.val[offset++] = (uint8_t)(lid >> 16);
2468
0
  esi.val[offset++] = (uint8_t)(lid >> 8);
2469
0
  esi.val[offset++] = (uint8_t)lid;
2470
2471
0
  return zebra_evpn_local_es_update(zif, &esi);
2472
0
}
2473
2474
int zebra_evpn_remote_es_del(const esi_t *esi, struct in_addr vtep_ip)
2475
0
{
2476
0
  char buf[ESI_STR_LEN];
2477
0
  struct zebra_evpn_es *es;
2478
2479
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2480
0
    zlog_debug("remote es %s vtep %pI4 del",
2481
0
         esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
2482
2483
0
  es = zebra_evpn_es_find(esi);
2484
0
  if (!es) {
2485
0
    zlog_warn("remote es %s vtep %pI4 del failed, es missing",
2486
0
        esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
2487
0
    return -1;
2488
0
  }
2489
2490
0
  zebra_evpn_es_vtep_del(es, vtep_ip);
2491
0
  zebra_evpn_es_remote_info_re_eval(&es);
2492
2493
0
  return 0;
2494
0
}
2495
2496
/* force delete a remote ES on the way down */
2497
static void zebra_evpn_remote_es_flush(struct zebra_evpn_es **esp)
2498
0
{
2499
0
  struct zebra_evpn_es_vtep *es_vtep;
2500
0
  struct listnode *node;
2501
0
  struct listnode *nnode;
2502
0
  struct zebra_evpn_es *es = *esp;
2503
2504
0
  for (ALL_LIST_ELEMENTS(es->es_vtep_list, node, nnode, es_vtep)) {
2505
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2506
0
      zlog_debug("es %s vtep %pI4 flush",
2507
0
          es->esi_str,
2508
0
          &es_vtep->vtep_ip);
2509
0
    zebra_evpn_es_vtep_free(es_vtep);
2510
0
  }
2511
0
  zebra_evpn_es_remote_info_re_eval(esp);
2512
0
}
2513
2514
int zebra_evpn_remote_es_add(const esi_t *esi, struct in_addr vtep_ip,
2515
           bool esr_rxed, uint8_t df_alg, uint16_t df_pref)
2516
0
{
2517
0
  char buf[ESI_STR_LEN];
2518
0
  struct zebra_evpn_es *es;
2519
2520
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2521
0
    zlog_debug("remote es %s vtep %pI4 add %s df_alg %d df_pref %d",
2522
0
         esi_to_str(esi, buf, sizeof(buf)),
2523
0
         &vtep_ip, esr_rxed ? "esr" : "", df_alg,
2524
0
         df_pref);
2525
2526
0
  es = zebra_evpn_es_find(esi);
2527
0
  if (!es) {
2528
0
    es = zebra_evpn_es_new(esi);
2529
0
    if (!es) {
2530
0
      zlog_warn(
2531
0
        "remote es %s vtep %pI4 add failed, es missing",
2532
0
        esi_to_str(esi, buf, sizeof(buf)), &vtep_ip);
2533
0
      return -1;
2534
0
    }
2535
0
  }
2536
2537
0
  if (df_alg != EVPN_MH_DF_ALG_PREF)
2538
0
    zlog_warn(
2539
0
      "remote es %s vtep %pI4 add %s with unsupported df_alg %d",
2540
0
      esi_to_str(esi, buf, sizeof(buf)), &vtep_ip,
2541
0
      esr_rxed ? "esr" : "", df_alg);
2542
2543
0
  zebra_evpn_es_vtep_add(es, vtep_ip, esr_rxed, df_alg, df_pref);
2544
0
  zebra_evpn_es_remote_info_re_eval(&es);
2545
2546
0
  return 0;
2547
0
}
2548
2549
void zebra_evpn_proc_remote_es(ZAPI_HANDLER_ARGS)
2550
0
{
2551
0
  struct stream *s;
2552
0
  struct in_addr vtep_ip;
2553
0
  esi_t esi;
2554
2555
0
  if (!is_evpn_enabled()) {
2556
0
    zlog_debug(
2557
0
      "%s: EVPN not enabled yet we received a es_add zapi call",
2558
0
      __func__);
2559
0
    return;
2560
0
  }
2561
2562
0
  memset(&esi, 0, sizeof(esi_t));
2563
0
  s = msg;
2564
2565
0
  STREAM_GET(&esi, s, sizeof(esi_t));
2566
0
  STREAM_GET(&vtep_ip.s_addr, s, sizeof(vtep_ip.s_addr));
2567
2568
0
  if (hdr->command == ZEBRA_REMOTE_ES_VTEP_ADD) {
2569
0
    uint32_t zapi_flags;
2570
0
    uint8_t df_alg;
2571
0
    uint16_t df_pref;
2572
0
    bool esr_rxed;
2573
2574
0
    STREAM_GETL(s, zapi_flags);
2575
0
    esr_rxed = (zapi_flags & ZAPI_ES_VTEP_FLAG_ESR_RXED) ? true
2576
0
                     : false;
2577
0
    STREAM_GETC(s, df_alg);
2578
0
    STREAM_GETW(s, df_pref);
2579
0
    zebra_rib_queue_evpn_rem_es_add(&esi, &vtep_ip, esr_rxed,
2580
0
            df_alg, df_pref);
2581
0
  } else {
2582
0
    zebra_rib_queue_evpn_rem_es_del(&esi, &vtep_ip);
2583
0
  }
2584
2585
0
stream_failure:
2586
0
  return;
2587
0
}
2588
2589
void zebra_evpn_es_mac_deref_entry(struct zebra_mac *mac)
2590
0
{
2591
0
  struct zebra_evpn_es *es = mac->es;
2592
2593
0
  mac->es = NULL;
2594
0
  if (!es)
2595
0
    return;
2596
2597
0
  list_delete_node(es->mac_list, &mac->es_listnode);
2598
0
  if (!listcount(es->mac_list))
2599
0
    zebra_evpn_es_free(&es);
2600
0
}
2601
2602
/* Associate a MAC entry with a local or remote ES. Returns false if there
2603
 * was no ES change.
2604
 */
2605
bool zebra_evpn_es_mac_ref_entry(struct zebra_mac *mac,
2606
         struct zebra_evpn_es *es)
2607
0
{
2608
0
  if (mac->es == es)
2609
0
    return false;
2610
2611
0
  if (mac->es)
2612
0
    zebra_evpn_es_mac_deref_entry(mac);
2613
2614
0
  if (!es)
2615
0
    return true;
2616
2617
0
  mac->es = es;
2618
0
  listnode_init(&mac->es_listnode, mac);
2619
0
  listnode_add(es->mac_list, &mac->es_listnode);
2620
2621
0
  return true;
2622
0
}
2623
2624
bool zebra_evpn_es_mac_ref(struct zebra_mac *mac, const esi_t *esi)
2625
0
{
2626
0
  struct zebra_evpn_es *es;
2627
2628
0
  es = zebra_evpn_es_find(esi);
2629
0
  if (!es) {
2630
    /* If non-zero esi implicitly create a new ES */
2631
0
    if (memcmp(esi, zero_esi, sizeof(esi_t))) {
2632
0
      es = zebra_evpn_es_new(esi);
2633
0
      if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2634
0
        zlog_debug("auto es %s add on mac ref",
2635
0
             es->esi_str);
2636
0
    }
2637
0
  }
2638
2639
0
  return zebra_evpn_es_mac_ref_entry(mac, es);
2640
0
}
2641
2642
/* Inform BGP about local ES-EVI add or del */
2643
static int zebra_evpn_es_evi_send_to_client(struct zebra_evpn_es *es,
2644
              struct zebra_evpn *zevpn, bool add)
2645
0
{
2646
0
  struct zserv *client;
2647
0
  struct stream *s;
2648
2649
0
  client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
2650
  /* BGP may not be running. */
2651
0
  if (!client)
2652
0
    return 0;
2653
2654
0
  s = stream_new(ZEBRA_MAX_PACKET_SIZ);
2655
2656
0
  zclient_create_header(s,
2657
0
      add ? ZEBRA_LOCAL_ES_EVI_ADD : ZEBRA_LOCAL_ES_EVI_DEL,
2658
0
      zebra_vrf_get_evpn_id());
2659
0
  stream_put(s, &es->esi, sizeof(esi_t));
2660
0
  stream_putl(s, zevpn->vni);
2661
2662
  /* Write packet size. */
2663
0
  stream_putw_at(s, 0, stream_get_endp(s));
2664
2665
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2666
0
    zlog_debug("send %s local es %s evi %u to %s",
2667
0
        add ? "add" : "del",
2668
0
        es->esi_str, zevpn->vni,
2669
0
        zebra_route_string(client->proto));
2670
2671
0
  client->local_es_add_cnt++;
2672
0
  return zserv_send_message(client, s);
2673
0
}
2674
2675
/* sysmac part of a local ESI has changed */
2676
static int zebra_evpn_es_sys_mac_update(struct zebra_if *zif,
2677
    struct ethaddr *sysmac)
2678
0
{
2679
0
  int rv;
2680
2681
0
  rv = zebra_evpn_type3_esi_update(zif, zif->es_info.lid, sysmac);
2682
0
  if (!rv)
2683
0
    memcpy(&zif->es_info.sysmac, sysmac, sizeof(struct ethaddr));
2684
2685
0
  return rv;
2686
0
}
2687
2688
/* local-ID part of ESI has changed */
2689
static int zebra_evpn_es_lid_update(struct zebra_if *zif, uint32_t lid)
2690
0
{
2691
0
  int rv;
2692
2693
0
  rv = zebra_evpn_type3_esi_update(zif, lid, &zif->es_info.sysmac);
2694
0
  if (!rv)
2695
0
    zif->es_info.lid = lid;
2696
2697
0
  return rv;
2698
0
}
2699
2700
/* type-0 esi has changed */
2701
static int zebra_evpn_es_type0_esi_update(struct zebra_if *zif, esi_t *esi)
2702
0
{
2703
0
  int rv;
2704
2705
0
  rv = zebra_evpn_local_es_update(zif, esi);
2706
2707
  /* clear the old es_lid, es_sysmac - type-0 is being set so old
2708
   * type-3 params need to be flushed
2709
   */
2710
0
  memset(&zif->es_info.sysmac, 0, sizeof(struct ethaddr));
2711
0
  zif->es_info.lid = 0;
2712
2713
0
  return rv;
2714
0
}
2715
2716
void zebra_evpn_es_cleanup(void)
2717
0
{
2718
0
  struct zebra_evpn_es *es;
2719
0
  struct zebra_evpn_es *es_next;
2720
2721
0
  RB_FOREACH_SAFE(es, zebra_es_rb_head,
2722
0
      &zmh_info->es_rb_tree, es_next) {
2723
0
    zebra_evpn_local_es_del(&es);
2724
0
    if (es)
2725
0
      zebra_evpn_remote_es_flush(&es);
2726
0
  }
2727
0
}
2728
2729
static void zebra_evpn_es_df_pref_update(struct zebra_if *zif, uint16_t df_pref)
2730
0
{
2731
0
  struct zebra_evpn_es *es;
2732
0
  uint16_t tmp_pref;
2733
2734
0
  if (zif->es_info.df_pref == df_pref)
2735
0
    return;
2736
2737
0
  zif->es_info.df_pref = df_pref;
2738
0
  es = zif->es_info.es;
2739
2740
0
  if (!es)
2741
0
    return;
2742
2743
0
  tmp_pref = zif->es_info.df_pref ? zif->es_info.df_pref
2744
0
          : EVPN_MH_DF_PREF_DEFAULT;
2745
2746
0
  if (es->df_pref == tmp_pref)
2747
0
    return;
2748
2749
0
  es->df_pref = tmp_pref;
2750
  /* run df election */
2751
0
  zebra_evpn_es_run_df_election(es, __func__);
2752
  /* notify bgp */
2753
0
  if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2754
0
    zebra_evpn_es_send_add_to_client(es);
2755
0
}
2756
2757
/* If bypass mode on an es changed we set all local macs to
2758
 * inactive and drop the sync info
2759
 */
2760
static void zebra_evpn_es_bypass_update_macs(struct zebra_evpn_es *es,
2761
               struct interface *ifp, bool bypass)
2762
0
{
2763
0
  struct zebra_mac *mac;
2764
0
  struct listnode *node;
2765
0
  struct listnode *nnode;
2766
0
  struct zebra_if *zif;
2767
2768
  /* Flush all MACs linked to the ES */
2769
0
  for (ALL_LIST_ELEMENTS(es->mac_list, node, nnode, mac)) {
2770
0
    if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
2771
0
      continue;
2772
2773
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2774
0
      zlog_debug("VNI %u mac %pEA %s update es %s",
2775
0
           mac->zevpn->vni,
2776
0
           &mac->macaddr,
2777
0
           bypass ? "bypass" : "non-bypass",
2778
0
           es->esi_str);
2779
0
    zebra_evpn_flush_local_mac(mac, ifp);
2780
0
  }
2781
2782
  /* While in bypass-mode locally learnt MACs are linked
2783
   * to the access port instead of the ES
2784
   */
2785
0
  zif = ifp->info;
2786
0
  if (!zif->mac_list)
2787
0
    return;
2788
2789
0
  for (ALL_LIST_ELEMENTS(zif->mac_list, node, nnode, mac)) {
2790
0
    if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
2791
0
      continue;
2792
2793
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2794
0
      zlog_debug("VNI %u mac %pEA %s update ifp %s",
2795
0
           mac->zevpn->vni,
2796
0
           &mac->macaddr,
2797
0
           bypass ? "bypass" : "non-bypass", ifp->name);
2798
0
    zebra_evpn_flush_local_mac(mac, ifp);
2799
0
  }
2800
0
}
2801
2802
void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es,
2803
         struct interface *ifp, bool bypass)
2804
0
{
2805
0
  bool old_bypass;
2806
0
  bool dplane_updated;
2807
2808
0
  old_bypass = !!(es->flags & ZEBRA_EVPNES_BYPASS);
2809
0
  if (old_bypass == bypass)
2810
0
    return;
2811
2812
0
  if (bypass)
2813
0
    es->flags |= ZEBRA_EVPNES_BYPASS;
2814
0
  else
2815
0
    es->flags &= ~ZEBRA_EVPNES_BYPASS;
2816
2817
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
2818
0
    zlog_debug("bond %s es %s lacp bypass changed to %s", ifp->name,
2819
0
         es->esi_str, bypass ? "on" : "off");
2820
2821
  /* send bypass update to BGP */
2822
0
  if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
2823
0
    zebra_evpn_es_send_add_to_client(es);
2824
2825
0
  zebra_evpn_es_bypass_update_macs(es, ifp, bypass);
2826
2827
  /* re-run DF election */
2828
0
  dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
2829
2830
  /* disable SPH filter */
2831
0
  if (!dplane_updated && (es->flags & ZEBRA_EVPNES_LOCAL)
2832
0
      && (listcount(es->es_vtep_list) > ES_VTEP_MAX_CNT))
2833
0
    zebra_evpn_es_br_port_dplane_update(es, __func__);
2834
0
}
2835
2836
static void zebra_evpn_es_bypass_cfg_update(struct zebra_if *zif, bool bypass)
2837
0
{
2838
0
  bool old_bypass = !!(zif->es_info.flags & ZIF_CFG_ES_FLAG_BYPASS);
2839
2840
0
  if (old_bypass == bypass)
2841
0
    return;
2842
2843
0
  if (bypass)
2844
0
    zif->es_info.flags |= ZIF_CFG_ES_FLAG_BYPASS;
2845
0
  else
2846
0
    zif->es_info.flags &= ~ZIF_CFG_ES_FLAG_BYPASS;
2847
2848
2849
0
  if (zif->es_info.es)
2850
0
    zebra_evpn_es_bypass_update(zif->es_info.es, zif->ifp, bypass);
2851
0
}
2852
2853
2854
/* Only certain types of access ports can be setup as an Ethernet Segment */
2855
bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
2856
0
{
2857
0
  if (zif->zif_type == ZEBRA_IF_BOND)
2858
0
    return true;
2859
2860
  /* relax the checks to allow config to be applied in zebra
2861
   * before interface is rxed from the kernel
2862
   */
2863
0
  if (zif->ifp->ifindex == IFINDEX_INTERNAL)
2864
0
    return true;
2865
2866
  /* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
2867
0
  return false;
2868
0
}
2869
2870
void zebra_evpn_if_es_print(struct vty *vty, json_object *json,
2871
          struct zebra_if *zif)
2872
0
{
2873
0
  char buf[ETHER_ADDR_STRLEN];
2874
0
  char esi_buf[ESI_STR_LEN];
2875
2876
0
  if (json) {
2877
0
    json_object *json_evpn;
2878
2879
0
    json_evpn = json_object_new_object();
2880
0
    json_object_object_add(json, "evpnMh", json_evpn);
2881
2882
0
    if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
2883
0
      json_object_int_add(json_evpn, "esId",
2884
0
              zif->es_info.lid);
2885
0
      json_object_string_add(
2886
0
        json_evpn, "esSysmac",
2887
0
        prefix_mac2str(&zif->es_info.sysmac, buf,
2888
0
                 sizeof(buf)));
2889
0
    } else if (memcmp(&zif->es_info.esi, zero_esi,
2890
0
          sizeof(*zero_esi))) {
2891
0
      json_object_string_add(json_evpn, "esId",
2892
0
                 esi_to_str(&zif->es_info.esi,
2893
0
                esi_buf,
2894
0
                sizeof(esi_buf)));
2895
0
    }
2896
2897
0
    if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
2898
0
      json_object_string_add(
2899
0
        json_evpn, "uplink",
2900
0
        CHECK_FLAG(zif->flags,
2901
0
             ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
2902
0
          ? "up"
2903
0
          : "down");
2904
0
  } else {
2905
0
    char mh_buf[80];
2906
0
    bool vty_print = false;
2907
2908
0
    mh_buf[0] = '\0';
2909
0
    strlcat(mh_buf, "  EVPN-MH:", sizeof(mh_buf));
2910
0
    if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
2911
0
      vty_print = true;
2912
0
      snprintf(mh_buf + strlen(mh_buf),
2913
0
         sizeof(mh_buf) - strlen(mh_buf),
2914
0
         " ES id %u ES sysmac %s", zif->es_info.lid,
2915
0
         prefix_mac2str(&zif->es_info.sysmac, buf,
2916
0
            sizeof(buf)));
2917
0
    } else if (memcmp(&zif->es_info.esi, zero_esi,
2918
0
          sizeof(*zero_esi))) {
2919
0
      vty_print = true;
2920
0
      snprintf(mh_buf + strnlen(mh_buf, sizeof(mh_buf)),
2921
0
         sizeof(mh_buf)
2922
0
           - strnlen(mh_buf, sizeof(mh_buf)),
2923
0
         " ES id %s",
2924
0
         esi_to_str(&zif->es_info.esi, esi_buf,
2925
0
              sizeof(esi_buf)));
2926
0
    }
2927
2928
0
    if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) {
2929
0
      vty_print = true;
2930
0
      if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
2931
0
        strlcat(mh_buf, " uplink (up)", sizeof(mh_buf));
2932
0
      else
2933
0
        strlcat(mh_buf, " uplink (down)",
2934
0
          sizeof(mh_buf));
2935
0
    }
2936
2937
0
    if (vty_print)
2938
0
      vty_out(vty, "%s\n", mh_buf);
2939
0
  }
2940
0
}
2941
2942
static void zebra_evpn_local_mac_oper_state_change(struct zebra_evpn_es *es)
2943
0
{
2944
0
  struct zebra_mac *mac;
2945
0
  struct listnode *node;
2946
2947
  /* If fast-failover is supported by the dataplane via the use
2948
   * of an ES backup NHG there is nothing to be done in the
2949
   * control plane
2950
   */
2951
0
  if (!(zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF))
2952
0
    return;
2953
2954
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2955
0
    zlog_debug("mac slow-fail on es %s %s ", es->esi_str,
2956
0
         (es->flags & ZEBRA_EVPNES_OPER_UP) ? "up" : "down");
2957
2958
0
  for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) {
2959
0
    if (!(mac->flags & ZEBRA_MAC_LOCAL)
2960
0
        || !zebra_evpn_mac_is_static(mac))
2961
0
      continue;
2962
2963
0
    if (es->flags & ZEBRA_EVPNES_OPER_UP) {
2964
0
      if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2965
0
        zlog_debug(
2966
0
          "VNI %u mac %pEA move to acc %s es %s %s ",
2967
0
          mac->zevpn->vni,
2968
0
          &mac->macaddr,
2969
0
          es->zif->ifp->name, es->esi_str,
2970
0
          (es->flags & ZEBRA_EVPNES_OPER_UP)
2971
0
            ? "up"
2972
0
            : "down");
2973
      /* switch the local macs to access port */
2974
0
      if (zebra_evpn_sync_mac_dp_install(
2975
0
            mac, false /*set_inactive*/,
2976
0
            false /*force_clear_static*/, __func__)
2977
0
          < 0)
2978
        /* if the local mac install fails get rid of the
2979
         * old rem entry
2980
         */
2981
0
        zebra_evpn_rem_mac_uninstall(mac->zevpn, mac,
2982
0
                   true /*force*/);
2983
0
    } else {
2984
      /* switch the local macs to network port. if there
2985
       * is no active NHG we don't bother deleting the MAC;
2986
       * that is left up to the dataplane to handle.
2987
       */
2988
0
      if (!(es->flags & ZEBRA_EVPNES_NHG_ACTIVE))
2989
0
        continue;
2990
0
      if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
2991
0
        zlog_debug(
2992
0
          "VNI %u mac %pEA move to nhg %u es %s %s ",
2993
0
          mac->zevpn->vni,
2994
0
          &mac->macaddr,
2995
0
          es->nhg_id, es->esi_str,
2996
0
          (es->flags & ZEBRA_EVPNES_OPER_UP)
2997
0
            ? "up"
2998
0
            : "down");
2999
0
      zebra_evpn_rem_mac_install(mac->zevpn, mac,
3000
0
               true /*was_static*/);
3001
0
    }
3002
0
  }
3003
0
}
3004
3005
void zebra_evpn_es_if_oper_state_change(struct zebra_if *zif, bool up)
3006
0
{
3007
0
  struct zebra_evpn_es *es = zif->es_info.es;
3008
0
  bool old_up = !!(es->flags & ZEBRA_EVPNES_OPER_UP);
3009
3010
0
  if (old_up == up)
3011
0
    return;
3012
3013
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3014
0
    zlog_debug("es %s state changed to %s ",
3015
0
        es->esi_str,
3016
0
        up ? "up" : "down");
3017
0
  if (up)
3018
0
    es->flags |= ZEBRA_EVPNES_OPER_UP;
3019
0
  else
3020
0
    es->flags &= ~ZEBRA_EVPNES_OPER_UP;
3021
3022
0
  zebra_evpn_es_run_df_election(es, __func__);
3023
0
  zebra_evpn_local_mac_oper_state_change(es);
3024
3025
  /* inform BGP of the ES oper state change */
3026
0
  if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
3027
0
    zebra_evpn_es_send_add_to_client(es);
3028
0
}
3029
3030
static char *zebra_evpn_es_vtep_str(char *vtep_str, struct zebra_evpn_es *es,
3031
            uint8_t vtep_str_size)
3032
0
{
3033
0
  struct zebra_evpn_es_vtep *zvtep;
3034
0
  struct listnode *node;
3035
0
  bool first = true;
3036
0
  char ip_buf[INET6_ADDRSTRLEN];
3037
3038
0
  vtep_str[0] = '\0';
3039
0
  for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, zvtep)) {
3040
0
    if (first) {
3041
0
      first = false;
3042
0
      strlcat(vtep_str,
3043
0
        inet_ntop(AF_INET, &zvtep->vtep_ip, ip_buf,
3044
0
            sizeof(ip_buf)),
3045
0
        vtep_str_size);
3046
0
    } else {
3047
0
      strlcat(vtep_str, ",", vtep_str_size);
3048
0
      strlcat(vtep_str,
3049
0
        inet_ntop(AF_INET, &zvtep->vtep_ip, ip_buf,
3050
0
            sizeof(ip_buf)),
3051
0
        vtep_str_size);
3052
0
    }
3053
0
  }
3054
0
  return vtep_str;
3055
0
}
3056
3057
static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es *es,
3058
           json_object *json_vteps)
3059
0
{
3060
0
  struct zebra_evpn_es_vtep *es_vtep;
3061
0
  struct listnode *node;
3062
0
  json_object *json_vtep_entry;
3063
0
  char alg_buf[EVPN_DF_ALG_STR_LEN];
3064
3065
0
  for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
3066
0
    json_vtep_entry = json_object_new_object();
3067
0
    json_object_string_addf(json_vtep_entry, "vtep", "%pI4",
3068
0
          &es_vtep->vtep_ip);
3069
0
    if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) {
3070
0
      json_object_string_add(
3071
0
        json_vtep_entry, "dfAlgorithm",
3072
0
        evpn_es_df_alg2str(es_vtep->df_alg, alg_buf,
3073
0
               sizeof(alg_buf)));
3074
0
      json_object_int_add(json_vtep_entry, "dfPreference",
3075
0
              es_vtep->df_pref);
3076
0
    }
3077
0
    if (es_vtep->nh)
3078
0
      json_object_int_add(json_vtep_entry, "nexthopId",
3079
0
              es_vtep->nh->nh_id);
3080
0
    json_object_array_add(json_vteps, json_vtep_entry);
3081
0
  }
3082
0
}
3083
3084
static void zebra_evpn_es_show_entry(struct vty *vty, struct zebra_evpn_es *es,
3085
             json_object *json_array)
3086
0
{
3087
0
  char type_str[5];
3088
0
  char vtep_str[ES_VTEP_LIST_STR_SZ];
3089
3090
0
  if (json_array) {
3091
0
    json_object *json = NULL;
3092
0
    json_object *json_vteps;
3093
0
    json_object *json_flags;
3094
3095
0
    json = json_object_new_object();
3096
0
    json_object_string_add(json, "esi", es->esi_str);
3097
3098
0
    if (es->flags
3099
0
        & (ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_REMOTE
3100
0
           | ZEBRA_EVPNES_NON_DF)) {
3101
0
      json_flags = json_object_new_array();
3102
0
      if (es->flags & ZEBRA_EVPNES_LOCAL)
3103
0
        json_array_string_add(json_flags, "local");
3104
0
      if (es->flags & ZEBRA_EVPNES_REMOTE)
3105
0
        json_array_string_add(json_flags, "remote");
3106
0
      if (es->flags & ZEBRA_EVPNES_NON_DF)
3107
0
        json_array_string_add(json_flags, "nonDF");
3108
0
      if (es->flags & ZEBRA_EVPNES_BYPASS)
3109
0
        json_array_string_add(json_flags, "bypass");
3110
0
      json_object_object_add(json, "flags", json_flags);
3111
0
    }
3112
3113
0
    if (es->zif)
3114
0
      json_object_string_add(json, "accessPort",
3115
0
                 es->zif->ifp->name);
3116
3117
0
    if (listcount(es->es_vtep_list)) {
3118
0
      json_vteps = json_object_new_array();
3119
0
      zebra_evpn_es_json_vtep_fill(es, json_vteps);
3120
0
      json_object_object_add(json, "vteps", json_vteps);
3121
0
    }
3122
0
    json_object_array_add(json_array, json);
3123
0
  } else {
3124
0
    type_str[0] = '\0';
3125
0
    if (es->flags & ZEBRA_EVPNES_LOCAL)
3126
0
      strlcat(type_str, "L", sizeof(type_str));
3127
0
    if (es->flags & ZEBRA_EVPNES_REMOTE)
3128
0
      strlcat(type_str, "R", sizeof(type_str));
3129
0
    if (es->flags & ZEBRA_EVPNES_NON_DF)
3130
0
      strlcat(type_str, "N", sizeof(type_str));
3131
0
    if (es->flags & ZEBRA_EVPNES_BYPASS)
3132
0
      strlcat(type_str, "B", sizeof(type_str));
3133
3134
0
    zebra_evpn_es_vtep_str(vtep_str, es, sizeof(vtep_str));
3135
3136
0
    vty_out(vty, "%-30s %-4s %-21s %s\n",
3137
0
        es->esi_str, type_str,
3138
0
        es->zif ? es->zif->ifp->name : "-",
3139
0
        vtep_str);
3140
0
  }
3141
0
}
3142
3143
static void zebra_evpn_es_show_entry_detail(struct vty *vty,
3144
    struct zebra_evpn_es *es, json_object *json)
3145
0
{
3146
0
  char type_str[80];
3147
0
  char alg_buf[EVPN_DF_ALG_STR_LEN];
3148
0
  struct zebra_evpn_es_vtep *es_vtep;
3149
0
  struct listnode *node;
3150
0
  char thread_buf[EVENT_TIMER_STRLEN];
3151
3152
0
  if (json) {
3153
0
    json_object *json_vteps;
3154
0
    json_object *json_flags;
3155
3156
0
    json_object_string_add(json, "esi", es->esi_str);
3157
0
    if (es->zif)
3158
0
      json_object_string_add(json, "accessPort",
3159
0
                 es->zif->ifp->name);
3160
3161
3162
0
    if (es->flags) {
3163
0
      json_flags = json_object_new_array();
3164
0
      if (es->flags & ZEBRA_EVPNES_LOCAL)
3165
0
        json_array_string_add(json_flags, "local");
3166
0
      if (es->flags & ZEBRA_EVPNES_REMOTE)
3167
0
        json_array_string_add(json_flags, "remote");
3168
0
      if (es->flags & ZEBRA_EVPNES_LOCAL &&
3169
0
          !(es->flags & ZEBRA_EVPNES_NON_DF))
3170
0
        json_array_string_add(json_flags, "df");
3171
0
      if (es->flags & ZEBRA_EVPNES_NON_DF)
3172
0
        json_array_string_add(json_flags, "nonDF");
3173
0
      if (es->flags & ZEBRA_EVPNES_BYPASS)
3174
0
        json_array_string_add(json_flags, "bypass");
3175
0
      if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
3176
0
        json_array_string_add(json_flags,
3177
0
                  "readyForBgp");
3178
0
      if (es->flags & ZEBRA_EVPNES_BR_PORT)
3179
0
        json_array_string_add(json_flags, "bridgePort");
3180
0
      if (es->flags & ZEBRA_EVPNES_OPER_UP)
3181
0
        json_array_string_add(json_flags, "operUp");
3182
0
      if (es->flags & ZEBRA_EVPNES_NHG_ACTIVE)
3183
0
        json_array_string_add(json_flags,
3184
0
                  "nexthopGroupActive");
3185
0
      json_object_object_add(json, "flags", json_flags);
3186
0
    }
3187
3188
0
    json_object_int_add(json, "vniCount",
3189
0
            listcount(es->es_evi_list));
3190
0
    json_object_int_add(json, "macCount", listcount(es->mac_list));
3191
0
    json_object_int_add(json, "dfPreference", es->df_pref);
3192
0
    if (es->df_delay_timer)
3193
0
      json_object_string_add(
3194
0
        json, "dfDelayTimer",
3195
0
        event_timer_to_hhmmss(thread_buf,
3196
0
                  sizeof(thread_buf),
3197
0
                  es->df_delay_timer));
3198
0
    json_object_int_add(json, "nexthopGroup", es->nhg_id);
3199
0
    if (listcount(es->es_vtep_list)) {
3200
0
      json_vteps = json_object_new_array();
3201
0
      zebra_evpn_es_json_vtep_fill(es, json_vteps);
3202
0
      json_object_object_add(json, "vteps", json_vteps);
3203
0
    }
3204
0
  } else {
3205
0
    type_str[0] = '\0';
3206
0
    if (es->flags & ZEBRA_EVPNES_LOCAL)
3207
0
      strlcat(type_str, "Local", sizeof(type_str));
3208
0
    if (es->flags & ZEBRA_EVPNES_REMOTE) {
3209
0
      if (strnlen(type_str, sizeof(type_str)))
3210
0
        strlcat(type_str, ",", sizeof(type_str));
3211
0
      strlcat(type_str, "Remote", sizeof(type_str));
3212
0
    }
3213
3214
0
    vty_out(vty, "ESI: %s\n", es->esi_str);
3215
0
    vty_out(vty, " Type: %s\n", type_str);
3216
0
    vty_out(vty, " Interface: %s\n",
3217
0
        (es->zif) ?
3218
0
        es->zif->ifp->name : "-");
3219
0
    if (es->flags & ZEBRA_EVPNES_LOCAL) {
3220
0
      vty_out(vty, " State: %s\n",
3221
0
        (es->flags & ZEBRA_EVPNES_OPER_UP) ? "up"
3222
0
                   : "down");
3223
0
      vty_out(vty, " Bridge port: %s\n",
3224
0
        (es->flags & ZEBRA_EVPNES_BR_PORT) ? "yes"
3225
0
                   : "no");
3226
0
    }
3227
0
    vty_out(vty, " Ready for BGP: %s\n",
3228
0
        (es->flags & ZEBRA_EVPNES_READY_FOR_BGP) ?
3229
0
        "yes" : "no");
3230
0
    if (es->flags & ZEBRA_EVPNES_BYPASS)
3231
0
      vty_out(vty, " LACP bypass: on\n");
3232
0
    vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
3233
0
    vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
3234
0
    if (es->flags & ZEBRA_EVPNES_LOCAL)
3235
0
      vty_out(vty, " DF status: %s \n",
3236
0
        (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df"
3237
0
                  : "df");
3238
0
    if (es->df_delay_timer)
3239
0
      vty_out(vty, " DF delay: %s\n",
3240
0
        event_timer_to_hhmmss(thread_buf,
3241
0
                  sizeof(thread_buf),
3242
0
                  es->df_delay_timer));
3243
0
    vty_out(vty, " DF preference: %u\n", es->df_pref);
3244
0
    vty_out(vty, " Nexthop group: %u\n", es->nhg_id);
3245
0
    vty_out(vty, " VTEPs:\n");
3246
0
    for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
3247
0
      vty_out(vty, "     %pI4",
3248
0
          &es_vtep->vtep_ip);
3249
0
      if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR)
3250
0
        vty_out(vty, " df_alg: %s df_pref: %d",
3251
0
          evpn_es_df_alg2str(es_vtep->df_alg,
3252
0
                 alg_buf,
3253
0
                 sizeof(alg_buf)),
3254
0
          es_vtep->df_pref);
3255
0
      vty_out(vty, " nh: %u\n",
3256
0
        es_vtep->nh ? es_vtep->nh->nh_id : 0);
3257
0
    }
3258
3259
0
    vty_out(vty, "\n");
3260
0
  }
3261
0
}
3262
3263
void zebra_evpn_es_show(struct vty *vty, bool uj)
3264
0
{
3265
0
  struct zebra_evpn_es *es;
3266
0
  json_object *json_array = NULL;
3267
3268
0
  if (uj) {
3269
0
    json_array = json_object_new_array();
3270
0
  } else {
3271
0
    vty_out(vty, "Type: B bypass, L local, R remote, N non-DF\n");
3272
0
    vty_out(vty, "%-30s %-4s %-21s %s\n",
3273
0
        "ESI", "Type", "ES-IF", "VTEPs");
3274
0
  }
3275
3276
0
  RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree)
3277
0
    zebra_evpn_es_show_entry(vty, es, json_array);
3278
3279
0
  if (uj)
3280
0
    vty_json(vty, json_array);
3281
0
}
3282
3283
void zebra_evpn_es_show_detail(struct vty *vty, bool uj)
3284
0
{
3285
0
  struct zebra_evpn_es *es;
3286
0
  json_object *json_array = NULL;
3287
3288
0
  if (uj)
3289
0
    json_array = json_object_new_array();
3290
3291
0
  RB_FOREACH (es, zebra_es_rb_head, &zmh_info->es_rb_tree) {
3292
0
    json_object *json = NULL;
3293
3294
0
    if (uj)
3295
0
      json = json_object_new_object();
3296
0
    zebra_evpn_es_show_entry_detail(vty, es, json);
3297
0
    if (uj)
3298
0
      json_object_array_add(json_array, json);
3299
0
  }
3300
3301
0
  if (uj)
3302
0
    vty_json(vty, json_array);
3303
0
}
3304
3305
void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi)
3306
0
{
3307
0
  struct zebra_evpn_es *es;
3308
0
  char esi_str[ESI_STR_LEN];
3309
0
  json_object *json = NULL;
3310
3311
0
  if (uj)
3312
0
    json = json_object_new_object();
3313
3314
0
  es = zebra_evpn_es_find(esi);
3315
3316
0
  if (es) {
3317
0
    zebra_evpn_es_show_entry_detail(vty, es, json);
3318
0
  } else {
3319
0
    if (!uj) {
3320
0
      esi_to_str(esi, esi_str, sizeof(esi_str));
3321
0
      vty_out(vty, "ESI %s does not exist\n", esi_str);
3322
0
    }
3323
0
  }
3324
3325
0
  if (uj)
3326
0
    vty_json(vty, json);
3327
0
}
3328
3329
int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
3330
0
{
3331
0
  struct zebra_if *zif = ifp->info;
3332
0
  char buf[ETHER_ADDR_STRLEN];
3333
0
  bool type_3_esi = false;
3334
0
  char esi_buf[ESI_STR_LEN];
3335
3336
0
  if (zif->es_info.lid) {
3337
0
    vty_out(vty, " evpn mh es-id %u\n", zif->es_info.lid);
3338
0
    type_3_esi = true;
3339
0
  }
3340
3341
0
  if (!is_zero_mac(&zif->es_info.sysmac)) {
3342
0
    vty_out(vty, " evpn mh es-sys-mac %s\n",
3343
0
        prefix_mac2str(&zif->es_info.sysmac,
3344
0
          buf, sizeof(buf)));
3345
0
    type_3_esi = true;
3346
0
  }
3347
3348
0
  if (!type_3_esi
3349
0
      && memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
3350
0
    vty_out(vty, " evpn mh es-id %s\n",
3351
0
        esi_to_str(&zif->es_info.esi, esi_buf, sizeof(esi_buf)));
3352
3353
0
  if (zif->es_info.df_pref)
3354
0
    vty_out(vty, " evpn mh es-df-pref %u\n", zif->es_info.df_pref);
3355
3356
0
  if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
3357
0
    vty_out(vty, " evpn mh uplink\n");
3358
3359
0
  return 0;
3360
0
}
3361
3362
#include "zebra/zebra_evpn_mh_clippy.c"
3363
/* CLI for setting an ES in bypass mode */
3364
DEFPY_HIDDEN(zebra_evpn_es_bypass, zebra_evpn_es_bypass_cmd,
3365
       "[no] evpn mh bypass",
3366
       NO_STR "EVPN\n" EVPN_MH_VTY_STR "set bypass mode\n")
3367
0
{
3368
0
  VTY_DECLVAR_CONTEXT(interface, ifp);
3369
0
  struct zebra_if *zif;
3370
3371
0
  zif = ifp->info;
3372
3373
0
  if (no) {
3374
0
    zebra_evpn_es_bypass_cfg_update(zif, false);
3375
0
  } else {
3376
0
    if (!zebra_evpn_is_if_es_capable(zif)) {
3377
0
      vty_out(vty,
3378
0
        "%% DF bypass cannot be associated with this interface type\n");
3379
0
      return CMD_WARNING;
3380
0
    }
3381
0
    zebra_evpn_es_bypass_cfg_update(zif, true);
3382
0
  }
3383
0
  return CMD_SUCCESS;
3384
0
}
3385
3386
/* CLI for configuring DF preference part for an ES */
3387
DEFPY(zebra_evpn_es_pref, zebra_evpn_es_pref_cmd,
3388
      "[no$no] evpn mh es-df-pref [(1-65535)$df_pref]",
3389
      NO_STR "EVPN\n" EVPN_MH_VTY_STR
3390
       "preference value used for DF election\n"
3391
       "pref\n")
3392
0
{
3393
0
  VTY_DECLVAR_CONTEXT(interface, ifp);
3394
0
  struct zebra_if *zif;
3395
3396
0
  zif = ifp->info;
3397
3398
0
  if (no) {
3399
0
    zebra_evpn_es_df_pref_update(zif, 0);
3400
0
  } else {
3401
0
    if (!zebra_evpn_is_if_es_capable(zif)) {
3402
0
      vty_out(vty,
3403
0
        "%% DF preference cannot be associated with this interface type\n");
3404
0
      return CMD_WARNING;
3405
0
    }
3406
0
    zebra_evpn_es_df_pref_update(zif, df_pref);
3407
0
  }
3408
0
  return CMD_SUCCESS;
3409
0
}
3410
3411
/* CLI for setting up sysmac part of ESI on an access port */
3412
DEFPY(zebra_evpn_es_sys_mac,
3413
      zebra_evpn_es_sys_mac_cmd,
3414
      "[no$no] evpn mh es-sys-mac [X:X:X:X:X:X$mac]",
3415
      NO_STR
3416
      "EVPN\n"
3417
      EVPN_MH_VTY_STR
3418
      "Ethernet segment system MAC\n"
3419
      MAC_STR
3420
)
3421
0
{
3422
0
  VTY_DECLVAR_CONTEXT(interface, ifp);
3423
0
  struct zebra_if *zif;
3424
0
  int ret = 0;
3425
3426
0
  zif = ifp->info;
3427
3428
0
  if (no) {
3429
0
    static struct ethaddr zero_mac;
3430
3431
0
    ret = zebra_evpn_es_sys_mac_update(zif, &zero_mac);
3432
0
    if (ret == -1) {
3433
0
      vty_out(vty, "%% Failed to clear ES sysmac\n");
3434
0
      return CMD_WARNING;
3435
0
    }
3436
0
  } else {
3437
3438
0
    if (!zebra_evpn_is_if_es_capable(zif)) {
3439
0
      vty_out(vty,
3440
0
        "%% ESI cannot be associated with this interface type\n");
3441
0
      return CMD_WARNING;
3442
0
    }
3443
3444
0
    if  (!mac || is_zero_mac(&mac->eth_addr)) {
3445
0
      vty_out(vty, "%% ES sysmac value is invalid\n");
3446
0
      return CMD_WARNING;
3447
0
    }
3448
3449
0
    ret = zebra_evpn_es_sys_mac_update(zif, &mac->eth_addr);
3450
0
    if (ret == -1) {
3451
0
      vty_out(vty,
3452
0
        "%% ESI already exists on a different interface\n");
3453
0
      return CMD_WARNING;
3454
0
    }
3455
0
  }
3456
0
  return CMD_SUCCESS;
3457
0
}
3458
3459
/* CLI for setting up local-ID part of ESI on an access port */
3460
DEFPY(zebra_evpn_es_id,
3461
      zebra_evpn_es_id_cmd,
3462
      "[no$no] evpn mh es-id [(1-16777215)$es_lid | NAME$esi_str]",
3463
      NO_STR
3464
      "EVPN\n"
3465
      EVPN_MH_VTY_STR
3466
      "Ethernet segment identifier\n"
3467
      "local discriminator\n"
3468
      "10-byte ID - 00:AA:BB:CC:DD:EE:FF:GG:HH:II\n"
3469
)
3470
0
{
3471
0
  VTY_DECLVAR_CONTEXT(interface, ifp);
3472
0
  struct zebra_if *zif;
3473
0
  int ret = 0;
3474
0
  esi_t esi;
3475
3476
0
  zif = ifp->info;
3477
3478
0
  if (no) {
3479
0
    if (zif->es_info.lid)
3480
0
      ret = zebra_evpn_es_lid_update(zif, 0);
3481
0
    else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi)))
3482
0
      ret = zebra_evpn_es_type0_esi_update(zif, zero_esi);
3483
3484
0
    if (ret == -1) {
3485
0
      vty_out(vty,
3486
0
        "%% Failed to clear ES local id or ESI name\n");
3487
0
      return CMD_WARNING;
3488
0
    }
3489
0
  } else {
3490
0
    if (!zebra_evpn_is_if_es_capable(zif)) {
3491
0
      vty_out(vty,
3492
0
        "%% ESI cannot be associated with this interface type\n");
3493
0
      return CMD_WARNING;
3494
0
    }
3495
3496
0
    if (esi_str) {
3497
0
      if (!str_to_esi(esi_str, &esi)) {
3498
0
        vty_out(vty, "%% Malformed ESI name\n");
3499
0
        return CMD_WARNING;
3500
0
      }
3501
0
      ret = zebra_evpn_es_type0_esi_update(zif, &esi);
3502
0
    } else {
3503
0
      if (!es_lid) {
3504
0
        vty_out(vty,
3505
0
          "%% Specify ES local id or ESI name\n");
3506
0
        return CMD_WARNING;
3507
0
      }
3508
0
      ret = zebra_evpn_es_lid_update(zif, es_lid);
3509
0
    }
3510
3511
0
    if (ret == -1) {
3512
0
      vty_out(vty,
3513
0
        "%% ESI already exists on a different interface\n");
3514
0
      return CMD_WARNING;
3515
0
    }
3516
0
  }
3517
0
  return CMD_SUCCESS;
3518
0
}
3519
3520
/* CLI for tagging an interface as an uplink */
3521
DEFPY(zebra_evpn_mh_uplink, zebra_evpn_mh_uplink_cmd, "[no] evpn mh uplink",
3522
      NO_STR "EVPN\n" EVPN_MH_VTY_STR "uplink to the VxLAN core\n")
3523
0
{
3524
0
  VTY_DECLVAR_CONTEXT(interface, ifp);
3525
0
  struct zebra_if *zif;
3526
3527
0
  zif = ifp->info;
3528
0
  zebra_evpn_mh_uplink_cfg_update(zif, no ? false : true);
3529
3530
0
  return CMD_SUCCESS;
3531
0
}
3532
3533
void zebra_evpn_mh_json(json_object *json)
3534
0
{
3535
0
  json_object *json_array;
3536
0
  char thread_buf[EVENT_TIMER_STRLEN];
3537
3538
0
  json_object_int_add(json, "macHoldtime", zmh_info->mac_hold_time);
3539
0
  json_object_int_add(json, "neighHoldtime", zmh_info->neigh_hold_time);
3540
0
  json_object_int_add(json, "startupDelay", zmh_info->startup_delay_time);
3541
0
  json_object_string_add(
3542
0
    json, "startupDelayTimer",
3543
0
    event_timer_to_hhmmss(thread_buf, sizeof(thread_buf),
3544
0
              zmh_info->startup_delay_timer));
3545
0
  json_object_int_add(json, "uplinkConfigCount",
3546
0
          zmh_info->uplink_cfg_cnt);
3547
0
  json_object_int_add(json, "uplinkActiveCount",
3548
0
          zmh_info->uplink_oper_up_cnt);
3549
3550
0
  if (zmh_info->protodown_rc) {
3551
0
    json_array = json_object_new_array();
3552
0
    if (CHECK_FLAG(zmh_info->protodown_rc,
3553
0
             ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY))
3554
0
      json_object_array_add(
3555
0
        json_array,
3556
0
        json_object_new_string("startupDelay"));
3557
0
    if (CHECK_FLAG(zmh_info->protodown_rc,
3558
0
             ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN))
3559
0
      json_object_array_add(
3560
0
        json_array,
3561
0
        json_object_new_string("uplinkDown"));
3562
0
    json_object_object_add(json, "protodownReasons", json_array);
3563
0
  }
3564
0
}
3565
3566
void zebra_evpn_mh_print(struct vty *vty)
3567
0
{
3568
0
  char pd_buf[ZEBRA_PROTODOWN_RC_STR_LEN];
3569
0
  char thread_buf[EVENT_TIMER_STRLEN];
3570
3571
0
  vty_out(vty, "EVPN MH:\n");
3572
0
  vty_out(vty, "  mac-holdtime: %ds, neigh-holdtime: %ds\n",
3573
0
    zmh_info->mac_hold_time, zmh_info->neigh_hold_time);
3574
0
  vty_out(vty, "  startup-delay: %ds, start-delay-timer: %s\n",
3575
0
    zmh_info->startup_delay_time,
3576
0
    event_timer_to_hhmmss(thread_buf, sizeof(thread_buf),
3577
0
              zmh_info->startup_delay_timer));
3578
0
  vty_out(vty, "  uplink-cfg-cnt: %u, uplink-active-cnt: %u\n",
3579
0
    zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
3580
0
  if (zmh_info->protodown_rc)
3581
0
    vty_out(vty, "  protodown reasons: %s\n",
3582
0
      zebra_protodown_rc_str(zmh_info->protodown_rc, pd_buf,
3583
0
                 sizeof(pd_buf)));
3584
0
}
3585
3586
/*****************************************************************************/
3587
/* A base L2-VNI is maintained to derive parameters such as ES originator-IP.
3588
 * XXX: once single vxlan device model becomes available this will not be
3589
 * necessary
3590
 */
3591
/* called when a new vni is added or becomes oper up or becomes a bridge port */
3592
void zebra_evpn_es_set_base_evpn(struct zebra_evpn *zevpn)
3593
0
{
3594
0
  struct listnode *node;
3595
0
  struct zebra_evpn_es *es;
3596
3597
0
  if (zmh_info->es_base_evpn) {
3598
0
    if (zmh_info->es_base_evpn != zevpn) {
3599
      /* unrelated EVPN; ignore it */
3600
0
      return;
3601
0
    }
3602
    /* check if the local vtep-ip has changed */
3603
0
  } else {
3604
    /* check if the EVPN can be used as base EVPN */
3605
0
    if (!zebra_evpn_send_to_client_ok(zevpn))
3606
0
      return;
3607
3608
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3609
0
      zlog_debug("es base vni set to %d",
3610
0
          zevpn->vni);
3611
0
    zmh_info->es_base_evpn = zevpn;
3612
0
  }
3613
3614
  /* update local VTEP-IP */
3615
0
  if (zmh_info->es_originator_ip.s_addr ==
3616
0
      zmh_info->es_base_evpn->local_vtep_ip.s_addr)
3617
0
    return;
3618
3619
0
  zmh_info->es_originator_ip.s_addr =
3620
0
    zmh_info->es_base_evpn->local_vtep_ip.s_addr;
3621
3622
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3623
0
    zlog_debug("es originator ip set to %pI4",
3624
0
      &zmh_info->es_base_evpn->local_vtep_ip);
3625
3626
  /* if originator ip changes we need to update bgp */
3627
0
  for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
3628
0
    zebra_evpn_es_run_df_election(es, __func__);
3629
3630
0
    if (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)
3631
0
      zebra_evpn_es_send_add_to_client(es);
3632
0
    else
3633
0
      zebra_evpn_es_re_eval_send_to_client(es,
3634
0
          true /* es_evi_re_reval */);
3635
0
  }
3636
0
}
3637
3638
/* called when a vni is removed or becomes oper down or is removed from a
3639
 * bridge
3640
 */
3641
void zebra_evpn_es_clear_base_evpn(struct zebra_evpn *zevpn)
3642
0
{
3643
0
  struct listnode *node;
3644
0
  struct zebra_evpn_es *es;
3645
3646
0
  if (zmh_info->es_base_evpn != zevpn)
3647
0
    return;
3648
3649
0
  zmh_info->es_base_evpn = NULL;
3650
  /* lost current base EVPN; try to find a new one */
3651
0
  zebra_evpn_es_get_one_base_evpn();
3652
3653
  /* couldn't locate an eligible base evpn */
3654
0
  if (!zmh_info->es_base_evpn && zmh_info->es_originator_ip.s_addr) {
3655
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3656
0
      zlog_debug("es originator ip cleared");
3657
3658
0
    zmh_info->es_originator_ip.s_addr = 0;
3659
    /* lost originator ip */
3660
0
    for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es)) {
3661
0
      zebra_evpn_es_re_eval_send_to_client(es,
3662
0
          true /* es_evi_re_reval */);
3663
0
    }
3664
0
  }
3665
0
}
3666
3667
/* Locate an "eligible" L2-VNI to follow */
3668
static int zebra_evpn_es_get_one_base_evpn_cb(struct hash_bucket *b, void *data)
3669
0
{
3670
0
  struct zebra_evpn *zevpn = b->data;
3671
3672
0
  zebra_evpn_es_set_base_evpn(zevpn);
3673
3674
0
  if (zmh_info->es_base_evpn)
3675
0
    return HASHWALK_ABORT;
3676
3677
0
  return HASHWALK_CONTINUE;
3678
0
}
3679
3680
/* locate a base_evpn to follow for the purposes of common params like
3681
 * originator IP
3682
 */
3683
static void zebra_evpn_es_get_one_base_evpn(void)
3684
0
{
3685
0
  struct zebra_vrf *zvrf;
3686
3687
0
  zvrf = zebra_vrf_get_evpn();
3688
0
  hash_walk(zvrf->evpn_table, zebra_evpn_es_get_one_base_evpn_cb, NULL);
3689
0
}
3690
3691
/*****************************************************************************
3692
 * local ethernet segments can be error-disabled if the switch is not
3693
 * ready to start transmitting traffic via the VxLAN overlay
3694
 */
3695
bool zebra_evpn_is_es_bond(struct interface *ifp)
3696
0
{
3697
0
  struct zebra_if *zif = ifp->info;
3698
3699
0
  return !!(struct zebra_if *)zif->es_info.es;
3700
0
}
3701
3702
bool zebra_evpn_is_es_bond_member(struct interface *ifp)
3703
0
{
3704
0
  struct zebra_if *zif = ifp->info;
3705
3706
0
  return IS_ZEBRA_IF_BOND_SLAVE(zif->ifp) && zif->bondslave_info.bond_if
3707
0
         && ((struct zebra_if *)zif->bondslave_info.bond_if->info)
3708
0
        ->es_info.es;
3709
0
}
3710
3711
void zebra_evpn_mh_update_protodown_bond_mbr(struct zebra_if *zif, bool clear,
3712
               const char *caller)
3713
0
{
3714
0
  bool new_protodown;
3715
0
  uint32_t old_protodown_rc = 0;
3716
0
  uint32_t new_protodown_rc = 0;
3717
0
  uint32_t protodown_rc = 0;
3718
3719
0
  if (!clear) {
3720
0
    struct zebra_if *bond_zif;
3721
3722
0
    bond_zif = zif->bondslave_info.bond_if->info;
3723
0
    protodown_rc = bond_zif->protodown_rc;
3724
0
  }
3725
3726
0
  old_protodown_rc = zif->protodown_rc;
3727
0
  new_protodown_rc = (old_protodown_rc & ~ZEBRA_PROTODOWN_EVPN_ALL);
3728
0
  new_protodown_rc |= (protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
3729
0
  new_protodown = !!new_protodown_rc;
3730
3731
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES && (new_protodown_rc != old_protodown_rc))
3732
0
    zlog_debug(
3733
0
      "%s bond mbr %s protodown_rc changed; old 0x%x new 0x%x",
3734
0
      caller, zif->ifp->name, old_protodown_rc,
3735
0
      new_protodown_rc);
3736
3737
0
  if (zebra_if_update_protodown_rc(zif->ifp, new_protodown,
3738
0
           new_protodown_rc) == 0) {
3739
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3740
0
      zlog_debug("%s protodown %s", zif->ifp->name,
3741
0
           new_protodown ? "on" : "off");
3742
0
  }
3743
0
}
3744
3745
/* The bond members inherit the protodown reason code from the bond */
3746
static void zebra_evpn_mh_update_protodown_bond(struct zebra_if *bond_zif)
3747
0
{
3748
0
  struct zebra_if *zif;
3749
0
  struct listnode *node;
3750
3751
0
  if (!bond_zif->bond_info.mbr_zifs)
3752
0
    return;
3753
3754
0
  for (ALL_LIST_ELEMENTS_RO(bond_zif->bond_info.mbr_zifs, node, zif)) {
3755
0
    zebra_evpn_mh_update_protodown_bond_mbr(zif, false /*clear*/,
3756
0
              __func__);
3757
0
  }
3758
0
}
3759
3760
/* The global EVPN MH protodown rc is applied to all local ESs */
3761
static void zebra_evpn_mh_update_protodown_es(struct zebra_evpn_es *es,
3762
                bool resync_dplane)
3763
0
{
3764
0
  struct zebra_if *zif;
3765
0
  uint32_t old_protodown_rc;
3766
3767
0
  zif = es->zif;
3768
  /* if the reason code is the same bail unless it is a new
3769
   * ES bond in that case we would need to ensure that the
3770
   * dplane is really in sync with zebra
3771
   */
3772
0
  if (!resync_dplane
3773
0
      && (zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL)
3774
0
           == (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
3775
0
    return;
3776
3777
0
  old_protodown_rc = zif->protodown_rc;
3778
0
  zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
3779
0
  zif->protodown_rc |=
3780
0
    (zmh_info->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL);
3781
3782
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES
3783
0
      && (old_protodown_rc != zif->protodown_rc))
3784
0
    zlog_debug(
3785
0
      "es %s ifp %s protodown_rc changed; old 0x%x new 0x%x",
3786
0
      es->esi_str, zif->ifp->name, old_protodown_rc,
3787
0
      zif->protodown_rc);
3788
3789
  /* update dataplane with the new protodown setting */
3790
0
  zebra_evpn_mh_update_protodown_bond(zif);
3791
0
}
3792
3793
static void zebra_evpn_mh_clear_protodown_es(struct zebra_evpn_es *es)
3794
0
{
3795
0
  struct zebra_if *zif;
3796
0
  uint32_t old_protodown_rc;
3797
3798
0
  zif = es->zif;
3799
0
  if (!(zif->protodown_rc & ZEBRA_PROTODOWN_EVPN_ALL))
3800
0
    return;
3801
3802
0
  old_protodown_rc = zif->protodown_rc;
3803
0
  zif->protodown_rc &= ~ZEBRA_PROTODOWN_EVPN_ALL;
3804
3805
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3806
0
    zlog_debug(
3807
0
      "clear: es %s ifp %s protodown_rc cleared; old 0x%x new 0x%x",
3808
0
      es->esi_str, zif->ifp->name, old_protodown_rc,
3809
0
      zif->protodown_rc);
3810
3811
  /* update dataplane with the new protodown setting */
3812
0
  zebra_evpn_mh_update_protodown_bond(zif);
3813
0
}
3814
3815
static void zebra_evpn_mh_update_protodown_es_all(void)
3816
1
{
3817
1
  struct listnode *node;
3818
1
  struct zebra_evpn_es *es;
3819
3820
1
  for (ALL_LIST_ELEMENTS_RO(zmh_info->local_es_list, node, es))
3821
0
    zebra_evpn_mh_update_protodown_es(es, false /*resync_dplane*/);
3822
1
}
3823
3824
static void zebra_evpn_mh_update_protodown(uint32_t protodown_rc, bool set)
3825
1
{
3826
1
  uint32_t old_protodown_rc = zmh_info->protodown_rc;
3827
3828
1
  if (set) {
3829
1
    if ((protodown_rc & zmh_info->protodown_rc) == protodown_rc)
3830
0
      return;
3831
3832
1
    zmh_info->protodown_rc |= protodown_rc;
3833
1
  } else {
3834
0
    if (!(protodown_rc & zmh_info->protodown_rc))
3835
0
      return;
3836
0
    zmh_info->protodown_rc &= ~protodown_rc;
3837
0
  }
3838
3839
1
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3840
0
    zlog_debug("mh protodown_rc changed; old 0x%x new 0x%x",
3841
1
         old_protodown_rc, zmh_info->protodown_rc);
3842
1
  zebra_evpn_mh_update_protodown_es_all();
3843
1
}
3844
3845
static inline bool zebra_evpn_mh_is_all_uplinks_down(void)
3846
0
{
3847
0
  return zmh_info->uplink_cfg_cnt && !zmh_info->uplink_oper_up_cnt;
3848
0
}
3849
3850
static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if *zif,
3851
               bool set)
3852
0
{
3853
0
  if (set && if_is_operative(zif->ifp)) {
3854
0
    if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)) {
3855
0
      zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
3856
0
      ++zmh_info->uplink_oper_up_cnt;
3857
0
    }
3858
0
  } else {
3859
0
    if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP) {
3860
0
      zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
3861
0
      if (zmh_info->uplink_oper_up_cnt)
3862
0
        --zmh_info->uplink_oper_up_cnt;
3863
0
    }
3864
0
  }
3865
0
}
3866
3867
static void zebra_evpn_mh_uplink_cfg_update(struct zebra_if *zif, bool set)
3868
0
{
3869
0
  bool old_protodown = zebra_evpn_mh_is_all_uplinks_down();
3870
0
  bool new_protodown;
3871
3872
0
  if (set) {
3873
0
    if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
3874
0
      return;
3875
3876
0
    zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK;
3877
0
    ++zmh_info->uplink_cfg_cnt;
3878
0
  } else {
3879
0
    if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK))
3880
0
      return;
3881
3882
0
    zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK;
3883
0
    if (zmh_info->uplink_cfg_cnt)
3884
0
      --zmh_info->uplink_cfg_cnt;
3885
0
  }
3886
3887
0
  zebra_evpn_mh_uplink_oper_flags_update(zif, set);
3888
0
  new_protodown = zebra_evpn_mh_is_all_uplinks_down();
3889
0
  if (old_protodown == new_protodown)
3890
0
    return;
3891
3892
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3893
0
    zlog_debug(
3894
0
      "mh-uplink-cfg-chg on if %s/%d %s uplinks cfg %u up %u",
3895
0
      zif->ifp->name, zif->ifp->ifindex, set ? "set" : "down",
3896
0
      zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
3897
3898
0
  zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
3899
0
               new_protodown);
3900
0
}
3901
3902
void zebra_evpn_mh_uplink_oper_update(struct zebra_if *zif)
3903
0
{
3904
0
  bool old_protodown = zebra_evpn_mh_is_all_uplinks_down();
3905
0
  bool new_protodown;
3906
3907
0
  zebra_evpn_mh_uplink_oper_flags_update(zif, true /*set*/);
3908
3909
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3910
0
    zlog_debug(
3911
0
      "mh-uplink-oper-chg on if %s/%d %s; uplinks cfg %u up %u",
3912
0
      zif->ifp->name, zif->ifp->ifindex,
3913
0
      if_is_operative(zif->ifp) ? "up" : "down",
3914
0
      zmh_info->uplink_cfg_cnt, zmh_info->uplink_oper_up_cnt);
3915
3916
0
  new_protodown = zebra_evpn_mh_is_all_uplinks_down();
3917
0
  if (old_protodown == new_protodown)
3918
0
    return;
3919
3920
  /* if protodown_rc XXX_UPLINK_DOWN is about to be cleared
3921
   * fire up the start-up delay timer to allow the EVPN network
3922
   * to converge (Type-2 routes need to be advertised and processed)
3923
   */
3924
0
  if (!new_protodown && (zmh_info->uplink_oper_up_cnt == 1))
3925
0
    zebra_evpn_mh_startup_delay_timer_start("uplink-up");
3926
3927
0
  zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_UPLINK_DOWN,
3928
0
               new_protodown);
3929
0
}
3930
3931
static void zebra_evpn_mh_startup_delay_exp_cb(struct event *t)
3932
0
{
3933
0
  if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3934
0
    zlog_debug("startup-delay expired");
3935
0
3936
0
  zebra_evpn_mh_update_protodown(ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY,
3937
0
               false /* set */);
3938
0
}
3939
3940
static void zebra_evpn_mh_startup_delay_timer_start(const char *rc)
3941
1
{
3942
1
  if (zmh_info->startup_delay_timer) {
3943
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3944
0
      zlog_debug("startup-delay timer cancelled");
3945
0
    EVENT_OFF(zmh_info->startup_delay_timer);
3946
0
  }
3947
3948
1
  if (zmh_info->startup_delay_time) {
3949
1
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
3950
0
      zlog_debug(
3951
1
        "startup-delay timer started for %d sec on %s",
3952
1
        zmh_info->startup_delay_time, rc);
3953
1
    event_add_timer(zrouter.master,
3954
1
        zebra_evpn_mh_startup_delay_exp_cb, NULL,
3955
1
        zmh_info->startup_delay_time,
3956
1
        &zmh_info->startup_delay_timer);
3957
1
    zebra_evpn_mh_update_protodown(
3958
1
      ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY, true /* set */);
3959
1
  } else {
3960
0
    zebra_evpn_mh_update_protodown(
3961
0
      ZEBRA_PROTODOWN_EVPN_STARTUP_DELAY, false /* set */);
3962
0
  }
3963
1
}
3964
3965
/*****************************************************************************
3966
 * Nexthop management: nexthops associated with Type-2 routes that have
3967
 * an ES as destination are consolidated by BGP into a per-VRF nh->rmac
3968
 * mapping which is the installed as a remote neigh/fdb entry with a
3969
 * dummy (type-1) prefix referencing it.
3970
 * This handling is needed because Type-2 routes with ES as dest use NHG
3971
 * that are setup using EAD routes (i.e. such NHGs do not include the
3972
 * RMAC info).
3973
 ****************************************************************************/
3974
void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS)
3975
0
{
3976
0
  struct stream *s;
3977
0
  vrf_id_t vrf_id;
3978
0
  struct ipaddr nh;
3979
0
  struct ethaddr rmac;
3980
0
  struct prefix_evpn dummy_prefix;
3981
0
  size_t min_len = 4 + sizeof(nh);
3982
3983
0
  s = msg;
3984
3985
  /*
3986
   * Ensure that the stream sent to us is long enough
3987
   */
3988
0
  if (hdr->command == ZEBRA_EVPN_REMOTE_NH_ADD)
3989
0
    min_len += sizeof(rmac);
3990
0
  if (hdr->length < min_len)
3991
0
    return;
3992
3993
0
  vrf_id = stream_getl(s);
3994
0
  stream_get(&nh, s, sizeof(nh));
3995
3996
0
  memset(&dummy_prefix, 0, sizeof(dummy_prefix));
3997
0
  dummy_prefix.family = AF_EVPN;
3998
0
  dummy_prefix.prefixlen = (sizeof(struct evpn_addr) * 8);
3999
0
  dummy_prefix.prefix.route_type = 1; /* XXX - fixup to type-1 def */
4000
0
  dummy_prefix.prefix.ead_addr.ip.ipa_type = nh.ipa_type;
4001
4002
0
  if (hdr->command == ZEBRA_EVPN_REMOTE_NH_ADD) {
4003
0
    stream_get(&rmac, s, sizeof(rmac));
4004
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
4005
0
      zlog_debug(
4006
0
        "evpn remote nh %d %pIA rmac %pEA add pfx %pFX",
4007
0
        vrf_id, &nh, &rmac, &dummy_prefix);
4008
0
    zebra_rib_queue_evpn_route_add(vrf_id, &rmac, &nh,
4009
0
                 (struct prefix *)&dummy_prefix);
4010
0
  } else {
4011
0
    if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
4012
0
      zlog_debug("evpn remote nh %d %pIA del pfx %pFX",
4013
0
           vrf_id, &nh, &dummy_prefix);
4014
0
    zebra_rib_queue_evpn_route_del(vrf_id, &nh,
4015
0
                 (struct prefix *)&dummy_prefix);
4016
0
  }
4017
0
}
4018
4019
/*****************************************************************************/
4020
void zebra_evpn_mh_config_write(struct vty *vty)
4021
0
{
4022
0
  if (zmh_info->mac_hold_time != ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF)
4023
0
    vty_out(vty, "evpn mh mac-holdtime %d\n",
4024
0
      zmh_info->mac_hold_time);
4025
4026
0
  if (zmh_info->neigh_hold_time != ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF)
4027
0
    vty_out(vty, "evpn mh neigh-holdtime %d\n",
4028
0
      zmh_info->neigh_hold_time);
4029
4030
0
  if (zmh_info->startup_delay_time != ZEBRA_EVPN_MH_STARTUP_DELAY_DEF)
4031
0
    vty_out(vty, "evpn mh startup-delay %d\n",
4032
0
      zmh_info->startup_delay_time);
4033
4034
0
  if (zmh_info->flags & ZEBRA_EVPN_MH_REDIRECT_OFF)
4035
0
    vty_out(vty, "evpn mh redirect-off\n");
4036
0
}
4037
4038
int zebra_evpn_mh_neigh_holdtime_update(struct vty *vty,
4039
    uint32_t duration, bool set_default)
4040
0
{
4041
0
  if (set_default)
4042
0
    duration = ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF;
4043
4044
0
  zmh_info->neigh_hold_time = duration;
4045
4046
0
  return 0;
4047
0
}
4048
4049
int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
4050
    uint32_t duration, bool set_default)
4051
0
{
4052
0
  if (set_default)
4053
0
    duration = ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF;
4054
4055
0
  zmh_info->mac_hold_time = duration;
4056
4057
0
  return 0;
4058
0
}
4059
4060
int zebra_evpn_mh_startup_delay_update(struct vty *vty, uint32_t duration,
4061
               bool set_default)
4062
0
{
4063
0
  if (set_default)
4064
0
    duration = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
4065
4066
0
  zmh_info->startup_delay_time = duration;
4067
4068
  /* if startup_delay_timer is running allow it to be adjusted
4069
   * up or down
4070
   */
4071
0
  if (zmh_info->startup_delay_timer)
4072
0
    zebra_evpn_mh_startup_delay_timer_start("config");
4073
4074
0
  return 0;
4075
0
}
4076
4077
int zebra_evpn_mh_redirect_off(struct vty *vty, bool redirect_off)
4078
0
{
4079
  /* This knob needs to be set before ESs are configured
4080
   * i.e. cannot be changed on the fly
4081
   */
4082
0
  if (redirect_off)
4083
0
    zmh_info->flags |= ZEBRA_EVPN_MH_REDIRECT_OFF;
4084
0
  else
4085
0
    zmh_info->flags &= ~ZEBRA_EVPN_MH_REDIRECT_OFF;
4086
4087
0
  return 0;
4088
0
}
4089
4090
void zebra_evpn_interface_init(void)
4091
1
{
4092
1
  install_element(INTERFACE_NODE, &zebra_evpn_es_id_cmd);
4093
1
  install_element(INTERFACE_NODE, &zebra_evpn_es_sys_mac_cmd);
4094
1
  install_element(INTERFACE_NODE, &zebra_evpn_es_pref_cmd);
4095
1
  install_element(INTERFACE_NODE, &zebra_evpn_es_bypass_cmd);
4096
1
  install_element(INTERFACE_NODE, &zebra_evpn_mh_uplink_cmd);
4097
1
}
4098
4099
void zebra_evpn_mh_init(void)
4100
1
{
4101
1
  zrouter.mh_info = XCALLOC(MTYPE_ZMH_INFO, sizeof(*zrouter.mh_info));
4102
4103
1
  zmh_info->mac_hold_time = ZEBRA_EVPN_MH_MAC_HOLD_TIME_DEF;
4104
1
  zmh_info->neigh_hold_time = ZEBRA_EVPN_MH_NEIGH_HOLD_TIME_DEF;
4105
  /* setup ES tables */
4106
1
  RB_INIT(zebra_es_rb_head, &zmh_info->es_rb_tree);
4107
1
  zmh_info->local_es_list = list_new();
4108
1
  listset_app_node_mem(zmh_info->local_es_list);
4109
4110
1
  bf_init(zmh_info->nh_id_bitmap, EVPN_NH_ID_MAX);
4111
1
  bf_assign_zero_index(zmh_info->nh_id_bitmap);
4112
1
  zmh_info->nhg_table = hash_create(zebra_evpn_nhg_hash_keymake,
4113
1
            zebra_evpn_nhg_cmp, "l2 NHG table");
4114
1
  zmh_info->nh_ip_table =
4115
1
    hash_create(zebra_evpn_nh_ip_hash_keymake, zebra_evpn_nh_ip_cmp,
4116
1
          "l2 NH IP table");
4117
4118
  /* setup broadcast domain tables */
4119
1
  zmh_info->evpn_vlan_table = hash_create(zebra_evpn_acc_vl_hash_keymake,
4120
1
      zebra_evpn_acc_vl_cmp, "access VLAN hash table");
4121
4122
1
  zmh_info->startup_delay_time = ZEBRA_EVPN_MH_STARTUP_DELAY_DEF;
4123
1
  zebra_evpn_mh_startup_delay_timer_start("init");
4124
1
}
4125
4126
void zebra_evpn_mh_terminate(void)
4127
0
{
4128
0
  list_delete(&zmh_info->local_es_list);
4129
4130
0
  hash_iterate(zmh_info->evpn_vlan_table,
4131
0
      zebra_evpn_acc_vl_cleanup_all, NULL);
4132
0
  hash_free(zmh_info->evpn_vlan_table);
4133
0
  hash_free(zmh_info->nhg_table);
4134
0
  hash_free(zmh_info->nh_ip_table);
4135
0
  bf_free(zmh_info->nh_id_bitmap);
4136
4137
  XFREE(MTYPE_ZMH_INFO, zrouter.mh_info);
4138
0
}