/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 | } |