Coverage Report

Created: 2025-07-14 06:48

/src/frr/zebra/zebra_l2_bridge_if.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Zebra L2 bridge interface handling
3
 *
4
 * Copyright (C) 2021 Cumulus Networks, Inc.
5
 * Sharath Ramamurthy
6
 *
7
 * This file is part of FRR.
8
 *
9
 * FRR is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU General Public License as published by the
11
 * Free Software Foundation; either version 2, or (at your option) any
12
 * later version.
13
 *
14
 * FRR is distributed in the hope that it will be useful, but
15
 * WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * General Public License for more details.
18
 */
19
20
#include <zebra.h>
21
22
#include "hash.h"
23
#include "if.h"
24
#include "jhash.h"
25
#include "linklist.h"
26
#include "log.h"
27
#include "memory.h"
28
#include "prefix.h"
29
#include "stream.h"
30
#include "table.h"
31
#include "vlan.h"
32
#include "vxlan.h"
33
#ifdef GNU_LINUX
34
#include <linux/neighbour.h>
35
#endif
36
37
#include "zebra/zebra_router.h"
38
#include "zebra/debug.h"
39
#include "zebra/interface.h"
40
#include "zebra/rib.h"
41
#include "zebra/rt.h"
42
#include "zebra/rt_netlink.h"
43
#include "zebra/zebra_errors.h"
44
#include "zebra/zebra_l2.h"
45
#include "zebra/zebra_l2_bridge_if.h"
46
#include "zebra/zebra_ns.h"
47
#include "zebra/zebra_vrf.h"
48
#include "zebra/zebra_vxlan.h"
49
#include "zebra/zebra_vxlan_if.h"
50
#include "zebra/zebra_evpn.h"
51
#include "zebra/zebra_evpn_mac.h"
52
#include "zebra/zebra_evpn_neigh.h"
53
#include "zebra/zebra_vxlan_private.h"
54
#include "zebra/zebra_evpn_mh.h"
55
#include "zebra/zebra_evpn_vxlan.h"
56
#include "zebra/zebra_router.h"
57
58
static unsigned int zebra_l2_bridge_vlan_hash_keymake(const void *p)
59
0
{
60
0
  const struct zebra_l2_bridge_vlan *bvlan;
61
62
0
  bvlan = (const struct zebra_l2_bridge_vlan *)p;
63
0
  return jhash(&bvlan->vid, sizeof(bvlan->vid), 0);
64
0
}
65
66
static bool zebra_l2_bridge_vlan_hash_cmp(const void *p1, const void *p2)
67
0
{
68
0
  const struct zebra_l2_bridge_vlan *bv1;
69
0
  const struct zebra_l2_bridge_vlan *bv2;
70
71
0
  bv1 = (const struct zebra_l2_bridge_vlan *)p1;
72
0
  bv2 = (const struct zebra_l2_bridge_vlan *)p2;
73
74
0
  return (bv1->vid == bv2->vid);
75
0
}
76
77
static int zebra_l2_bridge_if_vlan_walk_callback(struct hash_bucket *bucket,
78
             void *ctxt)
79
0
{
80
0
  int ret;
81
0
  struct zebra_l2_bridge_vlan *bvlan;
82
0
  struct zebra_l2_bridge_if_ctx *ctx;
83
84
0
  bvlan = (struct zebra_l2_bridge_vlan *)bucket->data;
85
0
  ctx = (struct zebra_l2_bridge_if_ctx *)ctxt;
86
87
0
  ret = ctx->func(ctx->zif, bvlan, ctx->arg);
88
0
  return ret;
89
0
}
90
91
static void zebra_l2_bridge_if_vlan_iterate_callback(struct hash_bucket *bucket,
92
                 void *ctxt)
