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