]>
Commit | Line | Data |
---|---|---|
239b26f9 SR |
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 | { | |
60 | const struct zebra_l2_bridge_vlan *bvlan; | |
61 | ||
62 | bvlan = (const struct zebra_l2_bridge_vlan *)p; | |
63 | return jhash(&bvlan->vid, sizeof(bvlan->vid), 0); | |
64 | } | |
65 | ||
66 | static bool zebra_l2_bridge_vlan_hash_cmp(const void *p1, const void *p2) | |
67 | { | |
68 | const struct zebra_l2_bridge_vlan *bv1; | |
69 | const struct zebra_l2_bridge_vlan *bv2; | |
70 | ||
71 | bv1 = (const struct zebra_l2_bridge_vlan *)p1; | |
72 | bv2 = (const struct zebra_l2_bridge_vlan *)p2; | |
73 | ||
74 | return (bv1->vid == bv2->vid); | |
75 | } | |
76 | ||
77 | static int zebra_l2_bridge_if_vlan_walk_callback(struct hash_bucket *bucket, | |
78 | void *ctxt) | |
79 | { | |
80 | int ret; | |
81 | struct zebra_l2_bridge_vlan *bvlan; | |
82 | struct zebra_l2_bridge_if_ctx *ctx; | |
83 | ||
84 | bvlan = (struct zebra_l2_bridge_vlan *)bucket->data; | |
85 | ctx = (struct zebra_l2_bridge_if_ctx *)ctxt; | |
86 | ||
87 | ret = ctx->func(ctx->zif, bvlan, ctx->arg); | |
88 | return ret; | |
89 | } | |
90 | ||
91 | static void zebra_l2_bridge_if_vlan_iterate_callback(struct hash_bucket *bucket, | |
92 | void *ctxt) | |
93 | { | |
94 | struct zebra_l2_bridge_vlan *bvlan; | |
95 | struct zebra_l2_bridge_if_ctx *ctx; | |
96 | ||
97 | bvlan = (struct zebra_l2_bridge_vlan *)bucket->data; | |
98 | ctx = (struct zebra_l2_bridge_if_ctx *)ctxt; | |
99 | ||
100 | ctx->func(ctx->zif, bvlan, ctx->arg); | |
101 | } | |
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 | { | |
107 | struct zebra_evpn_access_bd *acc_bd; | |
108 | ||
109 | if (IS_ZEBRA_DEBUG_VXLAN) | |
110 | zlog_debug("access vlan %d bridge %s cleanup", bvlan->vid, | |
111 | zif->ifp->name); | |
112 | ||
113 | acc_bd = zebra_evpn_acc_vl_find(bvlan->vid, zif->ifp); | |
114 | if (acc_bd) | |
115 | zebra_evpn_access_bd_bridge_cleanup(bvlan->vid, zif->ifp, | |
116 | acc_bd); | |
117 | ||
118 | bvlan->access_bd = NULL; | |
119 | return 0; | |
120 | } | |
121 | ||
122 | static void zebra_l2_bridge_vlan_free(void *arg) | |
123 | { | |
124 | struct zebra_l2_bridge_vlan *bvl; | |
125 | ||
126 | bvl = (struct zebra_l2_bridge_vlan *)arg; | |
127 | XFREE(MTYPE_TMP, bvl); | |
128 | } | |
129 | ||
130 | static void *zebra_l2_bridge_vlan_alloc(void *p) | |
131 | { | |
132 | struct zebra_l2_bridge_vlan *bvlan; | |
133 | const struct zebra_l2_bridge_vlan *bvl; | |
134 | ||
135 | bvl = (const struct zebra_l2_bridge_vlan *)p; | |
136 | bvlan = XCALLOC(MTYPE_TMP, sizeof(*bvlan)); | |
137 | bvlan->vid = bvl->vid; | |
138 | bvlan->access_bd = bvl->access_bd; | |
139 | ||
140 | return (void *)bvlan; | |
141 | } | |
142 | ||
143 | static void zebra_l2_bridge_vlan_table_destroy(struct hash *vlan_table) | |
144 | { | |
d8bc11a5 | 145 | hash_clean_and_free(&vlan_table, zebra_l2_bridge_vlan_free); |
239b26f9 SR |
146 | } |
147 | ||
148 | static struct hash *zebra_l2_bridge_vlan_table_create(void) | |
149 | { | |
150 | return hash_create(zebra_l2_bridge_vlan_hash_keymake, | |
151 | zebra_l2_bridge_vlan_hash_cmp, | |
152 | "Zebra L2 Bridge Vlan Table"); | |
153 | } | |
154 | ||
155 | static void zebra_l2_bridge_if_vlan_table_destroy(struct zebra_if *zif) | |
156 | { | |
157 | struct zebra_l2_bridge_if *br; | |
158 | ||
159 | br = BRIDGE_FROM_ZEBRA_IF(zif); | |
160 | zebra_l2_bridge_if_vlan_iterate(zif, zebra_l2_bridge_if_vlan_clean, | |
161 | NULL); | |
162 | zebra_l2_bridge_vlan_table_destroy(br->vlan_table); | |
163 | br->vlan_table = NULL; | |
164 | } | |
165 | ||
166 | static int zebra_l2_bridge_if_vlan_table_create(struct zebra_if *zif) | |
167 | { | |
168 | struct zebra_l2_bridge_if *br; | |
169 | ||
170 | br = BRIDGE_FROM_ZEBRA_IF(zif); | |
171 | if (!br->vlan_table) { | |
172 | br->vlan_table = zebra_l2_bridge_vlan_table_create(); | |
173 | if (!br->vlan_table) | |
9464e5b8 | 174 | return -ENOMEM; |
239b26f9 SR |
175 | } |
176 | ||
177 | return 0; | |
178 | } | |
179 | ||
180 | static int zebra_l2_bridge_if_vlan_del(struct interface *ifp, vlanid_t vid) | |
181 | { | |
182 | struct zebra_if *zif; | |
183 | struct zebra_l2_bridge_if *br; | |
184 | struct zebra_l2_bridge_vlan bvl; | |
185 | struct zebra_l2_bridge_vlan *bvlan; | |
186 | ||
187 | zif = (struct zebra_if *)ifp->info; | |
188 | memset(&bvl, 0, sizeof(bvl)); | |
189 | bvl.vid = vid; | |
190 | ||
191 | br = BRIDGE_FROM_ZEBRA_IF(zif); | |
192 | bvlan = hash_release(br->vlan_table, &bvl); | |
193 | ||
194 | if (bvlan) | |
195 | zebra_l2_bridge_vlan_free(bvlan); | |
196 | ||
197 | return 0; | |
198 | } | |
199 | ||
200 | static int zebra_l2_bridge_if_vlan_update(struct interface *ifp, | |
201 | struct zebra_l2_bridge_vlan *bvl, | |
202 | int chgflags) | |
203 | { | |
204 | struct zebra_if *zif; | |
205 | struct zebra_l2_bridge_vlan *bvlan; | |
206 | ||
207 | zif = (struct zebra_if *)ifp->info; | |
208 | bvlan = zebra_l2_bridge_if_vlan_find(zif, bvl->vid); | |
578c0b13 DS |
209 | if (!bvlan) |
210 | return 0; | |
239b26f9 SR |
211 | |
212 | if (chgflags & ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE) | |
213 | bvlan->access_bd = bvl->access_bd; | |
214 | ||
215 | if (!bvlan->access_bd) | |
216 | return zebra_l2_bridge_if_vlan_del(ifp, bvl->vid); | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
221 | static int zebra_l2_bridge_if_vlan_add(struct interface *ifp, | |
222 | struct zebra_l2_bridge_vlan *bvlan) | |
223 | { | |
224 | struct zebra_if *zif; | |
225 | struct zebra_l2_bridge_if *br; | |
226 | ||
227 | zif = (struct zebra_if *)ifp->info; | |
228 | br = BRIDGE_FROM_ZEBRA_IF(zif); | |
229 | hash_get(br->vlan_table, (void *)bvlan, zebra_l2_bridge_vlan_alloc); | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | struct zebra_l2_bridge_vlan * | |
235 | zebra_l2_bridge_if_vlan_find(const struct zebra_if *zif, vlanid_t vid) | |
236 | { | |
237 | const struct zebra_l2_bridge_if *br; | |
238 | struct zebra_l2_bridge_vlan *bvl; | |
239 | struct zebra_l2_bridge_vlan bvlan; | |
240 | ||
241 | br = BRIDGE_FROM_ZEBRA_IF(zif); | |
242 | memset(&bvlan, 0, sizeof(bvlan)); | |
243 | bvlan.vid = vid; | |
244 | bvl = (struct zebra_l2_bridge_vlan *)hash_lookup(br->vlan_table, | |
245 | (void *)&bvlan); | |
246 | ||
247 | /* TODO: For debugging. Remove later */ | |
248 | if (bvl) | |
249 | assert(bvl->vid == vid); | |
250 | ||
251 | return bvl; | |
252 | } | |
253 | ||
254 | vni_t zebra_l2_bridge_if_vni_find(const struct zebra_if *zif, vlanid_t vid) | |
255 | { | |
256 | vni_t vni_id = 0; | |
257 | struct zebra_l2_bridge_vlan *bvlan; | |
258 | ||
259 | bvlan = zebra_l2_bridge_if_vlan_find(zif, vid); | |
260 | if (bvlan && bvlan->access_bd && bvlan->access_bd->vni) | |
261 | vni_id = bvlan->access_bd->vni; | |
262 | ||
263 | return vni_id; | |
264 | } | |
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 | { | |
272 | struct zebra_l2_bridge_if *br; | |
273 | struct zebra_l2_bridge_if_ctx ctx; | |
274 | ||
275 | br = BRIDGE_FROM_ZEBRA_IF(zif); | |
276 | memset(&ctx, 0, sizeof(ctx)); | |
277 | ctx.zif = zif; | |
278 | ctx.func = func; | |
279 | ctx.arg = arg; | |
280 | hash_iterate(br->vlan_table, zebra_l2_bridge_if_vlan_iterate_callback, | |
281 | &ctx); | |
282 | } | |
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 | { | |
290 | struct zebra_l2_bridge_if *br; | |
291 | struct zebra_l2_bridge_if_ctx ctx; | |
292 | ||
293 | br = BRIDGE_FROM_ZEBRA_IF(zif); | |
294 | memset(&ctx, 0, sizeof(ctx)); | |
295 | ctx.zif = zif; | |
296 | ctx.func = func; | |
297 | ctx.arg = arg; | |
298 | hash_walk(br->vlan_table, zebra_l2_bridge_if_vlan_walk_callback, &ctx); | |
299 | } | |
300 | ||
301 | int zebra_l2_bridge_if_vlan_access_bd_deref(struct zebra_evpn_access_bd *bd) | |
302 | { | |
303 | int chgflags = 0; | |
304 | struct zebra_if *zif; | |
305 | struct zebra_l2_bridge_vlan bvl; | |
306 | struct zebra_l2_bridge_vlan *bvlan; | |
307 | ||
308 | zif = bd->bridge_zif; | |
309 | if (!zif) | |
310 | return -1; | |
311 | ||
312 | bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid); | |
313 | if (!bvlan) | |
314 | return 0; | |
315 | ||
316 | memset(&bvl, 0, sizeof(bvl)); | |
317 | bvl.vid = bd->vid; | |
318 | bvl.access_bd = NULL; | |
319 | chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE; | |
320 | return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags); | |
321 | } | |
322 | ||
323 | int zebra_l2_bridge_if_vlan_access_bd_ref(struct zebra_evpn_access_bd *bd) | |
324 | { | |
325 | int chgflags = 0; | |
326 | struct zebra_if *zif; | |
327 | struct zebra_l2_bridge_vlan bvl; | |
328 | struct zebra_l2_bridge_vlan *bvlan; | |
329 | ||
330 | zif = bd->bridge_zif; | |
331 | if (!zif) | |
332 | return -1; | |
333 | ||
334 | if (!bd->vid) | |
335 | return -1; | |
336 | ||
337 | memset(&bvl, 0, sizeof(bvl)); | |
338 | bvl.vid = bd->vid; | |
339 | bvl.access_bd = bd; | |
340 | ||
341 | bvlan = zebra_l2_bridge_if_vlan_find(zif, bd->vid); | |
9464e5b8 | 342 | if (!bvlan) |
239b26f9 | 343 | return zebra_l2_bridge_if_vlan_add(zif->ifp, &bvl); |
239b26f9 SR |
344 | |
345 | chgflags = ZEBRA_BRIDGEIF_ACCESS_BD_CHANGE; | |
346 | return zebra_l2_bridge_if_vlan_update(zif->ifp, &bvl, chgflags); | |
347 | } | |
348 | ||
349 | int zebra_l2_bridge_if_cleanup(struct interface *ifp) | |
350 | { | |
351 | struct zebra_if *zif; | |
352 | ||
353 | if (!IS_ZEBRA_IF_BRIDGE(ifp)) | |
354 | return 0; | |
355 | ||
356 | if (IS_ZEBRA_DEBUG_VXLAN) | |
357 | zlog_debug("bridge %s cleanup", ifp->name); | |
358 | ||
359 | zif = (struct zebra_if *)ifp->info; | |
360 | zebra_l2_bridge_if_vlan_table_destroy(zif); | |
361 | return 0; | |
362 | } | |
363 | ||
364 | int zebra_l2_bridge_if_del(struct interface *ifp) | |
365 | { | |
366 | if (IS_ZEBRA_DEBUG_VXLAN) | |
367 | zlog_debug("bridge %s delete", ifp->name); | |
368 | ||
369 | return zebra_l2_bridge_if_cleanup(ifp); | |
370 | } | |
371 | ||
372 | int zebra_l2_bridge_if_add(struct interface *ifp) | |
373 | { | |
374 | struct zebra_if *zif; | |
375 | struct zebra_l2_bridge_if *br; | |
376 | ||
377 | zif = (struct zebra_if *)ifp->info; | |
378 | br = BRIDGE_FROM_ZEBRA_IF(zif); | |
379 | br->br_zif = (struct zebra_if *)ifp->info; | |
380 | zebra_l2_bridge_if_vlan_table_create(zif); | |
381 | return 0; | |
382 | } |