93
0
{
94
0
  struct zebra_l2_bridge_vlan *bvlan;
95
0
  struct zebra_l2_bridge_if_ctx *ctx;
96
97
0
  bvlan = (struct zebra_l2_bridge_vlan *)bucket->data;
98
0
  ctx = (struct zebra_l2_bridge_if_ctx *)ctxt;
99
100
0
  ctx->func(ctx->zif, bvlan, ctx->arg);
101
0
}
102
103
static int zebra_l2_bridge_if_vlan_clean(struct zebra_if *zif,
104
           struct zebra_l2_bridge_vlan *bvlan,
105
           void *ctxt)
106
0
{
107
0
  struct zebra_evpn_access_bd *acc_bd;
108
109
0
  if (IS_ZEBRA_DEBUG_VXLAN)
110
0
    zlog_debug("access vlan %d bridge %s cleanup", bvlan->vid,
111
0
         zif->ifp->name);
112
113
0
  acc_bd = zebra_evpn_acc_vl_find(bvlan->vid, zif->ifp);
114
0
  if (acc_bd)
115
0
    zebra_evpn_access_bd_bridge_cleanup(bvlan->vid, zif->ifp,
116
0
                acc_bd);
117
118
0
  bvlan->access_bd = NULL;
119
0
  return 0;
120
0
}
121
122
static void zebra_l2_bridge_vlan_free(void *arg)
123
0
{
124
0
  struct zebra_l2_bridge_vlan *bvl;
125
126
0
  bvl = (struct zebra_l2_bridge_vlan *)arg;
127
0
  XFREE(MTYPE_TMP, bvl);
128
0
}
129
130
static void *zebra_l2_bridge_vlan_alloc(void *p)
131
0
{
132
0
  struct zebra_l2_bridge_vlan *bvlan;
133
0
  const struct zebra_l2_bridge_vlan *bvl;
134
135
0
  bvl = (const struct zebra_l2_bridge_vlan *)p;
136
0
  bvlan = XCALLOC(MTYPE_TMP, sizeof(*bvlan));
137
0
  bvlan->vid = bvl->vid;
138
0
  bvlan->access_bd = bvl->access_bd;
139
140
0
  return (void *)bvlan;
141
0
}
142
143
static void zebra_l2_bridge_vlan_table_destroy(struct hash *vlan_table)
144
0
{
145
0
  hash_clean_and_free(&vlan_table, zebra_l2_bridge_vlan_free);
146
0
}
147
148
static struct hash *zebra_l2_bridge_vlan_table_create(void)
149
0
{
150
0
  return hash_create(zebra_l2_bridge_vlan_hash_keymake,
151
0
         zebra_l2_bridge_vlan_hash_cmp,
152
0
         "Zebra L2 Bridge Vlan Table");
153
0
}
154
155
static void zebra_l2_bridge_if_vlan_table_destroy(struct zebra_if *zif)
156
0
{
157
0
  struct zebra_l2_bridge_if *br;
158
159
0
  br = BRIDGE_FROM_ZEBRA_IF(zif);
160
0
  zebra_l2_bridge_if_vlan_iterate(zif, zebra_l2_bridge_if_vlan_clean,
161
0
          NULL);
162
0
  zebra_l2_bridge_vlan_table_destroy(br->vlan_table);
163
0
  br->vlan_table = NULL;
164
0
}
165
166
static int zebra_l2_bridge_if_vlan_table_create(struct zebra_if *zif)
167
0
{
168
0
  struct zebra_l2_bridge_if *br;
169
170
0
  br = BRIDGE_FROM_ZEBRA_IF(zif);
171
0
  if (!br->vlan_table) {
172
0
    br->vlan_table = zebra_l2_bridge_vlan_table_create();
173
0
    if (!br->vlan_table)
174
0
      return -ENOMEM;
175
0
  }
176
177
0
  return 0;
178
0
}
179
180
static int zebra_l2_bridge_if_vlan_del(struct interface *ifp, vlanid_t vid)
181
0
{
182
0
  struct zebra_if *zif;
183
0
  struct zebra_l2_bridge_if *br;
184
0
  struct zebra_l2_bridge_vlan bvl;
185
0
  struct zebra_l2_bridge_vlan *bvlan;
186
187
0
  zif = (struct zebra_if *)ifp->info;
188
0
  memset(&bvl, 0, sizeof(bvl));
189
0
  bvl.vid = vid;
190
191
0
  br = BRIDGE_FROM_ZEBRA_IF(zif);
192
0
  bvlan = hash_release(br->vlan_table, &bvl);
193
194
0
  if (bvlan)
195
0
    zebra_l2_bridge_vlan_free(bvlan);
196
197
0
  return 0;
198
0
}
199
200
static int zebra_l2_bridge_if_vlan_update(struct interface *ifp,
201
            struct zebra_l2_bridge_vlan *bvl,
202
            int chgflags)
