/src/frr/zebra/zebra_l2.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * Zebra Layer-2 interface handling code |
4 | | * Copyright (C) 2016, 2017 Cumulus Networks, Inc. |
5 | | */ |
6 | | |
7 | | #include <zebra.h> |
8 | | |
9 | | #include "if.h" |
10 | | #include "prefix.h" |
11 | | #include "table.h" |
12 | | #include "memory.h" |
13 | | #include "log.h" |
14 | | #include "linklist.h" |
15 | | #include "stream.h" |
16 | | #include "hash.h" |
17 | | #include "jhash.h" |
18 | | |
19 | | #include "zebra/rib.h" |
20 | | #include "zebra/rt.h" |
21 | | #include "zebra/zebra_ns.h" |
22 | | #include "zebra/zserv.h" |
23 | | #include "zebra/debug.h" |
24 | | #include "zebra/interface.h" |
25 | | #include "zebra/zebra_vrf.h" |
26 | | #include "zebra/rt_netlink.h" |
27 | | #include "zebra/interface.h" |
28 | | #include "zebra/zebra_l2.h" |
29 | | #include "zebra/zebra_l2_bridge_if.h" |
30 | | #include "zebra/zebra_vxlan.h" |
31 | | #include "zebra/zebra_vxlan_if.h" |
32 | | #include "zebra/zebra_evpn_mh.h" |
33 | | |
34 | | /* definitions */ |
35 | | |
36 | | /* static function declarations */ |
37 | | |
38 | | /* Private functions */ |
39 | | static void map_slaves_to_bridge(struct interface *br_if, int link, |
40 | | bool update_slave, uint8_t chgflags) |
41 | 0 | { |
42 | 0 | struct vrf *vrf; |
43 | 0 | struct interface *ifp; |
44 | 0 | struct zebra_vrf *zvrf; |
45 | 0 | struct zebra_ns *zns; |
46 | |
|
47 | 0 | zvrf = br_if->vrf->info; |
48 | 0 | assert(zvrf); |
49 | 0 | zns = zvrf->zns; |
50 | 0 | assert(zns); |
51 | 0 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { |
52 | 0 | FOR_ALL_INTERFACES (vrf, ifp) { |
53 | 0 | struct zebra_if *zif; |
54 | 0 | struct zebra_l2info_brslave *br_slave; |
55 | |
|
56 | 0 | if (ifp->ifindex == IFINDEX_INTERNAL || !ifp->info) |
57 | 0 | continue; |
58 | 0 | if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) |
59 | 0 | continue; |
60 | | |
61 | | /* NOTE: This assumes 'zebra_l2info_brslave' is the |
62 | | * first field |
63 | | * for any L2 interface. |
64 | | */ |
65 | 0 | zif = (struct zebra_if *)ifp->info; |
66 | 0 | br_slave = &zif->brslave_info; |
67 | |
|
68 | 0 | if (link) { |
69 | 0 | if (br_slave->bridge_ifindex == br_if->ifindex |
70 | 0 | && br_slave->ns_id == zns->ns_id) { |
71 | 0 | br_slave->br_if = br_if; |
72 | 0 | if (update_slave) { |
73 | 0 | zebra_l2if_update_bridge_slave( |
74 | 0 | ifp, |
75 | 0 | br_slave->bridge_ifindex, |
76 | 0 | br_slave->ns_id, |
77 | 0 | chgflags); |
78 | 0 | } |
79 | 0 | } |
80 | 0 | } else { |
81 | 0 | if (br_slave->br_if == br_if) |
82 | 0 | br_slave->br_if = NULL; |
83 | 0 | } |
84 | 0 | } |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | | /* Public functions */ |
89 | | void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave, |
90 | | struct zebra_ns *zns) |
91 | 0 | { |
92 | 0 | struct interface *br_if; |
93 | | |
94 | | /* TODO: Handle change of master */ |
95 | 0 | assert(zns); |
96 | 0 | br_if = if_lookup_by_index_per_ns(zebra_ns_lookup(zns->ns_id), |
97 | 0 | br_slave->bridge_ifindex); |
98 | 0 | if (br_if) |
99 | 0 | br_slave->br_if = br_if; |
100 | 0 | } |
101 | | |
102 | | void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave) |
103 | 0 | { |
104 | 0 | br_slave->br_if = NULL; |
105 | 0 | } |
106 | | |
107 | | /* If any of the bond members are in bypass state the bond is placed |
108 | | * in bypass state |
109 | | */ |
110 | | static void zebra_l2_bond_lacp_bypass_eval(struct zebra_if *bond_zif) |
111 | 0 | { |
112 | 0 | struct listnode *node; |
113 | 0 | struct zebra_if *bond_mbr; |
114 | 0 | bool old_bypass = !!(bond_zif->flags & ZIF_FLAG_LACP_BYPASS); |
115 | 0 | bool new_bypass = false; |
116 | |
|
117 | 0 | if (bond_zif->bond_info.mbr_zifs) { |
118 | 0 | for (ALL_LIST_ELEMENTS_RO(bond_zif->bond_info.mbr_zifs, node, |
119 | 0 | bond_mbr)) { |
120 | 0 | if (bond_mbr->flags & ZIF_FLAG_LACP_BYPASS) { |
121 | 0 | new_bypass = true; |
122 | 0 | break; |
123 | 0 | } |
124 | 0 | } |
125 | 0 | } |
126 | | |
127 | 0 | if (old_bypass == new_bypass) |
128 | 0 | return; |
129 | | |
130 | 0 | if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) |
131 | 0 | zlog_debug("bond %s lacp bypass changed to %s", |
132 | 0 | bond_zif->ifp->name, new_bypass ? "on" : "off"); |
133 | |
|
134 | 0 | if (new_bypass) |
135 | 0 | bond_zif->flags |= ZIF_FLAG_LACP_BYPASS; |
136 | 0 | else |
137 | 0 | bond_zif->flags &= ~ZIF_FLAG_LACP_BYPASS; |
138 | |
|
139 | 0 | if (bond_zif->es_info.es) |
140 | 0 | zebra_evpn_es_bypass_update(bond_zif->es_info.es, bond_zif->ifp, |
141 | 0 | new_bypass); |
142 | 0 | } |
143 | | |
144 | | /* Returns true if member was newly linked to bond */ |
145 | | void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf_id) |
146 | 0 | { |
147 | 0 | struct interface *bond_if; |
148 | 0 | struct zebra_if *bond_zif; |
149 | 0 | struct zebra_l2info_bondslave *bond_slave = &zif->bondslave_info; |
150 | |
|
151 | 0 | bond_if = if_lookup_by_index(bond_slave->bond_ifindex, vrf_id); |
152 | 0 | if (bond_if == bond_slave->bond_if) |
153 | 0 | return; |
154 | | |
155 | | /* unlink the slave from the old master */ |
156 | 0 | zebra_l2_unmap_slave_from_bond(zif); |
157 | | |
158 | | /* If the bond is present and ready link the bond-member |
159 | | * to it |
160 | | */ |
161 | 0 | if (bond_if && (bond_zif = bond_if->info)) { |
162 | 0 | if (bond_zif->bond_info.mbr_zifs) { |
163 | 0 | if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) |
164 | 0 | zlog_debug("bond mbr %s linked to %s", |
165 | 0 | zif->ifp->name, bond_if->name); |
166 | 0 | bond_slave->bond_if = bond_if; |
167 | | /* link the slave to the new bond master */ |
168 | 0 | listnode_add(bond_zif->bond_info.mbr_zifs, zif); |
169 | | /* inherit protodown flags from the es-bond */ |
170 | 0 | if (zebra_evpn_is_es_bond(bond_if)) |
171 | 0 | zebra_evpn_mh_update_protodown_bond_mbr( |
172 | 0 | zif, false /*clear*/, __func__); |
173 | 0 | zebra_l2_bond_lacp_bypass_eval(bond_zif); |
174 | 0 | } |
175 | 0 | } else { |
176 | 0 | if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) |
177 | 0 | zlog_debug("bond mbr %s link to bond skipped", |
178 | 0 | zif->ifp->name); |
179 | 0 | } |
180 | 0 | } |
181 | | |
182 | | void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif) |
183 | 0 | { |
184 | 0 | struct zebra_l2info_bondslave *bond_slave = &zif->bondslave_info; |
185 | 0 | struct zebra_if *bond_zif; |
186 | |
|
187 | 0 | if (!bond_slave->bond_if) { |
188 | 0 | if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) |
189 | 0 | zlog_debug("bond mbr %s unlink from bond skipped", |
190 | 0 | zif->ifp->name); |
191 | 0 | return; |
192 | 0 | } |
193 | | |
194 | 0 | if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) |
195 | 0 | zlog_debug("bond mbr %s un-linked from %s", zif->ifp->name, |
196 | 0 | bond_slave->bond_if->name); |
197 | | |
198 | | /* unlink the slave from the bond master */ |
199 | 0 | bond_zif = bond_slave->bond_if->info; |
200 | | /* clear protodown flags */ |
201 | 0 | if (zebra_evpn_is_es_bond(bond_zif->ifp)) |
202 | 0 | zebra_evpn_mh_update_protodown_bond_mbr(zif, true /*clear*/, |
203 | 0 | __func__); |
204 | 0 | listnode_delete(bond_zif->bond_info.mbr_zifs, zif); |
205 | 0 | bond_slave->bond_if = NULL; |
206 | 0 | zebra_l2_bond_lacp_bypass_eval(bond_zif); |
207 | 0 | } |
208 | | |
209 | | void zebra_l2if_update_bond(struct interface *ifp, bool add) |
210 | 0 | { |
211 | 0 | struct zebra_if *zif; |
212 | 0 | struct zebra_l2info_bond *bond; |
213 | |
|
214 | 0 | zif = ifp->info; |
215 | 0 | assert(zif); |
216 | 0 | bond = &zif->bond_info; |
217 | |
|
218 | 0 | if (add) { |
219 | 0 | if (!bond->mbr_zifs) { |
220 | 0 | if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) |
221 | 0 | zlog_debug("bond %s mbr list create", |
222 | 0 | ifp->name); |
223 | 0 | bond->mbr_zifs = list_new(); |
224 | 0 | } |
225 | 0 | } else { |
226 | 0 | struct listnode *node; |
227 | 0 | struct listnode *nnode; |
228 | 0 | struct zebra_if *bond_mbr; |
229 | |
|
230 | 0 | if (!bond->mbr_zifs) |
231 | 0 | return; |
232 | | |
233 | 0 | if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) |
234 | 0 | zlog_debug("bond %s mbr list delete", ifp->name); |
235 | 0 | for (ALL_LIST_ELEMENTS(bond->mbr_zifs, node, nnode, bond_mbr)) |
236 | 0 | zebra_l2_unmap_slave_from_bond(bond_mbr); |
237 | | |
238 | 0 | list_delete(&bond->mbr_zifs); |
239 | 0 | } |
240 | 0 | } |
241 | | |
242 | | /* |
243 | | * Handle Bridge interface add or update. Update relevant info, |
244 | | * map slaves (if any) to the bridge. |
245 | | */ |
246 | | void zebra_l2_bridge_add_update(struct interface *ifp, |
247 | | struct zebra_l2info_bridge *bridge_info, |
248 | | int add) |
249 | 0 | { |
250 | 0 | struct zebra_if *zif; |
251 | 0 | struct zebra_l2_bridge_if *br; |
252 | |
|
253 | 0 | zif = ifp->info; |
254 | 0 | assert(zif); |
255 | | |
256 | 0 | br = BRIDGE_FROM_ZEBRA_IF(zif); |
257 | 0 | br->vlan_aware = bridge_info->bridge.vlan_aware; |
258 | 0 | zebra_l2_bridge_if_add(ifp); |
259 | | |
260 | | /* Link all slaves to this bridge */ |
261 | 0 | map_slaves_to_bridge(ifp, 1, false, ZEBRA_BRIDGE_NO_ACTION); |
262 | 0 | } |
263 | | |
264 | | /* |
265 | | * Handle Bridge interface delete. |
266 | | */ |
267 | | void zebra_l2_bridge_del(struct interface *ifp) |
268 | 0 | { |
269 | 0 | zebra_l2_bridge_if_del(ifp); |
270 | | |
271 | | /* Unlink all slaves to this bridge */ |
272 | 0 | map_slaves_to_bridge(ifp, 0, false, ZEBRA_BRIDGE_NO_ACTION); |
273 | 0 | } |
274 | | |
275 | | void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags) |
276 | 0 | { |
277 | 0 | if (!chgflags) |
278 | 0 | return; |
279 | 0 | map_slaves_to_bridge(ifp, 1, true, chgflags); |
280 | 0 | } |
281 | | |
282 | | /* |
283 | | * Update L2 info for a VLAN interface. Only relevant parameter is the |
284 | | * VLAN Id and this cannot change. |
285 | | */ |
286 | | void zebra_l2_vlanif_update(struct interface *ifp, |
287 | | struct zebra_l2info_vlan *vlan_info) |
288 | 0 | { |
289 | 0 | struct zebra_if *zif; |
290 | |
|
291 | 0 | zif = ifp->info; |
292 | 0 | assert(zif); |
293 | | |
294 | | /* Copy over the L2 information. */ |
295 | 0 | memcpy(&zif->l2info.vl, vlan_info, sizeof(*vlan_info)); |
296 | 0 | } |
297 | | |
298 | | /* |
299 | | * Update L2 info for a GRE interface. This is called upon interface |
300 | | * addition as well as update. Upon add/update, need to inform |
301 | | * clients about GRE information. |
302 | | */ |
303 | | void zebra_l2_greif_add_update(struct interface *ifp, |
304 | | struct zebra_l2info_gre *gre_info, int add) |
305 | 0 | { |
306 | 0 | struct zebra_if *zif; |
307 | 0 | struct in_addr old_vtep_ip; |
308 | |
|
309 | 0 | zif = ifp->info; |
310 | 0 | assert(zif); |
311 | | |
312 | 0 | if (add) { |
313 | 0 | memcpy(&zif->l2info.gre, gre_info, sizeof(*gre_info)); |
314 | 0 | return; |
315 | 0 | } |
316 | | |
317 | 0 | old_vtep_ip = zif->l2info.gre.vtep_ip; |
318 | 0 | if (IPV4_ADDR_SAME(&old_vtep_ip, &gre_info->vtep_ip)) |
319 | 0 | return; |
320 | | |
321 | 0 | zif->l2info.gre.vtep_ip = gre_info->vtep_ip; |
322 | 0 | } |
323 | | |
324 | | /* |
325 | | * Update L2 info for a VxLAN interface. This is called upon interface |
326 | | * addition as well as update. Upon add, need to invoke the VNI create |
327 | | * function. Upon update, the params of interest are the local tunnel |
328 | | * IP and VLAN mapping, but the latter is handled separately. |
329 | | */ |
330 | | void zebra_l2_vxlanif_add_update(struct interface *ifp, |
331 | | struct zebra_l2info_vxlan *vxlan_info, int add) |
332 | 0 | { |
333 | 0 | struct zebra_if *zif; |
334 | 0 | uint16_t chgflags = 0; |
335 | 0 | struct zebra_vxlan_if_update_ctx ctx; |
336 | |
|
337 | 0 | zif = ifp->info; |
338 | 0 | assert(zif); |
339 | | |
340 | 0 | if (add) { |
341 | 0 | memcpy(&zif->l2info.vxl, vxlan_info, sizeof(*vxlan_info)); |
342 | 0 | zebra_vxlan_if_add(ifp); |
343 | 0 | return; |
344 | 0 | } |
345 | | |
346 | 0 | memset(&ctx, 0, sizeof(ctx)); |
347 | 0 | ctx.old_vtep_ip = zif->l2info.vxl.vtep_ip; |
348 | |
|
349 | 0 | if (!IPV4_ADDR_SAME(&ctx.old_vtep_ip, &vxlan_info->vtep_ip)) { |
350 | 0 | chgflags |= ZEBRA_VXLIF_LOCAL_IP_CHANGE; |
351 | 0 | zif->l2info.vxl.vtep_ip = vxlan_info->vtep_ip; |
352 | 0 | } |
353 | |
|
354 | 0 | if (IS_ZEBRA_VXLAN_IF_VNI(zif)) { |
355 | 0 | ctx.old_vni = vxlan_info->vni_info.vni; |
356 | 0 | if (!IPV4_ADDR_SAME(&zif->l2info.vxl.vni_info.vni.mcast_grp, |
357 | 0 | &vxlan_info->vni_info.vni.mcast_grp)) { |
358 | 0 | chgflags |= ZEBRA_VXLIF_MCAST_GRP_CHANGE; |
359 | 0 | zif->l2info.vxl.vni_info.vni.mcast_grp = |
360 | 0 | vxlan_info->vni_info.vni.mcast_grp; |
361 | 0 | } |
362 | 0 | } |
363 | |
|
364 | 0 | if (chgflags) { |
365 | 0 | ctx.chgflags = chgflags; |
366 | 0 | zebra_vxlan_if_update(ifp, &ctx); |
367 | 0 | } |
368 | 0 | } |
369 | | |
370 | | /* |
371 | | * Handle change to VLAN to VNI mapping. |
372 | | */ |
373 | | void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp, |
374 | | vlanid_t access_vlan) |
375 | 0 | { |
376 | 0 | struct zebra_if *zif; |
377 | 0 | vlanid_t old_access_vlan; |
378 | 0 | struct zebra_vxlan_vni *vni; |
379 | 0 | struct zebra_vxlan_if_update_ctx ctx; |
380 | | |
381 | |
|
382 | 0 | zif = ifp->info; |
383 | 0 | assert(zif); |
384 | | |
385 | | /* This would be called only in non svd case */ |
386 | 0 | assert(IS_ZEBRA_VXLAN_IF_VNI(zif)); |
387 | | |
388 | 0 | old_access_vlan = zif->l2info.vxl.vni_info.vni.access_vlan; |
389 | 0 | ; |
390 | 0 | if (old_access_vlan == access_vlan) |
391 | 0 | return; |
392 | | |
393 | 0 | memset(&ctx, 0, sizeof(ctx)); |
394 | 0 | vni = zebra_vxlan_if_vni_find(zif, 0); |
395 | 0 | ctx.old_vni = *vni; |
396 | 0 | ctx.chgflags = ZEBRA_VXLIF_VLAN_CHANGE; |
397 | 0 | vni->access_vlan = access_vlan; |
398 | |
|
399 | 0 | zebra_evpn_vl_vxl_deref(old_access_vlan, vni->vni, zif); |
400 | 0 | zebra_evpn_vl_vxl_ref(access_vlan, vni->vni, zif); |
401 | 0 | zebra_vxlan_if_update(ifp, &ctx); |
402 | 0 | } |
403 | | |
404 | | /* |
405 | | * Handle VxLAN interface delete. |
406 | | */ |
407 | | void zebra_l2_vxlanif_del(struct interface *ifp) |
408 | 0 | { |
409 | 0 | struct zebra_if *zif; |
410 | |
|
411 | 0 | zif = ifp->info; |
412 | 0 | assert(zif); |
413 | | |
414 | 0 | zebra_vxlan_if_del(ifp); |
415 | 0 | } |
416 | | |
417 | | /* |
418 | | * Map or unmap interface from bridge. |
419 | | * NOTE: It is currently assumped that an interface has to be unmapped |
420 | | * from a bridge before it can be mapped to another bridge. |
421 | | */ |
422 | | void zebra_l2if_update_bridge_slave(struct interface *ifp, |
423 | | ifindex_t bridge_ifindex, ns_id_t ns_id, |
424 | | uint8_t chgflags) |
425 | 0 | { |
426 | 0 | struct zebra_if *zif; |
427 | 0 | ifindex_t old_bridge_ifindex; |
428 | 0 | ns_id_t old_ns_id; |
429 | 0 | struct zebra_vrf *zvrf; |
430 | 0 | struct zebra_vxlan_if_update_ctx ctx; |
431 | |
|
432 | 0 | memset(&ctx, 0, sizeof(ctx)); |
433 | |
|
434 | 0 | zif = ifp->info; |
435 | 0 | assert(zif); |
436 | | |
437 | 0 | zvrf = ifp->vrf->info; |
438 | 0 | if (!zvrf) |
439 | 0 | return; |
440 | | |
441 | 0 | if (zif->zif_type == ZEBRA_IF_VXLAN |
442 | 0 | && chgflags != ZEBRA_BRIDGE_NO_ACTION) { |
443 | 0 | if (chgflags & ZEBRA_BRIDGE_MASTER_MAC_CHANGE) { |
444 | 0 | ctx.chgflags = ZEBRA_VXLIF_MASTER_MAC_CHANGE; |
445 | 0 | zebra_vxlan_if_update(ifp, &ctx); |
446 | 0 | } |
447 | 0 | if (chgflags & ZEBRA_BRIDGE_MASTER_UP) { |
448 | 0 | ctx.chgflags = ZEBRA_VXLIF_MASTER_CHANGE; |
449 | 0 | zebra_vxlan_if_update(ifp, &ctx); |
450 | 0 | } |
451 | 0 | } |
452 | 0 | old_bridge_ifindex = zif->brslave_info.bridge_ifindex; |
453 | 0 | old_ns_id = zif->brslave_info.ns_id; |
454 | 0 | if (old_bridge_ifindex == bridge_ifindex && |
455 | 0 | old_ns_id == zif->brslave_info.ns_id) |
456 | 0 | return; |
457 | | |
458 | 0 | ctx.chgflags = ZEBRA_VXLIF_MASTER_CHANGE; |
459 | | |
460 | |
|
461 | 0 | zif->brslave_info.ns_id = ns_id; |
462 | 0 | zif->brslave_info.bridge_ifindex = bridge_ifindex; |
463 | | /* Set up or remove link with master */ |
464 | 0 | if (bridge_ifindex != IFINDEX_INTERNAL) { |
465 | 0 | zebra_l2_map_slave_to_bridge(&zif->brslave_info, zvrf->zns); |
466 | | /* In the case of VxLAN, invoke the handler for EVPN. */ |
467 | 0 | if (zif->zif_type == ZEBRA_IF_VXLAN) |
468 | 0 | zebra_vxlan_if_update(ifp, &ctx); |
469 | 0 | if (zif->es_info.es) |
470 | 0 | zebra_evpn_es_local_br_port_update(zif); |
471 | 0 | } else if (old_bridge_ifindex != IFINDEX_INTERNAL) { |
472 | | /* |
473 | | * In the case of VxLAN, invoke the handler for EVPN. |
474 | | * Note that this should be done *prior* |
475 | | * to unmapping the interface from the bridge. |
476 | | */ |
477 | 0 | if (zif->zif_type == ZEBRA_IF_VXLAN) |
478 | 0 | zebra_vxlan_if_update(ifp, &ctx); |
479 | 0 | if (zif->es_info.es) |
480 | 0 | zebra_evpn_es_local_br_port_update(zif); |
481 | 0 | zebra_l2_unmap_slave_from_bridge(&zif->brslave_info); |
482 | 0 | } |
483 | 0 | } |
484 | | |
485 | | void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex, |
486 | | bool new_bypass) |
487 | 0 | { |
488 | 0 | struct zebra_if *zif; |
489 | 0 | ifindex_t old_bond_ifindex; |
490 | 0 | bool old_bypass; |
491 | 0 | struct zebra_l2info_bondslave *bond_mbr; |
492 | |
|
493 | 0 | zif = ifp->info; |
494 | 0 | assert(zif); |
495 | | |
496 | 0 | old_bypass = !!(zif->flags & ZIF_FLAG_LACP_BYPASS); |
497 | 0 | if (old_bypass != new_bypass) { |
498 | 0 | if (IS_ZEBRA_DEBUG_EVPN_MH_ES || IS_ZEBRA_DEBUG_EVENT) |
499 | 0 | zlog_debug("bond-mbr %s lacp bypass changed to %s", |
500 | 0 | zif->ifp->name, new_bypass ? "on" : "off"); |
501 | |
|
502 | 0 | if (new_bypass) |
503 | 0 | zif->flags |= ZIF_FLAG_LACP_BYPASS; |
504 | 0 | else |
505 | 0 | zif->flags &= ~ZIF_FLAG_LACP_BYPASS; |
506 | |
|
507 | 0 | bond_mbr = &zif->bondslave_info; |
508 | 0 | if (bond_mbr->bond_if) { |
509 | 0 | struct zebra_if *bond_zif = bond_mbr->bond_if->info; |
510 | |
|
511 | 0 | zebra_l2_bond_lacp_bypass_eval(bond_zif); |
512 | 0 | } |
513 | 0 | } |
514 | |
|
515 | 0 | old_bond_ifindex = zif->bondslave_info.bond_ifindex; |
516 | 0 | if (old_bond_ifindex == bond_ifindex) |
517 | 0 | return; |
518 | | |
519 | 0 | zif->bondslave_info.bond_ifindex = bond_ifindex; |
520 | | |
521 | | /* Set up or remove link with master */ |
522 | 0 | if (bond_ifindex != IFINDEX_INTERNAL) |
523 | 0 | zebra_l2_map_slave_to_bond(zif, ifp->vrf->vrf_id); |
524 | 0 | else if (old_bond_ifindex != IFINDEX_INTERNAL) |
525 | 0 | zebra_l2_unmap_slave_from_bond(zif); |
526 | 0 | } |
527 | | |
528 | | void zebra_vlan_bitmap_compute(struct interface *ifp, |
529 | | uint32_t vid_start, uint16_t vid_end) |
530 | 0 | { |
531 | 0 | uint32_t vid; |
532 | 0 | struct zebra_if *zif; |
533 | |
|
534 | 0 | zif = (struct zebra_if *)ifp->info; |
535 | 0 | assert(zif); |
536 | | |
537 | 0 | for (vid = vid_start; vid <= vid_end; ++vid) |
538 | 0 | bf_set_bit(zif->vlan_bitmap, vid); |
539 | 0 | } |
540 | | |
541 | | void zebra_vlan_mbr_re_eval(struct interface *ifp, bitfield_t old_vlan_bitmap) |
542 | 0 | { |
543 | 0 | uint32_t vid; |
544 | 0 | struct zebra_if *zif; |
545 | |
|
546 | 0 | zif = (struct zebra_if *)ifp->info; |
547 | 0 | assert(zif); |
548 | | |
549 | 0 | if (!bf_cmp(zif->vlan_bitmap, old_vlan_bitmap)) |
550 | | /* no change */ |
551 | 0 | return; |
552 | | |
553 | 0 | bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) { |
554 | | /* if not already set create new reference */ |
555 | 0 | if (!bf_test_index(old_vlan_bitmap, vid)) |
556 | 0 | zebra_evpn_vl_mbr_ref(vid, zif); |
557 | | |
558 | | /* also clear from the old vlan bitmap */ |
559 | 0 | bf_release_index(old_vlan_bitmap, vid); |
560 | 0 | } |
561 | | |
562 | | /* any bits remaining in the old vlan bitmap are stale references */ |
563 | 0 | bf_for_each_set_bit(old_vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) { |
564 | 0 | zebra_evpn_vl_mbr_deref(vid, zif); |
565 | 0 | } |
566 | 0 | } |