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