203
0
{
204
0
  struct zebra_if *zif;
205
0
  struct zebra_l2_bridge_vlan *bvlan;
206
207
0
  zif = (struct zebra_if *)ifp->info;
208
0
  bvlan = zebra_l2_bridge_if_vlan_find(zif, bvl->vid);
209
0
  if (!bvlan)
210
0
    return 0;
211
212
0
  if (chgflags & ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE)
213
0
    bvlan->access_bd = bvl->access_bd;
214
215
0
  if (!bvlan->access_bd)
216
0
    return zebra_l2_bridge_if_vlan_del(ifp, bvl->vid);
217
218
0
  return 0;
219
0
}
220
221
static int zebra_l2_bridge_if_vlan_add(struct interface *ifp,
222
               struct zebra_l2_bridge_vlan *bvlan)
223
0
{
224
0
  struct zebra_if *zif;
225
0
  struct zebra_l2_bridge_if *br;
226
227
0
  zif = (struct zebra_if *)ifp->info;
228
0
  br = BRIDGE_FROM_ZEBRA_IF(zif);
229
0
  hash_get(br->vlan_table, (void *)bvlan, zebra_l2_bridge_vlan_alloc);
230
231
0
  return 0;
232
0
}
233
234
struct zebra_l2_bridge_vlan *
235
zebra_l2_bridge_if_vlan_find(const struct zebra_if *zif, vlanid_t vid)
236
0
{
237
0
  const struct zebra_l2_bridge_if *br;
238
0
  struct zebra_l2_bridge_vlan *bvl;
239
0
  struct zebra_l2_bridge_vlan bvlan;
240
241
0
  br = BRIDGE_FROM_ZEBRA_IF(zif);
242
0
  memset(&bvlan, 0, sizeof(bvlan));
243
0
  bvlan.vid = vid;
244
0
  bvl = (struct zebra_l2_bridge_vlan *)hash_lookup(br->vlan_table,
245
0
               (void *)&bvlan);
246
247
  /* TODO: For debugging. Remove later */
248
0
  if (bvl)
249
0
    assert(bvl->vid == vid);
250
251
0
  return bvl;
252
0
}
253
254
vni_t zebra_l2_bridge_if_vni_find(const struct zebra_if *zif, vlanid_t vid)
255
0
{
256
0
  vni_t vni_id = 0;
257
0
  struct zebra_l2_bridge_vlan *bvlan;
258
259
0
  bvlan = zebra_l2_bridge_if_vlan_find(zif, vid);
260
0
  if (bvlan && bvlan->access_bd && bvlan->access_bd->vni)
261
0
    vni_id = bvlan->access_bd->vni;
262
263
0
  return vni_id;
264
0
}
265
266
void zebra_l2_bridge_if_vlan_iterate(struct zebra_if *zif,
267
             int (*func)(struct zebra_if *zif,
268
             struct zebra_l2_bridge_vlan *,
269
             void *),
270
             void *arg)
