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