/src/frr/zebra/zebra_vxlan_if.c
Line | Count | Source |
1 | | /* |
2 | | * Zebra EVPN for VxLAN interface handling |
3 | | * |
4 | | * Copyright (C) 2021 Cumulus Networks, Inc. |
5 | | * Vivek Venkatraman, Stephen Worley, 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_ns.h" |
46 | | #include "zebra/zebra_vrf.h" |
47 | | #include "zebra/zebra_vxlan.h" |
48 | | #include "zebra/zebra_vxlan_if.h" |
49 | | #include "zebra/zebra_evpn.h" |
50 | | #include "zebra/zebra_evpn_mac.h" |
51 | | #include "zebra/zebra_evpn_neigh.h" |
52 | | #include "zebra/zebra_vxlan_private.h" |
53 | | #include "zebra/zebra_evpn_mh.h" |
54 | | #include "zebra/zebra_evpn_vxlan.h" |
55 | | #include "zebra/zebra_router.h" |
56 | | |
57 | | static unsigned int zebra_vxlan_vni_hash_keymake(const void *p) |
58 | 0 | { |
59 | 0 | const struct zebra_vxlan_vni *vni; |
60 | |
|
61 | 0 | vni = (const struct zebra_vxlan_vni *)p; |
62 | 0 | return jhash_1word(vni->vni, 0); |
63 | 0 | } |
64 | | |
65 | | static bool zebra_vxlan_vni_hash_cmp(const void *p1, const void *p2) |
66 | 0 | { |
67 | 0 | const struct zebra_vxlan_vni *vni1; |
68 | 0 | const struct zebra_vxlan_vni *vni2; |
69 | |
|
70 | 0 | vni1 = (const struct zebra_vxlan_vni *)p1; |
71 | 0 | vni2 = (const struct zebra_vxlan_vni *)p2; |
72 | |
|
73 | 0 | return (vni1->vni == vni2->vni); |
74 | 0 | } |
75 | | |
76 | | static int zebra_vxlan_if_vni_walk_callback(struct hash_bucket *bucket, |
77 | | void *ctxt) |
78 | 0 | { |
79 | 0 | int ret; |
80 | 0 | struct zebra_vxlan_vni *vni; |
81 | 0 | struct zebra_vxlan_if_ctx *ctx; |
82 | |
|
83 | 0 | vni = (struct zebra_vxlan_vni *)bucket->data; |
84 | 0 | ctx = (struct zebra_vxlan_if_ctx *)ctxt; |
85 | |
|
86 | 0 | ret = ctx->func(ctx->zif, vni, ctx->arg); |
87 | 0 | return ret; |
88 | 0 | } |
89 | | |
90 | | static void zebra_vxlan_if_vni_iterate_callback(struct hash_bucket *bucket, |
91 | | void *ctxt) |
92 | 0 | { |
93 | 0 | struct zebra_vxlan_vni *vni; |
94 | 0 | struct zebra_vxlan_if_ctx *ctx; |
95 | |
|
96 | 0 | vni = (struct zebra_vxlan_vni *)bucket->data; |
97 | 0 | ctx = (struct zebra_vxlan_if_ctx *)ctxt; |
98 | |
|
99 | 0 | ctx->func(ctx->zif, vni, ctx->arg); |
100 | 0 | } |
101 | | |
102 | | static int zebra_vxlan_if_del_vni(struct interface *ifp, |
103 | | struct zebra_vxlan_vni *vnip) |
104 | 0 | { |
105 | 0 | vni_t vni; |
106 | 0 | struct zebra_if *zif; |
107 | 0 | struct zebra_evpn *zevpn; |
108 | 0 | struct zebra_l3vni *zl3vni; |
109 | 0 | struct interface *br_if; |
110 | | |
111 | | /* Check if EVPN is enabled. */ |
112 | 0 | if (!is_evpn_enabled()) |
113 | 0 | return 0; |
114 | | |
115 | 0 | zif = ifp->info; |
116 | 0 | assert(zif); |
117 | 0 | vni = vnip->vni; |
118 | |
|
119 | 0 | zl3vni = zl3vni_lookup(vni); |
120 | 0 | if (zl3vni) { |
121 | |
|
122 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
123 | 0 | zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name, |
124 | 0 | ifp->ifindex); |
125 | | |
126 | | /* process oper-down for l3-vni */ |
127 | 0 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
128 | | |
129 | | /* remove the association with vxlan_if */ |
130 | 0 | memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr)); |
131 | 0 | zl3vni->vxlan_if = NULL; |
132 | 0 | zl3vni->vid = 0; |
133 | 0 | br_if = zif->brslave_info.br_if; |
134 | 0 | zl3vni_bridge_if_set(zl3vni, br_if, false /* unset */); |
135 | 0 | } else { |
136 | | |
137 | | /* process if-del for l2-vni*/ |
138 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
139 | 0 | zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name, |
140 | 0 | ifp->ifindex); |
141 | | |
142 | | /* Locate hash entry; it is expected to exist. */ |
143 | 0 | zevpn = zebra_evpn_lookup(vni); |
144 | 0 | if (!zevpn) { |
145 | 0 | zlog_debug( |
146 | 0 | "Failed to locate VNI hash at del, IF %s(%u) VNI %u", |
147 | 0 | ifp->name, ifp->ifindex, vni); |
148 | 0 | return 0; |
149 | 0 | } |
150 | | |
151 | | /* remove from l3-vni list */ |
152 | 0 | zl3vni = zl3vni_from_vrf(zevpn->vrf_id); |
153 | 0 | if (zl3vni) |
154 | 0 | listnode_delete(zl3vni->l2vnis, zevpn); |
155 | | /* Delete VNI from BGP. */ |
156 | 0 | zebra_evpn_send_del_to_client(zevpn); |
157 | | |
158 | | /* Free up all neighbors and MAC, if any. */ |
159 | 0 | zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); |
160 | 0 | zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); |
161 | | |
162 | | /* Free up all remote VTEPs, if any. */ |
163 | 0 | zebra_evpn_vtep_del_all(zevpn, 1); |
164 | | |
165 | | /* Delete the hash entry. */ |
166 | 0 | if (zebra_evpn_vxlan_del(zevpn)) { |
167 | 0 | flog_err(EC_ZEBRA_VNI_DEL_FAILED, |
168 | 0 | "Failed to del EVPN hash %p, IF %s(%u) VNI %u", |
169 | 0 | zevpn, ifp->name, ifp->ifindex, zevpn->vni); |
170 | 0 | return -1; |
171 | 0 | } |
172 | 0 | } |
173 | 0 | return 0; |
174 | 0 | } |
175 | | |
176 | | static int zebra_vxlan_if_update_vni(struct interface *ifp, |
177 | | struct zebra_vxlan_vni *vnip, |
178 | | struct zebra_vxlan_if_update_ctx *ctx) |
179 | 0 | { |
180 | 0 | vni_t vni; |
181 | 0 | uint16_t chgflags; |
182 | 0 | vlanid_t access_vlan; |
183 | 0 | struct zebra_if *zif; |
184 | 0 | struct zebra_l2info_vxlan *vxl; |
185 | 0 | struct zebra_evpn *zevpn; |
186 | 0 | struct zebra_l3vni *zl3vni; |
187 | 0 | struct interface *vlan_if; |
188 | 0 | struct interface *br_if; |
189 | | |
190 | | /* Check if EVPN is enabled. */ |
191 | 0 | if (!is_evpn_enabled()) |
192 | 0 | return 0; |
193 | | |
194 | 0 | zif = ifp->info; |
195 | 0 | assert(zif); |
196 | 0 | vxl = &zif->l2info.vxl; |
197 | 0 | vni = vnip->vni; |
198 | 0 | chgflags = ctx->chgflags; |
199 | |
|
200 | 0 | zl3vni = zl3vni_lookup(vni); |
201 | 0 | if (zl3vni) { |
202 | |
|
203 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
204 | 0 | zlog_debug( |
205 | 0 | "Update L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x", |
206 | 0 | vni, ifp->name, ifp->ifindex, vnip->access_vlan, |
207 | 0 | &vxl->vtep_ip, zif->brslave_info.bridge_ifindex, |
208 | 0 | chgflags); |
209 | | |
210 | | /* Removed from bridge? Cleanup and return */ |
211 | 0 | if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && |
212 | 0 | (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { |
213 | 0 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
214 | 0 | return 0; |
215 | 0 | } |
216 | | |
217 | 0 | if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) && |
218 | 0 | if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { |
219 | 0 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
220 | 0 | zebra_vxlan_process_l3vni_oper_up(zl3vni); |
221 | 0 | return 0; |
222 | 0 | } |
223 | | |
224 | | /* access-vlan change - process oper down, associate with new |
225 | | * svi_if and then process oper up again |
226 | | */ |
227 | 0 | if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { |
228 | 0 | if (if_is_operative(ifp)) { |
229 | 0 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
230 | 0 | zl3vni->svi_if = NULL; |
231 | 0 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); |
232 | 0 | zl3vni->mac_vlan_if = |
233 | 0 | zl3vni_map_to_mac_vlan_if(zl3vni); |
234 | 0 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
235 | 0 | if (is_l3vni_oper_up(zl3vni)) |
236 | 0 | zebra_vxlan_process_l3vni_oper_up( |
237 | 0 | zl3vni); |
238 | 0 | } |
239 | 0 | } |
240 | | |
241 | | /* |
242 | | * local-ip change - process oper down, associate with new |
243 | | * local-ip and then process oper up again |
244 | | */ |
245 | 0 | if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { |
246 | 0 | if (if_is_operative(ifp)) { |
247 | 0 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
248 | 0 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
249 | 0 | if (is_l3vni_oper_up(zl3vni)) |
250 | 0 | zebra_vxlan_process_l3vni_oper_up( |
251 | 0 | zl3vni); |
252 | 0 | } |
253 | 0 | } |
254 | | |
255 | | /* Update local tunnel IP. */ |
256 | 0 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
257 | |
|
258 | 0 | zl3vni->vid = (zl3vni->vid != vnip->access_vlan) |
259 | 0 | ? vnip->access_vlan |
260 | 0 | : zl3vni->vid; |
261 | 0 | br_if = zif->brslave_info.br_if; |
262 | 0 | zl3vni_bridge_if_set(zl3vni, br_if, true /* set */); |
263 | | |
264 | | /* if we have a valid new master, process l3-vni oper up */ |
265 | 0 | if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { |
266 | 0 | if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) |
267 | 0 | zebra_vxlan_process_l3vni_oper_up(zl3vni); |
268 | 0 | } |
269 | 0 | } else { |
270 | | |
271 | | /* Update VNI hash. */ |
272 | 0 | zevpn = zebra_evpn_lookup(vni); |
273 | 0 | if (!zevpn) { |
274 | 0 | zlog_debug( |
275 | 0 | "Failed to find EVPN hash on update, IF %s(%u) VNI %u", |
276 | 0 | ifp->name, ifp->ifindex, vni); |
277 | 0 | return -1; |
278 | 0 | } |
279 | | |
280 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
281 | 0 | zlog_debug( |
282 | 0 | "Update L2-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u chg 0x%x", |
283 | 0 | vni, ifp->name, ifp->ifindex, vnip->access_vlan, |
284 | 0 | &vxl->vtep_ip, zif->brslave_info.bridge_ifindex, |
285 | 0 | chgflags); |
286 | | |
287 | | /* Removed from bridge? Cleanup and return */ |
288 | 0 | if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && |
289 | 0 | (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { |
290 | | /* Delete from client, remove all remote VTEPs */ |
291 | | /* Also, free up all MACs and neighbors. */ |
292 | 0 | zevpn->svi_if = NULL; |
293 | 0 | zebra_evpn_send_del_to_client(zevpn); |
294 | 0 | zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); |
295 | 0 | zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); |
296 | 0 | zebra_evpn_vtep_del_all(zevpn, 1); |
297 | 0 | return 0; |
298 | 0 | } |
299 | | |
300 | | /* Handle other changes. */ |
301 | 0 | if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { |
302 | | /* Remove all existing local neigh and MACs for this VNI |
303 | | * (including from BGP) |
304 | | */ |
305 | 0 | access_vlan = vnip->access_vlan; |
306 | 0 | vnip->access_vlan = ctx->old_vni.access_vlan; |
307 | 0 | zebra_evpn_neigh_del_all(zevpn, 0, 1, DEL_LOCAL_MAC); |
308 | 0 | zebra_evpn_mac_del_all(zevpn, 0, 1, DEL_LOCAL_MAC); |
309 | 0 | zebra_evpn_rem_mac_uninstall_all(zevpn); |
310 | 0 | vnip->access_vlan = access_vlan; |
311 | 0 | } |
312 | |
|
313 | 0 | if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr || |
314 | 0 | zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) { |
315 | 0 | zebra_vxlan_sg_deref(zevpn->local_vtep_ip, |
316 | 0 | zevpn->mcast_grp); |
317 | 0 | zebra_vxlan_sg_ref(vxl->vtep_ip, vnip->mcast_grp); |
318 | 0 | zevpn->local_vtep_ip = vxl->vtep_ip; |
319 | 0 | zevpn->mcast_grp = vnip->mcast_grp; |
320 | | /* on local vtep-ip check if ES orig-ip |
321 | | * needs to be updated |
322 | | */ |
323 | 0 | zebra_evpn_es_set_base_evpn(zevpn); |
324 | 0 | } |
325 | 0 | zevpn_vxlan_if_set(zevpn, ifp, true /* set */); |
326 | 0 | zevpn->vid = (zevpn->vid != vnip->access_vlan) |
327 | 0 | ? vnip->access_vlan |
328 | 0 | : zevpn->vid; |
329 | 0 | br_if = zif->brslave_info.br_if; |
330 | 0 | zevpn_bridge_if_set(zevpn, br_if, true /* set */); |
331 | |
|
332 | 0 | vlan_if = zvni_map_to_svi(vnip->access_vlan, br_if); |
333 | 0 | if (vlan_if) |
334 | 0 | zevpn->svi_if = vlan_if; |
335 | | |
336 | | /* Take further actions needed. |
337 | | * Note that if we are here, there is a change of interest. |
338 | | */ |
339 | | /* If down or not mapped to a bridge, we're done. */ |
340 | 0 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
341 | 0 | return 0; |
342 | | |
343 | | /* Inform BGP, if there is a change of interest. */ |
344 | 0 | if (chgflags & |
345 | 0 | (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE | |
346 | 0 | ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE)) |
347 | 0 | zebra_evpn_send_add_to_client(zevpn); |
348 | | |
349 | | /* If there is a valid new master or a VLAN mapping change, |
350 | | * read and populate local MACs and neighbors. |
351 | | * Also, reinstall any remote MACs and neighbors |
352 | | * for this VNI (based on new VLAN). |
353 | | */ |
354 | 0 | if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) |
355 | 0 | zebra_evpn_read_mac_neigh(zevpn, ifp); |
356 | 0 | else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { |
357 | 0 | struct neigh_walk_ctx n_wctx; |
358 | |
|
359 | 0 | zebra_evpn_read_mac_neigh(zevpn, ifp); |
360 | |
|
361 | 0 | zebra_evpn_rem_mac_install_all(zevpn); |
362 | |
|
363 | 0 | memset(&n_wctx, 0, sizeof(n_wctx)); |
364 | 0 | n_wctx.zevpn = zevpn; |
365 | 0 | hash_iterate(zevpn->neigh_table, |
366 | 0 | zebra_evpn_install_neigh_hash, &n_wctx); |
367 | 0 | } |
368 | 0 | } |
369 | | |
370 | 0 | return 0; |
371 | 0 | } |
372 | | |
373 | | static int zebra_vxlan_if_add_vni(struct interface *ifp, |
374 | | struct zebra_vxlan_vni *vnip) |
375 | 0 | { |
376 | 0 | vni_t vni; |
377 | 0 | struct zebra_if *zif; |
378 | 0 | struct zebra_l2info_vxlan *vxl; |
379 | 0 | struct zebra_evpn *zevpn; |
380 | 0 | struct zebra_l3vni *zl3vni; |
381 | 0 | struct interface *br_if; |
382 | | |
383 | | /* Check if EVPN is enabled. */ |
384 | 0 | if (!is_evpn_enabled()) |
385 | 0 | return 0; |
386 | | |
387 | 0 | zif = ifp->info; |
388 | 0 | assert(zif); |
389 | 0 | vxl = &zif->l2info.vxl; |
390 | 0 | vni = vnip->vni; |
391 | |
|
392 | 0 | zl3vni = zl3vni_lookup(vni); |
393 | 0 | if (zl3vni) { |
394 | | |
395 | | /* process if-add for l3-vni*/ |
396 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
397 | 0 | zlog_debug( |
398 | 0 | "Add L3-VNI %u intf %s(%u) VLAN %u local IP %pI4 master %u", |
399 | 0 | vni, ifp->name, ifp->ifindex, vnip->access_vlan, |
400 | 0 | &vxl->vtep_ip, |
401 | 0 | zif->brslave_info.bridge_ifindex); |
402 | | |
403 | | /* associate with vxlan_if */ |
404 | 0 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
405 | 0 | zl3vni->vxlan_if = ifp; |
406 | | |
407 | | /* |
408 | | * Associate with SVI, if any. We can associate with svi-if only |
409 | | * after association with vxlan_if is complete |
410 | | */ |
411 | 0 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); |
412 | |
|
413 | 0 | zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); |
414 | |
|
415 | 0 | zl3vni->vid = vnip->access_vlan; |
416 | 0 | br_if = zif->brslave_info.br_if; |
417 | 0 | zl3vni_bridge_if_set(zl3vni, br_if, true /* set */); |
418 | |
|
419 | 0 | if (is_l3vni_oper_up(zl3vni)) |
420 | 0 | zebra_vxlan_process_l3vni_oper_up(zl3vni); |
421 | 0 | } else { |
422 | | |
423 | | /* process if-add for l2-vni */ |
424 | 0 | struct interface *vlan_if = NULL; |
425 | | |
426 | | /* Create or update EVPN hash. */ |
427 | 0 | zevpn = zebra_evpn_lookup(vni); |
428 | 0 | if (!zevpn) |
429 | 0 | zevpn = zebra_evpn_add(vni); |
430 | |
|
431 | 0 | if (zevpn->local_vtep_ip.s_addr != vxl->vtep_ip.s_addr || |
432 | 0 | zevpn->mcast_grp.s_addr != vnip->mcast_grp.s_addr) { |
433 | 0 | zebra_vxlan_sg_deref(zevpn->local_vtep_ip, |
434 | 0 | zevpn->mcast_grp); |
435 | 0 | zebra_vxlan_sg_ref(vxl->vtep_ip, vnip->mcast_grp); |
436 | 0 | zevpn->local_vtep_ip = vxl->vtep_ip; |
437 | 0 | zevpn->mcast_grp = vnip->mcast_grp; |
438 | | /* on local vtep-ip check if ES orig-ip |
439 | | * needs to be updated |
440 | | */ |
441 | 0 | zebra_evpn_es_set_base_evpn(zevpn); |
442 | 0 | } |
443 | 0 | zevpn_vxlan_if_set(zevpn, ifp, true /* set */); |
444 | 0 | br_if = zif->brslave_info.br_if; |
445 | 0 | zevpn_bridge_if_set(zevpn, br_if, true /* set */); |
446 | 0 | vlan_if = zvni_map_to_svi(vnip->access_vlan, br_if); |
447 | 0 | if (vlan_if) { |
448 | 0 | zevpn->vid = vnip->access_vlan; |
449 | 0 | zevpn->svi_if = vlan_if; |
450 | 0 | zevpn->vrf_id = vlan_if->vrf->vrf_id; |
451 | 0 | zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); |
452 | 0 | if (zl3vni) |
453 | 0 | listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); |
454 | 0 | } |
455 | |
|
456 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
457 | 0 | zlog_debug( |
458 | 0 | "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %pI4 mcast_grp %pI4 master %u", |
459 | 0 | vni, |
460 | 0 | vlan_if ? vlan_if->vrf->name : VRF_DEFAULT_NAME, |
461 | 0 | ifp->name, ifp->ifindex, vnip->access_vlan, |
462 | 0 | &vxl->vtep_ip, &vnip->mcast_grp, |
463 | 0 | zif->brslave_info.bridge_ifindex); |
464 | | |
465 | | /* If down or not mapped to a bridge, we're done. */ |
466 | 0 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
467 | 0 | return 0; |
468 | | |
469 | | /* Inform BGP */ |
470 | 0 | zebra_evpn_send_add_to_client(zevpn); |
471 | | |
472 | | /* Read and populate local MACs and neighbors */ |
473 | 0 | zebra_evpn_read_mac_neigh(zevpn, ifp); |
474 | 0 | } |
475 | | |
476 | 0 | return 0; |
477 | 0 | } |
478 | | |
479 | | static void zebra_vxlan_if_vni_entry_del(struct zebra_if *zif, |
480 | | struct zebra_vxlan_vni *vni) |
481 | 0 | { |
482 | 0 | if (vni) { |
483 | 0 | zebra_evpn_vl_vxl_deref(vni->access_vlan, vni->vni, zif); |
484 | 0 | zebra_vxlan_if_del_vni(zif->ifp, vni); |
485 | 0 | } |
486 | 0 | } |
487 | | |
488 | | static int zebra_vxlan_if_vni_entry_add(struct zebra_if *zif, |
489 | | struct zebra_vxlan_vni *vni) |
490 | 0 | { |
491 | 0 | zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif); |
492 | 0 | return zebra_vxlan_if_add_vni(zif->ifp, vni); |
493 | 0 | } |
494 | | |
495 | | static int zebra_vxlan_if_add_update_vni(struct zebra_if *zif, |
496 | | struct zebra_vxlan_vni *vni, |
497 | | void *ctxt) |
498 | 0 | { |
499 | 0 | struct zebra_vxlan_vni vni_tmp; |
500 | 0 | struct zebra_vxlan_if_update_ctx *ctx; |
501 | 0 | struct zebra_vxlan_vni *old_vni = NULL; |
502 | |
|
503 | 0 | ctx = (struct zebra_vxlan_if_update_ctx *)ctxt; |
504 | 0 | memcpy(&vni_tmp, vni, sizeof(*vni)); |
505 | |
|
506 | 0 | if ((hashcount(ctx->old_vni_table) == 0) || |
507 | 0 | !(old_vni = hash_release(ctx->old_vni_table, &vni_tmp))) { |
508 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
509 | 0 | zlog_debug("vxlan %s adding vni(%d, %d)", |
510 | 0 | zif->ifp->name, vni->vni, vni->access_vlan); |
511 | |
|
512 | 0 | zebra_vxlan_if_vni_entry_add(zif, &vni_tmp); |
513 | 0 | return 0; |
514 | 0 | } |
515 | | |
516 | 0 | ctx->old_vni = *old_vni; |
517 | 0 | ctx->chgflags = ZEBRA_VXLIF_VLAN_CHANGE; |
518 | | |
519 | | /* copy mcast group from old_vni as thats not being changed here */ |
520 | 0 | vni->mcast_grp = old_vni->mcast_grp; |
521 | |
|
522 | 0 | if (old_vni->access_vlan != vni->access_vlan) { |
523 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
524 | 0 | zlog_debug( |
525 | 0 | "vxlan %s updating vni(%d, %d) -> vni(%d, %d)", |
526 | 0 | zif->ifp->name, old_vni->vni, |
527 | 0 | old_vni->access_vlan, vni->vni, |
528 | 0 | vni->access_vlan); |
529 | |
|
530 | 0 | zebra_evpn_vl_vxl_deref(old_vni->access_vlan, old_vni->vni, |
531 | 0 | zif); |
532 | 0 | zebra_evpn_vl_vxl_ref(vni->access_vlan, vni->vni, zif); |
533 | 0 | zebra_vxlan_if_update_vni(zif->ifp, vni, ctx); |
534 | 0 | zebra_vxlan_vni_free(old_vni); |
535 | 0 | } |
536 | |
|
537 | 0 | return 0; |
538 | 0 | } |
539 | | |
540 | | static int zebra_vxlan_if_vni_entry_update_callback(struct zebra_if *zif, |
541 | | struct zebra_vxlan_vni *vni, |
542 | | void *ctxt) |
543 | 0 | { |
544 | 0 | struct zebra_vxlan_if_update_ctx *ctx; |
545 | |
|
546 | 0 | ctx = (struct zebra_vxlan_if_update_ctx *)ctxt; |
547 | 0 | return zebra_vxlan_if_update_vni(zif->ifp, vni, ctx); |
548 | 0 | } |
549 | | |
550 | | static int zebra_vxlan_if_vni_entry_del_callback(struct zebra_if *zif, |
551 | | struct zebra_vxlan_vni *vni, |
552 | | void *ctxt) |
553 | 0 | { |
554 | 0 | zebra_vxlan_if_vni_entry_del(zif, vni); |
555 | 0 | return 0; |
556 | 0 | } |
557 | | |
558 | | static int zebra_vxlan_if_vni_entry_down_callback(struct zebra_if *zif, |
559 | | struct zebra_vxlan_vni *vni, |
560 | | void *ctxt) |
561 | 0 | { |
562 | 0 | return zebra_vxlan_if_vni_down(zif->ifp, vni); |
563 | 0 | } |
564 | | |
565 | | static int zebra_vxlan_if_vni_entry_up_callback(struct zebra_if *zif, |
566 | | struct zebra_vxlan_vni *vni, |
567 | | void *ctxt) |
568 | 0 | { |
569 | 0 | return zebra_vxlan_if_vni_up(zif->ifp, vni); |
570 | 0 | } |
571 | | |
572 | | static void zebra_vxlan_if_vni_clean(struct hash_bucket *bucket, void *arg) |
573 | 0 | { |
574 | 0 | struct zebra_if *zif; |
575 | 0 | struct zebra_vxlan_vni *vni; |
576 | |
|
577 | 0 | zif = (struct zebra_if *)arg; |
578 | 0 | vni = (struct zebra_vxlan_vni *)bucket->data; |
579 | 0 | zebra_vxlan_if_vni_entry_del(zif, vni); |
580 | 0 | } |
581 | | |
582 | | void zebra_vxlan_vni_free(void *arg) |
583 | 0 | { |
584 | 0 | struct zebra_vxlan_vni *vni; |
585 | |
|
586 | 0 | vni = (struct zebra_vxlan_vni *)arg; |
587 | |
|
588 | 0 | XFREE(MTYPE_TMP, vni); |
589 | 0 | } |
590 | | |
591 | | void *zebra_vxlan_vni_alloc(void *p) |
592 | 0 | { |
593 | 0 | struct zebra_vxlan_vni *vni; |
594 | 0 | const struct zebra_vxlan_vni *vnip; |
595 | |
|
596 | 0 | vnip = (const struct zebra_vxlan_vni *)p; |
597 | 0 | vni = XCALLOC(MTYPE_TMP, sizeof(*vni)); |
598 | 0 | vni->vni = vnip->vni; |
599 | 0 | vni->access_vlan = vnip->access_vlan; |
600 | 0 | vni->mcast_grp = vnip->mcast_grp; |
601 | |
|
602 | 0 | return (void *)vni; |
603 | 0 | } |
604 | | |
605 | | struct hash *zebra_vxlan_vni_table_create(void) |
606 | 0 | { |
607 | 0 | return hash_create(zebra_vxlan_vni_hash_keymake, |
608 | 0 | zebra_vxlan_vni_hash_cmp, "Zebra Vxlan VNI Table"); |
609 | 0 | } |
610 | | |
611 | | void zebra_vxlan_vni_table_destroy(struct hash *vni_table) |
612 | 0 | { |
613 | 0 | hash_clean_and_free(&vni_table, zebra_vxlan_vni_free); |
614 | 0 | } |
615 | | |
616 | | int zebra_vxlan_if_vni_table_destroy(struct zebra_if *zif) |
617 | 0 | { |
618 | 0 | struct zebra_vxlan_vni_info *vni_info; |
619 | |
|
620 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
621 | 0 | if (vni_info->vni_table) { |
622 | 0 | zebra_vxlan_if_vni_iterate( |
623 | 0 | zif, zebra_vxlan_if_vni_entry_del_callback, NULL); |
624 | 0 | zebra_vxlan_vni_table_destroy(vni_info->vni_table); |
625 | 0 | vni_info->vni_table = NULL; |
626 | 0 | } |
627 | 0 | return 0; |
628 | 0 | } |
629 | | |
630 | | int zebra_vxlan_if_vni_table_create(struct zebra_if *zif) |
631 | 0 | { |
632 | 0 | struct zebra_vxlan_vni_info *vni_info; |
633 | |
|
634 | 0 | if (!IS_ZEBRA_VXLAN_IF_SVD(zif)) |
635 | 0 | return 0; |
636 | | |
637 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
638 | 0 | vni_info->vni_table = zebra_vxlan_vni_table_create(); |
639 | 0 | if (!vni_info->vni_table) |
640 | 0 | return -ENOMEM; |
641 | | |
642 | 0 | return 0; |
643 | 0 | } |
644 | | |
645 | | struct zebra_vxlan_vni *zebra_vxlan_if_vni_find(const struct zebra_if *zif, |
646 | | vni_t vni) |
647 | 0 | { |
648 | 0 | struct zebra_vxlan_vni *vnip = NULL; |
649 | 0 | const struct zebra_vxlan_vni_info *vni_info; |
650 | 0 | struct zebra_vxlan_vni vni_tmp; |
651 | |
|
652 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
653 | 0 | if (IS_ZEBRA_VXLAN_IF_VNI(zif)) { |
654 | 0 | vnip = (struct zebra_vxlan_vni *)&vni_info->vni; |
655 | 0 | assert(vnip); |
656 | 0 | if (vni && (vnip->vni != vni)) |
657 | 0 | vnip = NULL; |
658 | |
|
659 | 0 | return vnip; |
660 | 0 | } |
661 | | |
662 | | /* For SVD, the VNI value is a required parameter. */ |
663 | 0 | assert(vni); |
664 | |
|
665 | 0 | memset(&vni_tmp, 0, sizeof(vni_tmp)); |
666 | 0 | vni_tmp.vni = vni; |
667 | 0 | vnip = (struct zebra_vxlan_vni *)hash_lookup(vni_info->vni_table, |
668 | 0 | (void *)&vni_tmp); |
669 | | |
670 | | /* TODO: For debugging. Remove later */ |
671 | 0 | if (vnip) |
672 | 0 | assert(vnip->vni == vni); |
673 | |
|
674 | 0 | return vnip; |
675 | 0 | } |
676 | | |
677 | | static int zif_vlanid_vni_walker(struct zebra_if *zif, |
678 | | struct zebra_vxlan_vni *vnip, void *arg) |
679 | 0 | { |
680 | 0 | struct zebra_vxlan_if_vlan_ctx *ctx; |
681 | |
|
682 | 0 | ctx = (struct zebra_vxlan_if_vlan_ctx *)arg; |
683 | |
|
684 | 0 | if (vnip->access_vlan == ctx->vid) { |
685 | 0 | ctx->vni = vnip; |
686 | 0 | return HASHWALK_ABORT; |
687 | 0 | } |
688 | | |
689 | 0 | return HASHWALK_CONTINUE; |
690 | 0 | } |
691 | | |
692 | | struct zebra_vxlan_vni *zebra_vxlan_if_vlanid_vni_find(struct zebra_if *zif, |
693 | | vlanid_t vid) |
694 | 0 | { |
695 | 0 | struct zebra_vxlan_if_vlan_ctx ctx = {}; |
696 | |
|
697 | 0 | if (!IS_ZEBRA_VXLAN_IF_SVD(zif)) |
698 | 0 | return NULL; |
699 | | |
700 | 0 | ctx.vid = vid; |
701 | |
|
702 | 0 | zebra_vxlan_if_vni_walk(zif, zif_vlanid_vni_walker, &ctx); |
703 | |
|
704 | 0 | return ctx.vni; |
705 | 0 | } |
706 | | |
707 | | void zebra_vxlan_if_vni_iterate(struct zebra_if *zif, |
708 | | int (*func)(struct zebra_if *zif, |
709 | | struct zebra_vxlan_vni *, void *), |
710 | | void *arg) |
711 | 0 | { |
712 | 0 | struct zebra_vxlan_vni_info *vni_info; |
713 | 0 | struct zebra_vxlan_vni *vni = NULL; |
714 | 0 | struct zebra_vxlan_if_ctx ctx; |
715 | |
|
716 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
717 | 0 | if (IS_ZEBRA_VXLAN_IF_VNI(zif)) { |
718 | 0 | vni = zebra_vxlan_if_vni_find(zif, 0); |
719 | 0 | func(zif, vni, arg); |
720 | 0 | return; |
721 | 0 | } |
722 | | |
723 | 0 | memset(&ctx, 0, sizeof(ctx)); |
724 | 0 | ctx.zif = zif; |
725 | 0 | ctx.func = func; |
726 | 0 | ctx.arg = arg; |
727 | 0 | hash_iterate(vni_info->vni_table, zebra_vxlan_if_vni_iterate_callback, |
728 | 0 | &ctx); |
729 | 0 | } |
730 | | |
731 | | void zebra_vxlan_if_vni_walk(struct zebra_if *zif, |
732 | | int (*func)(struct zebra_if *zif, |
733 | | struct zebra_vxlan_vni *, void *), |
734 | | void *arg) |
735 | 0 | { |
736 | 0 | struct zebra_vxlan_vni_info *vni_info; |
737 | 0 | struct zebra_vxlan_vni *vni = NULL; |
738 | 0 | struct zebra_vxlan_if_ctx ctx; |
739 | |
|
740 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
741 | 0 | if (IS_ZEBRA_VXLAN_IF_VNI(zif)) { |
742 | 0 | vni = zebra_vxlan_if_vni_find(zif, 0); |
743 | 0 | func(zif, vni, arg); |
744 | 0 | return; |
745 | 0 | } |
746 | | |
747 | 0 | memset(&ctx, 0, sizeof(ctx)); |
748 | 0 | ctx.zif = zif; |
749 | 0 | ctx.func = func; |
750 | 0 | ctx.arg = arg; |
751 | 0 | hash_walk(vni_info->vni_table, zebra_vxlan_if_vni_walk_callback, &ctx); |
752 | 0 | } |
753 | | |
754 | | vni_t zebra_vxlan_if_access_vlan_vni_find(struct zebra_if *zif, |
755 | | struct interface *br_if) |
756 | 0 | { |
757 | 0 | struct zebra_vxlan_vni *vni = NULL; |
758 | | |
759 | | /* Expected to be called only for vlan-unware bridges. In this case, |
760 | | * we only support a per-VNI VXLAN interface model. |
761 | | */ |
762 | 0 | if (!IS_ZEBRA_VXLAN_IF_VNI(zif)) |
763 | 0 | return 0; |
764 | | |
765 | 0 | vni = zebra_vxlan_if_vni_find(zif, 0); |
766 | 0 | assert(vni); |
767 | |
|
768 | 0 | return vni->vni; |
769 | 0 | } |
770 | | |
771 | | int zebra_vxlan_if_vni_table_add_update(struct interface *ifp, |
772 | | struct hash *vni_table) |
773 | 0 | { |
774 | 0 | struct zebra_if *zif; |
775 | 0 | struct zebra_vxlan_vni_info *vni_info; |
776 | 0 | struct zebra_vxlan_if_update_ctx ctx; |
777 | |
|
778 | 0 | zif = (struct zebra_if *)ifp->info; |
779 | |
|
780 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
781 | |
|
782 | 0 | memset(&ctx, 0, sizeof(ctx)); |
783 | 0 | ctx.old_vni_table = vni_info->vni_table; |
784 | 0 | vni_info->vni_table = vni_table; |
785 | |
|
786 | 0 | zebra_vxlan_if_vni_iterate(zif, zebra_vxlan_if_add_update_vni, &ctx); |
787 | | |
788 | | /* release kernel deleted vnis */ |
789 | 0 | if (ctx.old_vni_table) { |
790 | 0 | if (hashcount(ctx.old_vni_table)) { |
791 | | /* UGLY HACK: Put back the old table so that delete of |
792 | | * MACs goes through and then flip back. |
793 | | */ |
794 | 0 | vni_info->vni_table = ctx.old_vni_table; |
795 | 0 | hash_iterate(ctx.old_vni_table, |
796 | 0 | zebra_vxlan_if_vni_clean, zif); |
797 | 0 | vni_info->vni_table = vni_table; |
798 | 0 | } |
799 | 0 | zebra_vxlan_vni_table_destroy(ctx.old_vni_table); |
800 | 0 | ctx.old_vni_table = NULL; |
801 | 0 | } |
802 | |
|
803 | 0 | return 0; |
804 | 0 | } |
805 | | |
806 | | int zebra_vxlan_if_vni_mcast_group_add_update(struct interface *ifp, |
807 | | vni_t vni_id, |
808 | | struct in_addr *mcast_group) |
809 | 0 | { |
810 | 0 | struct zebra_if *zif; |
811 | 0 | struct zebra_vxlan_vni *vni; |
812 | 0 | struct zebra_vxlan_if_update_ctx ctx; |
813 | |
|
814 | 0 | zif = (struct zebra_if *)ifp->info; |
815 | |
|
816 | 0 | if (!IS_ZEBRA_VXLAN_IF_SVD(zif)) |
817 | 0 | return 0; |
818 | | |
819 | 0 | vni = zebra_vxlan_if_vni_find(zif, vni_id); |
820 | 0 | if (!vni) |
821 | 0 | return 0; |
822 | | |
823 | 0 | memset(&ctx, 0, sizeof(ctx)); |
824 | 0 | ctx.old_vni.mcast_grp = vni->mcast_grp; |
825 | 0 | ctx.chgflags = ZEBRA_VXLIF_MCAST_GRP_CHANGE; |
826 | |
|
827 | 0 | vni->mcast_grp = *mcast_group; |
828 | |
|
829 | 0 | return zebra_vxlan_if_update_vni(ifp, vni, &ctx); |
830 | 0 | } |
831 | | |
832 | | int zebra_vxlan_if_vni_mcast_group_del(struct interface *ifp, vni_t vni_id, |
833 | | struct in_addr *mcast_group) |
834 | 0 | { |
835 | 0 | struct zebra_if *zif = NULL; |
836 | 0 | struct zebra_vxlan_vni *vni; |
837 | 0 | struct zebra_vxlan_if_update_ctx ctx; |
838 | |
|
839 | 0 | zif = (struct zebra_if *)ifp->info; |
840 | |
|
841 | 0 | if (!IS_ZEBRA_VXLAN_IF_SVD(zif)) |
842 | 0 | return 0; |
843 | | |
844 | 0 | vni = zebra_vxlan_if_vni_find(zif, vni_id); |
845 | 0 | if (!vni) |
846 | 0 | return 0; |
847 | | |
848 | 0 | if (memcmp(mcast_group, &vni->mcast_grp, sizeof(*mcast_group))) |
849 | 0 | return 0; |
850 | | |
851 | 0 | memset(&ctx, 0, sizeof(ctx)); |
852 | 0 | ctx.old_vni.mcast_grp = vni->mcast_grp; |
853 | 0 | ctx.chgflags = ZEBRA_VXLIF_MCAST_GRP_CHANGE; |
854 | |
|
855 | 0 | memset(&vni->mcast_grp, 0, sizeof(vni->mcast_grp)); |
856 | |
|
857 | 0 | return zebra_vxlan_if_update_vni(ifp, vni, &ctx); |
858 | 0 | } |
859 | | |
860 | | int zebra_vxlan_if_vni_down(struct interface *ifp, struct zebra_vxlan_vni *vnip) |
861 | 0 | { |
862 | 0 | vni_t vni; |
863 | 0 | struct zebra_if *zif; |
864 | 0 | struct zebra_l3vni *zl3vni; |
865 | 0 | struct zebra_evpn *zevpn; |
866 | | |
867 | | /* Check if EVPN is enabled. */ |
868 | 0 | if (!is_evpn_enabled()) |
869 | 0 | return 0; |
870 | | |
871 | 0 | zif = ifp->info; |
872 | 0 | assert(zif); |
873 | 0 | vni = vnip->vni; |
874 | |
|
875 | 0 | zl3vni = zl3vni_lookup(vni); |
876 | 0 | if (zl3vni) { |
877 | | /* process-if-down for l3-vni */ |
878 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
879 | 0 | zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name, |
880 | 0 | ifp->ifindex, vni); |
881 | |
|
882 | 0 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
883 | 0 | } else { |
884 | | /* process if-down for l2-vni */ |
885 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
886 | 0 | zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name, |
887 | 0 | ifp->ifindex, vni); |
888 | | |
889 | | /* Locate hash entry; it is expected to exist. */ |
890 | 0 | zevpn = zebra_evpn_lookup(vni); |
891 | 0 | if (!zevpn) { |
892 | 0 | zlog_debug( |
893 | 0 | "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u", |
894 | 0 | ifp->name, ifp->ifindex, vni); |
895 | 0 | return -1; |
896 | 0 | } |
897 | | |
898 | 0 | assert(zevpn->vxlan_if == ifp); |
899 | | |
900 | | /* remove from l3-vni list */ |
901 | 0 | zl3vni = zl3vni_from_vrf(zevpn->vrf_id); |
902 | 0 | if (zl3vni) |
903 | 0 | listnode_delete(zl3vni->l2vnis, zevpn); |
904 | |
|
905 | 0 | zebra_evpn_vl_vxl_deref(vnip->access_vlan, vnip->vni, zif); |
906 | | |
907 | | /* Delete this VNI from BGP. */ |
908 | 0 | zebra_evpn_send_del_to_client(zevpn); |
909 | | |
910 | | /* Free up all neighbors and MACs, if any. */ |
911 | 0 | zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); |
912 | 0 | zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); |
913 | | |
914 | | /* Free up all remote VTEPs, if any. */ |
915 | 0 | zebra_evpn_vtep_del_all(zevpn, 1); |
916 | 0 | } |
917 | 0 | return 0; |
918 | 0 | } |
919 | | |
920 | | /* |
921 | | * Handle VxLAN interface down |
922 | | */ |
923 | | int zebra_vxlan_if_down(struct interface *ifp) |
924 | 0 | { |
925 | 0 | struct zebra_if *zif; |
926 | 0 | struct zebra_vxlan_vni_info *vni_info; |
927 | | |
928 | | /* Check if EVPN is enabled. */ |
929 | 0 | if (!is_evpn_enabled()) |
930 | 0 | return 0; |
931 | | |
932 | 0 | zif = ifp->info; |
933 | 0 | assert(zif); |
934 | |
|
935 | 0 | if (IS_ZEBRA_VXLAN_IF_VNI(zif)) { |
936 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
937 | 0 | return zebra_vxlan_if_vni_down(ifp, &vni_info->vni); |
938 | 0 | } |
939 | | |
940 | 0 | zebra_vxlan_if_vni_iterate(zif, zebra_vxlan_if_vni_entry_down_callback, |
941 | 0 | NULL); |
942 | |
|
943 | 0 | return 0; |
944 | 0 | } |
945 | | |
946 | | int zebra_vxlan_if_vni_up(struct interface *ifp, struct zebra_vxlan_vni *vnip) |
947 | 0 | { |
948 | 0 | vni_t vni; |
949 | 0 | struct zebra_if *zif; |
950 | 0 | struct zebra_evpn *zevpn; |
951 | 0 | struct zebra_l3vni *zl3vni; |
952 | | |
953 | | /* Check if EVPN is enabled. */ |
954 | 0 | if (!is_evpn_enabled()) |
955 | 0 | return 0; |
956 | | |
957 | 0 | zif = ifp->info; |
958 | 0 | assert(zif); |
959 | 0 | vni = vnip->vni; |
960 | |
|
961 | 0 | zl3vni = zl3vni_lookup(vni); |
962 | 0 | if (zl3vni) { |
963 | | /* we need to associate with SVI, if any, we can associate with |
964 | | * svi-if only after association with vxlan-intf is complete |
965 | | */ |
966 | 0 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); |
967 | 0 | zl3vni->mac_vlan_if = zl3vni_map_to_mac_vlan_if(zl3vni); |
968 | |
|
969 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
970 | 0 | zlog_debug( |
971 | 0 | "Intf %s(%u) L3-VNI %u is UP svi_if %s mac_vlan_if %s", |
972 | 0 | ifp->name, ifp->ifindex, vni, |
973 | 0 | zl3vni->svi_if ? zl3vni->svi_if->name : "NIL", |
974 | 0 | zl3vni->mac_vlan_if ? zl3vni->mac_vlan_if->name |
975 | 0 | : "NIL"); |
976 | |
|
977 | 0 | if (is_l3vni_oper_up(zl3vni)) |
978 | 0 | zebra_vxlan_process_l3vni_oper_up(zl3vni); |
979 | 0 | } else { |
980 | | /* Handle L2-VNI add */ |
981 | 0 | struct interface *vlan_if = NULL; |
982 | |
|
983 | 0 | if (IS_ZEBRA_DEBUG_VXLAN) |
984 | 0 | zlog_debug("Intf %s(%u) L2-VNI %u is UP", ifp->name, |
985 | 0 | ifp->ifindex, vni); |
986 | | |
987 | | /* Locate hash entry; it is expected to exist. */ |
988 | 0 | zevpn = zebra_evpn_lookup(vni); |
989 | 0 | if (!zevpn) { |
990 | 0 | zlog_debug( |
991 | 0 | "Failed to locate EVPN hash at UP, IF %s(%u) VNI %u", |
992 | 0 | ifp->name, ifp->ifindex, vni); |
993 | 0 | return -1; |
994 | 0 | } |
995 | | |
996 | 0 | assert(zevpn->vxlan_if == ifp); |
997 | 0 | zebra_evpn_vl_vxl_ref(vnip->access_vlan, vnip->vni, zif); |
998 | 0 | vlan_if = zvni_map_to_svi(vnip->access_vlan, |
999 | 0 | zif->brslave_info.br_if); |
1000 | 0 | if (vlan_if) { |
1001 | 0 | zevpn->svi_if = vlan_if; |
1002 | 0 | zevpn->vrf_id = vlan_if->vrf->vrf_id; |
1003 | 0 | zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); |
1004 | 0 | if (zl3vni) |
1005 | 0 | listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); |
1006 | 0 | } |
1007 | | |
1008 | | /* If part of a bridge, inform BGP about this VNI. */ |
1009 | | /* Also, read and populate local MACs and neighbors. */ |
1010 | 0 | if (zif->brslave_info.br_if) { |
1011 | 0 | zebra_evpn_send_add_to_client(zevpn); |
1012 | 0 | zebra_evpn_read_mac_neigh(zevpn, ifp); |
1013 | 0 | } |
1014 | 0 | } |
1015 | | |
1016 | 0 | return 0; |
1017 | 0 | } |
1018 | | |
1019 | | /* |
1020 | | * Handle VxLAN interface up - update BGP if required. |
1021 | | */ |
1022 | | int zebra_vxlan_if_up(struct interface *ifp) |
1023 | 0 | { |
1024 | 0 | struct zebra_if *zif; |
1025 | 0 | struct zebra_vxlan_vni_info *vni_info; |
1026 | | |
1027 | | /* Check if EVPN is enabled. */ |
1028 | 0 | if (!is_evpn_enabled()) |
1029 | 0 | return 0; |
1030 | | |
1031 | 0 | zif = ifp->info; |
1032 | 0 | assert(zif); |
1033 | |
|
1034 | 0 | if (IS_ZEBRA_VXLAN_IF_VNI(zif)) { |
1035 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
1036 | 0 | return zebra_vxlan_if_vni_up(ifp, &vni_info->vni); |
1037 | 0 | } |
1038 | | |
1039 | 0 | zebra_vxlan_if_vni_iterate(zif, zebra_vxlan_if_vni_entry_up_callback, |
1040 | 0 | NULL); |
1041 | |
|
1042 | 0 | return 0; |
1043 | 0 | } |
1044 | | |
1045 | | int zebra_vxlan_if_vni_del(struct interface *ifp, vni_t vni) |
1046 | 0 | { |
1047 | 0 | struct zebra_if *zif; |
1048 | 0 | struct zebra_vxlan_vni *vnip; |
1049 | 0 | struct zebra_vxlan_vni vni_tmp; |
1050 | 0 | struct zebra_vxlan_vni_info *vni_info; |
1051 | |
|
1052 | 0 | zif = ifp->info; |
1053 | 0 | assert(zif); |
1054 | | |
1055 | | /* This should be called in SVD context only */ |
1056 | 0 | assert(IS_ZEBRA_VXLAN_IF_SVD(zif)); |
1057 | |
|
1058 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
1059 | 0 | memset(&vni_tmp, 0, sizeof(vni_tmp)); |
1060 | 0 | vni_tmp.vni = vni; |
1061 | |
|
1062 | 0 | vnip = hash_release(vni_info->vni_table, &vni_tmp); |
1063 | 0 | if (vnip) { |
1064 | 0 | zebra_vxlan_if_vni_entry_del(zif, vnip); |
1065 | 0 | zebra_vxlan_vni_free(vnip); |
1066 | 0 | } |
1067 | 0 | return 0; |
1068 | 0 | } |
1069 | | |
1070 | | /* |
1071 | | * Handle VxLAN interface delete. Locate and remove entry in hash table |
1072 | | * and update BGP, if required. |
1073 | | */ |
1074 | | int zebra_vxlan_if_del(struct interface *ifp) |
1075 | 0 | { |
1076 | 0 | struct zebra_if *zif; |
1077 | 0 | struct zebra_vxlan_vni_info *vni_info; |
1078 | |
|
1079 | 0 | zif = ifp->info; |
1080 | 0 | assert(zif); |
1081 | |
|
1082 | 0 | if (IS_ZEBRA_VXLAN_IF_VNI(zif)) { |
1083 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
1084 | 0 | zebra_evpn_vl_vxl_deref(vni_info->vni.access_vlan, |
1085 | 0 | vni_info->vni.vni, zif); |
1086 | 0 | return zebra_vxlan_if_del_vni(ifp, &vni_info->vni); |
1087 | 0 | } |
1088 | | |
1089 | 0 | zebra_vxlan_if_vni_table_destroy(zif); |
1090 | |
|
1091 | 0 | return 0; |
1092 | 0 | } |
1093 | | |
1094 | | /* |
1095 | | * Handle VxLAN interface update - change to tunnel IP, master or VLAN. |
1096 | | */ |
1097 | | int zebra_vxlan_if_update(struct interface *ifp, |
1098 | | struct zebra_vxlan_if_update_ctx *ctx) |
1099 | 0 | { |
1100 | 0 | struct zebra_if *zif; |
1101 | 0 | struct zebra_vxlan_vni_info *vni_info; |
1102 | |
|
1103 | 0 | zif = ifp->info; |
1104 | 0 | assert(zif); |
1105 | |
|
1106 | 0 | if (IS_ZEBRA_VXLAN_IF_VNI(zif)) { |
1107 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
1108 | 0 | return zebra_vxlan_if_update_vni(ifp, &vni_info->vni, ctx); |
1109 | 0 | } |
1110 | | |
1111 | 0 | zebra_vxlan_if_vni_iterate( |
1112 | 0 | zif, zebra_vxlan_if_vni_entry_update_callback, ctx); |
1113 | |
|
1114 | 0 | return 0; |
1115 | 0 | } |
1116 | | |
1117 | | int zebra_vxlan_if_vni_add(struct interface *ifp, struct zebra_vxlan_vni *vni) |
1118 | 0 | { |
1119 | 0 | struct zebra_if *zif; |
1120 | 0 | struct zebra_vxlan_vni_info *vni_info; |
1121 | |
|
1122 | 0 | zif = ifp->info; |
1123 | 0 | assert(zif); |
1124 | | |
1125 | | /* This should be called in SVD context only */ |
1126 | 0 | assert(IS_ZEBRA_VXLAN_IF_SVD(zif)); |
1127 | | |
1128 | | /* First insert into the table */ |
1129 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
1130 | 0 | hash_get(vni_info->vni_table, (void *)vni, zebra_vxlan_vni_alloc); |
1131 | |
|
1132 | 0 | return zebra_vxlan_if_vni_entry_add(zif, vni); |
1133 | 0 | } |
1134 | | |
1135 | | /* |
1136 | | * Handle VxLAN interface add. |
1137 | | */ |
1138 | | int zebra_vxlan_if_add(struct interface *ifp) |
1139 | 0 | { |
1140 | 0 | int ret; |
1141 | 0 | struct zebra_if *zif; |
1142 | 0 | struct zebra_vxlan_vni_info *vni_info; |
1143 | |
|
1144 | 0 | zif = ifp->info; |
1145 | 0 | assert(zif); |
1146 | |
|
1147 | 0 | if (IS_ZEBRA_VXLAN_IF_VNI(zif)) { |
1148 | 0 | vni_info = VNI_INFO_FROM_ZEBRA_IF(zif); |
1149 | 0 | zebra_evpn_vl_vxl_ref(vni_info->vni.access_vlan, |
1150 | 0 | vni_info->vni.vni, zif); |
1151 | 0 | return zebra_vxlan_if_add_vni(ifp, &vni_info->vni); |
1152 | 0 | } |
1153 | | |
1154 | 0 | ret = zebra_vxlan_if_vni_table_create(zif); |
1155 | 0 | if (ret < 0) |
1156 | 0 | return ret; |
1157 | | |
1158 | 0 | return 0; |
1159 | 0 | } |