271
0
{
272
0
  struct zebra_l2_bridge_if *br;
273
0
  struct zebra_l2_bridge_if_ctx ctx;
274
275
0
  br = BRIDGE_FROM_ZEBRA_IF(zif);
276
0
  memset(&ctx, 0, sizeof(ctx));
277
0
  ctx.zif = zif;
278
0
  ctx.func = func;
279
0
  ctx.arg = arg;
280
0
  hash_iterate(br->vlan_table, zebra_l2_bridge_if_vlan_iterate_callback,
281
0
         &ctx);
282
0
}
283
284
void zebra_l2_bridge_if_vlan_walk(struct zebra_if *zif,
285
          int (*func)(struct zebra_if *zif,
286
                struct zebra_l2_bridge_vlan *,
287
                void *),
288
          void *arg)
289
0
{
290
0
  struct zebra_l2_bridge_if *br;
291
0
  struct zebra_l2_bridge_if_ctx ctx;
292
293
0
  br = BRIDGE_FROM_ZEBRA_IF(zif);
294
0
  memset(&ctx, 0, sizeof(ctx));
295
0
  ctx.zif = zif;
296
0
  ctx.func = func;
297
0
  ctx.arg = arg;
298
0
  hash_walk(br->vlan_table, zebra_l2_bridge_if_vlan_walk_callback, &ctx);
299
0
}
300
301
int zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd)
302
0
{
303
0
  int chgflags = 0;
304
0
  struct zebra_if *zif;
305
0
  struct zebra_l2_bridge_vlan bvl;
306
0
  struct zebra_l2_bridge_vlan *bvlan;
307
308
0
  zif = bd->bridge_zif;
309
0
  if (!zif)
310
0
    return -1;
311
312
0
  bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid);
313
0
  if (!bvlan)
314
0
    return 0;
315
316
0
  memset(&bvl, 0, sizeof(bvl));
317
0
  bvl.vid = bd->vid;
318
0
  bvl.access_bd = NULL;
319
0
  chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE;
320
0
  return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags);
321
0
}
322
323
int zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd)
324
0
{
325
0
  int chgflags = 0;
326
0
  struct zebra_if *zif;
327
0
  struct zebra_l2_bridge_vlan bvl;
328
0
  struct zebra_l2_bridge_vlan *bvlan;
329
330
0
  zif = bd->bridge_zif;
331
0
  if (!zif)
332
0
    return -1;
333
334
0
  if (!bd->vid)
335
0
    return -1;
336
337
0
  memset(&bvl, 0, sizeof(bvl));
338
0
  bvl.vid = bd->vid;
339
0
  bvl.access_bd = bd;
340
341
0
  bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid);
342
0
  if (!bvlan)
343
0
    return zebra_l2_bridge_if_vlan_add(zif->ifp, &bvl);
344
345
0
  chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE;
346
0
  return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags);
347
0
}
348
349
int zebra_l2_bridge_if_cleanup(struct interface *ifp)
350
0
{
351
0
  struct zebra_if *zif;
352
353
0
  if (!IS_ZEBRA_IF_BRIDGE(ifp))
354
0
    return 0;
355
356
0
  if (IS_ZEBRA_DEBUG_VXLAN)
357
0
    zlog_debug("bridge %s cleanup", ifp->name);
358
359
0
  zif = (struct zebra_if *)ifp->info;
360
0
  zebra_l2_bridge_if_vlan_table_destroy(zif);
361
0
  return 0;
362
0
}
363
364
int zebra_l2_bridge_if_del(struct interface *ifp)
365
0
{
366
0
  if (IS_ZEBRA_DEBUG_VXLAN)
367
0
    zlog_debug("bridge %s delete", ifp->name);
368
369
0
  return zebra_l2_bridge_if_cleanup(ifp);
370
0
}
371
372
int zebra_l2_bridge_if_add(struct interface *ifp)
373
0
{
374
0
  struct zebra_if *zif;
375
0
  struct zebra_l2_bridge_if *br;
376
377
0
  zif = (struct zebra_if *)ifp->info;
378
0
  br = BRIDGE_FROM_ZEBRA_IF(zif);
379
0
  br->br_zif = (struct zebra_if *)ifp->info;
380
0
  zebra_l2_bridge_if_vlan_table_create(zif);
381
0
  return 0;
382
0
}