]>
Commit | Line | Data |
---|---|---|
6006414d PR |
1 | /* |
2 | * Zebra EVPN for VxLAN code | |
3 | * Copyright (C) 2016, 2017 Cumulus Networks, Inc. | |
4 | * | |
5 | * This file is part of FRR. | |
6 | * | |
7 | * FRR is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2, or (at your option) any | |
10 | * later version. | |
11 | * | |
12 | * FRR is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with FRR; see the file COPYING. If not, write to the Free | |
19 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
20 | * 02111-1307, USA. | |
21 | */ | |
6006414d PR |
22 | #include <zebra.h> |
23 | ||
24 | #include "hash.h" | |
25 | #include "if.h" | |
26 | #include "jhash.h" | |
27 | #include "linklist.h" | |
28 | #include "log.h" | |
29 | #include "memory.h" | |
30 | #include "prefix.h" | |
31 | #include "stream.h" | |
32 | #include "table.h" | |
33 | #include "vlan.h" | |
34 | #include "vxlan.h" | |
35 | #ifdef GNU_LINUX | |
36 | #include <linux/neighbour.h> | |
37 | #endif | |
38 | ||
39 | #include "zebra/zebra_router.h" | |
40 | #include "zebra/debug.h" | |
41 | #include "zebra/interface.h" | |
42 | #include "zebra/rib.h" | |
43 | #include "zebra/rt.h" | |
44 | #include "zebra/rt_netlink.h" | |
45 | #include "zebra/zebra_errors.h" | |
46 | #include "zebra/zebra_l2.h" | |
6006414d PR |
47 | #include "zebra/zebra_ns.h" |
48 | #include "zebra/zebra_vrf.h" | |
49 | #include "zebra/zebra_vxlan.h" | |
50 | #include "zebra/zebra_evpn.h" | |
51 | #include "zebra/zebra_evpn_mac.h" | |
52 | #include "zebra/zebra_evpn_neigh.h" | |
53 | #include "zebra/zebra_vxlan_private.h" | |
54 | #include "zebra/zebra_evpn_mh.h" | |
8b5fdf2e | 55 | #include "zebra/zebra_evpn_vxlan.h" |
6006414d PR |
56 | #include "zebra/zebra_router.h" |
57 | ||
8b5fdf2e PR |
58 | DEFINE_MTYPE_STATIC(ZEBRA, ZEVPN, "VNI hash"); |
59 | DEFINE_MTYPE_STATIC(ZEBRA, ZEVPN_VTEP, "VNI remote VTEP"); | |
6006414d | 60 | |
6006414d PR |
61 | /* PMSI strings. */ |
62 | #define VXLAN_FLOOD_STR_NO_INFO "-" | |
63 | #define VXLAN_FLOOD_STR_DEFAULT VXLAN_FLOOD_STR_NO_INFO | |
64 | static const struct message zvtep_flood_str[] = { | |
65 | {VXLAN_FLOOD_DISABLED, VXLAN_FLOOD_STR_NO_INFO}, | |
66 | {VXLAN_FLOOD_PIM_SM, "PIM-SM"}, | |
67 | {VXLAN_FLOOD_HEAD_END_REPL, "HER"}, | |
68 | {0} | |
69 | }; | |
70 | ||
f6371c34 | 71 | int advertise_gw_macip_enabled(struct zebra_evpn *zevpn) |
6006414d PR |
72 | { |
73 | struct zebra_vrf *zvrf; | |
74 | ||
75 | zvrf = zebra_vrf_get_evpn(); | |
76 | if (zvrf && zvrf->advertise_gw_macip) | |
77 | return 1; | |
78 | ||
79 | if (zevpn && zevpn->advertise_gw_macip) | |
80 | return 1; | |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
f6371c34 | 85 | int advertise_svi_macip_enabled(struct zebra_evpn *zevpn) |
6006414d PR |
86 | { |
87 | struct zebra_vrf *zvrf; | |
88 | ||
89 | zvrf = zebra_vrf_get_evpn(); | |
90 | if (zvrf && zvrf->advertise_svi_macip) | |
91 | return 1; | |
92 | ||
93 | if (zevpn && zevpn->advertise_svi_macip) | |
94 | return 1; | |
95 | ||
96 | return 0; | |
97 | } | |
98 | ||
6006414d PR |
99 | /* |
100 | * Print a specific EVPN entry. | |
101 | */ | |
f6371c34 | 102 | void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt) |
6006414d PR |
103 | { |
104 | struct vty *vty; | |
c172c032 | 105 | struct zebra_vtep *zvtep; |
6006414d PR |
106 | uint32_t num_macs; |
107 | uint32_t num_neigh; | |
108 | json_object *json = NULL; | |
109 | json_object *json_vtep_list = NULL; | |
110 | json_object *json_ip_str = NULL; | |
9bcef951 | 111 | char buf[PREFIX_STRLEN]; |
6006414d PR |
112 | |
113 | vty = ctxt[0]; | |
114 | json = ctxt[1]; | |
115 | ||
116 | if (json == NULL) { | |
117 | vty_out(vty, "VNI: %u\n", zevpn->vni); | |
118 | vty_out(vty, " Type: %s\n", "L2"); | |
119 | vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zevpn->vrf_id)); | |
120 | } else { | |
121 | json_object_int_add(json, "vni", zevpn->vni); | |
122 | json_object_string_add(json, "type", "L2"); | |
123 | json_object_string_add(json, "vrf", | |
124 | vrf_id_to_name(zevpn->vrf_id)); | |
125 | } | |
126 | ||
127 | if (!zevpn->vxlan_if) { // unexpected | |
128 | if (json == NULL) | |
129 | vty_out(vty, " VxLAN interface: unknown\n"); | |
130 | return; | |
131 | } | |
132 | num_macs = num_valid_macs(zevpn); | |
133 | num_neigh = hashcount(zevpn->neigh_table); | |
134 | if (json == NULL) { | |
135 | vty_out(vty, " VxLAN interface: %s\n", zevpn->vxlan_if->name); | |
136 | vty_out(vty, " VxLAN ifIndex: %u\n", zevpn->vxlan_if->ifindex); | |
9daa5d47 AD |
137 | vty_out(vty, " SVI interface: %s\n", |
138 | (zevpn->svi_if ? zevpn->svi_if->name : "")); | |
139 | vty_out(vty, " SVI ifIndex: %u\n", | |
140 | (zevpn->svi_if ? zevpn->svi_if->ifindex : 0)); | |
9bcef951 MS |
141 | vty_out(vty, " Local VTEP IP: %pI4\n", |
142 | &zevpn->local_vtep_ip); | |
143 | vty_out(vty, " Mcast group: %pI4\n", | |
144 | &zevpn->mcast_grp); | |
6006414d PR |
145 | } else { |
146 | json_object_string_add(json, "vxlanInterface", | |
147 | zevpn->vxlan_if->name); | |
148 | json_object_int_add(json, "ifindex", zevpn->vxlan_if->ifindex); | |
9daa5d47 AD |
149 | if (zevpn->svi_if) { |
150 | json_object_string_add(json, "sviInterface", | |
151 | zevpn->svi_if->name); | |
152 | json_object_int_add(json, "sviIfindex", | |
153 | zevpn->svi_if->ifindex); | |
154 | } | |
6006414d | 155 | json_object_string_add(json, "vtepIp", |
9bcef951 MS |
156 | inet_ntop(AF_INET, &zevpn->local_vtep_ip, |
157 | buf, sizeof(buf))); | |
6006414d | 158 | json_object_string_add(json, "mcastGroup", |
9bcef951 MS |
159 | inet_ntop(AF_INET, &zevpn->mcast_grp, |
160 | buf, sizeof(buf))); | |
6006414d PR |
161 | json_object_string_add(json, "advertiseGatewayMacip", |
162 | zevpn->advertise_gw_macip ? "Yes" : "No"); | |
c0c7707d AK |
163 | json_object_string_add(json, "advertiseSviMacip", |
164 | zevpn->advertise_svi_macip ? "Yes" | |
165 | : "No"); | |
6006414d PR |
166 | json_object_int_add(json, "numMacs", num_macs); |
167 | json_object_int_add(json, "numArpNd", num_neigh); | |
168 | } | |
169 | if (!zevpn->vteps) { | |
170 | if (json == NULL) | |
171 | vty_out(vty, " No remote VTEPs known for this VNI\n"); | |
172 | } else { | |
173 | if (json == NULL) | |
174 | vty_out(vty, " Remote VTEPs for this VNI:\n"); | |
175 | else | |
176 | json_vtep_list = json_object_new_array(); | |
177 | for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { | |
178 | const char *flood_str = lookup_msg(zvtep_flood_str, | |
179 | zvtep->flood_control, | |
180 | VXLAN_FLOOD_STR_DEFAULT); | |
181 | ||
182 | if (json == NULL) { | |
9bcef951 MS |
183 | vty_out(vty, " %pI4 flood: %s\n", |
184 | &zvtep->vtep_ip, | |
6006414d PR |
185 | flood_str); |
186 | } else { | |
187 | json_ip_str = json_object_new_string( | |
9bcef951 MS |
188 | inet_ntop(AF_INET, |
189 | &zvtep->vtep_ip, buf, | |
190 | sizeof(buf))); | |
6006414d PR |
191 | json_object_array_add(json_vtep_list, |
192 | json_ip_str); | |
193 | } | |
194 | } | |
195 | if (json) | |
196 | json_object_object_add(json, "numRemoteVteps", | |
197 | json_vtep_list); | |
198 | } | |
199 | if (json == NULL) { | |
200 | vty_out(vty, | |
201 | " Number of MACs (local and remote) known for this VNI: %u\n", | |
202 | num_macs); | |
203 | vty_out(vty, | |
204 | " Number of ARPs (IPv4 and IPv6, local and remote) " | |
205 | "known for this VNI: %u\n", | |
206 | num_neigh); | |
207 | vty_out(vty, " Advertise-gw-macip: %s\n", | |
208 | zevpn->advertise_gw_macip ? "Yes" : "No"); | |
c0c7707d AK |
209 | vty_out(vty, " Advertise-svi-macip: %s\n", |
210 | zevpn->advertise_svi_macip ? "Yes" : "No"); | |
6006414d PR |
211 | } |
212 | } | |
213 | ||
8b5fdf2e PR |
214 | /* |
215 | * Print an EVPN hash entry - called for display of all VNIs. | |
216 | */ | |
217 | void zebra_evpn_print_hash(struct hash_bucket *bucket, void *ctxt[]) | |
6006414d | 218 | { |
8b5fdf2e | 219 | struct vty *vty; |
f6371c34 | 220 | struct zebra_evpn *zevpn; |
c172c032 | 221 | struct zebra_vtep *zvtep; |
8b5fdf2e PR |
222 | uint32_t num_vteps = 0; |
223 | uint32_t num_macs = 0; | |
224 | uint32_t num_neigh = 0; | |
6006414d PR |
225 | json_object *json = NULL; |
226 | json_object *json_evpn = NULL; | |
8b5fdf2e PR |
227 | json_object *json_ip_str = NULL; |
228 | json_object *json_vtep_list = NULL; | |
9bcef951 | 229 | char buf[PREFIX_STRLEN]; |
6006414d | 230 | |
8b5fdf2e PR |
231 | vty = ctxt[0]; |
232 | json = ctxt[1]; | |
6006414d | 233 | |
f6371c34 | 234 | zevpn = (struct zebra_evpn *)bucket->data; |
6006414d | 235 | |
8b5fdf2e PR |
236 | zvtep = zevpn->vteps; |
237 | while (zvtep) { | |
238 | num_vteps++; | |
239 | zvtep = zvtep->next; | |
6006414d PR |
240 | } |
241 | ||
242 | num_macs = num_valid_macs(zevpn); | |
243 | num_neigh = hashcount(zevpn->neigh_table); | |
244 | if (json == NULL) | |
245 | vty_out(vty, "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n", | |
246 | zevpn->vni, "L2", | |
247 | zevpn->vxlan_if ? zevpn->vxlan_if->name : "unknown", | |
248 | num_macs, num_neigh, num_vteps, | |
249 | vrf_id_to_name(zevpn->vrf_id)); | |
250 | else { | |
251 | char vni_str[VNI_STR_LEN]; | |
252 | snprintf(vni_str, VNI_STR_LEN, "%u", zevpn->vni); | |
253 | json_evpn = json_object_new_object(); | |
254 | json_object_int_add(json_evpn, "vni", zevpn->vni); | |
255 | json_object_string_add(json_evpn, "type", "L2"); | |
256 | json_object_string_add(json_evpn, "vxlanIf", | |
257 | zevpn->vxlan_if ? zevpn->vxlan_if->name | |
258 | : "unknown"); | |
259 | json_object_int_add(json_evpn, "numMacs", num_macs); | |
260 | json_object_int_add(json_evpn, "numArpNd", num_neigh); | |
261 | json_object_int_add(json_evpn, "numRemoteVteps", num_vteps); | |
262 | json_object_string_add(json_evpn, "tenantVrf", | |
263 | vrf_id_to_name(zevpn->vrf_id)); | |
264 | if (num_vteps) { | |
265 | json_vtep_list = json_object_new_array(); | |
266 | for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { | |
267 | json_ip_str = json_object_new_string( | |
9bcef951 MS |
268 | inet_ntop(AF_INET, &zvtep->vtep_ip, buf, |
269 | sizeof(buf))); | |
6006414d PR |
270 | json_object_array_add(json_vtep_list, |
271 | json_ip_str); | |
272 | } | |
273 | json_object_object_add(json_evpn, "remoteVteps", | |
274 | json_vtep_list); | |
275 | } | |
276 | json_object_object_add(json, vni_str, json_evpn); | |
277 | } | |
278 | } | |
279 | ||
280 | /* | |
281 | * Print an EVPN hash entry in detail - called for display of all EVPNs. | |
282 | */ | |
8b5fdf2e | 283 | void zebra_evpn_print_hash_detail(struct hash_bucket *bucket, void *data) |
6006414d PR |
284 | { |
285 | struct vty *vty; | |
f6371c34 | 286 | struct zebra_evpn *zevpn; |
6006414d PR |
287 | json_object *json_array = NULL; |
288 | bool use_json = false; | |
8b5fdf2e | 289 | struct zebra_evpn_show *zes = data; |
6006414d PR |
290 | |
291 | vty = zes->vty; | |
292 | json_array = zes->json; | |
293 | use_json = zes->use_json; | |
294 | ||
f6371c34 | 295 | zevpn = (struct zebra_evpn *)bucket->data; |
6006414d PR |
296 | |
297 | zebra_vxlan_print_vni(vty, zes->zvrf, zevpn->vni, use_json, json_array); | |
298 | ||
299 | if (!use_json) | |
300 | vty_out(vty, "\n"); | |
301 | } | |
302 | ||
f6371c34 DS |
303 | int zebra_evpn_del_macip_for_intf(struct interface *ifp, |
304 | struct zebra_evpn *zevpn) | |
6006414d PR |
305 | { |
306 | struct listnode *cnode = NULL, *cnnode = NULL; | |
307 | struct connected *c = NULL; | |
308 | struct ethaddr macaddr; | |
309 | ||
310 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); | |
311 | ||
312 | for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { | |
313 | struct ipaddr ip; | |
314 | ||
315 | memset(&ip, 0, sizeof(struct ipaddr)); | |
316 | if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) | |
317 | continue; | |
318 | ||
319 | if (c->address->family == AF_INET) { | |
320 | ip.ipa_type = IPADDR_V4; | |
321 | memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), | |
322 | sizeof(struct in_addr)); | |
323 | } else if (c->address->family == AF_INET6) { | |
324 | ip.ipa_type = IPADDR_V6; | |
325 | memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6), | |
326 | sizeof(struct in6_addr)); | |
327 | } else { | |
328 | continue; | |
329 | } | |
330 | ||
8b5fdf2e | 331 | zebra_evpn_gw_macip_del(ifp, zevpn, &ip); |
6006414d PR |
332 | } |
333 | ||
334 | return 0; | |
335 | } | |
336 | ||
f6371c34 DS |
337 | int zebra_evpn_add_macip_for_intf(struct interface *ifp, |
338 | struct zebra_evpn *zevpn) | |
6006414d PR |
339 | { |
340 | struct listnode *cnode = NULL, *cnnode = NULL; | |
341 | struct connected *c = NULL; | |
342 | struct ethaddr macaddr; | |
343 | ||
344 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); | |
345 | ||
346 | for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { | |
347 | struct ipaddr ip; | |
348 | ||
349 | memset(&ip, 0, sizeof(struct ipaddr)); | |
350 | if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) | |
351 | continue; | |
352 | ||
353 | if (c->address->family == AF_INET) { | |
354 | ip.ipa_type = IPADDR_V4; | |
355 | memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), | |
356 | sizeof(struct in_addr)); | |
357 | } else if (c->address->family == AF_INET6) { | |
358 | ip.ipa_type = IPADDR_V6; | |
359 | memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6), | |
360 | sizeof(struct in6_addr)); | |
361 | } else { | |
362 | continue; | |
363 | } | |
364 | ||
8b5fdf2e | 365 | zebra_evpn_gw_macip_add(ifp, zevpn, &macaddr, &ip); |
6006414d PR |
366 | } |
367 | return 0; | |
368 | } | |
369 | ||
8b5fdf2e PR |
370 | static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, |
371 | uint16_t cmd) | |
372 | { | |
373 | struct zserv *client = NULL; | |
374 | struct stream *s = NULL; | |
8b5fdf2e PR |
375 | |
376 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); | |
377 | /* BGP may not be running. */ | |
378 | if (!client) | |
379 | return 0; | |
380 | ||
381 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); | |
382 | ||
383 | zclient_create_header(s, cmd, vrf_id); | |
384 | stream_put(s, p, sizeof(struct prefix)); | |
385 | ||
386 | /* Write packet size. */ | |
387 | stream_putw_at(s, 0, stream_get_endp(s)); | |
388 | ||
389 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2dbe669b | 390 | zlog_debug("Send ip prefix %pFX %s on vrf %s", p, |
8b5fdf2e PR |
391 | (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL", |
392 | vrf_id_to_name(vrf_id)); | |
393 | ||
394 | if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) | |
395 | client->prefixadd_cnt++; | |
396 | else | |
397 | client->prefixdel_cnt++; | |
398 | ||
399 | return zserv_send_message(client, s); | |
400 | } | |
6006414d | 401 | |
f6371c34 | 402 | int zebra_evpn_advertise_subnet(struct zebra_evpn *zevpn, struct interface *ifp, |
8b5fdf2e | 403 | int advertise) |
6006414d PR |
404 | { |
405 | struct listnode *cnode = NULL, *cnnode = NULL; | |
406 | struct connected *c = NULL; | |
407 | struct ethaddr macaddr; | |
408 | ||
409 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); | |
410 | ||
411 | for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { | |
412 | struct prefix p; | |
413 | ||
414 | memcpy(&p, c->address, sizeof(struct prefix)); | |
415 | ||
416 | /* skip link local address */ | |
417 | if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) | |
418 | continue; | |
419 | ||
420 | apply_mask(&p); | |
421 | if (advertise) | |
422 | ip_prefix_send_to_client(ifp->vrf_id, &p, | |
423 | ZEBRA_IP_PREFIX_ROUTE_ADD); | |
424 | else | |
425 | ip_prefix_send_to_client(ifp->vrf_id, &p, | |
426 | ZEBRA_IP_PREFIX_ROUTE_DEL); | |
427 | } | |
428 | return 0; | |
429 | } | |
430 | ||
431 | /* | |
8b5fdf2e | 432 | * zebra_evpn_gw_macip_add_to_client |
6006414d | 433 | */ |
f6371c34 | 434 | int zebra_evpn_gw_macip_add(struct interface *ifp, struct zebra_evpn *zevpn, |
8b5fdf2e | 435 | struct ethaddr *macaddr, struct ipaddr *ip) |
6006414d | 436 | { |
3198b2b3 | 437 | struct zebra_mac *mac = NULL; |
6006414d PR |
438 | struct zebra_if *zif = NULL; |
439 | struct zebra_l2info_vxlan *vxl = NULL; | |
440 | ||
441 | zif = zevpn->vxlan_if->info; | |
442 | if (!zif) | |
443 | return -1; | |
444 | ||
445 | vxl = &zif->l2info.vxl; | |
446 | ||
447 | if (zebra_evpn_mac_gw_macip_add(ifp, zevpn, ip, &mac, macaddr, | |
e4c3ece6 | 448 | vxl->access_vlan, true) |
6006414d PR |
449 | != 0) |
450 | return -1; | |
451 | ||
452 | return zebra_evpn_neigh_gw_macip_add(ifp, zevpn, ip, mac); | |
453 | } | |
454 | ||
455 | /* | |
8b5fdf2e | 456 | * zebra_evpn_gw_macip_del_from_client |
6006414d | 457 | */ |
f6371c34 | 458 | int zebra_evpn_gw_macip_del(struct interface *ifp, struct zebra_evpn *zevpn, |
8b5fdf2e | 459 | struct ipaddr *ip) |
6006414d | 460 | { |
6006414d | 461 | zebra_neigh_t *n = NULL; |
3198b2b3 | 462 | struct zebra_mac *mac = NULL; |
6006414d PR |
463 | |
464 | /* If the neigh entry is not present nothing to do*/ | |
465 | n = zebra_evpn_neigh_lookup(zevpn, ip); | |
466 | if (!n) | |
467 | return 0; | |
468 | ||
469 | /* mac entry should be present */ | |
470 | mac = zebra_evpn_mac_lookup(zevpn, &n->emac); | |
471 | if (!mac) { | |
472 | if (IS_ZEBRA_DEBUG_VXLAN) | |
ef7b8be4 DL |
473 | zlog_debug("MAC %pEA doesn't exist for neigh %pIA on VNI %u", |
474 | &n->emac, ip, zevpn->vni); | |
6006414d PR |
475 | return -1; |
476 | } | |
477 | ||
478 | /* If the entry is not local nothing to do*/ | |
479 | if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) | |
480 | return -1; | |
481 | ||
482 | /* only need to delete the entry from bgp if we sent it before */ | |
483 | if (IS_ZEBRA_DEBUG_VXLAN) | |
484 | zlog_debug( | |
ef7b8be4 | 485 | "%u:SVI %s(%u) VNI %u, sending GW MAC %pEA IP %pIA del to BGP", |
6006414d | 486 | ifp->vrf_id, ifp->name, ifp->ifindex, zevpn->vni, |
ef7b8be4 | 487 | &n->emac, ip); |
6006414d PR |
488 | |
489 | /* Remove neighbor from BGP. */ | |
490 | zebra_evpn_neigh_send_del_to_client(zevpn->vni, &n->ip, &n->emac, | |
491 | n->flags, ZEBRA_NEIGH_ACTIVE, | |
492 | false /*force*/); | |
493 | ||
494 | /* Delete this neighbor entry. */ | |
495 | zebra_evpn_neigh_del(zevpn, n); | |
496 | ||
497 | /* see if the mac needs to be deleted as well*/ | |
498 | if (mac) | |
499 | zebra_evpn_deref_ip2mac(zevpn, mac); | |
500 | ||
501 | return 0; | |
502 | } | |
503 | ||
8b5fdf2e | 504 | void zebra_evpn_gw_macip_del_for_evpn_hash(struct hash_bucket *bucket, |
6006414d PR |
505 | void *ctxt) |
506 | { | |
f6371c34 | 507 | struct zebra_evpn *zevpn = NULL; |
6006414d PR |
508 | struct zebra_if *zif = NULL; |
509 | struct zebra_l2info_vxlan zl2_info; | |
510 | struct interface *vlan_if = NULL; | |
511 | struct interface *vrr_if = NULL; | |
512 | struct interface *ifp; | |
513 | ||
514 | /* Add primary SVI MAC*/ | |
f6371c34 | 515 | zevpn = (struct zebra_evpn *)bucket->data; |
6006414d PR |
516 | |
517 | /* Global (Zvrf) advertise-default-gw is disabled, | |
518 | * but zevpn advertise-default-gw is enabled | |
519 | */ | |
520 | if (zevpn->advertise_gw_macip) { | |
521 | if (IS_ZEBRA_DEBUG_VXLAN) | |
522 | zlog_debug("VNI: %u GW-MACIP enabled, retain gw-macip", | |
523 | zevpn->vni); | |
524 | return; | |
525 | } | |
526 | ||
527 | ifp = zevpn->vxlan_if; | |
528 | if (!ifp) | |
529 | return; | |
530 | zif = ifp->info; | |
531 | ||
532 | /* If down or not mapped to a bridge, we're done. */ | |
533 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
534 | return; | |
535 | ||
536 | zl2_info = zif->l2info.vxl; | |
537 | ||
538 | vlan_if = | |
539 | zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); | |
540 | if (!vlan_if) | |
541 | return; | |
542 | ||
543 | /* Del primary MAC-IP */ | |
8b5fdf2e | 544 | zebra_evpn_del_macip_for_intf(vlan_if, zevpn); |
6006414d PR |
545 | |
546 | /* Del VRR MAC-IP - if any*/ | |
547 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
548 | if (vrr_if) | |
8b5fdf2e | 549 | zebra_evpn_del_macip_for_intf(vrr_if, zevpn); |
6006414d PR |
550 | |
551 | return; | |
552 | } | |
553 | ||
8b5fdf2e | 554 | void zebra_evpn_gw_macip_add_for_evpn_hash(struct hash_bucket *bucket, |
6006414d PR |
555 | void *ctxt) |
556 | { | |
f6371c34 | 557 | struct zebra_evpn *zevpn = NULL; |
6006414d PR |
558 | struct zebra_if *zif = NULL; |
559 | struct zebra_l2info_vxlan zl2_info; | |
560 | struct interface *vlan_if = NULL; | |
561 | struct interface *vrr_if = NULL; | |
562 | struct interface *ifp = NULL; | |
563 | ||
f6371c34 | 564 | zevpn = (struct zebra_evpn *)bucket->data; |
6006414d PR |
565 | |
566 | ifp = zevpn->vxlan_if; | |
567 | if (!ifp) | |
568 | return; | |
569 | zif = ifp->info; | |
570 | ||
571 | /* If down or not mapped to a bridge, we're done. */ | |
572 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
573 | return; | |
574 | zl2_info = zif->l2info.vxl; | |
575 | ||
576 | vlan_if = | |
577 | zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); | |
578 | if (!vlan_if) | |
579 | return; | |
580 | ||
581 | /* Add primary SVI MAC-IP */ | |
c0c7707d AK |
582 | if (advertise_svi_macip_enabled(zevpn) |
583 | || advertise_gw_macip_enabled(zevpn)) | |
584 | zebra_evpn_add_macip_for_intf(vlan_if, zevpn); | |
6006414d PR |
585 | |
586 | if (advertise_gw_macip_enabled(zevpn)) { | |
587 | /* Add VRR MAC-IP - if any*/ | |
588 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
589 | if (vrr_if) | |
8b5fdf2e | 590 | zebra_evpn_add_macip_for_intf(vrr_if, zevpn); |
6006414d PR |
591 | } |
592 | ||
593 | return; | |
594 | } | |
595 | ||
8b5fdf2e PR |
596 | void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket, |
597 | void *ctxt) | |
6006414d | 598 | { |
f6371c34 | 599 | struct zebra_evpn *zevpn = NULL; |
6006414d PR |
600 | struct zebra_if *zif = NULL; |
601 | struct zebra_l2info_vxlan zl2_info; | |
602 | struct interface *vlan_if = NULL; | |
603 | struct interface *ifp; | |
604 | ||
605 | /* Add primary SVI MAC*/ | |
f6371c34 | 606 | zevpn = (struct zebra_evpn *)bucket->data; |
6006414d PR |
607 | if (!zevpn) |
608 | return; | |
609 | ||
610 | /* Global(vrf) advertise-svi-ip disabled, but zevpn advertise-svi-ip | |
611 | * enabled | |
612 | */ | |
613 | if (zevpn->advertise_svi_macip) { | |
614 | if (IS_ZEBRA_DEBUG_VXLAN) | |
615 | zlog_debug("VNI: %u SVI-MACIP enabled, retain svi-macip", | |
616 | zevpn->vni); | |
617 | return; | |
618 | } | |
619 | ||
620 | ifp = zevpn->vxlan_if; | |
621 | if (!ifp) | |
622 | return; | |
623 | zif = ifp->info; | |
624 | ||
625 | /* If down or not mapped to a bridge, we're done. */ | |
626 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
627 | return; | |
628 | ||
629 | zl2_info = zif->l2info.vxl; | |
630 | ||
631 | vlan_if = | |
632 | zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); | |
633 | if (!vlan_if) | |
634 | return; | |
635 | ||
636 | /* Del primary MAC-IP */ | |
8b5fdf2e | 637 | zebra_evpn_del_macip_for_intf(vlan_if, zevpn); |
6006414d PR |
638 | |
639 | return; | |
640 | } | |
641 | ||
2961d060 PG |
642 | static int zebra_evpn_map_vlan_ns(struct ns *ns, |
643 | void *_in_param, | |
644 | void **_p_zevpn) | |
6006414d | 645 | { |
2961d060 | 646 | struct zebra_ns *zns = ns->info; |
6006414d | 647 | struct route_node *rn; |
9609fab7 | 648 | struct interface *br_if; |
f6371c34 DS |
649 | struct zebra_evpn **p_zevpn = (struct zebra_evpn **)_p_zevpn; |
650 | struct zebra_evpn *zevpn; | |
6006414d PR |
651 | struct interface *tmp_if = NULL; |
652 | struct zebra_if *zif; | |
6006414d | 653 | struct zebra_l2info_vxlan *vxl = NULL; |
9609fab7 PG |
654 | struct zebra_from_svi_param *in_param = |
655 | (struct zebra_from_svi_param *)_in_param; | |
6006414d PR |
656 | int found = 0; |
657 | ||
9609fab7 | 658 | if (!in_param) |
2961d060 | 659 | return NS_WALK_STOP; |
9609fab7 PG |
660 | br_if = in_param->br_if; |
661 | zif = in_param->zif; | |
6006414d | 662 | assert(zif); |
9609fab7 | 663 | assert(br_if); |
6006414d PR |
664 | |
665 | /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ | |
666 | /* TODO: Optimize with a hash. */ | |
6006414d PR |
667 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { |
668 | tmp_if = (struct interface *)rn->info; | |
669 | if (!tmp_if) | |
670 | continue; | |
671 | zif = tmp_if->info; | |
672 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
673 | continue; | |
674 | if (!if_is_operative(tmp_if)) | |
675 | continue; | |
676 | vxl = &zif->l2info.vxl; | |
677 | ||
678 | if (zif->brslave_info.br_if != br_if) | |
679 | continue; | |
680 | ||
9609fab7 PG |
681 | if (!in_param->bridge_vlan_aware |
682 | || vxl->access_vlan == in_param->vid) { | |
6006414d PR |
683 | found = 1; |
684 | break; | |
685 | } | |
686 | } | |
6006414d | 687 | if (!found) |
2961d060 | 688 | return NS_WALK_CONTINUE; |
6006414d | 689 | |
8b5fdf2e | 690 | zevpn = zebra_evpn_lookup(vxl->vni); |
9609fab7 PG |
691 | if (p_zevpn) |
692 | *p_zevpn = zevpn; | |
2961d060 | 693 | return NS_WALK_STOP; |
9609fab7 PG |
694 | } |
695 | ||
6006414d PR |
696 | /* |
697 | * Map port or (port, VLAN) to an EVPN. This is invoked upon getting MAC | |
698 | * notifications, to see if they are of interest. | |
699 | */ | |
f6371c34 DS |
700 | struct zebra_evpn *zebra_evpn_map_vlan(struct interface *ifp, |
701 | struct interface *br_if, vlanid_t vid) | |
6006414d | 702 | { |
6006414d PR |
703 | struct zebra_if *zif; |
704 | struct zebra_l2info_bridge *br; | |
f6371c34 DS |
705 | struct zebra_evpn **p_zevpn; |
706 | struct zebra_evpn *zevpn = NULL; | |
9609fab7 | 707 | struct zebra_from_svi_param in_param; |
6006414d PR |
708 | |
709 | /* Determine if bridge is VLAN-aware or not */ | |
710 | zif = br_if->info; | |
711 | assert(zif); | |
712 | br = &zif->l2info.br; | |
9609fab7 PG |
713 | in_param.bridge_vlan_aware = br->vlan_aware; |
714 | in_param.vid = vid; | |
715 | in_param.br_if = br_if; | |
716 | in_param.zif = zif; | |
717 | p_zevpn = &zevpn; | |
718 | ||
2961d060 PG |
719 | ns_walk_func(zebra_evpn_map_vlan_ns, |
720 | (void *)&in_param, | |
721 | (void **)p_zevpn); | |
6006414d PR |
722 | return zevpn; |
723 | } | |
724 | ||
2961d060 PG |
725 | static int zebra_evpn_from_svi_ns(struct ns *ns, |
726 | void *_in_param, | |
727 | void **_p_zevpn) | |
6006414d | 728 | { |
2961d060 | 729 | struct zebra_ns *zns = ns->info; |
6006414d | 730 | struct route_node *rn; |
9d277b8c | 731 | struct interface *br_if; |
f6371c34 DS |
732 | struct zebra_evpn **p_zevpn = (struct zebra_evpn **)_p_zevpn; |
733 | struct zebra_evpn *zevpn; | |
6006414d PR |
734 | struct interface *tmp_if = NULL; |
735 | struct zebra_if *zif; | |
6006414d | 736 | struct zebra_l2info_vxlan *vxl = NULL; |
a237058f PG |
737 | struct zebra_from_svi_param *in_param = |
738 | (struct zebra_from_svi_param *)_in_param; | |
6006414d PR |
739 | int found = 0; |
740 | ||
9d277b8c | 741 | if (!in_param) |
2961d060 | 742 | return NS_WALK_STOP; |
9d277b8c PG |
743 | br_if = in_param->br_if; |
744 | zif = in_param->zif; | |
6006414d | 745 | assert(zif); |
6006414d | 746 | |
6006414d | 747 | /* TODO: Optimize with a hash. */ |
6006414d PR |
748 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { |
749 | tmp_if = (struct interface *)rn->info; | |
750 | if (!tmp_if) | |
751 | continue; | |
752 | zif = tmp_if->info; | |
753 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
754 | continue; | |
755 | if (!if_is_operative(tmp_if)) | |
756 | continue; | |
757 | vxl = &zif->l2info.vxl; | |
758 | ||
759 | if (zif->brslave_info.br_if != br_if) | |
760 | continue; | |
761 | ||
9d277b8c PG |
762 | if (!in_param->bridge_vlan_aware |
763 | || vxl->access_vlan == in_param->vid) { | |
6006414d PR |
764 | found = 1; |
765 | break; | |
766 | } | |
767 | } | |
768 | ||
769 | if (!found) | |
2961d060 | 770 | return NS_WALK_CONTINUE; |
6006414d | 771 | |
8b5fdf2e | 772 | zevpn = zebra_evpn_lookup(vxl->vni); |
9d277b8c PG |
773 | if (p_zevpn) |
774 | *p_zevpn = zevpn; | |
2961d060 | 775 | return NS_WALK_STOP; |
6006414d PR |
776 | } |
777 | ||
778 | /* | |
8b5fdf2e | 779 | * Map SVI and associated bridge to an EVPN. This is invoked upon getting |
6006414d PR |
780 | * neighbor notifications, to see if they are of interest. |
781 | */ | |
f6371c34 DS |
782 | struct zebra_evpn *zebra_evpn_from_svi(struct interface *ifp, |
783 | struct interface *br_if) | |
6006414d | 784 | { |
6006414d | 785 | struct zebra_l2info_bridge *br; |
f6371c34 DS |
786 | struct zebra_evpn *zevpn = NULL; |
787 | struct zebra_evpn **p_zevpn; | |
9d277b8c | 788 | struct zebra_if *zif; |
a237058f | 789 | struct zebra_from_svi_param in_param; |
6006414d PR |
790 | |
791 | if (!br_if) | |
792 | return NULL; | |
793 | ||
794 | /* Make sure the linked interface is a bridge. */ | |
795 | if (!IS_ZEBRA_IF_BRIDGE(br_if)) | |
796 | return NULL; | |
797 | ||
798 | /* Determine if bridge is VLAN-aware or not */ | |
799 | zif = br_if->info; | |
800 | assert(zif); | |
801 | br = &zif->l2info.br; | |
9d277b8c PG |
802 | in_param.bridge_vlan_aware = br->vlan_aware; |
803 | in_param.vid = 0; | |
804 | ||
805 | if (in_param.bridge_vlan_aware) { | |
6006414d PR |
806 | struct zebra_l2info_vlan *vl; |
807 | ||
808 | if (!IS_ZEBRA_IF_VLAN(ifp)) | |
809 | return NULL; | |
810 | ||
811 | zif = ifp->info; | |
812 | assert(zif); | |
813 | vl = &zif->l2info.vl; | |
9d277b8c | 814 | in_param.vid = vl->vid; |
6006414d PR |
815 | } |
816 | ||
9d277b8c PG |
817 | in_param.br_if = br_if; |
818 | in_param.zif = zif; | |
819 | p_zevpn = &zevpn; | |
6006414d | 820 | /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ |
2961d060 PG |
821 | ns_walk_func(zebra_evpn_from_svi_ns, (void *)&in_param, |
822 | (void **)p_zevpn); | |
6006414d PR |
823 | return zevpn; |
824 | } | |
825 | ||
a1ce03e1 PG |
826 | static int zvni_map_to_macvlan_ns(struct ns *ns, |
827 | void *_in_param, | |
828 | void **_p_ifp) | |
829 | { | |
830 | struct zebra_ns *zns = ns->info; | |
831 | struct zebra_from_svi_param *in_param = | |
832 | (struct zebra_from_svi_param *)_in_param; | |
833 | struct interface **p_ifp = (struct interface **)_p_ifp; | |
834 | struct route_node *rn; | |
835 | struct interface *tmp_if = NULL; | |
836 | struct zebra_if *zif; | |
837 | ||
838 | if (!in_param) | |
839 | return NS_WALK_STOP; | |
840 | ||
841 | /* Identify corresponding VLAN interface. */ | |
6006414d PR |
842 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { |
843 | tmp_if = (struct interface *)rn->info; | |
a1ce03e1 PG |
844 | /* Check oper status of the SVI. */ |
845 | if (!tmp_if || !if_is_operative(tmp_if)) | |
6006414d PR |
846 | continue; |
847 | zif = tmp_if->info; | |
6006414d | 848 | |
a1ce03e1 | 849 | if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN) |
6006414d PR |
850 | continue; |
851 | ||
a1ce03e1 PG |
852 | if (zif->link == in_param->svi_if) { |
853 | if (p_ifp) | |
854 | *p_ifp = tmp_if; | |
855 | return NS_WALK_STOP; | |
6006414d PR |
856 | } |
857 | } | |
858 | ||
a1ce03e1 | 859 | return NS_WALK_CONTINUE; |
6006414d PR |
860 | } |
861 | ||
6006414d PR |
862 | /* Map to MAC-VLAN interface corresponding to specified SVI interface. |
863 | */ | |
8b5fdf2e PR |
864 | struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if, |
865 | struct interface *svi_if) | |
6006414d | 866 | { |
6006414d PR |
867 | struct interface *tmp_if = NULL; |
868 | struct zebra_if *zif; | |
a1ce03e1 PG |
869 | struct interface **p_ifp; |
870 | struct zebra_from_svi_param in_param; | |
6006414d PR |
871 | |
872 | /* Defensive check, caller expected to invoke only with valid bridge. */ | |
873 | if (!br_if) | |
874 | return NULL; | |
875 | ||
876 | if (!svi_if) { | |
877 | zlog_debug("svi_if is not passed."); | |
878 | return NULL; | |
879 | } | |
880 | ||
881 | /* Determine if bridge is VLAN-aware or not */ | |
882 | zif = br_if->info; | |
883 | assert(zif); | |
884 | ||
a1ce03e1 PG |
885 | in_param.vid = 0; |
886 | in_param.br_if = br_if; | |
887 | in_param.zif = NULL; | |
888 | in_param.svi_if = svi_if; | |
889 | p_ifp = &tmp_if; | |
6006414d | 890 | |
a1ce03e1 PG |
891 | /* Identify corresponding VLAN interface. */ |
892 | ns_walk_func(zvni_map_to_macvlan_ns, | |
893 | (void *)&in_param, | |
894 | (void **)p_ifp); | |
895 | return tmp_if; | |
6006414d PR |
896 | } |
897 | ||
898 | /* | |
899 | * Install MAC hash entry - called upon access VLAN change. | |
900 | */ | |
8b5fdf2e | 901 | void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt) |
6006414d | 902 | { |
3198b2b3 | 903 | struct zebra_mac *mac; |
6006414d PR |
904 | struct mac_walk_ctx *wctx = ctxt; |
905 | ||
3198b2b3 | 906 | mac = (struct zebra_mac *)bucket->data; |
6006414d PR |
907 | |
908 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) | |
909 | zebra_evpn_rem_mac_install(wctx->zevpn, mac, false); | |
910 | } | |
911 | ||
912 | /* | |
913 | * Read and populate local MACs and neighbors corresponding to this EVPN. | |
914 | */ | |
f6371c34 | 915 | void zebra_evpn_read_mac_neigh(struct zebra_evpn *zevpn, struct interface *ifp) |
6006414d PR |
916 | { |
917 | struct zebra_ns *zns; | |
b5fde6fd | 918 | struct zebra_vrf *zvrf; |
6006414d PR |
919 | struct zebra_if *zif; |
920 | struct interface *vlan_if; | |
921 | struct zebra_l2info_vxlan *vxl; | |
922 | struct interface *vrr_if; | |
923 | ||
924 | zif = ifp->info; | |
925 | vxl = &zif->l2info.vxl; | |
b5fde6fd PG |
926 | zvrf = zebra_vrf_lookup_by_id(zevpn->vrf_id); |
927 | if (!zvrf || !zvrf->zns) | |
928 | return; | |
929 | zns = zvrf->zns; | |
6006414d PR |
930 | |
931 | if (IS_ZEBRA_DEBUG_VXLAN) | |
932 | zlog_debug( | |
933 | "Reading MAC FDB and Neighbors for intf %s(%u) VNI %u master %u", | |
934 | ifp->name, ifp->ifindex, zevpn->vni, | |
935 | zif->brslave_info.bridge_ifindex); | |
936 | ||
937 | macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if); | |
938 | vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); | |
939 | if (vlan_if) { | |
243b74ed AK |
940 | /* Add SVI MAC */ |
941 | zebra_evpn_acc_bd_svi_mac_add(vlan_if); | |
6006414d PR |
942 | |
943 | /* Add SVI MAC-IP */ | |
c0c7707d AK |
944 | if (advertise_svi_macip_enabled(zevpn) |
945 | || advertise_gw_macip_enabled(zevpn)) | |
946 | zebra_evpn_add_macip_for_intf(vlan_if, zevpn); | |
6006414d PR |
947 | |
948 | /* Add VRR MAC-IP - if any*/ | |
c0c7707d AK |
949 | if (advertise_gw_macip_enabled(zevpn)) { |
950 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
951 | if (vrr_if) | |
952 | zebra_evpn_add_macip_for_intf(vrr_if, zevpn); | |
953 | } | |
6006414d PR |
954 | |
955 | neigh_read_for_vlan(zns, vlan_if); | |
956 | } | |
957 | } | |
958 | ||
959 | /* | |
8b5fdf2e | 960 | * Hash function for EVPN. |
6006414d | 961 | */ |
8b5fdf2e | 962 | unsigned int zebra_evpn_hash_keymake(const void *p) |
6006414d | 963 | { |
f6371c34 | 964 | const struct zebra_evpn *zevpn = p; |
6006414d PR |
965 | |
966 | return (jhash_1word(zevpn->vni, 0)); | |
967 | } | |
968 | ||
969 | /* | |
8b5fdf2e | 970 | * Compare 2 evpn hash entries. |
6006414d | 971 | */ |
8b5fdf2e | 972 | bool zebra_evpn_hash_cmp(const void *p1, const void *p2) |
6006414d | 973 | { |
f6371c34 DS |
974 | const struct zebra_evpn *zevpn1 = p1; |
975 | const struct zebra_evpn *zevpn2 = p2; | |
6006414d PR |
976 | |
977 | return (zevpn1->vni == zevpn2->vni); | |
978 | } | |
979 | ||
8b5fdf2e | 980 | int zebra_evpn_list_cmp(void *p1, void *p2) |
6006414d | 981 | { |
f6371c34 DS |
982 | const struct zebra_evpn *zevpn1 = p1; |
983 | const struct zebra_evpn *zevpn2 = p2; | |
6006414d PR |
984 | |
985 | if (zevpn1->vni == zevpn2->vni) | |
986 | return 0; | |
987 | return (zevpn1->vni < zevpn2->vni) ? -1 : 1; | |
988 | } | |
989 | ||
990 | /* | |
991 | * Callback to allocate VNI hash entry. | |
992 | */ | |
8b5fdf2e | 993 | void *zebra_evpn_alloc(void *p) |
6006414d | 994 | { |
f6371c34 DS |
995 | const struct zebra_evpn *tmp_vni = p; |
996 | struct zebra_evpn *zevpn; | |
6006414d | 997 | |
f6371c34 | 998 | zevpn = XCALLOC(MTYPE_ZEVPN, sizeof(struct zebra_evpn)); |
6006414d PR |
999 | zevpn->vni = tmp_vni->vni; |
1000 | return ((void *)zevpn); | |
1001 | } | |
1002 | ||
1003 | /* | |
1004 | * Look up EVPN hash entry. | |
1005 | */ | |
f6371c34 | 1006 | struct zebra_evpn *zebra_evpn_lookup(vni_t vni) |
6006414d PR |
1007 | { |
1008 | struct zebra_vrf *zvrf; | |
f6371c34 DS |
1009 | struct zebra_evpn tmp_vni; |
1010 | struct zebra_evpn *zevpn = NULL; | |
6006414d PR |
1011 | |
1012 | zvrf = zebra_vrf_get_evpn(); | |
1013 | assert(zvrf); | |
f6371c34 | 1014 | memset(&tmp_vni, 0, sizeof(struct zebra_evpn)); |
6006414d PR |
1015 | tmp_vni.vni = vni; |
1016 | zevpn = hash_lookup(zvrf->evpn_table, &tmp_vni); | |
1017 | ||
1018 | return zevpn; | |
1019 | } | |
1020 | ||
1021 | /* | |
1022 | * Add EVPN hash entry. | |
1023 | */ | |
f6371c34 | 1024 | struct zebra_evpn *zebra_evpn_add(vni_t vni) |
6006414d | 1025 | { |
38078b1d | 1026 | char buffer[80]; |
6006414d | 1027 | struct zebra_vrf *zvrf; |
f6371c34 DS |
1028 | struct zebra_evpn tmp_zevpn; |
1029 | struct zebra_evpn *zevpn = NULL; | |
6006414d PR |
1030 | |
1031 | zvrf = zebra_vrf_get_evpn(); | |
1032 | assert(zvrf); | |
f6371c34 | 1033 | memset(&tmp_zevpn, 0, sizeof(struct zebra_evpn)); |
6006414d | 1034 | tmp_zevpn.vni = vni; |
8b5fdf2e | 1035 | zevpn = hash_get(zvrf->evpn_table, &tmp_zevpn, zebra_evpn_alloc); |
6006414d PR |
1036 | assert(zevpn); |
1037 | ||
945ee7b2 | 1038 | zebra_evpn_es_evi_init(zevpn); |
6006414d | 1039 | |
38078b1d | 1040 | snprintf(buffer, sizeof(buffer), "Zebra EVPN MAC Table vni: %u", vni); |
6006414d | 1041 | /* Create hash table for MAC */ |
38078b1d | 1042 | zevpn->mac_table = zebra_mac_db_create(buffer); |
6006414d | 1043 | |
e2071325 DL |
1044 | snprintf(buffer, sizeof(buffer), "Zebra EVPN Neighbor Table vni: %u", |
1045 | vni); | |
6006414d | 1046 | /* Create hash table for neighbors */ |
38078b1d | 1047 | zevpn->neigh_table = zebra_neigh_db_create(buffer); |
6006414d PR |
1048 | |
1049 | return zevpn; | |
1050 | } | |
1051 | ||
6006414d PR |
1052 | /* |
1053 | * Delete EVPN hash entry. | |
1054 | */ | |
f6371c34 | 1055 | int zebra_evpn_del(struct zebra_evpn *zevpn) |
6006414d PR |
1056 | { |
1057 | struct zebra_vrf *zvrf; | |
f6371c34 | 1058 | struct zebra_evpn *tmp_zevpn; |
6006414d PR |
1059 | |
1060 | zvrf = zebra_vrf_get_evpn(); | |
1061 | assert(zvrf); | |
1062 | ||
9daa5d47 AD |
1063 | zevpn->svi_if = NULL; |
1064 | ||
6006414d PR |
1065 | /* Free the neighbor hash table. */ |
1066 | hash_free(zevpn->neigh_table); | |
1067 | zevpn->neigh_table = NULL; | |
1068 | ||
1069 | /* Free the MAC hash table. */ | |
1070 | hash_free(zevpn->mac_table); | |
1071 | zevpn->mac_table = NULL; | |
1072 | ||
963b0c55 AK |
1073 | /* Remove references to the zevpn in the MH databases */ |
1074 | if (zevpn->vxlan_if) | |
1075 | zebra_evpn_vxl_evpn_set(zevpn->vxlan_if->info, zevpn, false); | |
945ee7b2 | 1076 | zebra_evpn_es_evi_cleanup(zevpn); |
6006414d PR |
1077 | |
1078 | /* Free the EVPN hash entry and allocated memory. */ | |
1079 | tmp_zevpn = hash_release(zvrf->evpn_table, zevpn); | |
1080 | XFREE(MTYPE_ZEVPN, tmp_zevpn); | |
1081 | ||
1082 | return 0; | |
1083 | } | |
1084 | ||
1085 | /* | |
1086 | * Inform BGP about local EVPN addition. | |
1087 | */ | |
f6371c34 | 1088 | int zebra_evpn_send_add_to_client(struct zebra_evpn *zevpn) |
6006414d PR |
1089 | { |
1090 | struct zserv *client; | |
1091 | struct stream *s; | |
9daa5d47 | 1092 | ifindex_t svi_index; |
6006414d PR |
1093 | int rc; |
1094 | ||
1095 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); | |
1096 | /* BGP may not be running. */ | |
1097 | if (!client) | |
1098 | return 0; | |
1099 | ||
9daa5d47 AD |
1100 | svi_index = zevpn->svi_if ? zevpn->svi_if->ifindex : 0; |
1101 | ||
6006414d PR |
1102 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
1103 | ||
1104 | zclient_create_header(s, ZEBRA_VNI_ADD, zebra_vrf_get_evpn_id()); | |
1105 | stream_putl(s, zevpn->vni); | |
1106 | stream_put_in_addr(s, &zevpn->local_vtep_ip); | |
1107 | stream_put(s, &zevpn->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */ | |
1108 | stream_put_in_addr(s, &zevpn->mcast_grp); | |
9daa5d47 | 1109 | stream_put(s, &svi_index, sizeof(ifindex_t)); |
6006414d PR |
1110 | |
1111 | /* Write packet size. */ | |
1112 | stream_putw_at(s, 0, stream_get_endp(s)); | |
1113 | ||
1114 | if (IS_ZEBRA_DEBUG_VXLAN) | |
9daa5d47 AD |
1115 | zlog_debug( |
1116 | "Send EVPN_ADD %u %pI4 tenant vrf %s(%u) SVI index %u to %s", | |
1117 | zevpn->vni, &zevpn->local_vtep_ip, | |
1118 | vrf_id_to_name(zevpn->vrf_id), zevpn->vrf_id, | |
1119 | (zevpn->svi_if ? zevpn->svi_if->ifindex : 0), | |
1120 | zebra_route_string(client->proto)); | |
6006414d PR |
1121 | |
1122 | client->vniadd_cnt++; | |
1123 | rc = zserv_send_message(client, s); | |
1124 | ||
1125 | if (!(zevpn->flags & ZEVPN_READY_FOR_BGP)) { | |
1126 | zevpn->flags |= ZEVPN_READY_FOR_BGP; | |
1127 | /* once the EVPN is sent the ES-EVIs can also be replayed | |
1128 | * to BGP | |
1129 | */ | |
1130 | zebra_evpn_update_all_es(zevpn); | |
1131 | } | |
1132 | return rc; | |
1133 | } | |
1134 | ||
1135 | /* | |
1136 | * Inform BGP about local EVPN deletion. | |
1137 | */ | |
f6371c34 | 1138 | int zebra_evpn_send_del_to_client(struct zebra_evpn *zevpn) |
6006414d PR |
1139 | { |
1140 | struct zserv *client; | |
1141 | struct stream *s; | |
1142 | ||
1143 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); | |
1144 | /* BGP may not be running. */ | |
1145 | if (!client) | |
1146 | return 0; | |
1147 | ||
1148 | if (zevpn->flags & ZEVPN_READY_FOR_BGP) { | |
1149 | zevpn->flags &= ~ZEVPN_READY_FOR_BGP; | |
1150 | /* the ES-EVIs must be removed from BGP before the EVPN is */ | |
1151 | zebra_evpn_update_all_es(zevpn); | |
1152 | } | |
1153 | ||
1154 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); | |
1155 | stream_reset(s); | |
1156 | ||
1157 | zclient_create_header(s, ZEBRA_VNI_DEL, zebra_vrf_get_evpn_id()); | |
1158 | stream_putl(s, zevpn->vni); | |
1159 | ||
1160 | /* Write packet size. */ | |
1161 | stream_putw_at(s, 0, stream_get_endp(s)); | |
1162 | ||
1163 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1164 | zlog_debug("Send EVPN_DEL %u to %s", zevpn->vni, | |
1165 | zebra_route_string(client->proto)); | |
1166 | ||
1167 | client->vnidel_cnt++; | |
1168 | return zserv_send_message(client, s); | |
1169 | } | |
1170 | ||
6006414d PR |
1171 | /* |
1172 | * See if remote VTEP matches with prefix. | |
1173 | */ | |
c172c032 DS |
1174 | static int zebra_evpn_vtep_match(struct in_addr *vtep_ip, |
1175 | struct zebra_vtep *zvtep) | |
6006414d PR |
1176 | { |
1177 | return (IPV4_ADDR_SAME(vtep_ip, &zvtep->vtep_ip)); | |
1178 | } | |
1179 | ||
1180 | /* | |
1181 | * Locate remote VTEP in EVPN hash table. | |
1182 | */ | |
c172c032 DS |
1183 | struct zebra_vtep *zebra_evpn_vtep_find(struct zebra_evpn *zevpn, |
1184 | struct in_addr *vtep_ip) | |
6006414d | 1185 | { |
c172c032 | 1186 | struct zebra_vtep *zvtep; |
6006414d PR |
1187 | |
1188 | if (!zevpn) | |
1189 | return NULL; | |
1190 | ||
1191 | for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { | |
8b5fdf2e | 1192 | if (zebra_evpn_vtep_match(vtep_ip, zvtep)) |
6006414d PR |
1193 | break; |
1194 | } | |
1195 | ||
1196 | return zvtep; | |
1197 | } | |
1198 | ||
1199 | /* | |
1200 | * Add remote VTEP to EVPN hash table. | |
1201 | */ | |
c172c032 DS |
1202 | struct zebra_vtep *zebra_evpn_vtep_add(struct zebra_evpn *zevpn, |
1203 | struct in_addr *vtep_ip, | |
1204 | int flood_control) | |
6006414d PR |
1205 | |
1206 | { | |
c172c032 | 1207 | struct zebra_vtep *zvtep; |
6006414d | 1208 | |
c172c032 | 1209 | zvtep = XCALLOC(MTYPE_ZEVPN_VTEP, sizeof(struct zebra_vtep)); |
6006414d PR |
1210 | |
1211 | zvtep->vtep_ip = *vtep_ip; | |
1212 | zvtep->flood_control = flood_control; | |
1213 | ||
1214 | if (zevpn->vteps) | |
1215 | zevpn->vteps->prev = zvtep; | |
1216 | zvtep->next = zevpn->vteps; | |
1217 | zevpn->vteps = zvtep; | |
1218 | ||
1219 | return zvtep; | |
1220 | } | |
1221 | ||
1222 | /* | |
1223 | * Remove remote VTEP from EVPN hash table. | |
1224 | */ | |
c172c032 | 1225 | int zebra_evpn_vtep_del(struct zebra_evpn *zevpn, struct zebra_vtep *zvtep) |
6006414d PR |
1226 | { |
1227 | if (zvtep->next) | |
1228 | zvtep->next->prev = zvtep->prev; | |
1229 | if (zvtep->prev) | |
1230 | zvtep->prev->next = zvtep->next; | |
1231 | else | |
1232 | zevpn->vteps = zvtep->next; | |
1233 | ||
1234 | zvtep->prev = zvtep->next = NULL; | |
1235 | XFREE(MTYPE_ZEVPN_VTEP, zvtep); | |
1236 | ||
1237 | return 0; | |
1238 | } | |
1239 | ||
1240 | /* | |
1241 | * Delete all remote VTEPs for this EVPN (upon VNI delete). Also | |
1242 | * uninstall from kernel if asked to. | |
1243 | */ | |
f6371c34 | 1244 | int zebra_evpn_vtep_del_all(struct zebra_evpn *zevpn, int uninstall) |
6006414d | 1245 | { |
c172c032 | 1246 | struct zebra_vtep *zvtep, *zvtep_next; |
6006414d PR |
1247 | |
1248 | if (!zevpn) | |
1249 | return -1; | |
1250 | ||
1251 | for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep_next) { | |
1252 | zvtep_next = zvtep->next; | |
1253 | if (uninstall) | |
8b5fdf2e PR |
1254 | zebra_evpn_vtep_uninstall(zevpn, &zvtep->vtep_ip); |
1255 | zebra_evpn_vtep_del(zevpn, zvtep); | |
6006414d PR |
1256 | } |
1257 | ||
1258 | return 0; | |
1259 | } | |
1260 | ||
1261 | /* | |
1262 | * Install remote VTEP into the kernel if the remote VTEP has asked | |
1263 | * for head-end-replication. | |
1264 | */ | |
c172c032 | 1265 | int zebra_evpn_vtep_install(struct zebra_evpn *zevpn, struct zebra_vtep *zvtep) |
6006414d PR |
1266 | { |
1267 | if (is_vxlan_flooding_head_end() && | |
1268 | (zvtep->flood_control == VXLAN_FLOOD_HEAD_END_REPL)) { | |
1269 | if (ZEBRA_DPLANE_REQUEST_FAILURE == | |
1270 | dplane_vtep_add(zevpn->vxlan_if, | |
1271 | &zvtep->vtep_ip, zevpn->vni)) | |
1272 | return -1; | |
1273 | } | |
1274 | ||
1275 | return 0; | |
1276 | } | |
1277 | ||
1278 | /* | |
1279 | * Uninstall remote VTEP from the kernel. | |
1280 | */ | |
f6371c34 | 1281 | int zebra_evpn_vtep_uninstall(struct zebra_evpn *zevpn, struct in_addr *vtep_ip) |
6006414d PR |
1282 | { |
1283 | if (!zevpn->vxlan_if) { | |
1284 | zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", | |
1285 | zevpn->vni, zevpn); | |
1286 | return -1; | |
1287 | } | |
1288 | ||
1289 | if (ZEBRA_DPLANE_REQUEST_FAILURE == | |
1290 | dplane_vtep_delete(zevpn->vxlan_if, vtep_ip, zevpn->vni)) | |
1291 | return -1; | |
1292 | ||
1293 | return 0; | |
1294 | } | |
1295 | ||
1296 | /* | |
1297 | * Install or uninstall flood entries in the kernel corresponding to | |
1298 | * remote VTEPs. This is invoked upon change to BUM handling. | |
1299 | */ | |
8b5fdf2e PR |
1300 | void zebra_evpn_handle_flooding_remote_vteps(struct hash_bucket *bucket, |
1301 | void *zvrf) | |
6006414d | 1302 | { |
f6371c34 | 1303 | struct zebra_evpn *zevpn; |
c172c032 | 1304 | struct zebra_vtep *zvtep; |
6006414d | 1305 | |
f6371c34 | 1306 | zevpn = (struct zebra_evpn *)bucket->data; |
6006414d PR |
1307 | if (!zevpn) |
1308 | return; | |
1309 | ||
1310 | for (zvtep = zevpn->vteps; zvtep; zvtep = zvtep->next) { | |
1311 | if (is_vxlan_flooding_head_end()) | |
8b5fdf2e | 1312 | zebra_evpn_vtep_install(zevpn, zvtep); |
6006414d | 1313 | else |
8b5fdf2e | 1314 | zebra_evpn_vtep_uninstall(zevpn, &zvtep->vtep_ip); |
6006414d PR |
1315 | } |
1316 | } | |
1317 | ||
1318 | /* | |
1319 | * Cleanup EVPN/VTEP and update kernel | |
1320 | */ | |
8b5fdf2e | 1321 | void zebra_evpn_cleanup_all(struct hash_bucket *bucket, void *arg) |
6006414d | 1322 | { |
f6371c34 | 1323 | struct zebra_evpn *zevpn = NULL; |
6006414d | 1324 | |
f6371c34 | 1325 | zevpn = (struct zebra_evpn *)bucket->data; |
6006414d | 1326 | |
6006414d PR |
1327 | /* Free up all neighbors and MACs, if any. */ |
1328 | zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH); | |
1329 | zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC); | |
1330 | ||
1331 | /* Free up all remote VTEPs, if any. */ | |
8b5fdf2e | 1332 | zebra_evpn_vtep_del_all(zevpn, 1); |
6006414d PR |
1333 | |
1334 | /* Delete the hash entry. */ | |
8b5fdf2e | 1335 | zebra_evpn_del(zevpn); |
6006414d PR |
1336 | } |
1337 | ||
f6371c34 | 1338 | static void zebra_evpn_process_sync_macip_add(struct zebra_evpn *zevpn, |
1a3bd37f MS |
1339 | const struct ethaddr *macaddr, |
1340 | uint16_t ipa_len, | |
1341 | const struct ipaddr *ipaddr, | |
1342 | uint8_t flags, uint32_t seq, | |
1343 | const esi_t *esi) | |
6006414d | 1344 | { |
8b5fdf2e | 1345 | struct sync_mac_ip_ctx ctx; |
8b5fdf2e PR |
1346 | char ipbuf[INET6_ADDRSTRLEN]; |
1347 | bool sticky; | |
1348 | bool remote_gw; | |
1349 | zebra_neigh_t *n = NULL; | |
6006414d | 1350 | |
8b5fdf2e PR |
1351 | sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); |
1352 | remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW); | |
1353 | /* if sticky or remote-gw ignore updates from the peer */ | |
1354 | if (sticky || remote_gw) { | |
1355 | if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_NEIGH | |
1356 | || IS_ZEBRA_DEBUG_EVPN_MH_MAC) | |
1357 | zlog_debug( | |
ef7b8be4 | 1358 | "Ignore sync-macip vni %u mac %pEA%s%s%s%s", |
8b5fdf2e | 1359 | zevpn->vni, |
ef7b8be4 | 1360 | macaddr, |
8b5fdf2e PR |
1361 | ipa_len ? " IP " : "", |
1362 | ipa_len ? ipaddr2str(ipaddr, ipbuf, | |
1363 | sizeof(ipbuf)) | |
1364 | : "", | |
1365 | sticky ? " sticky" : "", | |
1366 | remote_gw ? " remote_gw" : ""); | |
1367 | return; | |
1368 | } | |
6006414d | 1369 | |
8b5fdf2e PR |
1370 | if (ipa_len) { |
1371 | n = zebra_evpn_neigh_lookup(zevpn, ipaddr); | |
1372 | if (n | |
16de1338 AK |
1373 | && !zebra_evpn_neigh_is_bgp_seq_ok(zevpn, n, macaddr, seq, |
1374 | true)) | |
8b5fdf2e PR |
1375 | return; |
1376 | } | |
6006414d | 1377 | |
8b5fdf2e PR |
1378 | memset(&ctx, 0, sizeof(ctx)); |
1379 | ctx.mac = zebra_evpn_proc_sync_mac_update( | |
1380 | zevpn, macaddr, ipa_len, ipaddr, flags, seq, esi, &ctx); | |
1381 | if (ctx.ignore_macip || !ctx.mac || !ipa_len) | |
6006414d PR |
1382 | return; |
1383 | ||
8b5fdf2e PR |
1384 | zebra_evpn_proc_sync_neigh_update(zevpn, n, ipa_len, ipaddr, flags, seq, |
1385 | esi, &ctx); | |
6006414d PR |
1386 | } |
1387 | ||
8b5fdf2e PR |
1388 | /************************** remote mac-ip handling **************************/ |
1389 | /* Process a remote MACIP add from BGP. */ | |
1a3bd37f MS |
1390 | void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, |
1391 | uint16_t ipa_len, const struct ipaddr *ipaddr, | |
8b5fdf2e | 1392 | uint8_t flags, uint32_t seq, |
1a3bd37f | 1393 | struct in_addr vtep_ip, const esi_t *esi) |
6006414d | 1394 | { |
f6371c34 | 1395 | struct zebra_evpn *zevpn; |
c172c032 | 1396 | struct zebra_vtep *zvtep; |
3198b2b3 | 1397 | struct zebra_mac *mac = NULL; |
8b5fdf2e PR |
1398 | struct interface *ifp = NULL; |
1399 | struct zebra_if *zif = NULL; | |
1400 | struct zebra_vrf *zvrf; | |
6006414d | 1401 | |
8b5fdf2e PR |
1402 | /* Locate EVPN hash entry - expected to exist. */ |
1403 | zevpn = zebra_evpn_lookup(vni); | |
1404 | if (!zevpn) { | |
34c9b28b DS |
1405 | if (IS_ZEBRA_DEBUG_VXLAN) |
1406 | zlog_debug("Unknown VNI %u upon remote MACIP ADD", vni); | |
8b5fdf2e | 1407 | return; |
6006414d PR |
1408 | } |
1409 | ||
8b5fdf2e PR |
1410 | ifp = zevpn->vxlan_if; |
1411 | if (ifp) | |
1412 | zif = ifp->info; | |
1413 | if (!ifp || !if_is_operative(ifp) || !zif || !zif->brslave_info.br_if) { | |
1414 | zlog_warn( | |
1415 | "Ignoring remote MACIP ADD VNI %u, invalid interface state or info", | |
1416 | vni); | |
1417 | return; | |
1418 | } | |
6006414d | 1419 | |
8b5fdf2e PR |
1420 | /* Type-2 routes from another PE can be interpreted as remote or |
1421 | * SYNC based on the destination ES - | |
1422 | * SYNC - if ES is local | |
1423 | * REMOTE - if ES is not local | |
1424 | */ | |
1425 | if (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) { | |
1426 | zebra_evpn_process_sync_macip_add(zevpn, macaddr, ipa_len, | |
1427 | ipaddr, flags, seq, esi); | |
1428 | return; | |
1429 | } | |
6006414d | 1430 | |
8b5fdf2e PR |
1431 | /* The remote VTEP specified should normally exist, but it is |
1432 | * possible that when peering comes up, peer may advertise MACIP | |
1433 | * routes before advertising type-3 routes. | |
1434 | */ | |
1435 | if (vtep_ip.s_addr) { | |
1436 | zvtep = zebra_evpn_vtep_find(zevpn, &vtep_ip); | |
1437 | if (!zvtep) { | |
1438 | zvtep = zebra_evpn_vtep_add(zevpn, &vtep_ip, | |
1439 | VXLAN_FLOOD_DISABLED); | |
1440 | if (!zvtep) { | |
1441 | flog_err( | |
1442 | EC_ZEBRA_VTEP_ADD_FAILED, | |
1443 | "Failed to add remote VTEP, VNI %u zevpn %p upon remote MACIP ADD", | |
1444 | vni, zevpn); | |
1445 | return; | |
1446 | } | |
6006414d | 1447 | |
8b5fdf2e PR |
1448 | zebra_evpn_vtep_install(zevpn, zvtep); |
1449 | } | |
6006414d PR |
1450 | } |
1451 | ||
d6bf8f13 | 1452 | zvrf = zebra_vrf_get_evpn(); |
6006414d PR |
1453 | if (!zvrf) |
1454 | return; | |
6006414d | 1455 | |
6006414d | 1456 | |
272e11bf MS |
1457 | if (zebra_evpn_mac_remote_macip_add(zevpn, zvrf, macaddr, ipa_len, |
1458 | ipaddr, &mac, vtep_ip, flags, seq, | |
1459 | esi) | |
8b5fdf2e | 1460 | != 0) |
6006414d | 1461 | return; |
6006414d | 1462 | |
272e11bf MS |
1463 | zebra_evpn_neigh_remote_macip_add(zevpn, zvrf, ipaddr, mac, vtep_ip, |
1464 | flags, seq); | |
6006414d PR |
1465 | } |
1466 | ||
8b5fdf2e | 1467 | /* Process a remote MACIP delete from BGP. */ |
1a3bd37f MS |
1468 | void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, |
1469 | uint16_t ipa_len, const struct ipaddr *ipaddr, | |
8b5fdf2e | 1470 | struct in_addr vtep_ip) |
6006414d | 1471 | { |
f6371c34 | 1472 | struct zebra_evpn *zevpn; |
3198b2b3 | 1473 | struct zebra_mac *mac = NULL; |
8b5fdf2e PR |
1474 | zebra_neigh_t *n = NULL; |
1475 | struct interface *ifp = NULL; | |
1476 | struct zebra_if *zif = NULL; | |
1477 | struct zebra_ns *zns; | |
1478 | struct zebra_l2info_vxlan *vxl; | |
6006414d | 1479 | struct zebra_vrf *zvrf; |
8b5fdf2e | 1480 | char buf1[INET6_ADDRSTRLEN]; |
6006414d | 1481 | |
8b5fdf2e PR |
1482 | /* Locate EVPN hash entry - expected to exist. */ |
1483 | zevpn = zebra_evpn_lookup(vni); | |
1484 | if (!zevpn) { | |
1485 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1486 | zlog_debug("Unknown VNI %u upon remote MACIP DEL", vni); | |
6006414d | 1487 | return; |
6006414d PR |
1488 | } |
1489 | ||
8b5fdf2e PR |
1490 | ifp = zevpn->vxlan_if; |
1491 | if (ifp) | |
1492 | zif = ifp->info; | |
1493 | if (!ifp || !if_is_operative(ifp) || !zif || !zif->brslave_info.br_if) { | |
1494 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1495 | zlog_debug( | |
1496 | "Ignoring remote MACIP DEL VNI %u, invalid interface state or info", | |
1497 | vni); | |
6006414d | 1498 | return; |
8b5fdf2e PR |
1499 | } |
1500 | zns = zebra_ns_lookup(NS_DEFAULT); | |
1501 | vxl = &zif->l2info.vxl; | |
6006414d | 1502 | |
8b5fdf2e PR |
1503 | mac = zebra_evpn_mac_lookup(zevpn, macaddr); |
1504 | if (ipa_len) | |
1505 | n = zebra_evpn_neigh_lookup(zevpn, ipaddr); | |
6006414d | 1506 | |
8b5fdf2e PR |
1507 | if (n && !mac) { |
1508 | zlog_warn( | |
ef7b8be4 DL |
1509 | "Failed to locate MAC %pEA for neigh %pIA VNI %u upon remote MACIP DEL", |
1510 | macaddr, ipaddr, vni); | |
6006414d | 1511 | return; |
8b5fdf2e | 1512 | } |
6006414d | 1513 | |
8b5fdf2e PR |
1514 | /* If the remote mac or neighbor doesn't exist there is nothing |
1515 | * more to do. Otherwise, uninstall the entry and then remove it. | |
1516 | */ | |
1517 | if (!mac && !n) | |
6006414d PR |
1518 | return; |
1519 | ||
8b5fdf2e | 1520 | zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id); |
6006414d | 1521 | |
8b5fdf2e PR |
1522 | /* Ignore the delete if this mac is a gateway mac-ip */ |
1523 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) | |
1524 | && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) { | |
1525 | zlog_warn( | |
ef7b8be4 DL |
1526 | "Ignore remote MACIP DEL VNI %u MAC %pEA%s%s as MAC is already configured as gateway MAC", |
1527 | vni, macaddr, | |
8b5fdf2e PR |
1528 | ipa_len ? " IP " : "", |
1529 | ipa_len ? ipaddr2str(ipaddr, buf1, sizeof(buf1)) : ""); | |
6006414d | 1530 | return; |
8b5fdf2e | 1531 | } |
6006414d | 1532 | |
8b5fdf2e PR |
1533 | /* Uninstall remote neighbor or MAC. */ |
1534 | if (n) | |
1535 | zebra_evpn_neigh_remote_uninstall(zevpn, zvrf, n, mac, ipaddr); | |
1536 | else { | |
1537 | /* DAD: when MAC is freeze state as remote learn event, | |
1538 | * remote mac-ip delete event is received will result in freeze | |
1539 | * entry removal, first fetch kernel for the same entry present | |
1540 | * as LOCAL and reachable, avoid deleting this entry instead | |
1541 | * use kerenel local entry to update during unfreeze time. | |
1542 | */ | |
1543 | if (zvrf->dad_freeze | |
1544 | && CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) | |
1545 | && CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { | |
1546 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1547 | zlog_debug( | |
ef7b8be4 DL |
1548 | "%s: MAC %pEA (flags 0x%x) is remote and duplicate, read kernel for local entry", |
1549 | __func__, macaddr, mac->flags); | |
8b5fdf2e PR |
1550 | macfdb_read_specific_mac(zns, zif->brslave_info.br_if, |
1551 | macaddr, vxl->access_vlan); | |
1552 | } | |
6006414d | 1553 | |
8b5fdf2e PR |
1554 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { |
1555 | if (!ipa_len) | |
1556 | zebra_evpn_sync_mac_del(mac); | |
1557 | } else if (CHECK_FLAG(mac->flags, ZEBRA_NEIGH_REMOTE)) { | |
1558 | zebra_evpn_rem_mac_del(zevpn, mac); | |
1559 | } | |
6006414d | 1560 | } |
6006414d PR |
1561 | } |
1562 | ||
1563 | /************************** EVPN BGP config management ************************/ | |
8b5fdf2e | 1564 | void zebra_evpn_cfg_cleanup(struct hash_bucket *bucket, void *ctxt) |
6006414d | 1565 | { |
f6371c34 | 1566 | struct zebra_evpn *zevpn = NULL; |
6006414d | 1567 | |
f6371c34 | 1568 | zevpn = (struct zebra_evpn *)bucket->data; |
6006414d PR |
1569 | zevpn->advertise_gw_macip = 0; |
1570 | zevpn->advertise_svi_macip = 0; | |
1571 | zevpn->advertise_subnet = 0; | |
1572 | ||
1573 | zebra_evpn_neigh_del_all(zevpn, 1, 0, | |
1574 | DEL_REMOTE_NEIGH | DEL_REMOTE_NEIGH_FROM_VTEP); | |
1575 | zebra_evpn_mac_del_all(zevpn, 1, 0, | |
1576 | DEL_REMOTE_MAC | DEL_REMOTE_MAC_FROM_VTEP); | |
8b5fdf2e | 1577 | zebra_evpn_vtep_del_all(zevpn, 1); |
6006414d | 1578 | } |