]>
Commit | Line | Data |
---|---|---|
13d60d35 | 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 | */ | |
22 | ||
23 | #include <zebra.h> | |
24 | ||
25 | #include "if.h" | |
26 | #include "prefix.h" | |
27 | #include "table.h" | |
28 | #include "memory.h" | |
29 | #include "log.h" | |
30 | #include "linklist.h" | |
31 | #include "stream.h" | |
32 | #include "hash.h" | |
33 | #include "jhash.h" | |
34 | #include "vlan.h" | |
35 | #include "vxlan.h" | |
36 | ||
37 | #include "zebra/rib.h" | |
38 | #include "zebra/rt.h" | |
39 | #include "zebra/zebra_ns.h" | |
40 | #include "zebra/zserv.h" | |
41 | #include "zebra/debug.h" | |
42 | #include "zebra/interface.h" | |
43 | #include "zebra/zebra_vrf.h" | |
44 | #include "zebra/rt_netlink.h" | |
45 | #include "zebra/zebra_vxlan_private.h" | |
46 | #include "zebra/zebra_vxlan.h" | |
47 | #include "zebra/zebra_memory.h" | |
48 | #include "zebra/zebra_l2.h" | |
cd233079 | 49 | #include "lib/json.h" |
13d60d35 | 50 | |
d62a17ae | 51 | DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash"); |
13d60d35 | 52 | DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP"); |
d62a17ae | 53 | DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC"); |
54 | DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); | |
13d60d35 | 55 | |
56 | /* definitions */ | |
57 | ||
58 | ||
59 | /* static function declarations */ | |
cd233079 | 60 | static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json); |
d62a17ae | 61 | static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt); |
62 | static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, | |
cd233079 | 63 | void **args); |
d62a17ae | 64 | static void zvni_print_mac(zebra_mac_t *mac, void *ctxt); |
65 | static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt); | |
66 | static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt); | |
cd233079 CS |
67 | static void zvni_print(zebra_vni_t *zvni, void **ctxt); |
68 | static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]); | |
d62a17ae | 69 | |
70 | static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni, | |
71 | struct ethaddr *macaddr, | |
1a98c087 | 72 | struct ipaddr *ip, u_char flags, |
d62a17ae | 73 | u_int16_t cmd); |
74 | static unsigned int neigh_hash_keymake(void *p); | |
75 | static int neigh_cmp(const void *p1, const void *p2); | |
76 | static void *zvni_neigh_alloc(void *p); | |
77 | static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip); | |
78 | static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n); | |
79 | static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg); | |
80 | static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall, | |
81 | struct in_addr *r_vtep_ip); | |
82 | static void zvni_neigh_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni, | |
83 | int uninstall, int upd_client, u_int32_t flags); | |
84 | static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip); | |
85 | static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, | |
86 | struct ipaddr *ip, | |
1a98c087 | 87 | struct ethaddr *macaddr, u_char flags); |
d62a17ae | 88 | static int zvni_neigh_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni, |
89 | struct ipaddr *ip, | |
1a98c087 | 90 | struct ethaddr *macaddr, u_char flags); |
d62a17ae | 91 | static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n); |
92 | static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n); | |
93 | static zebra_vni_t *zvni_map_svi(struct interface *ifp, | |
94 | struct interface *br_if); | |
95 | static struct interface *zvni_map_to_svi(struct zebra_vrf *zvrf, vlanid_t vid, | |
96 | struct interface *br_if); | |
97 | ||
98 | static unsigned int mac_hash_keymake(void *p); | |
99 | static int mac_cmp(const void *p1, const void *p2); | |
100 | static void *zvni_mac_alloc(void *p); | |
101 | static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr); | |
102 | static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac); | |
103 | static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg); | |
104 | static void zvni_mac_del_from_vtep(zebra_vni_t *zvni, int uninstall, | |
105 | struct in_addr *r_vtep_ip); | |
106 | static void zvni_mac_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni, | |
107 | int uninstall, int upd_client, u_int32_t flags); | |
108 | static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr); | |
109 | static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, | |
1a98c087 | 110 | struct ethaddr *macaddr, u_char flags); |
d62a17ae | 111 | static int zvni_mac_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni, |
1a98c087 | 112 | struct ethaddr *macaddr, u_char flags); |
d62a17ae | 113 | static zebra_vni_t *zvni_map_vlan(struct interface *ifp, |
114 | struct interface *br_if, vlanid_t vid); | |
115 | static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac); | |
116 | static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac, int local); | |
117 | static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt); | |
118 | ||
119 | static unsigned int vni_hash_keymake(void *p); | |
120 | static int vni_hash_cmp(const void *p1, const void *p2); | |
121 | static void *zvni_alloc(void *p); | |
122 | static zebra_vni_t *zvni_lookup(struct zebra_vrf *zvrf, vni_t vni); | |
123 | static zebra_vni_t *zvni_add(struct zebra_vrf *zvrf, vni_t vni); | |
124 | static int zvni_del(struct zebra_vrf *zvrf, zebra_vni_t *zvni); | |
125 | static int zvni_send_add_to_client(struct zebra_vrf *zvrf, zebra_vni_t *zvni); | |
126 | static int zvni_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni); | |
127 | static void zvni_build_hash_table(struct zebra_vrf *zvrf); | |
128 | static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep); | |
129 | static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip); | |
130 | static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip); | |
131 | static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep); | |
132 | static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall); | |
133 | static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip); | |
134 | static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip); | |
1a98c087 MK |
135 | static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni); |
136 | static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni); | |
137 | static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, | |
138 | struct ethaddr *macaddr, struct ipaddr *ip); | |
139 | static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, | |
140 | struct ipaddr *ip); | |
141 | struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp); | |
142 | static int advertise_gw_macip_enabled(struct zebra_vrf *zvrf, | |
143 | zebra_vni_t *zvni); | |
144 | static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac, | |
145 | int uninstall); | |
13d60d35 | 146 | |
147 | /* Private functions */ | |
148 | ||
1a98c087 MK |
149 | static int advertise_gw_macip_enabled(struct zebra_vrf *zvrf, zebra_vni_t *zvni) |
150 | { | |
151 | if (zvrf && zvrf->advertise_gw_macip) | |
152 | return 1; | |
153 | ||
154 | if (zvni && zvni->advertise_gw_macip) | |
155 | return 1; | |
156 | ||
157 | return 0; | |
158 | } | |
159 | ||
cec2e17d | 160 | /* |
161 | * Helper function to determine maximum width of neighbor IP address for | |
162 | * display - just because we're dealing with IPv6 addresses that can | |
163 | * widely vary. | |
164 | */ | |
d62a17ae | 165 | static void zvni_find_neigh_addr_width(struct hash_backet *backet, void *ctxt) |
cec2e17d | 166 | { |
d62a17ae | 167 | zebra_neigh_t *n; |
168 | char buf[INET6_ADDRSTRLEN]; | |
169 | struct neigh_walk_ctx *wctx = ctxt; | |
170 | int width; | |
cec2e17d | 171 | |
d62a17ae | 172 | n = (zebra_neigh_t *)backet->data; |
173 | if (!n) | |
174 | return; | |
cec2e17d | 175 | |
d62a17ae | 176 | ipaddr2str(&n->ip, buf, sizeof(buf)), width = strlen(buf); |
177 | if (width > wctx->addr_width) | |
178 | wctx->addr_width = width; | |
cec2e17d | 179 | } |
180 | ||
181 | /* | |
182 | * Print a specific neighbor entry. | |
183 | */ | |
cd233079 | 184 | static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) |
cec2e17d | 185 | { |
d62a17ae | 186 | struct vty *vty; |
187 | char buf1[ETHER_ADDR_STRLEN]; | |
188 | char buf2[INET6_ADDRSTRLEN]; | |
cec2e17d | 189 | |
cd233079 CS |
190 | ipaddr2str(&n->ip, buf2, sizeof(buf2)); |
191 | prefix_mac2str(&n->emac, buf1, sizeof(buf1)); | |
192 | vty = (struct vty *)ctxt; | |
193 | if (json == NULL) { | |
194 | vty_out(vty, "IP: %s\n", | |
195 | ipaddr2str(&n->ip, buf2, sizeof(buf2))); | |
196 | vty_out(vty, " MAC: %s", | |
197 | prefix_mac2str(&n->emac, buf1, sizeof(buf1))); | |
198 | } else { | |
199 | json_object_string_add(json, "ip", buf2); | |
200 | json_object_string_add(json, "mac", buf1); | |
201 | } | |
202 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
203 | if (json == NULL) | |
204 | vty_out(vty, " Remote VTEP: %s", | |
205 | inet_ntoa(n->r_vtep_ip)); | |
206 | else | |
207 | json_object_string_add(json, "remoteVtep", | |
208 | inet_ntoa(n->r_vtep_ip)); | |
209 | } | |
210 | if (json == NULL) | |
211 | vty_out(vty, "\n"); | |
cec2e17d | 212 | } |
213 | ||
214 | /* | |
215 | * Print neighbor hash entry - called for display of all neighbors. | |
216 | */ | |
d62a17ae | 217 | static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt) |
218 | { | |
219 | struct vty *vty; | |
cd233079 | 220 | json_object *json_vni = NULL, *json_row = NULL; |
d62a17ae | 221 | zebra_neigh_t *n; |
222 | char buf1[ETHER_ADDR_STRLEN]; | |
223 | char buf2[INET6_ADDRSTRLEN]; | |
224 | struct neigh_walk_ctx *wctx = ctxt; | |
225 | ||
226 | vty = wctx->vty; | |
cd233079 | 227 | json_vni = wctx->json; |
d62a17ae | 228 | n = (zebra_neigh_t *)backet->data; |
229 | if (!n) | |
230 | return; | |
231 | ||
cd233079 CS |
232 | if (json_vni) |
233 | json_row = json_object_new_object(); | |
234 | ||
d62a17ae | 235 | prefix_mac2str(&n->emac, buf1, sizeof(buf1)); |
236 | ipaddr2str(&n->ip, buf2, sizeof(buf2)); | |
237 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) | |
238 | && !(wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)) { | |
cd233079 CS |
239 | if (json_vni == NULL) { |
240 | vty_out(vty, "%*s %-6s %-17s\n", -wctx->addr_width, | |
241 | buf2, "local", buf1); | |
242 | } else { | |
243 | json_object_string_add(json_row, "type", "local"); | |
244 | json_object_string_add(json_row, "mac", buf1); | |
245 | } | |
d62a17ae | 246 | wctx->count++; |
247 | } else { | |
248 | if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) { | |
249 | if (IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip)) { | |
cd233079 CS |
250 | if (json_vni == NULL) { |
251 | if (wctx->count == 0) | |
252 | vty_out(vty, | |
253 | "%*s %-6s %-17s %-21s\n", | |
254 | -wctx->addr_width, | |
255 | "Neighbor", "Type", | |
256 | "MAC", "Remote VTEP"); | |
d62a17ae | 257 | vty_out(vty, "%*s %-6s %-17s %-21s\n", |
cd233079 CS |
258 | -wctx->addr_width, buf2, |
259 | "remote", buf1, | |
260 | inet_ntoa(n->r_vtep_ip)); | |
261 | } else { | |
262 | json_object_string_add(json_row, "type", | |
263 | "remote"); | |
264 | json_object_string_add(json_row, "mac", | |
265 | buf1); | |
266 | json_object_string_add( | |
267 | json_row, "remoteVtep", | |
268 | inet_ntoa(n->r_vtep_ip)); | |
269 | } | |
270 | wctx->count++; | |
271 | } | |
272 | } else { | |
273 | if (json_vni == NULL) { | |
d62a17ae | 274 | vty_out(vty, "%*s %-6s %-17s %-21s\n", |
275 | -wctx->addr_width, buf2, "remote", buf1, | |
276 | inet_ntoa(n->r_vtep_ip)); | |
cd233079 CS |
277 | } else { |
278 | json_object_string_add(json_row, "type", | |
279 | "remote"); | |
280 | json_object_string_add(json_row, "mac", buf1); | |
281 | json_object_string_add(json_row, "remoteVtep", | |
282 | inet_ntoa(n->r_vtep_ip)); | |
d62a17ae | 283 | } |
d62a17ae | 284 | wctx->count++; |
285 | } | |
286 | } | |
cd233079 CS |
287 | |
288 | if (json_vni) | |
289 | json_object_object_add(json_vni, buf2, json_row); | |
cec2e17d | 290 | } |
291 | ||
292 | /* | |
293 | * Print neighbors for all VNI. | |
294 | */ | |
d62a17ae | 295 | static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, |
cd233079 | 296 | void **args) |
cec2e17d | 297 | { |
d62a17ae | 298 | struct vty *vty; |
cd233079 | 299 | json_object *json = NULL, *json_vni = NULL; |
d62a17ae | 300 | zebra_vni_t *zvni; |
301 | u_int32_t num_neigh; | |
302 | struct neigh_walk_ctx wctx; | |
cd233079 CS |
303 | char vni_str[VNI_STR_LEN]; |
304 | ||
305 | vty = (struct vty *)args[0]; | |
306 | json = (json_object *)args[1]; | |
cec2e17d | 307 | |
d62a17ae | 308 | zvni = (zebra_vni_t *)backet->data; |
cd233079 CS |
309 | if (!zvni) { |
310 | if (json) | |
311 | vty_out(vty, "{}\n"); | |
d62a17ae | 312 | return; |
cd233079 | 313 | } |
d62a17ae | 314 | num_neigh = hashcount(zvni->neigh_table); |
cd233079 CS |
315 | if (json == NULL) |
316 | vty_out(vty, | |
317 | "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n", | |
318 | zvni->vni, num_neigh); | |
319 | else { | |
320 | json_vni = json_object_new_object(); | |
321 | json_object_int_add(json_vni, "numArpNd", num_neigh); | |
322 | snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); | |
323 | } | |
324 | if (!num_neigh) { | |
325 | if (json) | |
326 | json_object_object_add(json, vni_str, json_vni); | |
d62a17ae | 327 | return; |
cd233079 | 328 | } |
cec2e17d | 329 | |
d62a17ae | 330 | /* Since we have IPv6 addresses to deal with which can vary widely in |
331 | * size, we try to be a bit more elegant in display by first computing | |
332 | * the maximum width. | |
333 | */ | |
334 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); | |
335 | wctx.zvni = zvni; | |
336 | wctx.vty = vty; | |
337 | wctx.addr_width = 15; | |
cd233079 | 338 | wctx.json = json_vni; |
d62a17ae | 339 | hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); |
cec2e17d | 340 | |
cd233079 CS |
341 | if (json == NULL) |
342 | vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", | |
343 | "Type", "MAC", "Remote VTEP"); | |
d62a17ae | 344 | hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); |
cd233079 CS |
345 | |
346 | if (json) | |
347 | json_object_object_add(json, vni_str, json_vni); | |
cec2e17d | 348 | } |
349 | ||
350 | /* | |
351 | * Print a specific MAC entry. | |
352 | */ | |
d62a17ae | 353 | static void zvni_print_mac(zebra_mac_t *mac, void *ctxt) |
354 | { | |
355 | struct vty *vty; | |
356 | char buf1[20]; | |
357 | ||
358 | vty = (struct vty *)ctxt; | |
359 | vty_out(vty, "MAC: %s", | |
360 | prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1))); | |
361 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
362 | struct zebra_ns *zns; | |
363 | struct interface *ifp; | |
364 | ifindex_t ifindex; | |
365 | ||
366 | ifindex = mac->fwd_info.local.ifindex; | |
367 | zns = zebra_ns_lookup(NS_DEFAULT); | |
368 | ifp = if_lookup_by_index_per_ns(zns, ifindex); | |
369 | if (!ifp) // unexpected | |
370 | return; | |
371 | vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex); | |
372 | if (mac->fwd_info.local.vid) | |
373 | vty_out(vty, " VLAN: %u", mac->fwd_info.local.vid); | |
374 | } else { | |
375 | vty_out(vty, " Remote VTEP: %s", | |
376 | inet_ntoa(mac->fwd_info.r_vtep_ip)); | |
377 | } | |
378 | vty_out(vty, " ARP ref: %u", mac->neigh_refcnt); | |
379 | vty_out(vty, "\n"); | |
cec2e17d | 380 | } |
381 | ||
382 | /* | |
383 | * Print MAC hash entry - called for display of all MACs. | |
384 | */ | |
d62a17ae | 385 | static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) |
386 | { | |
387 | struct vty *vty; | |
cd233079 | 388 | json_object *json_mac_hdr = NULL, *json_mac = NULL; |
d62a17ae | 389 | zebra_mac_t *mac; |
390 | char buf1[20]; | |
391 | struct mac_walk_ctx *wctx = ctxt; | |
392 | ||
393 | vty = wctx->vty; | |
cd233079 | 394 | json_mac_hdr = wctx->json; |
d62a17ae | 395 | mac = (zebra_mac_t *)backet->data; |
396 | if (!mac) | |
397 | return; | |
398 | ||
399 | prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1)); | |
cd233079 CS |
400 | |
401 | if (json_mac_hdr) | |
402 | json_mac = json_object_new_object(); | |
403 | ||
d62a17ae | 404 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) |
405 | && !(wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)) { | |
406 | struct zebra_ns *zns; | |
407 | ifindex_t ifindex; | |
408 | struct interface *ifp; | |
409 | vlanid_t vid; | |
410 | ||
411 | zns = zebra_ns_lookup(NS_DEFAULT); | |
412 | ifindex = mac->fwd_info.local.ifindex; | |
413 | ifp = if_lookup_by_index_per_ns(zns, ifindex); | |
414 | if (!ifp) // unexpected | |
415 | return; | |
416 | vid = mac->fwd_info.local.vid; | |
cd233079 CS |
417 | if (json_mac_hdr == NULL) |
418 | vty_out(vty, "%-17s %-6s %-21s", buf1, "local", | |
419 | ifp->name); | |
420 | else { | |
421 | json_object_string_add(json_mac, "type", "local"); | |
422 | json_object_string_add(json_mac, "intf", ifp->name); | |
423 | } | |
424 | if (vid) { | |
425 | if (json_mac_hdr == NULL) | |
426 | vty_out(vty, " %-5u", vid); | |
427 | else | |
428 | json_object_int_add(json_mac, "vlan", vid); | |
429 | } | |
430 | if (json_mac_hdr == NULL) | |
431 | vty_out(vty, "\n"); | |
432 | else | |
433 | json_object_object_add(json_mac_hdr, buf1, json_mac); | |
d62a17ae | 434 | wctx->count++; |
435 | } else { | |
436 | if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) { | |
437 | if (IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, | |
438 | &wctx->r_vtep_ip)) { | |
439 | if (wctx->count == 0) { | |
cd233079 CS |
440 | if (json_mac_hdr == NULL) { |
441 | vty_out(vty, "\nVNI %u\n\n", | |
442 | wctx->zvni->vni); | |
443 | vty_out(vty, | |
444 | "%-17s %-6s %-21s %-5s\n", | |
445 | "MAC", "Type", | |
446 | "Intf/Remote VTEP", | |
447 | "VLAN"); | |
448 | } | |
449 | } | |
450 | if (json_mac_hdr == NULL) | |
451 | vty_out(vty, "%-17s %-6s %-21s\n", buf1, | |
452 | "remote", | |
453 | inet_ntoa(mac->fwd_info | |
454 | .r_vtep_ip)); | |
455 | else { | |
456 | json_object_string_add(json_mac, "type", | |
457 | "remote"); | |
458 | json_object_string_add( | |
459 | json_mac, "remoteVtep", | |
460 | inet_ntoa(mac->fwd_info | |
461 | .r_vtep_ip)); | |
462 | json_object_object_add(json_mac_hdr, | |
463 | buf1, json_mac); | |
d62a17ae | 464 | } |
d62a17ae | 465 | wctx->count++; |
466 | } | |
467 | } else { | |
cd233079 CS |
468 | if (json_mac_hdr == NULL) |
469 | vty_out(vty, "%-17s %-6s %-21s\n", buf1, | |
470 | "remote", | |
471 | inet_ntoa(mac->fwd_info.r_vtep_ip)); | |
472 | else { | |
473 | json_object_string_add(json_mac, "type", | |
474 | "remote"); | |
475 | json_object_string_add( | |
476 | json_mac, "remoteVtep", | |
477 | inet_ntoa(mac->fwd_info.r_vtep_ip)); | |
478 | json_object_object_add(json_mac_hdr, buf1, | |
479 | json_mac); | |
480 | } | |
d62a17ae | 481 | wctx->count++; |
482 | } | |
483 | } | |
cec2e17d | 484 | } |
485 | ||
486 | /* | |
487 | * Print MACs for all VNI. | |
488 | */ | |
d62a17ae | 489 | static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) |
cec2e17d | 490 | { |
d62a17ae | 491 | struct vty *vty; |
cd233079 CS |
492 | json_object *json = NULL, *json_vni = NULL; |
493 | json_object *json_mac = NULL; | |
d62a17ae | 494 | zebra_vni_t *zvni; |
495 | u_int32_t num_macs; | |
496 | struct mac_walk_ctx *wctx = ctxt; | |
cd233079 | 497 | char vni_str[VNI_STR_LEN]; |
cec2e17d | 498 | |
d62a17ae | 499 | vty = (struct vty *)wctx->vty; |
cd233079 | 500 | json = (struct json_object *)wctx->json; |
cec2e17d | 501 | |
d62a17ae | 502 | zvni = (zebra_vni_t *)backet->data; |
cd233079 CS |
503 | if (!zvni) { |
504 | if (json) | |
505 | vty_out(vty, "{}\n"); | |
d62a17ae | 506 | return; |
cd233079 | 507 | } |
d62a17ae | 508 | wctx->zvni = zvni; |
cec2e17d | 509 | |
d62a17ae | 510 | /*We are iterating over a new VNI, set the count to 0*/ |
511 | wctx->count = 0; | |
cec2e17d | 512 | |
d62a17ae | 513 | num_macs = hashcount(zvni->mac_table); |
514 | if (!num_macs) | |
515 | return; | |
cd233079 CS |
516 | |
517 | if (json) { | |
518 | json_vni = json_object_new_object(); | |
519 | json_mac = json_object_new_object(); | |
520 | snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); | |
d62a17ae | 521 | } |
cec2e17d | 522 | |
cd233079 CS |
523 | if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) { |
524 | if (json == NULL) { | |
525 | vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n", | |
526 | zvni->vni, num_macs); | |
527 | vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", | |
528 | "Intf/Remote VTEP", "VLAN"); | |
529 | } else | |
530 | json_object_int_add(json_vni, "numMacs", num_macs); | |
531 | } | |
532 | /* assign per-vni to wctx->json object to fill macs | |
533 | * under the vni. Re-assign primary json object to fill | |
534 | * next vni information. | |
535 | */ | |
536 | wctx->json = json_mac; | |
d62a17ae | 537 | hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx); |
cd233079 CS |
538 | wctx->json = json; |
539 | if (json) { | |
540 | if (wctx->count) | |
541 | json_object_object_add(json_vni, "macs", json_mac); | |
542 | json_object_object_add(json, vni_str, json_vni); | |
543 | } | |
cec2e17d | 544 | } |
545 | ||
546 | /* | |
547 | * Print a specific VNI entry. | |
548 | */ | |
cd233079 | 549 | static void zvni_print(zebra_vni_t *zvni, void **ctxt) |
d62a17ae | 550 | { |
551 | struct vty *vty; | |
552 | zebra_vtep_t *zvtep; | |
553 | u_int32_t num_macs; | |
554 | u_int32_t num_neigh; | |
cd233079 CS |
555 | json_object *json = NULL; |
556 | json_object *json_vtep_list = NULL; | |
557 | json_object *json_ip_str = NULL; | |
d62a17ae | 558 | |
cd233079 CS |
559 | vty = ctxt[0]; |
560 | json = ctxt[1]; | |
561 | ||
562 | if (json == NULL) | |
563 | vty_out(vty, "VNI: %u\n", zvni->vni); | |
564 | else | |
565 | json_object_int_add(json, "vni", zvni->vni); | |
d62a17ae | 566 | |
d62a17ae | 567 | if (!zvni->vxlan_if) { // unexpected |
cd233079 CS |
568 | if (json == NULL) |
569 | vty_out(vty, " VxLAN interface: unknown\n"); | |
d62a17ae | 570 | return; |
571 | } | |
cd233079 CS |
572 | num_macs = hashcount(zvni->mac_table); |
573 | num_neigh = hashcount(zvni->neigh_table); | |
574 | if (json == NULL) | |
575 | vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n", | |
576 | zvni->vxlan_if->name, zvni->vxlan_if->ifindex, | |
577 | inet_ntoa(zvni->local_vtep_ip)); | |
578 | else { | |
579 | json_object_string_add(json, "vxlanInterface", | |
580 | zvni->vxlan_if->name); | |
581 | json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex); | |
582 | json_object_string_add(json, "vtepIp", | |
583 | inet_ntoa(zvni->local_vtep_ip)); | |
584 | json_object_int_add(json, "numMacs", num_macs); | |
585 | json_object_int_add(json, "numArpNd", num_neigh); | |
586 | } | |
d62a17ae | 587 | if (!zvni->vteps) { |
cd233079 CS |
588 | if (json == NULL) |
589 | vty_out(vty, " No remote VTEPs known for this VNI\n"); | |
d62a17ae | 590 | } else { |
cd233079 CS |
591 | if (json == NULL) |
592 | vty_out(vty, " Remote VTEPs for this VNI:\n"); | |
593 | else | |
594 | json_vtep_list = json_object_new_array(); | |
595 | for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { | |
596 | if (json == NULL) | |
597 | vty_out(vty, " %s\n", | |
598 | inet_ntoa(zvtep->vtep_ip)); | |
599 | else { | |
600 | json_ip_str = json_object_new_string( | |
601 | inet_ntoa(zvtep->vtep_ip)); | |
602 | json_object_array_add(json_vtep_list, | |
603 | json_ip_str); | |
604 | } | |
605 | } | |
606 | if (json) | |
607 | json_object_object_add(json, "numRemoteVteps", | |
608 | json_vtep_list); | |
609 | } | |
610 | if (json == NULL) { | |
611 | vty_out(vty, | |
612 | " Number of MACs (local and remote) known for this VNI: %u\n", | |
613 | num_macs); | |
614 | vty_out(vty, | |
615 | " Number of ARPs (IPv4 and IPv6, local and remote) " | |
616 | "known for this VNI: %u\n", | |
617 | num_neigh); | |
d62a17ae | 618 | } |
cec2e17d | 619 | } |
620 | ||
621 | /* | |
622 | * Print a VNI hash entry - called for display of all VNIs. | |
623 | */ | |
cd233079 | 624 | static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) |
cec2e17d | 625 | { |
d62a17ae | 626 | struct vty *vty; |
627 | zebra_vni_t *zvni; | |
628 | zebra_vtep_t *zvtep; | |
629 | u_int32_t num_vteps = 0; | |
630 | u_int32_t num_macs = 0; | |
631 | u_int32_t num_neigh = 0; | |
cd233079 CS |
632 | json_object *json = NULL; |
633 | json_object *json_vni = NULL; | |
634 | json_object *json_ip_str = NULL; | |
635 | json_object *json_vtep_list = NULL; | |
636 | ||
637 | vty = ctxt[0]; | |
638 | json = ctxt[1]; | |
cec2e17d | 639 | |
d62a17ae | 640 | zvni = (zebra_vni_t *)backet->data; |
641 | if (!zvni) | |
642 | return; | |
cec2e17d | 643 | |
d62a17ae | 644 | zvtep = zvni->vteps; |
645 | while (zvtep) { | |
646 | num_vteps++; | |
647 | zvtep = zvtep->next; | |
648 | } | |
cec2e17d | 649 | |
d62a17ae | 650 | num_macs = hashcount(zvni->mac_table); |
651 | num_neigh = hashcount(zvni->neigh_table); | |
cd233079 CS |
652 | if (json == NULL) |
653 | vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni, | |
654 | zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", | |
655 | inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh, | |
656 | num_vteps); | |
657 | else { | |
658 | char vni_str[VNI_STR_LEN]; | |
659 | snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); | |
660 | json_vni = json_object_new_object(); | |
661 | json_object_string_add(json_vni, "vxlanIf", | |
662 | zvni->vxlan_if ? zvni->vxlan_if->name | |
663 | : "unknown"); | |
664 | json_object_string_add(json_vni, "vtepIp", | |
665 | inet_ntoa(zvni->local_vtep_ip)); | |
666 | json_object_int_add(json_vni, "numMacs", num_macs); | |
667 | json_object_int_add(json_vni, "numArpNd", num_neigh); | |
668 | json_object_int_add(json_vni, "numRemoteVteps", num_vteps); | |
669 | if (num_vteps) { | |
670 | json_vtep_list = json_object_new_array(); | |
671 | for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { | |
672 | json_ip_str = json_object_new_string( | |
673 | inet_ntoa(zvtep->vtep_ip)); | |
674 | json_object_array_add(json_vtep_list, | |
675 | json_ip_str); | |
676 | } | |
677 | json_object_object_add(json_vni, "remoteVteps", | |
678 | json_vtep_list); | |
679 | } | |
680 | json_object_object_add(json, vni_str, json_vni); | |
681 | } | |
cec2e17d | 682 | } |
683 | ||
13d60d35 | 684 | /* |
2232a77c | 685 | * Inform BGP about local MACIP. |
686 | */ | |
d62a17ae | 687 | static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni, |
688 | struct ethaddr *macaddr, | |
1a98c087 | 689 | struct ipaddr *ip, u_char flags, |
d62a17ae | 690 | u_int16_t cmd) |
691 | { | |
692 | struct zserv *client; | |
693 | struct stream *s; | |
694 | int ipa_len; | |
695 | char buf[ETHER_ADDR_STRLEN]; | |
696 | char buf2[INET6_ADDRSTRLEN]; | |
697 | ||
698 | client = zebra_find_client(ZEBRA_ROUTE_BGP); | |
699 | /* BGP may not be running. */ | |
700 | if (!client) | |
701 | return 0; | |
702 | ||
703 | s = client->obuf; | |
704 | stream_reset(s); | |
705 | ||
706 | zserv_create_header(s, cmd, zvrf_id(zvrf)); | |
707 | stream_putl(s, vni); | |
ff8b7eb8 | 708 | stream_put(s, macaddr->octet, ETH_ALEN); |
d62a17ae | 709 | if (ip) { |
710 | ipa_len = 0; | |
711 | if (IS_IPADDR_V4(ip)) | |
712 | ipa_len = IPV4_MAX_BYTELEN; | |
713 | else if (IS_IPADDR_V6(ip)) | |
714 | ipa_len = IPV6_MAX_BYTELEN; | |
715 | ||
716 | stream_putl(s, ipa_len); /* IP address length */ | |
717 | if (ipa_len) | |
718 | stream_put(s, &ip->ip.addr, ipa_len); /* IP address */ | |
719 | } else | |
720 | stream_putl(s, 0); /* Just MAC. */ | |
721 | ||
1a98c087 | 722 | stream_putc(s, flags); /* sticky mac/gateway mac */ |
d62a17ae | 723 | |
724 | /* Write packet size. */ | |
725 | stream_putw_at(s, 0, stream_get_endp(s)); | |
726 | ||
727 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1a98c087 MK |
728 | zlog_debug( |
729 | "%u:Send MACIP %s flags 0x%x MAC %s IP %s VNI %u to %s", | |
730 | zvrf_id(zvrf), (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", | |
731 | flags, prefix_mac2str(macaddr, buf, sizeof(buf)), | |
732 | ipaddr2str(ip, buf2, sizeof(buf2)), vni, | |
733 | zebra_route_string(client->proto)); | |
d62a17ae | 734 | |
735 | if (cmd == ZEBRA_MACIP_ADD) | |
736 | client->macipadd_cnt++; | |
737 | else | |
738 | client->macipdel_cnt++; | |
739 | ||
740 | return zebra_server_send_message(client); | |
2232a77c | 741 | } |
742 | ||
743 | /* | |
744 | * Make hash key for neighbors. | |
13d60d35 | 745 | */ |
d62a17ae | 746 | static unsigned int neigh_hash_keymake(void *p) |
13d60d35 | 747 | { |
d62a17ae | 748 | zebra_neigh_t *n = p; |
749 | struct ipaddr *ip = &n->ip; | |
13d60d35 | 750 | |
d62a17ae | 751 | if (IS_IPADDR_V4(ip)) |
752 | return jhash_1word(ip->ipaddr_v4.s_addr, 0); | |
2232a77c | 753 | |
d62a17ae | 754 | return jhash2(ip->ipaddr_v6.s6_addr32, |
755 | ZEBRA_NUM_OF(ip->ipaddr_v6.s6_addr32), 0); | |
13d60d35 | 756 | } |
757 | ||
758 | /* | |
2232a77c | 759 | * Compare two neighbor hash structures. |
13d60d35 | 760 | */ |
d62a17ae | 761 | static int neigh_cmp(const void *p1, const void *p2) |
13d60d35 | 762 | { |
d62a17ae | 763 | const zebra_neigh_t *n1 = p1; |
764 | const zebra_neigh_t *n2 = p2; | |
13d60d35 | 765 | |
d62a17ae | 766 | if (n1 == NULL && n2 == NULL) |
767 | return 1; | |
2232a77c | 768 | |
d62a17ae | 769 | if (n1 == NULL || n2 == NULL) |
770 | return 0; | |
2232a77c | 771 | |
d62a17ae | 772 | return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0); |
13d60d35 | 773 | } |
774 | ||
775 | /* | |
2232a77c | 776 | * Callback to allocate neighbor hash entry. |
13d60d35 | 777 | */ |
d62a17ae | 778 | static void *zvni_neigh_alloc(void *p) |
13d60d35 | 779 | { |
d62a17ae | 780 | const zebra_neigh_t *tmp_n = p; |
781 | zebra_neigh_t *n; | |
13d60d35 | 782 | |
d62a17ae | 783 | n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t)); |
784 | *n = *tmp_n; | |
2232a77c | 785 | |
d62a17ae | 786 | return ((void *)n); |
13d60d35 | 787 | } |
788 | ||
789 | /* | |
2232a77c | 790 | * Add neighbor entry. |
13d60d35 | 791 | */ |
d62a17ae | 792 | static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip) |
13d60d35 | 793 | { |
d62a17ae | 794 | zebra_neigh_t tmp_n; |
795 | zebra_neigh_t *n = NULL; | |
13d60d35 | 796 | |
d62a17ae | 797 | memset(&tmp_n, 0, sizeof(zebra_neigh_t)); |
798 | memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr)); | |
799 | n = hash_get(zvni->neigh_table, &tmp_n, zvni_neigh_alloc); | |
800 | assert(n); | |
13d60d35 | 801 | |
d62a17ae | 802 | return n; |
13d60d35 | 803 | } |
804 | ||
805 | /* | |
2232a77c | 806 | * Delete neighbor entry. |
13d60d35 | 807 | */ |
d62a17ae | 808 | static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n) |
13d60d35 | 809 | { |
d62a17ae | 810 | zebra_neigh_t *tmp_n; |
13d60d35 | 811 | |
d62a17ae | 812 | /* Free the VNI hash entry and allocated memory. */ |
813 | tmp_n = hash_release(zvni->neigh_table, n); | |
814 | if (tmp_n) | |
815 | XFREE(MTYPE_NEIGH, tmp_n); | |
13d60d35 | 816 | |
d62a17ae | 817 | return 0; |
13d60d35 | 818 | } |
819 | ||
820 | /* | |
2232a77c | 821 | * Free neighbor hash entry (callback) |
13d60d35 | 822 | */ |
d62a17ae | 823 | static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg) |
13d60d35 | 824 | { |
d62a17ae | 825 | struct neigh_walk_ctx *wctx = arg; |
826 | zebra_neigh_t *n = backet->data; | |
2232a77c | 827 | |
d62a17ae | 828 | if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL)) |
829 | || ((wctx->flags & DEL_REMOTE_NEIGH) | |
830 | && (n->flags & ZEBRA_NEIGH_REMOTE)) | |
831 | || ((wctx->flags & DEL_REMOTE_NEIGH_FROM_VTEP) | |
832 | && (n->flags & ZEBRA_NEIGH_REMOTE) | |
833 | && IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) { | |
834 | if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL)) | |
1a98c087 MK |
835 | zvni_neigh_send_del_to_client(wctx->zvrf, |
836 | wctx->zvni->vni, &n->ip, | |
837 | &n->emac, 0); | |
13d60d35 | 838 | |
d62a17ae | 839 | if (wctx->uninstall) |
840 | zvni_neigh_uninstall(wctx->zvni, n); | |
13d60d35 | 841 | |
d62a17ae | 842 | return zvni_neigh_del(wctx->zvni, n); |
843 | } | |
13d60d35 | 844 | |
d62a17ae | 845 | return 0; |
13d60d35 | 846 | } |
847 | ||
848 | /* | |
2232a77c | 849 | * Delete all neighbor entries from specific VTEP for a particular VNI. |
13d60d35 | 850 | */ |
d62a17ae | 851 | static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall, |
852 | struct in_addr *r_vtep_ip) | |
13d60d35 | 853 | { |
d62a17ae | 854 | struct neigh_walk_ctx wctx; |
13d60d35 | 855 | |
d62a17ae | 856 | if (!zvni->neigh_table) |
857 | return; | |
13d60d35 | 858 | |
d62a17ae | 859 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); |
860 | wctx.zvni = zvni; | |
861 | wctx.uninstall = uninstall; | |
862 | wctx.flags = DEL_REMOTE_NEIGH_FROM_VTEP; | |
863 | wctx.r_vtep_ip = *r_vtep_ip; | |
13d60d35 | 864 | |
d62a17ae | 865 | hash_iterate(zvni->neigh_table, |
866 | (void (*)(struct hash_backet *, | |
867 | void *))zvni_neigh_del_hash_entry, | |
868 | &wctx); | |
2232a77c | 869 | } |
13d60d35 | 870 | |
2232a77c | 871 | /* |
872 | * Delete all neighbor entries for this VNI. | |
873 | */ | |
d62a17ae | 874 | static void zvni_neigh_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni, |
875 | int uninstall, int upd_client, u_int32_t flags) | |
2232a77c | 876 | { |
d62a17ae | 877 | struct neigh_walk_ctx wctx; |
13d60d35 | 878 | |
d62a17ae | 879 | if (!zvni->neigh_table) |
880 | return; | |
13d60d35 | 881 | |
d62a17ae | 882 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); |
883 | wctx.zvni = zvni; | |
884 | wctx.zvrf = zvrf; | |
885 | wctx.uninstall = uninstall; | |
886 | wctx.upd_client = upd_client; | |
887 | wctx.flags = flags; | |
2232a77c | 888 | |
d62a17ae | 889 | hash_iterate(zvni->neigh_table, |
890 | (void (*)(struct hash_backet *, | |
891 | void *))zvni_neigh_del_hash_entry, | |
892 | &wctx); | |
13d60d35 | 893 | } |
894 | ||
895 | /* | |
2232a77c | 896 | * Look up neighbor hash entry. |
897 | */ | |
d62a17ae | 898 | static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip) |
2232a77c | 899 | { |
d62a17ae | 900 | zebra_neigh_t tmp; |
901 | zebra_neigh_t *n; | |
2232a77c | 902 | |
d62a17ae | 903 | memset(&tmp, 0, sizeof(tmp)); |
904 | memcpy(&tmp.ip, ip, sizeof(struct ipaddr)); | |
905 | n = hash_lookup(zvni->neigh_table, &tmp); | |
2232a77c | 906 | |
d62a17ae | 907 | return n; |
2232a77c | 908 | } |
909 | ||
910 | /* | |
911 | * Inform BGP about local neighbor addition. | |
13d60d35 | 912 | */ |
d62a17ae | 913 | static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, |
914 | struct ipaddr *ip, | |
1a98c087 | 915 | struct ethaddr *macaddr, u_char flags) |
13d60d35 | 916 | { |
1a98c087 | 917 | return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, flags, |
d62a17ae | 918 | ZEBRA_MACIP_ADD); |
2232a77c | 919 | } |
13d60d35 | 920 | |
2232a77c | 921 | /* |
922 | * Inform BGP about local neighbor deletion. | |
923 | */ | |
d62a17ae | 924 | static int zvni_neigh_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni, |
925 | struct ipaddr *ip, | |
1a98c087 | 926 | struct ethaddr *macaddr, u_char flags) |
2232a77c | 927 | { |
1a98c087 | 928 | return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, flags, |
d62a17ae | 929 | ZEBRA_MACIP_DEL); |
2232a77c | 930 | } |
931 | ||
932 | /* | |
933 | * Install remote neighbor into the kernel. | |
934 | */ | |
d62a17ae | 935 | static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n) |
2232a77c | 936 | { |
d62a17ae | 937 | struct zebra_vrf *zvrf; |
938 | struct zebra_if *zif; | |
939 | struct zebra_l2info_vxlan *vxl; | |
940 | struct interface *vlan_if; | |
2232a77c | 941 | |
d62a17ae | 942 | if (!(n->flags & ZEBRA_NEIGH_REMOTE)) |
943 | return 0; | |
13d60d35 | 944 | |
d62a17ae | 945 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); |
946 | assert(zvrf); | |
947 | zif = zvni->vxlan_if->info; | |
948 | if (!zif) | |
949 | return -1; | |
950 | vxl = &zif->l2info.vxl; | |
13d60d35 | 951 | |
d62a17ae | 952 | vlan_if = zvni_map_to_svi(zvrf, vxl->access_vlan, |
953 | zif->brslave_info.br_if); | |
954 | if (!vlan_if) | |
955 | return -1; | |
13d60d35 | 956 | |
d62a17ae | 957 | return kernel_add_neigh(vlan_if, &n->ip, &n->emac); |
2232a77c | 958 | } |
13d60d35 | 959 | |
2232a77c | 960 | /* |
961 | * Uninstall remote neighbor from the kernel. | |
962 | */ | |
d62a17ae | 963 | static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n) |
2232a77c | 964 | { |
d62a17ae | 965 | struct zebra_vrf *zvrf; |
966 | struct zebra_if *zif; | |
967 | struct zebra_l2info_vxlan *vxl; | |
968 | struct interface *vlan_if; | |
13d60d35 | 969 | |
d62a17ae | 970 | if (!(n->flags & ZEBRA_NEIGH_REMOTE)) |
971 | return 0; | |
2232a77c | 972 | |
d62a17ae | 973 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); |
974 | assert(zvrf); | |
975 | if (!zvni->vxlan_if) { | |
976 | zlog_err("VNI %u hash %p couldn't be uninstalled - no intf", | |
977 | zvni->vni, zvni); | |
978 | return -1; | |
979 | } | |
2232a77c | 980 | |
d62a17ae | 981 | zif = zvni->vxlan_if->info; |
982 | if (!zif) | |
983 | return -1; | |
984 | vxl = &zif->l2info.vxl; | |
985 | vlan_if = zvni_map_to_svi(zvrf, vxl->access_vlan, | |
986 | zif->brslave_info.br_if); | |
987 | if (!vlan_if) | |
988 | return -1; | |
2232a77c | 989 | |
d62a17ae | 990 | return kernel_del_neigh(vlan_if, &n->ip); |
13d60d35 | 991 | } |
992 | ||
993 | /* | |
2232a77c | 994 | * Install neighbor hash entry - called upon access VLAN change. |
13d60d35 | 995 | */ |
d62a17ae | 996 | static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt) |
13d60d35 | 997 | { |
d62a17ae | 998 | zebra_neigh_t *n; |
999 | struct neigh_walk_ctx *wctx = ctxt; | |
13d60d35 | 1000 | |
d62a17ae | 1001 | n = (zebra_neigh_t *)backet->data; |
1002 | if (!n) | |
1003 | return; | |
13d60d35 | 1004 | |
d62a17ae | 1005 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) |
1006 | zvni_neigh_install(wctx->zvni, n); | |
2232a77c | 1007 | } |
13d60d35 | 1008 | |
1a98c087 MK |
1009 | /* Get the VRR interface for SVI if any */ |
1010 | struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp) | |
1011 | { | |
1012 | struct zebra_vrf *zvrf = NULL; | |
1013 | struct interface *tmp_if = NULL; | |
1014 | struct zebra_if *zif = NULL; | |
1015 | struct listnode *node; | |
1016 | ||
1017 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
1018 | assert(zvrf); | |
1019 | ||
1020 | for (ALL_LIST_ELEMENTS_RO(vrf_iflist(zvrf_id(zvrf)), node, tmp_if)) { | |
1021 | zif = tmp_if->info; | |
1022 | if (!zif) | |
1023 | continue; | |
1024 | ||
1025 | if (!IS_ZEBRA_IF_MACVLAN(tmp_if)) | |
1026 | continue; | |
1027 | ||
1028 | if (zif->link == ifp) | |
1029 | return tmp_if; | |
1030 | } | |
1031 | ||
1032 | return NULL; | |
1033 | } | |
1034 | ||
1035 | static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni) | |
1036 | { | |
1037 | struct zebra_vrf *zvrf = NULL; | |
1038 | struct listnode *cnode = NULL, *cnnode = NULL; | |
1039 | struct connected *c = NULL; | |
1040 | struct ethaddr macaddr; | |
1041 | ||
1042 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); | |
1043 | if (!zvrf) | |
1044 | return -1; | |
1045 | ||
1046 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); | |
1047 | ||
1048 | for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { | |
1049 | struct ipaddr ip; | |
1050 | ||
1051 | memset(&ip, 0, sizeof(struct ipaddr)); | |
1052 | if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) | |
1053 | continue; | |
1054 | ||
1055 | if (c->address->family == AF_INET) { | |
1056 | ip.ipa_type = IPADDR_V4; | |
1057 | memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), | |
1058 | sizeof(struct in_addr)); | |
1059 | } else if (c->address->family == AF_INET6) { | |
1060 | ip.ipa_type = IPADDR_V6; | |
1061 | memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6), | |
1062 | sizeof(struct in6_addr)); | |
1063 | } else { | |
1064 | continue; | |
1065 | } | |
1066 | ||
1067 | zvni_gw_macip_del(ifp, zvni, &ip); | |
1068 | } | |
1069 | ||
1070 | return 0; | |
1071 | } | |
1072 | ||
1073 | static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni) | |
1074 | { | |
1075 | struct zebra_vrf *zvrf = NULL; | |
1076 | struct listnode *cnode = NULL, *cnnode = NULL; | |
1077 | struct connected *c = NULL; | |
1078 | struct ethaddr macaddr; | |
1079 | ||
1080 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); | |
1081 | if (!zvrf) | |
1082 | return -1; | |
1083 | ||
1084 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); | |
1085 | ||
1086 | for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { | |
1087 | struct ipaddr ip; | |
1088 | ||
1089 | memset(&ip, 0, sizeof(struct ipaddr)); | |
1090 | if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) | |
1091 | continue; | |
1092 | ||
1093 | if (c->address->family == AF_INET) { | |
1094 | ip.ipa_type = IPADDR_V4; | |
1095 | memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), | |
1096 | sizeof(struct in_addr)); | |
1097 | } else if (c->address->family == AF_INET6) { | |
1098 | ip.ipa_type = IPADDR_V6; | |
1099 | memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6), | |
1100 | sizeof(struct in6_addr)); | |
1101 | } else { | |
1102 | continue; | |
1103 | } | |
1104 | ||
1105 | zvni_gw_macip_add(ifp, zvni, &macaddr, &ip); | |
1106 | } | |
1107 | ||
1108 | return 0; | |
1109 | } | |
1110 | ||
1111 | /* | |
1112 | * zvni_gw_macip_add_to_client | |
1113 | */ | |
1114 | static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, | |
1115 | struct ethaddr *macaddr, struct ipaddr *ip) | |
1116 | { | |
1117 | struct zebra_vrf *zvrf = NULL; | |
1118 | struct zebra_if *zif = NULL; | |
1119 | struct zebra_l2info_vxlan *vxl = NULL; | |
1120 | zebra_neigh_t *n = NULL; | |
1121 | zebra_mac_t *mac = NULL; | |
1122 | char buf[ETHER_ADDR_STRLEN]; | |
1123 | char buf2[INET6_ADDRSTRLEN]; | |
1124 | ||
1125 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); | |
1126 | if (!zvrf) | |
1127 | return -1; | |
1128 | ||
1129 | zif = zvni->vxlan_if->info; | |
1130 | if (!zif) | |
1131 | return -1; | |
1132 | ||
1133 | vxl = &zif->l2info.vxl; | |
1134 | ||
1135 | mac = zvni_mac_lookup(zvni, macaddr); | |
1136 | if (!mac) { | |
1137 | mac = zvni_mac_add(zvni, macaddr); | |
1138 | if (!mac) { | |
1139 | zlog_err("%u:Failed to add MAC %s intf %s(%u) VID %u", | |
1140 | ifp->vrf_id, | |
1141 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
1142 | ifp->name, ifp->ifindex, vxl->access_vlan); | |
1143 | return -1; | |
1144 | } | |
1145 | } | |
1146 | ||
1147 | /* Set "local" forwarding info. */ | |
1148 | SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); | |
1149 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
1150 | memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); | |
1151 | mac->fwd_info.local.ifindex = ifp->ifindex; | |
1152 | mac->fwd_info.local.vid = vxl->access_vlan; | |
1153 | ||
1154 | n = zvni_neigh_lookup(zvni, ip); | |
1155 | if (!n) { | |
1156 | n = zvni_neigh_add(zvni, ip); | |
1157 | if (!n) { | |
1158 | zlog_err( | |
1159 | "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", | |
1160 | ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)), | |
1161 | prefix_mac2str(macaddr, NULL, | |
1162 | ETHER_ADDR_STRLEN), | |
1163 | ifp->name, ifp->ifindex, zvni->vni); | |
1164 | return -1; | |
1165 | } | |
1166 | } | |
1167 | ||
1168 | /* Set "local" forwarding info. */ | |
1169 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
1170 | memcpy(&n->emac, macaddr, ETH_ALEN); | |
1171 | n->ifindex = ifp->ifindex; | |
1172 | ||
1173 | /* We have a neigh associated to mac increment the refcnt*/ | |
1174 | mac->neigh_refcnt++; | |
1175 | ||
1176 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1177 | zlog_debug( | |
1178 | "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s add to BGP", | |
1179 | ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni, | |
1180 | prefix_mac2str(macaddr, NULL, ETHER_ADDR_STRLEN), | |
1181 | ipaddr2str(ip, buf2, sizeof(buf2))); | |
1182 | ||
1183 | zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, macaddr, | |
1184 | ZEBRA_MAC_TYPE_GW); | |
1185 | ||
1186 | return 0; | |
1187 | } | |
1188 | ||
1189 | /* | |
1190 | * zvni_gw_macip_del_from_client | |
1191 | */ | |
1192 | static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, | |
1193 | struct ipaddr *ip) | |
1194 | { | |
1195 | struct zebra_vrf *zvrf = NULL; | |
1196 | zebra_neigh_t *n = NULL; | |
1197 | zebra_mac_t *mac = NULL; | |
1198 | char buf2[INET6_ADDRSTRLEN]; | |
1199 | ||
1200 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); | |
1201 | if (!zvrf) | |
1202 | return -1; | |
1203 | ||
1204 | /* If the neigh entry is not present nothing to do*/ | |
1205 | n = zvni_neigh_lookup(zvni, ip); | |
1206 | if (!n) | |
1207 | return 0; | |
1208 | ||
1209 | /* mac entry should be present */ | |
1210 | mac = zvni_mac_lookup(zvni, &n->emac); | |
1211 | if (!mac) | |
1212 | zlog_err("%u: MAC %s doesnt exsists for neigh %s on VNI %u", | |
1213 | ifp->vrf_id, | |
1214 | prefix_mac2str(&n->emac, NULL, ETHER_ADDR_STRLEN), | |
1215 | ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni); | |
1216 | ||
1217 | /* If the entry is not local nothing to do*/ | |
1218 | if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) | |
1219 | return -1; | |
1220 | ||
1221 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1222 | zlog_debug( | |
1223 | "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", | |
1224 | ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni, | |
1225 | prefix_mac2str(&(n->emac), NULL, ETHER_ADDR_STRLEN), | |
1226 | ipaddr2str(ip, buf2, sizeof(buf2))); | |
1227 | ||
1228 | /* Remove neighbor from BGP. */ | |
1229 | zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, | |
1230 | ZEBRA_MAC_TYPE_GW); | |
1231 | ||
1232 | /* Delete this neighbor entry. */ | |
1233 | zvni_neigh_del(zvni, n); | |
1234 | ||
1235 | /* see if the mac needs to be deleted as well*/ | |
1236 | zvni_deref_ip2mac(zvni, mac, 0); | |
1237 | ||
1238 | return 0; | |
1239 | } | |
1240 | ||
1241 | static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, | |
1242 | void *zvrf) | |
1243 | { | |
1244 | zebra_vni_t *zvni = NULL; | |
1245 | struct zebra_if *zif = NULL; | |
1246 | struct zebra_l2info_vxlan zl2_info; | |
1247 | struct interface *vlan_if = NULL; | |
1248 | struct interface *vrr_if = NULL; | |
1249 | ||
1250 | /* Add primary SVI MAC*/ | |
1251 | zvni = (zebra_vni_t *)backet->data; | |
1252 | if (!zvni) | |
1253 | return; | |
1254 | ||
1255 | zif = zvni->vxlan_if->info; | |
1256 | zl2_info = zif->l2info.vxl; | |
1257 | ||
1258 | vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan, | |
1259 | zif->brslave_info.br_if); | |
1260 | if (!vlan_if) | |
1261 | return; | |
1262 | ||
1263 | /* Del primary MAC-IP */ | |
1264 | zvni_del_macip_for_intf(vlan_if, zvni); | |
1265 | ||
1266 | /* Del VRR MAC-IP - if any*/ | |
1267 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
1268 | if (vrr_if) | |
1269 | zvni_del_macip_for_intf(vrr_if, zvni); | |
1270 | ||
1271 | return; | |
1272 | } | |
1273 | ||
1274 | static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, | |
1275 | void *zvrf) | |
1276 | { | |
1277 | zebra_vni_t *zvni = NULL; | |
1278 | struct zebra_if *zif = NULL; | |
1279 | struct zebra_l2info_vxlan zl2_info; | |
1280 | struct interface *vlan_if = NULL; | |
1281 | struct interface *vrr_if = NULL; | |
1282 | ||
1283 | zvni = (zebra_vni_t *)backet->data; | |
1284 | if (!zvni) | |
1285 | return; | |
1286 | ||
1287 | if (!advertise_gw_macip_enabled(zvrf, zvni)) | |
1288 | return; | |
1289 | ||
1290 | zif = zvni->vxlan_if->info; | |
1291 | zl2_info = zif->l2info.vxl; | |
1292 | ||
1293 | vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan, | |
1294 | zif->brslave_info.br_if); | |
1295 | if (!vlan_if) | |
1296 | return; | |
1297 | ||
1298 | if (!advertise_gw_macip_enabled(zvrf, zvni)) | |
1299 | return; | |
1300 | ||
1301 | /* Add primary SVI MAC-IP */ | |
1302 | zvni_add_macip_for_intf(vlan_if, zvni); | |
1303 | ||
1304 | /* Add VRR MAC-IP - if any*/ | |
1305 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
1306 | if (vrr_if) | |
1307 | zvni_add_macip_for_intf(vrr_if, zvni); | |
1308 | ||
1309 | return; | |
1310 | } | |
1311 | ||
2232a77c | 1312 | /* |
1313 | * Make hash key for MAC. | |
1314 | */ | |
d62a17ae | 1315 | static unsigned int mac_hash_keymake(void *p) |
2232a77c | 1316 | { |
d62a17ae | 1317 | zebra_mac_t *pmac = p; |
25331def DS |
1318 | const void *pnt = (void *)pmac->macaddr.octet; |
1319 | ||
ff8b7eb8 | 1320 | return jhash(pnt, ETH_ALEN, 0xa5a5a55a); |
2232a77c | 1321 | } |
13d60d35 | 1322 | |
2232a77c | 1323 | /* |
1324 | * Compare two MAC addresses. | |
1325 | */ | |
d62a17ae | 1326 | static int mac_cmp(const void *p1, const void *p2) |
2232a77c | 1327 | { |
d62a17ae | 1328 | const zebra_mac_t *pmac1 = p1; |
1329 | const zebra_mac_t *pmac2 = p2; | |
2232a77c | 1330 | |
d62a17ae | 1331 | if (pmac1 == NULL && pmac2 == NULL) |
1332 | return 1; | |
2232a77c | 1333 | |
d62a17ae | 1334 | if (pmac1 == NULL || pmac2 == NULL) |
1335 | return 0; | |
2232a77c | 1336 | |
d62a17ae | 1337 | return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, |
ff8b7eb8 | 1338 | ETH_ALEN) |
d62a17ae | 1339 | == 0); |
2232a77c | 1340 | } |
1341 | ||
1342 | /* | |
1343 | * Callback to allocate MAC hash entry. | |
1344 | */ | |
d62a17ae | 1345 | static void *zvni_mac_alloc(void *p) |
2232a77c | 1346 | { |
d62a17ae | 1347 | const zebra_mac_t *tmp_mac = p; |
1348 | zebra_mac_t *mac; | |
2232a77c | 1349 | |
d62a17ae | 1350 | mac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t)); |
1351 | *mac = *tmp_mac; | |
2232a77c | 1352 | |
d62a17ae | 1353 | return ((void *)mac); |
2232a77c | 1354 | } |
1355 | ||
1356 | /* | |
1357 | * Add MAC entry. | |
1358 | */ | |
d62a17ae | 1359 | static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr) |
2232a77c | 1360 | { |
d62a17ae | 1361 | zebra_mac_t tmp_mac; |
1362 | zebra_mac_t *mac = NULL; | |
2232a77c | 1363 | |
d62a17ae | 1364 | memset(&tmp_mac, 0, sizeof(zebra_mac_t)); |
ff8b7eb8 | 1365 | memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN); |
d62a17ae | 1366 | mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc); |
1367 | assert(mac); | |
2232a77c | 1368 | |
d62a17ae | 1369 | return mac; |
2232a77c | 1370 | } |
1371 | ||
1372 | /* | |
1373 | * Delete MAC entry. | |
1374 | */ | |
d62a17ae | 1375 | static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) |
2232a77c | 1376 | { |
d62a17ae | 1377 | zebra_mac_t *tmp_mac; |
2232a77c | 1378 | |
d62a17ae | 1379 | /* Free the VNI hash entry and allocated memory. */ |
1380 | tmp_mac = hash_release(zvni->mac_table, mac); | |
1381 | if (tmp_mac) | |
1382 | XFREE(MTYPE_MAC, tmp_mac); | |
2232a77c | 1383 | |
d62a17ae | 1384 | return 0; |
2232a77c | 1385 | } |
1386 | ||
1387 | /* | |
1388 | * Free MAC hash entry (callback) | |
1389 | */ | |
d62a17ae | 1390 | static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) |
2232a77c | 1391 | { |
d62a17ae | 1392 | struct mac_walk_ctx *wctx = arg; |
1393 | zebra_mac_t *mac = backet->data; | |
1394 | u_char sticky = 0; | |
2232a77c | 1395 | |
d62a17ae | 1396 | if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) |
1397 | || ((wctx->flags & DEL_REMOTE_MAC) | |
1398 | && (mac->flags & ZEBRA_MAC_REMOTE)) | |
1399 | || ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) | |
1400 | && (mac->flags & ZEBRA_MAC_REMOTE) | |
1401 | && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, | |
1402 | &wctx->r_vtep_ip))) { | |
1403 | if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { | |
1404 | sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 | |
1405 | : 0; | |
1a98c087 MK |
1406 | zvni_mac_send_del_to_client( |
1407 | wctx->zvrf, wctx->zvni->vni, &mac->macaddr, | |
1408 | (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); | |
d62a17ae | 1409 | } |
2232a77c | 1410 | |
d62a17ae | 1411 | if (wctx->uninstall) |
1412 | zvni_mac_uninstall(wctx->zvni, mac, 0); | |
2232a77c | 1413 | |
d62a17ae | 1414 | return zvni_mac_del(wctx->zvni, mac); |
1415 | } | |
2232a77c | 1416 | |
d62a17ae | 1417 | return 0; |
2232a77c | 1418 | } |
1419 | ||
1420 | /* | |
1421 | * Delete all MAC entries from specific VTEP for a particular VNI. | |
1422 | */ | |
d62a17ae | 1423 | static void zvni_mac_del_from_vtep(zebra_vni_t *zvni, int uninstall, |
1424 | struct in_addr *r_vtep_ip) | |
2232a77c | 1425 | { |
d62a17ae | 1426 | struct mac_walk_ctx wctx; |
2232a77c | 1427 | |
d62a17ae | 1428 | if (!zvni->mac_table) |
1429 | return; | |
2232a77c | 1430 | |
d62a17ae | 1431 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
1432 | wctx.zvni = zvni; | |
1433 | wctx.uninstall = uninstall; | |
1434 | wctx.flags = DEL_REMOTE_MAC_FROM_VTEP; | |
1435 | wctx.r_vtep_ip = *r_vtep_ip; | |
2232a77c | 1436 | |
9d303b37 DL |
1437 | hash_iterate(zvni->mac_table, (void (*)(struct hash_backet *, |
1438 | void *))zvni_mac_del_hash_entry, | |
1439 | &wctx); | |
2232a77c | 1440 | } |
1441 | ||
1442 | /* | |
1443 | * Delete all MAC entries for this VNI. | |
1444 | */ | |
d62a17ae | 1445 | static void zvni_mac_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni, |
1446 | int uninstall, int upd_client, u_int32_t flags) | |
2232a77c | 1447 | { |
d62a17ae | 1448 | struct mac_walk_ctx wctx; |
2232a77c | 1449 | |
d62a17ae | 1450 | if (!zvni->mac_table) |
1451 | return; | |
2232a77c | 1452 | |
d62a17ae | 1453 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
1454 | wctx.zvni = zvni; | |
1455 | wctx.zvrf = zvrf; | |
1456 | wctx.uninstall = uninstall; | |
1457 | wctx.upd_client = upd_client; | |
1458 | wctx.flags = flags; | |
2232a77c | 1459 | |
9d303b37 DL |
1460 | hash_iterate(zvni->mac_table, (void (*)(struct hash_backet *, |
1461 | void *))zvni_mac_del_hash_entry, | |
1462 | &wctx); | |
2232a77c | 1463 | } |
1464 | ||
1465 | /* | |
1466 | * Look up MAC hash entry. | |
1467 | */ | |
d62a17ae | 1468 | static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac) |
2232a77c | 1469 | { |
d62a17ae | 1470 | zebra_mac_t tmp; |
1471 | zebra_mac_t *pmac; | |
2232a77c | 1472 | |
d62a17ae | 1473 | memset(&tmp, 0, sizeof(tmp)); |
ff8b7eb8 | 1474 | memcpy(&tmp.macaddr, mac, ETH_ALEN); |
d62a17ae | 1475 | pmac = hash_lookup(zvni->mac_table, &tmp); |
2232a77c | 1476 | |
d62a17ae | 1477 | return pmac; |
2232a77c | 1478 | } |
1479 | ||
1480 | /* | |
1481 | * Inform BGP about local MAC addition. | |
1482 | */ | |
d62a17ae | 1483 | static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, |
1a98c087 | 1484 | struct ethaddr *macaddr, u_char flags) |
2232a77c | 1485 | { |
1a98c087 | 1486 | return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, flags, |
d62a17ae | 1487 | ZEBRA_MACIP_ADD); |
2232a77c | 1488 | } |
1489 | ||
1490 | /* | |
1491 | * Inform BGP about local MAC deletion. | |
1492 | */ | |
d62a17ae | 1493 | static int zvni_mac_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni, |
1a98c087 | 1494 | struct ethaddr *macaddr, u_char flags) |
2232a77c | 1495 | { |
1a98c087 | 1496 | return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, flags, |
d62a17ae | 1497 | ZEBRA_MACIP_DEL); |
2232a77c | 1498 | } |
1499 | ||
1500 | /* | |
1501 | * Map port or (port, VLAN) to a VNI. This is invoked upon getting MAC | |
1502 | * notifications, to see if there are of interest. | |
1503 | * TODO: Need to make this as a hash table. | |
1504 | */ | |
d62a17ae | 1505 | static zebra_vni_t *zvni_map_vlan(struct interface *ifp, |
1506 | struct interface *br_if, vlanid_t vid) | |
2232a77c | 1507 | { |
d62a17ae | 1508 | struct zebra_vrf *zvrf; |
1509 | struct listnode *node; | |
1510 | struct interface *tmp_if; | |
1511 | struct zebra_if *zif; | |
1512 | struct zebra_l2info_bridge *br; | |
1513 | struct zebra_l2info_vxlan *vxl; | |
1514 | u_char bridge_vlan_aware; | |
1515 | zebra_vni_t *zvni; | |
2232a77c | 1516 | |
d62a17ae | 1517 | /* Locate VRF corresponding to interface. */ |
1518 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
1519 | assert(zvrf); | |
2232a77c | 1520 | |
d62a17ae | 1521 | /* Determine if bridge is VLAN-aware or not */ |
1522 | zif = br_if->info; | |
1523 | assert(zif); | |
1524 | br = &zif->l2info.br; | |
1525 | bridge_vlan_aware = br->vlan_aware; | |
2232a77c | 1526 | |
d62a17ae | 1527 | /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ |
1528 | /* TODO: Optimize with a hash. */ | |
1529 | for (ALL_LIST_ELEMENTS_RO(vrf_iflist(zvrf_id(zvrf)), node, tmp_if)) { | |
1530 | zif = tmp_if->info; | |
1531 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
1532 | continue; | |
1533 | if (!if_is_operative(tmp_if)) | |
1534 | continue; | |
1535 | vxl = &zif->l2info.vxl; | |
2232a77c | 1536 | |
d62a17ae | 1537 | if (zif->brslave_info.br_if != br_if) |
1538 | continue; | |
2232a77c | 1539 | |
d62a17ae | 1540 | if (!bridge_vlan_aware) |
1541 | break; | |
2232a77c | 1542 | |
d62a17ae | 1543 | if (vxl->access_vlan == vid) |
1544 | break; | |
1545 | } | |
2232a77c | 1546 | |
d62a17ae | 1547 | if (!tmp_if) |
1548 | return NULL; | |
2232a77c | 1549 | |
d62a17ae | 1550 | zvni = zvni_lookup(zvrf, vxl->vni); |
1551 | return zvni; | |
2232a77c | 1552 | } |
1553 | ||
1554 | /* | |
1555 | * Map SVI and associated bridge to a VNI. This is invoked upon getting | |
1556 | * neighbor notifications, to see if they are of interest. | |
1557 | * TODO: Need to make this as a hash table. | |
1558 | */ | |
d62a17ae | 1559 | static zebra_vni_t *zvni_map_svi(struct interface *ifp, struct interface *br_if) |
1560 | { | |
1561 | struct zebra_vrf *zvrf; | |
1562 | struct listnode *node; | |
1563 | struct interface *tmp_if; | |
1564 | struct zebra_if *zif; | |
1565 | struct zebra_l2info_bridge *br; | |
1566 | struct zebra_l2info_vxlan *vxl; | |
1567 | u_char bridge_vlan_aware; | |
1568 | vlanid_t vid = 0; | |
1569 | zebra_vni_t *zvni; | |
1570 | ||
1571 | /* Make sure the linked interface is a bridge. */ | |
1572 | if (!IS_ZEBRA_IF_BRIDGE(br_if)) | |
1573 | return NULL; | |
1574 | ||
1575 | /* Locate VRF corresponding to interface. */ | |
1576 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
1577 | assert(zvrf); | |
1578 | ||
1579 | /* Determine if bridge is VLAN-aware or not */ | |
1580 | zif = br_if->info; | |
1581 | assert(zif); | |
1582 | br = &zif->l2info.br; | |
1583 | bridge_vlan_aware = br->vlan_aware; | |
1584 | if (bridge_vlan_aware) { | |
1585 | struct zebra_l2info_vlan *vl; | |
1586 | ||
1587 | if (!IS_ZEBRA_IF_VLAN(ifp)) | |
1588 | return NULL; | |
1589 | ||
1590 | zif = ifp->info; | |
1591 | assert(zif); | |
1592 | vl = &zif->l2info.vl; | |
1593 | vid = vl->vid; | |
1594 | } | |
1595 | ||
1596 | /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ | |
1597 | /* TODO: Optimize with a hash. */ | |
1598 | for (ALL_LIST_ELEMENTS_RO(vrf_iflist(zvrf_id(zvrf)), node, tmp_if)) { | |
1599 | zif = tmp_if->info; | |
1600 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
1601 | continue; | |
1602 | if (!if_is_operative(tmp_if)) | |
1603 | continue; | |
1604 | vxl = &zif->l2info.vxl; | |
1605 | ||
1606 | if (zif->brslave_info.br_if != br_if) | |
1607 | continue; | |
1608 | ||
1609 | if (!bridge_vlan_aware) | |
1610 | break; | |
1611 | ||
1612 | if (vxl->access_vlan == vid) | |
1613 | break; | |
1614 | } | |
1615 | ||
1616 | if (!tmp_if) | |
1617 | return NULL; | |
1618 | ||
1619 | zvni = zvni_lookup(zvrf, vxl->vni); | |
1620 | return zvni; | |
2232a77c | 1621 | } |
1622 | ||
1623 | /* Map to SVI on bridge corresponding to specified VLAN. This can be one | |
1624 | * of two cases: | |
1625 | * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface | |
1626 | * linked to the bridge | |
1627 | * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface | |
1628 | * itself | |
1629 | */ | |
d62a17ae | 1630 | static struct interface *zvni_map_to_svi(struct zebra_vrf *zvrf, vlanid_t vid, |
1631 | struct interface *br_if) | |
1632 | { | |
1633 | struct listnode *node; | |
1634 | struct interface *tmp_if; | |
1635 | struct zebra_if *zif; | |
1636 | struct zebra_l2info_bridge *br; | |
1637 | struct zebra_l2info_vlan *vl; | |
1638 | u_char bridge_vlan_aware; | |
1639 | ||
1640 | /* Determine if bridge is VLAN-aware or not */ | |
1641 | zif = br_if->info; | |
1642 | assert(zif); | |
1643 | br = &zif->l2info.br; | |
1644 | bridge_vlan_aware = br->vlan_aware; | |
1645 | ||
1646 | /* Check oper status of the SVI. */ | |
1647 | if (!bridge_vlan_aware) | |
1648 | return if_is_operative(br_if) ? br_if : NULL; | |
1649 | ||
1650 | /* Identify corresponding VLAN interface. */ | |
1651 | /* TODO: Optimize with a hash. */ | |
1652 | for (ALL_LIST_ELEMENTS_RO(vrf_iflist(zvrf_id(zvrf)), node, tmp_if)) { | |
1653 | /* Check oper status of the SVI. */ | |
1654 | if (!if_is_operative(tmp_if)) | |
1655 | continue; | |
1656 | zif = tmp_if->info; | |
1657 | if (!zif || zif->zif_type != ZEBRA_IF_VLAN | |
1658 | || zif->link != br_if) | |
1659 | continue; | |
1660 | vl = (struct zebra_l2info_vlan *)&zif->l2info.vl; | |
1661 | ||
1662 | if (vl->vid == vid) | |
1663 | break; | |
1664 | } | |
1665 | ||
1666 | return tmp_if; | |
2232a77c | 1667 | } |
1668 | ||
1669 | /* | |
1670 | * Install remote MAC into the kernel. | |
1671 | */ | |
d62a17ae | 1672 | static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) |
2232a77c | 1673 | { |
d62a17ae | 1674 | struct zebra_if *zif; |
1675 | struct zebra_l2info_vxlan *vxl; | |
1676 | u_char sticky; | |
2232a77c | 1677 | |
d62a17ae | 1678 | if (!(mac->flags & ZEBRA_MAC_REMOTE)) |
1679 | return 0; | |
2232a77c | 1680 | |
d62a17ae | 1681 | zif = zvni->vxlan_if->info; |
1682 | if (!zif) | |
1683 | return -1; | |
1684 | vxl = &zif->l2info.vxl; | |
2232a77c | 1685 | |
d62a17ae | 1686 | sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; |
c85c03c7 | 1687 | |
d62a17ae | 1688 | return kernel_add_mac(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr, |
1689 | mac->fwd_info.r_vtep_ip, sticky); | |
2232a77c | 1690 | } |
1691 | ||
1692 | /* | |
1693 | * Uninstall remote MAC from the kernel. In the scenario where the MAC | |
1694 | * moves to remote, we have to uninstall any existing local entry first. | |
1695 | */ | |
d62a17ae | 1696 | static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac, int local) |
2232a77c | 1697 | { |
d62a17ae | 1698 | struct zebra_if *zif; |
1699 | struct zebra_l2info_vxlan *vxl; | |
1700 | struct in_addr vtep_ip = {.s_addr = 0}; | |
1701 | struct zebra_ns *zns; | |
1702 | struct interface *ifp; | |
2232a77c | 1703 | |
d62a17ae | 1704 | if (!local && !(mac->flags & ZEBRA_MAC_REMOTE)) |
1705 | return 0; | |
2232a77c | 1706 | |
d62a17ae | 1707 | if (!zvni->vxlan_if) { |
1708 | zlog_err("VNI %u hash %p couldn't be uninstalled - no intf", | |
1709 | zvni->vni, zvni); | |
1710 | return -1; | |
1711 | } | |
2232a77c | 1712 | |
d62a17ae | 1713 | zif = zvni->vxlan_if->info; |
1714 | if (!zif) | |
1715 | return -1; | |
1716 | vxl = &zif->l2info.vxl; | |
2232a77c | 1717 | |
d62a17ae | 1718 | if (local) { |
1719 | zns = zebra_ns_lookup(NS_DEFAULT); | |
1720 | ifp = if_lookup_by_index_per_ns(zns, | |
1721 | mac->fwd_info.local.ifindex); | |
1722 | if (!ifp) // unexpected | |
1723 | return -1; | |
1724 | } else { | |
1725 | ifp = zvni->vxlan_if; | |
1726 | vtep_ip = mac->fwd_info.r_vtep_ip; | |
1727 | } | |
2232a77c | 1728 | |
d62a17ae | 1729 | return kernel_del_mac(ifp, vxl->access_vlan, &mac->macaddr, vtep_ip, |
1730 | local); | |
2232a77c | 1731 | } |
1732 | ||
1733 | /* | |
1734 | * Install MAC hash entry - called upon access VLAN change. | |
1735 | */ | |
d62a17ae | 1736 | static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt) |
2232a77c | 1737 | { |
d62a17ae | 1738 | zebra_mac_t *mac; |
1739 | struct mac_walk_ctx *wctx = ctxt; | |
2232a77c | 1740 | |
d62a17ae | 1741 | mac = (zebra_mac_t *)backet->data; |
1742 | if (!mac) | |
1743 | return; | |
2232a77c | 1744 | |
d62a17ae | 1745 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) |
1746 | zvni_mac_install(wctx->zvni, mac); | |
2232a77c | 1747 | } |
1748 | ||
1749 | /* | |
1750 | * Decrement neighbor refcount of MAC; uninstall and free it if | |
1751 | * appropriate. | |
1752 | */ | |
d62a17ae | 1753 | static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac, |
1754 | int uninstall) | |
2232a77c | 1755 | { |
d62a17ae | 1756 | if (mac->neigh_refcnt) |
1757 | mac->neigh_refcnt--; | |
2232a77c | 1758 | |
d62a17ae | 1759 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) || mac->neigh_refcnt > 0) |
1760 | return; | |
2232a77c | 1761 | |
d62a17ae | 1762 | if (uninstall) |
1763 | zvni_mac_uninstall(zvni, mac, 0); | |
2232a77c | 1764 | |
d62a17ae | 1765 | zvni_mac_del(zvni, mac); |
2232a77c | 1766 | } |
1767 | ||
1768 | /* | |
1769 | * Read and populate local MACs and neighbors corresponding to this VNI. | |
1770 | */ | |
d62a17ae | 1771 | static void zvni_read_mac_neigh(struct zebra_vrf *zvrf, zebra_vni_t *zvni, |
1772 | struct interface *ifp) | |
2232a77c | 1773 | { |
d62a17ae | 1774 | struct zebra_if *zif; |
1775 | struct interface *vlan_if; | |
1776 | struct zebra_l2info_vxlan *vxl; | |
1a98c087 | 1777 | struct interface *vrr_if; |
2232a77c | 1778 | |
d62a17ae | 1779 | zif = ifp->info; |
1780 | vxl = &zif->l2info.vxl; | |
2232a77c | 1781 | |
d62a17ae | 1782 | if (IS_ZEBRA_DEBUG_VXLAN) |
1783 | zlog_debug( | |
1784 | "%u:Reading MAC FDB and Neighbors for intf %s(%u) VNI %u master %u", | |
1785 | ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni, | |
1786 | zif->brslave_info.bridge_ifindex); | |
2232a77c | 1787 | |
d62a17ae | 1788 | macfdb_read_for_bridge(zvrf->zns, ifp, zif->brslave_info.br_if); |
1789 | vlan_if = zvni_map_to_svi(zvrf, vxl->access_vlan, | |
1790 | zif->brslave_info.br_if); | |
1a98c087 MK |
1791 | if (vlan_if) { |
1792 | ||
1793 | if (advertise_gw_macip_enabled(zvrf, zvni)) { | |
1794 | /* Add SVI MAC-IP */ | |
1795 | zvni_add_macip_for_intf(vlan_if, zvni); | |
1796 | ||
1797 | /* Add VRR MAC-IP - if any*/ | |
1798 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
1799 | if (vrr_if) | |
1800 | zvni_add_macip_for_intf(vrr_if, zvni); | |
1801 | } | |
1802 | ||
d62a17ae | 1803 | neigh_read_for_vlan(zvrf->zns, vlan_if); |
1a98c087 | 1804 | } |
2232a77c | 1805 | } |
1806 | ||
1807 | /* | |
1808 | * Hash function for VNI. | |
1809 | */ | |
d62a17ae | 1810 | static unsigned int vni_hash_keymake(void *p) |
2232a77c | 1811 | { |
d62a17ae | 1812 | const zebra_vni_t *zvni = p; |
2232a77c | 1813 | |
d62a17ae | 1814 | return (jhash_1word(zvni->vni, 0)); |
2232a77c | 1815 | } |
1816 | ||
1817 | /* | |
1818 | * Compare 2 VNI hash entries. | |
1819 | */ | |
d62a17ae | 1820 | static int vni_hash_cmp(const void *p1, const void *p2) |
2232a77c | 1821 | { |
d62a17ae | 1822 | const zebra_vni_t *zvni1 = p1; |
1823 | const zebra_vni_t *zvni2 = p2; | |
2232a77c | 1824 | |
d62a17ae | 1825 | return (zvni1->vni == zvni2->vni); |
2232a77c | 1826 | } |
1827 | ||
1828 | /* | |
1829 | * Callback to allocate VNI hash entry. | |
1830 | */ | |
d62a17ae | 1831 | static void *zvni_alloc(void *p) |
2232a77c | 1832 | { |
d62a17ae | 1833 | const zebra_vni_t *tmp_vni = p; |
1834 | zebra_vni_t *zvni; | |
2232a77c | 1835 | |
d62a17ae | 1836 | zvni = XCALLOC(MTYPE_ZVNI, sizeof(zebra_vni_t)); |
1837 | zvni->vni = tmp_vni->vni; | |
1838 | return ((void *)zvni); | |
2232a77c | 1839 | } |
1840 | ||
1841 | /* | |
1842 | * Look up VNI hash entry. | |
1843 | */ | |
d62a17ae | 1844 | static zebra_vni_t *zvni_lookup(struct zebra_vrf *zvrf, vni_t vni) |
2232a77c | 1845 | { |
d62a17ae | 1846 | zebra_vni_t tmp_vni; |
1847 | zebra_vni_t *zvni = NULL; | |
2232a77c | 1848 | |
d62a17ae | 1849 | memset(&tmp_vni, 0, sizeof(zebra_vni_t)); |
1850 | tmp_vni.vni = vni; | |
1851 | zvni = hash_lookup(zvrf->vni_table, &tmp_vni); | |
2232a77c | 1852 | |
d62a17ae | 1853 | return zvni; |
2232a77c | 1854 | } |
1855 | ||
1856 | /* | |
1857 | * Add VNI hash entry. | |
1858 | */ | |
d62a17ae | 1859 | static zebra_vni_t *zvni_add(struct zebra_vrf *zvrf, vni_t vni) |
2232a77c | 1860 | { |
d62a17ae | 1861 | zebra_vni_t tmp_zvni; |
1862 | zebra_vni_t *zvni = NULL; | |
2232a77c | 1863 | |
d62a17ae | 1864 | memset(&tmp_zvni, 0, sizeof(zebra_vni_t)); |
1865 | tmp_zvni.vni = vni; | |
1866 | zvni = hash_get(zvrf->vni_table, &tmp_zvni, zvni_alloc); | |
1867 | assert(zvni); | |
2232a77c | 1868 | |
d62a17ae | 1869 | /* Create hash table for MAC */ |
1870 | zvni->mac_table = | |
1871 | hash_create(mac_hash_keymake, mac_cmp, "Zebra VNI MAC Table"); | |
2232a77c | 1872 | |
d62a17ae | 1873 | /* Create hash table for neighbors */ |
1874 | zvni->neigh_table = hash_create(neigh_hash_keymake, neigh_cmp, | |
1875 | "Zebra VNI Neighbor Table"); | |
2232a77c | 1876 | |
d62a17ae | 1877 | return zvni; |
2232a77c | 1878 | } |
1879 | ||
1880 | /* | |
1881 | * Delete VNI hash entry. | |
1882 | */ | |
d62a17ae | 1883 | static int zvni_del(struct zebra_vrf *zvrf, zebra_vni_t *zvni) |
2232a77c | 1884 | { |
d62a17ae | 1885 | zebra_vni_t *tmp_zvni; |
2232a77c | 1886 | |
d62a17ae | 1887 | zvni->vxlan_if = NULL; |
2232a77c | 1888 | |
d62a17ae | 1889 | /* Free the neighbor hash table. */ |
1890 | hash_free(zvni->neigh_table); | |
1891 | zvni->neigh_table = NULL; | |
2232a77c | 1892 | |
d62a17ae | 1893 | /* Free the MAC hash table. */ |
1894 | hash_free(zvni->mac_table); | |
1895 | zvni->mac_table = NULL; | |
2232a77c | 1896 | |
d62a17ae | 1897 | /* Free the VNI hash entry and allocated memory. */ |
1898 | tmp_zvni = hash_release(zvrf->vni_table, zvni); | |
1899 | if (tmp_zvni) | |
1900 | XFREE(MTYPE_ZVNI, tmp_zvni); | |
2232a77c | 1901 | |
d62a17ae | 1902 | return 0; |
2232a77c | 1903 | } |
1904 | ||
1905 | /* | |
1906 | * Inform BGP about local VNI addition. | |
1907 | */ | |
d62a17ae | 1908 | static int zvni_send_add_to_client(struct zebra_vrf *zvrf, zebra_vni_t *zvni) |
2232a77c | 1909 | { |
d62a17ae | 1910 | struct zserv *client; |
1911 | struct stream *s; | |
2232a77c | 1912 | |
d62a17ae | 1913 | client = zebra_find_client(ZEBRA_ROUTE_BGP); |
1914 | /* BGP may not be running. */ | |
1915 | if (!client) | |
1916 | return 0; | |
2232a77c | 1917 | |
d62a17ae | 1918 | s = client->obuf; |
1919 | stream_reset(s); | |
2232a77c | 1920 | |
d62a17ae | 1921 | zserv_create_header(s, ZEBRA_VNI_ADD, zvrf_id(zvrf)); |
1922 | stream_putl(s, zvni->vni); | |
1923 | stream_put_in_addr(s, &zvni->local_vtep_ip); | |
2232a77c | 1924 | |
d62a17ae | 1925 | /* Write packet size. */ |
1926 | stream_putw_at(s, 0, stream_get_endp(s)); | |
2232a77c | 1927 | |
d62a17ae | 1928 | if (IS_ZEBRA_DEBUG_VXLAN) |
1929 | zlog_debug("%u:Send VNI_ADD %u %s to %s", zvrf_id(zvrf), | |
1930 | zvni->vni, inet_ntoa(zvni->local_vtep_ip), | |
1931 | zebra_route_string(client->proto)); | |
2232a77c | 1932 | |
d62a17ae | 1933 | client->vniadd_cnt++; |
1934 | return zebra_server_send_message(client); | |
2232a77c | 1935 | } |
1936 | ||
1937 | /* | |
1938 | * Inform BGP about local VNI deletion. | |
1939 | */ | |
d62a17ae | 1940 | static int zvni_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni) |
2232a77c | 1941 | { |
d62a17ae | 1942 | struct zserv *client; |
1943 | struct stream *s; | |
2232a77c | 1944 | |
d62a17ae | 1945 | client = zebra_find_client(ZEBRA_ROUTE_BGP); |
1946 | /* BGP may not be running. */ | |
1947 | if (!client) | |
1948 | return 0; | |
2232a77c | 1949 | |
d62a17ae | 1950 | s = client->obuf; |
1951 | stream_reset(s); | |
2232a77c | 1952 | |
d62a17ae | 1953 | zserv_create_header(s, ZEBRA_VNI_DEL, zvrf_id(zvrf)); |
1954 | stream_putl(s, vni); | |
2232a77c | 1955 | |
d62a17ae | 1956 | /* Write packet size. */ |
1957 | stream_putw_at(s, 0, stream_get_endp(s)); | |
2232a77c | 1958 | |
d62a17ae | 1959 | if (IS_ZEBRA_DEBUG_VXLAN) |
1960 | zlog_debug("%u:Send VNI_DEL %u to %s", zvrf_id(zvrf), vni, | |
1961 | zebra_route_string(client->proto)); | |
2232a77c | 1962 | |
d62a17ae | 1963 | client->vnidel_cnt++; |
1964 | return zebra_server_send_message(client); | |
2232a77c | 1965 | } |
1966 | ||
1967 | /* | |
1968 | * Build the VNI hash table by going over the VxLAN interfaces. This | |
1969 | * is called when EVPN (advertise-all-vni) is enabled. | |
1970 | */ | |
d62a17ae | 1971 | static void zvni_build_hash_table(struct zebra_vrf *zvrf) |
2232a77c | 1972 | { |
d62a17ae | 1973 | struct listnode *node; |
1974 | struct interface *ifp; | |
2232a77c | 1975 | |
d62a17ae | 1976 | /* Walk VxLAN interfaces and create VNI hash. */ |
1977 | for (ALL_LIST_ELEMENTS_RO(vrf_iflist(zvrf_id(zvrf)), node, ifp)) { | |
1978 | struct zebra_if *zif; | |
1979 | struct zebra_l2info_vxlan *vxl; | |
1980 | zebra_vni_t *zvni; | |
1981 | vni_t vni; | |
2232a77c | 1982 | |
d62a17ae | 1983 | zif = ifp->info; |
1984 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
1985 | continue; | |
1986 | vxl = &zif->l2info.vxl; | |
2232a77c | 1987 | |
d62a17ae | 1988 | vni = vxl->vni; |
2232a77c | 1989 | |
d62a17ae | 1990 | if (IS_ZEBRA_DEBUG_VXLAN) |
1991 | zlog_debug( | |
1992 | "%u:Create VNI hash for intf %s(%u) VNI %u local IP %s", | |
1993 | zvrf_id(zvrf), ifp->name, ifp->ifindex, vni, | |
1994 | inet_ntoa(vxl->vtep_ip)); | |
2232a77c | 1995 | |
d62a17ae | 1996 | /* VNI hash entry is not expected to exist. */ |
1997 | zvni = zvni_lookup(zvrf, vni); | |
1998 | if (zvni) { | |
1999 | zlog_err( | |
2000 | "VNI hash already present for VRF %d IF %s(%u) VNI %u", | |
2001 | zvrf_id(zvrf), ifp->name, ifp->ifindex, vni); | |
2002 | continue; | |
2003 | } | |
2232a77c | 2004 | |
d62a17ae | 2005 | zvni = zvni_add(zvrf, vni); |
2006 | if (!zvni) { | |
2007 | zlog_err( | |
2008 | "Failed to add VNI hash, VRF %d IF %s(%u) VNI %u", | |
2009 | zvrf_id(zvrf), ifp->name, ifp->ifindex, vni); | |
2010 | return; | |
2011 | } | |
2232a77c | 2012 | |
d62a17ae | 2013 | zvni->local_vtep_ip = vxl->vtep_ip; |
2014 | zvni->vxlan_if = ifp; | |
2232a77c | 2015 | |
d62a17ae | 2016 | /* Inform BGP if interface is up and mapped to bridge. */ |
2017 | if (if_is_operative(ifp) && zif->brslave_info.br_if) | |
2018 | zvni_send_add_to_client(zvrf, zvni); | |
2019 | } | |
2232a77c | 2020 | } |
2021 | ||
2022 | /* | |
2023 | * See if remote VTEP matches with prefix. | |
2024 | */ | |
d62a17ae | 2025 | static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep) |
2232a77c | 2026 | { |
d62a17ae | 2027 | return (IPV4_ADDR_SAME(vtep_ip, &zvtep->vtep_ip)); |
2232a77c | 2028 | } |
2029 | ||
2030 | /* | |
2031 | * Locate remote VTEP in VNI hash table. | |
2032 | */ | |
d62a17ae | 2033 | static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip) |
2232a77c | 2034 | { |
d62a17ae | 2035 | zebra_vtep_t *zvtep; |
2232a77c | 2036 | |
d62a17ae | 2037 | if (!zvni) |
2038 | return NULL; | |
2232a77c | 2039 | |
d62a17ae | 2040 | for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { |
2041 | if (zvni_vtep_match(vtep_ip, zvtep)) | |
2042 | break; | |
2043 | } | |
2232a77c | 2044 | |
d62a17ae | 2045 | return zvtep; |
2232a77c | 2046 | } |
2047 | ||
2048 | /* | |
2049 | * Add remote VTEP to VNI hash table. | |
2050 | */ | |
d62a17ae | 2051 | static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip) |
2232a77c | 2052 | { |
d62a17ae | 2053 | zebra_vtep_t *zvtep; |
2232a77c | 2054 | |
d62a17ae | 2055 | zvtep = XCALLOC(MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t)); |
2056 | if (!zvtep) { | |
2057 | zlog_err("Failed to alloc VTEP entry, VNI %u", zvni->vni); | |
2058 | return NULL; | |
2059 | } | |
2232a77c | 2060 | |
d62a17ae | 2061 | zvtep->vtep_ip = *vtep_ip; |
2232a77c | 2062 | |
d62a17ae | 2063 | if (zvni->vteps) |
2064 | zvni->vteps->prev = zvtep; | |
2065 | zvtep->next = zvni->vteps; | |
2066 | zvni->vteps = zvtep; | |
2232a77c | 2067 | |
d62a17ae | 2068 | return zvtep; |
2232a77c | 2069 | } |
2070 | ||
2071 | /* | |
2072 | * Remove remote VTEP from VNI hash table. | |
2073 | */ | |
d62a17ae | 2074 | static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep) |
2232a77c | 2075 | { |
d62a17ae | 2076 | if (zvtep->next) |
2077 | zvtep->next->prev = zvtep->prev; | |
2078 | if (zvtep->prev) | |
2079 | zvtep->prev->next = zvtep->next; | |
2080 | else | |
2081 | zvni->vteps = zvtep->next; | |
2232a77c | 2082 | |
d62a17ae | 2083 | zvtep->prev = zvtep->next = NULL; |
2084 | XFREE(MTYPE_ZVNI_VTEP, zvtep); | |
2232a77c | 2085 | |
d62a17ae | 2086 | return 0; |
2232a77c | 2087 | } |
2088 | ||
2089 | /* | |
2090 | * Delete all remote VTEPs for this VNI (upon VNI delete). Also | |
2091 | * uninstall from kernel if asked to. | |
2092 | */ | |
d62a17ae | 2093 | static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall) |
2232a77c | 2094 | { |
d62a17ae | 2095 | zebra_vtep_t *zvtep, *zvtep_next; |
2232a77c | 2096 | |
d62a17ae | 2097 | if (!zvni) |
2098 | return -1; | |
2232a77c | 2099 | |
d62a17ae | 2100 | for (zvtep = zvni->vteps; zvtep; zvtep = zvtep_next) { |
2101 | zvtep_next = zvtep->next; | |
2102 | if (uninstall) | |
2103 | zvni_vtep_uninstall(zvni, &zvtep->vtep_ip); | |
2104 | zvni_vtep_del(zvni, zvtep); | |
2105 | } | |
2232a77c | 2106 | |
d62a17ae | 2107 | return 0; |
2232a77c | 2108 | } |
2109 | ||
2110 | /* | |
2111 | * Install remote VTEP into the kernel. | |
2112 | */ | |
d62a17ae | 2113 | static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip) |
2232a77c | 2114 | { |
d62a17ae | 2115 | return kernel_add_vtep(zvni->vni, zvni->vxlan_if, vtep_ip); |
2232a77c | 2116 | } |
2117 | ||
2118 | /* | |
2119 | * Uninstall remote VTEP from the kernel. | |
2120 | */ | |
d62a17ae | 2121 | static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip) |
2232a77c | 2122 | { |
d62a17ae | 2123 | if (!zvni->vxlan_if) { |
2124 | zlog_err("VNI %u hash %p couldn't be uninstalled - no intf", | |
2125 | zvni->vni, zvni); | |
2126 | return -1; | |
2127 | } | |
2232a77c | 2128 | |
d62a17ae | 2129 | return kernel_del_vtep(zvni->vni, zvni->vxlan_if, vtep_ip); |
2232a77c | 2130 | } |
2131 | ||
2132 | /* | |
2133 | * Cleanup VNI/VTEP and update kernel | |
2134 | */ | |
d62a17ae | 2135 | static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf) |
2232a77c | 2136 | { |
d62a17ae | 2137 | zebra_vni_t *zvni; |
2232a77c | 2138 | |
d62a17ae | 2139 | zvni = (zebra_vni_t *)backet->data; |
2140 | if (!zvni) | |
2141 | return; | |
2232a77c | 2142 | |
d62a17ae | 2143 | /* Free up all neighbors and MACs, if any. */ |
2144 | zvni_neigh_del_all(zvrf, zvni, 1, 0, DEL_ALL_NEIGH); | |
2145 | zvni_mac_del_all(zvrf, zvni, 1, 0, DEL_ALL_MAC); | |
2232a77c | 2146 | |
d62a17ae | 2147 | /* Free up all remote VTEPs, if any. */ |
2148 | zvni_vtep_del_all(zvni, 1); | |
2232a77c | 2149 | |
d62a17ae | 2150 | /* Delete the hash entry. */ |
2151 | zvni_del(zvrf, zvni); | |
2232a77c | 2152 | } |
2153 | ||
2154 | ||
2155 | /* Public functions */ | |
2156 | ||
cec2e17d | 2157 | /* |
2158 | * Display Neighbors for a VNI (VTY command handler). | |
2159 | */ | |
d62a17ae | 2160 | void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, |
cd233079 | 2161 | vni_t vni, u_char use_json) |
d62a17ae | 2162 | { |
2163 | zebra_vni_t *zvni; | |
2164 | u_int32_t num_neigh; | |
2165 | struct neigh_walk_ctx wctx; | |
cd233079 | 2166 | json_object *json = NULL; |
d62a17ae | 2167 | |
2168 | if (!EVPN_ENABLED(zvrf)) | |
2169 | return; | |
2170 | zvni = zvni_lookup(zvrf, vni); | |
2171 | if (!zvni) { | |
cd233079 CS |
2172 | if (use_json) |
2173 | vty_out(vty, "{}\n"); | |
2174 | else | |
2175 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2176 | return; |
2177 | } | |
2178 | num_neigh = hashcount(zvni->neigh_table); | |
2179 | if (!num_neigh) | |
2180 | return; | |
2181 | ||
cd233079 CS |
2182 | if (use_json) |
2183 | json = json_object_new_object(); | |
2184 | ||
d62a17ae | 2185 | /* Since we have IPv6 addresses to deal with which can vary widely in |
2186 | * size, we try to be a bit more elegant in display by first computing | |
2187 | * the maximum width. | |
2188 | */ | |
2189 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); | |
2190 | wctx.zvni = zvni; | |
2191 | wctx.vty = vty; | |
2192 | wctx.addr_width = 15; | |
cd233079 | 2193 | wctx.json = json; |
d62a17ae | 2194 | hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); |
2195 | ||
cd233079 CS |
2196 | if (!use_json) { |
2197 | vty_out(vty, | |
2198 | "Number of ARPs (local and remote) known for this VNI: %u\n", | |
2199 | num_neigh); | |
2200 | vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", | |
2201 | "Type", "MAC", "Remote VTEP"); | |
2202 | } else | |
2203 | json_object_int_add(json, "numArpNd", num_neigh); | |
d62a17ae | 2204 | |
2205 | hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); | |
cd233079 CS |
2206 | if (use_json) { |
2207 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2208 | json, JSON_C_TO_STRING_PRETTY)); | |
2209 | json_object_free(json); | |
2210 | } | |
cec2e17d | 2211 | } |
2212 | ||
2213 | /* | |
2214 | * Display neighbors across all VNIs (VTY command handler). | |
2215 | */ | |
cd233079 CS |
2216 | void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, |
2217 | u_char use_json) | |
cec2e17d | 2218 | { |
cd233079 CS |
2219 | json_object *json = NULL; |
2220 | void *args[2]; | |
2221 | ||
d62a17ae | 2222 | if (!EVPN_ENABLED(zvrf)) |
2223 | return; | |
cd233079 CS |
2224 | |
2225 | if (use_json) | |
2226 | json = json_object_new_object(); | |
2227 | ||
2228 | args[0] = vty; | |
2229 | args[1] = json; | |
2230 | hash_iterate(zvrf->vni_table, | |
2231 | (void (*)(struct hash_backet *, | |
2232 | void *))zvni_print_neigh_hash_all_vni, | |
2233 | args); | |
2234 | if (use_json) { | |
2235 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2236 | json, JSON_C_TO_STRING_PRETTY)); | |
2237 | json_object_free(json); | |
2238 | } | |
cec2e17d | 2239 | } |
2240 | ||
2241 | /* | |
2242 | * Display specific neighbor for a VNI, if present (VTY command handler). | |
2243 | */ | |
d62a17ae | 2244 | void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, |
2245 | struct zebra_vrf *zvrf, vni_t vni, | |
cd233079 | 2246 | struct ipaddr *ip, u_char use_json) |
cec2e17d | 2247 | { |
d62a17ae | 2248 | zebra_vni_t *zvni; |
2249 | zebra_neigh_t *n; | |
cd233079 | 2250 | json_object *json = NULL; |
cec2e17d | 2251 | |
d62a17ae | 2252 | if (!EVPN_ENABLED(zvrf)) |
2253 | return; | |
2254 | zvni = zvni_lookup(zvrf, vni); | |
2255 | if (!zvni) { | |
cd233079 CS |
2256 | if (use_json) |
2257 | vty_out(vty, "{}\n"); | |
2258 | else | |
2259 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2260 | return; |
2261 | } | |
2262 | n = zvni_neigh_lookup(zvni, ip); | |
2263 | if (!n) { | |
cd233079 CS |
2264 | if (!use_json) |
2265 | vty_out(vty, | |
2266 | "%% Requested neighbor does not exist in VNI %u\n", | |
2267 | vni); | |
d62a17ae | 2268 | return; |
2269 | } | |
cd233079 CS |
2270 | if (use_json) |
2271 | json = json_object_new_object(); | |
2272 | ||
2273 | zvni_print_neigh(n, vty, json); | |
cec2e17d | 2274 | |
cd233079 CS |
2275 | if (use_json) { |
2276 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2277 | json, JSON_C_TO_STRING_PRETTY)); | |
2278 | json_object_free(json); | |
2279 | } | |
cec2e17d | 2280 | } |
2281 | ||
2282 | /* | |
2283 | * Display neighbors for a VNI from specific VTEP (VTY command handler). | |
2284 | * By definition, these are remote neighbors. | |
2285 | */ | |
d62a17ae | 2286 | void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, |
cd233079 CS |
2287 | vni_t vni, struct in_addr vtep_ip, |
2288 | u_char use_json) | |
cec2e17d | 2289 | { |
d62a17ae | 2290 | zebra_vni_t *zvni; |
2291 | u_int32_t num_neigh; | |
2292 | struct neigh_walk_ctx wctx; | |
cd233079 | 2293 | json_object *json = NULL; |
cec2e17d | 2294 | |
d62a17ae | 2295 | if (!EVPN_ENABLED(zvrf)) |
2296 | return; | |
2297 | zvni = zvni_lookup(zvrf, vni); | |
2298 | if (!zvni) { | |
cd233079 CS |
2299 | if (use_json) |
2300 | vty_out(vty, "{}\n"); | |
2301 | else | |
2302 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2303 | return; |
2304 | } | |
2305 | num_neigh = hashcount(zvni->neigh_table); | |
2306 | if (!num_neigh) | |
2307 | return; | |
cec2e17d | 2308 | |
d62a17ae | 2309 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); |
2310 | wctx.zvni = zvni; | |
2311 | wctx.vty = vty; | |
2312 | wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP; | |
2313 | wctx.r_vtep_ip = vtep_ip; | |
cd233079 | 2314 | wctx.json = json; |
d62a17ae | 2315 | hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); |
cd233079 CS |
2316 | |
2317 | if (use_json) { | |
2318 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2319 | json, JSON_C_TO_STRING_PRETTY)); | |
2320 | json_object_free(json); | |
2321 | } | |
cec2e17d | 2322 | } |
2323 | ||
2324 | /* | |
2325 | * Display MACs for a VNI (VTY command handler). | |
2326 | */ | |
d62a17ae | 2327 | void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, |
cd233079 | 2328 | vni_t vni, u_char use_json) |
cec2e17d | 2329 | { |
d62a17ae | 2330 | zebra_vni_t *zvni; |
2331 | u_int32_t num_macs; | |
2332 | struct mac_walk_ctx wctx; | |
cd233079 CS |
2333 | json_object *json = NULL; |
2334 | json_object *json_mac = NULL; | |
cec2e17d | 2335 | |
d62a17ae | 2336 | if (!EVPN_ENABLED(zvrf)) |
2337 | return; | |
2338 | zvni = zvni_lookup(zvrf, vni); | |
2339 | if (!zvni) { | |
cd233079 CS |
2340 | if (use_json) |
2341 | vty_out(vty, "{}\n"); | |
2342 | else | |
2343 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2344 | return; |
2345 | } | |
2346 | num_macs = hashcount(zvni->mac_table); | |
2347 | if (!num_macs) | |
2348 | return; | |
cec2e17d | 2349 | |
cd233079 CS |
2350 | if (use_json) { |
2351 | json = json_object_new_object(); | |
2352 | json_mac = json_object_new_object(); | |
2353 | } | |
2354 | ||
d62a17ae | 2355 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
2356 | wctx.zvni = zvni; | |
2357 | wctx.vty = vty; | |
cd233079 | 2358 | wctx.json = json_mac; |
cec2e17d | 2359 | |
cd233079 CS |
2360 | if (!use_json) { |
2361 | vty_out(vty, | |
2362 | "Number of MACs (local and remote) known for this VNI: %u\n", | |
2363 | num_macs); | |
2364 | vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", | |
2365 | "Intf/Remote VTEP", "VLAN"); | |
2366 | } else | |
2367 | json_object_int_add(json, "numMacs", num_macs); | |
cec2e17d | 2368 | |
d62a17ae | 2369 | hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx); |
cd233079 CS |
2370 | |
2371 | if (use_json) { | |
2372 | json_object_object_add(json, "macs", json_mac); | |
2373 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2374 | json, JSON_C_TO_STRING_PRETTY)); | |
2375 | json_object_free(json); | |
2376 | } | |
cec2e17d | 2377 | } |
2378 | ||
2379 | /* | |
2380 | * Display MACs for all VNIs (VTY command handler). | |
2381 | */ | |
cd233079 CS |
2382 | void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf, |
2383 | u_char use_json) | |
cec2e17d | 2384 | { |
d62a17ae | 2385 | struct mac_walk_ctx wctx; |
cd233079 | 2386 | json_object *json = NULL; |
cec2e17d | 2387 | |
cd233079 CS |
2388 | if (!EVPN_ENABLED(zvrf)) { |
2389 | if (use_json) | |
2390 | vty_out(vty, "{}\n"); | |
d62a17ae | 2391 | return; |
cd233079 CS |
2392 | } |
2393 | if (use_json) | |
2394 | json = json_object_new_object(); | |
2395 | ||
d62a17ae | 2396 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
2397 | wctx.vty = vty; | |
cd233079 | 2398 | wctx.json = json; |
d62a17ae | 2399 | hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx); |
cd233079 CS |
2400 | |
2401 | if (use_json) { | |
2402 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2403 | json, JSON_C_TO_STRING_PRETTY)); | |
2404 | json_object_free(json); | |
2405 | } | |
cec2e17d | 2406 | } |
2407 | ||
2408 | /* | |
2409 | * Display MACs for all VNIs (VTY command handler). | |
2410 | */ | |
d62a17ae | 2411 | void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty, |
2412 | struct zebra_vrf *zvrf, | |
cd233079 CS |
2413 | struct in_addr vtep_ip, |
2414 | u_char use_json) | |
cec2e17d | 2415 | { |
d62a17ae | 2416 | struct mac_walk_ctx wctx; |
cd233079 | 2417 | json_object *json = NULL; |
cec2e17d | 2418 | |
d62a17ae | 2419 | if (!EVPN_ENABLED(zvrf)) |
2420 | return; | |
cd233079 CS |
2421 | |
2422 | if (use_json) | |
2423 | json = json_object_new_object(); | |
2424 | ||
d62a17ae | 2425 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
2426 | wctx.vty = vty; | |
2427 | wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; | |
2428 | wctx.r_vtep_ip = vtep_ip; | |
cd233079 | 2429 | wctx.json = json; |
d62a17ae | 2430 | hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx); |
cd233079 CS |
2431 | |
2432 | if (use_json) { | |
2433 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2434 | json, JSON_C_TO_STRING_PRETTY)); | |
2435 | json_object_free(json); | |
2436 | } | |
cec2e17d | 2437 | } |
2438 | ||
2439 | /* | |
2440 | * Display specific MAC for a VNI, if present (VTY command handler). | |
2441 | */ | |
d62a17ae | 2442 | void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf, |
2443 | vni_t vni, struct ethaddr *macaddr) | |
cec2e17d | 2444 | { |
d62a17ae | 2445 | zebra_vni_t *zvni; |
2446 | zebra_mac_t *mac; | |
cec2e17d | 2447 | |
d62a17ae | 2448 | if (!EVPN_ENABLED(zvrf)) |
2449 | return; | |
2450 | zvni = zvni_lookup(zvrf, vni); | |
2451 | if (!zvni) { | |
2452 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
2453 | return; | |
2454 | } | |
2455 | mac = zvni_mac_lookup(zvni, macaddr); | |
2456 | if (!mac) { | |
2457 | vty_out(vty, "%% Requested MAC does not exist in VNI %u\n", | |
2458 | vni); | |
2459 | return; | |
2460 | } | |
cec2e17d | 2461 | |
d62a17ae | 2462 | zvni_print_mac(mac, vty); |
cec2e17d | 2463 | } |
2464 | ||
2465 | /* | |
2466 | * Display MACs for a VNI from specific VTEP (VTY command handler). | |
2467 | */ | |
d62a17ae | 2468 | void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, |
cd233079 CS |
2469 | vni_t vni, struct in_addr vtep_ip, |
2470 | u_char use_json) | |
cec2e17d | 2471 | { |
d62a17ae | 2472 | zebra_vni_t *zvni; |
2473 | u_int32_t num_macs; | |
2474 | struct mac_walk_ctx wctx; | |
cd233079 CS |
2475 | json_object *json = NULL; |
2476 | json_object *json_mac = NULL; | |
cec2e17d | 2477 | |
d62a17ae | 2478 | if (!EVPN_ENABLED(zvrf)) |
2479 | return; | |
2480 | zvni = zvni_lookup(zvrf, vni); | |
2481 | if (!zvni) { | |
cd233079 CS |
2482 | if (use_json) |
2483 | vty_out(vty, "{}\n"); | |
2484 | else | |
2485 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2486 | return; |
2487 | } | |
2488 | num_macs = hashcount(zvni->mac_table); | |
2489 | if (!num_macs) | |
2490 | return; | |
cd233079 CS |
2491 | |
2492 | if (use_json) { | |
2493 | json = json_object_new_object(); | |
2494 | json_mac = json_object_new_object(); | |
2495 | } | |
2496 | ||
d62a17ae | 2497 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
2498 | wctx.zvni = zvni; | |
2499 | wctx.vty = vty; | |
2500 | wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; | |
2501 | wctx.r_vtep_ip = vtep_ip; | |
cd233079 | 2502 | wctx.json = json_mac; |
d62a17ae | 2503 | hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx); |
cd233079 CS |
2504 | |
2505 | if (use_json) { | |
2506 | json_object_int_add(json, "numMacs", wctx.count); | |
2507 | if (wctx.count) | |
2508 | json_object_object_add(json, "macs", json_mac); | |
2509 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2510 | json, JSON_C_TO_STRING_PRETTY)); | |
2511 | json_object_free(json); | |
2512 | } | |
cec2e17d | 2513 | } |
2514 | ||
2515 | ||
2516 | /* | |
2517 | * Display VNI information (VTY command handler). | |
2518 | */ | |
cd233079 CS |
2519 | void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, |
2520 | u_char use_json) | |
cec2e17d | 2521 | { |
d62a17ae | 2522 | zebra_vni_t *zvni; |
cd233079 CS |
2523 | json_object *json = NULL; |
2524 | void *args[2]; | |
cec2e17d | 2525 | |
d62a17ae | 2526 | if (!EVPN_ENABLED(zvrf)) |
2527 | return; | |
2528 | zvni = zvni_lookup(zvrf, vni); | |
2529 | if (!zvni) { | |
cd233079 CS |
2530 | if (use_json) |
2531 | vty_out(vty, "{}\n"); | |
2532 | else | |
2533 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 2534 | return; |
2535 | } | |
cd233079 CS |
2536 | if (use_json) |
2537 | json = json_object_new_object(); | |
2538 | args[0] = vty; | |
2539 | args[1] = json; | |
2540 | zvni_print(zvni, (void *)args); | |
2541 | if (use_json) { | |
2542 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2543 | json, JSON_C_TO_STRING_PRETTY)); | |
2544 | json_object_free(json); | |
2545 | } | |
cec2e17d | 2546 | } |
2547 | ||
2548 | /* | |
2549 | * Display VNI hash table (VTY command handler). | |
2550 | */ | |
cd233079 CS |
2551 | void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, |
2552 | u_char use_json) | |
cec2e17d | 2553 | { |
d62a17ae | 2554 | u_int32_t num_vnis; |
cd233079 CS |
2555 | json_object *json = NULL; |
2556 | void *args[2]; | |
cec2e17d | 2557 | |
d62a17ae | 2558 | if (!EVPN_ENABLED(zvrf)) |
2559 | return; | |
2560 | num_vnis = hashcount(zvrf->vni_table); | |
cd233079 CS |
2561 | if (!num_vnis) { |
2562 | if (use_json) | |
2563 | vty_out(vty, "{}\n"); | |
d62a17ae | 2564 | return; |
cd233079 CS |
2565 | } |
2566 | if (use_json) { | |
2567 | json = json_object_new_object(); | |
2568 | json_object_int_add(json, "numVnis", num_vnis); | |
2569 | } else { | |
2570 | vty_out(vty, "Number of VNIs: %u\n", num_vnis); | |
2571 | vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI", | |
2572 | "VxLAN IF", "VTEP IP", "# MACs", "# ARPs", | |
2573 | "# Remote VTEPs"); | |
2574 | } | |
2575 | args[0] = vty; | |
2576 | args[1] = json; | |
2577 | ||
2578 | hash_iterate(zvrf->vni_table, | |
2579 | (void (*)(struct hash_backet *, void *))zvni_print_hash, | |
2580 | args); | |
2581 | ||
2582 | if (use_json) { | |
2583 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
2584 | json, JSON_C_TO_STRING_PRETTY)); | |
2585 | json_object_free(json); | |
2586 | } | |
cec2e17d | 2587 | } |
2588 | ||
2232a77c | 2589 | /* |
2590 | * Handle neighbor delete (on a VLAN device / L3 interface) from the | |
2591 | * kernel. This may result in either the neighbor getting deleted from | |
2592 | * our database or being re-added to the kernel (if it is a valid | |
2593 | * remote neighbor). | |
2594 | */ | |
d62a17ae | 2595 | int zebra_vxlan_local_neigh_del(struct interface *ifp, |
2596 | struct interface *link_if, struct ipaddr *ip) | |
2597 | { | |
2598 | zebra_vni_t *zvni; | |
2599 | zebra_neigh_t *n; | |
2600 | struct zebra_vrf *zvrf; | |
2601 | char buf[INET6_ADDRSTRLEN]; | |
2602 | ||
2603 | /* We are only interested in neighbors on an SVI that resides on top | |
2604 | * of a VxLAN bridge. | |
2605 | */ | |
2606 | zvni = zvni_map_svi(ifp, link_if); | |
2607 | if (!zvni) | |
2608 | return 0; | |
2609 | if (!zvni->vxlan_if) { | |
2610 | zlog_err( | |
2611 | "VNI %u hash %p doesn't have intf upon local neighbor DEL", | |
2612 | zvni->vni, zvni); | |
2613 | return -1; | |
2614 | } | |
2615 | ||
2616 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2617 | zlog_debug("%u:Del neighbor %s intf %s(%u) -> VNI %u", | |
2618 | ifp->vrf_id, ipaddr2str(ip, buf, sizeof(buf)), | |
2619 | ifp->name, ifp->ifindex, zvni->vni); | |
2620 | ||
2621 | /* If entry doesn't exist, nothing to do. */ | |
2622 | n = zvni_neigh_lookup(zvni, ip); | |
2623 | if (!n) | |
2624 | return 0; | |
2625 | ||
2626 | /* If it is a remote entry, the kernel has aged this out or someone has | |
2627 | * deleted it, it needs to be re-installed as Quagga is the owner. | |
2628 | */ | |
2629 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
2630 | zvni_neigh_install(zvni, n); | |
2631 | return 0; | |
2632 | } | |
2633 | ||
2634 | /* Locate VRF corresponding to interface. */ | |
2635 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); | |
2636 | assert(zvrf); | |
2637 | ||
2638 | /* Remove neighbor from BGP. */ | |
1a98c087 | 2639 | zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, 0); |
d62a17ae | 2640 | |
2641 | /* Delete this neighbor entry. */ | |
2642 | zvni_neigh_del(zvni, n); | |
2643 | ||
2644 | return 0; | |
2232a77c | 2645 | } |
2646 | ||
2647 | /* | |
2648 | * Handle neighbor add or update (on a VLAN device / L3 interface) | |
2649 | * from the kernel. | |
2650 | */ | |
d62a17ae | 2651 | int zebra_vxlan_local_neigh_add_update(struct interface *ifp, |
2652 | struct interface *link_if, | |
2653 | struct ipaddr *ip, | |
2654 | struct ethaddr *macaddr, u_int16_t state, | |
2655 | u_char ext_learned) | |
2656 | { | |
2657 | zebra_vni_t *zvni; | |
2658 | zebra_neigh_t *n; | |
2659 | struct zebra_vrf *zvrf; | |
2660 | char buf[ETHER_ADDR_STRLEN]; | |
2661 | char buf2[INET6_ADDRSTRLEN]; | |
2662 | int send_upd = 1, send_del = 0; | |
2663 | ||
2664 | /* We are only interested in neighbors on an SVI that resides on top | |
2665 | * of a VxLAN bridge. | |
2666 | */ | |
2667 | zvni = zvni_map_svi(ifp, link_if); | |
2668 | if (!zvni) | |
2669 | return 0; | |
2670 | ||
2671 | /* Locate VRF corresponding to interface. */ | |
2672 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); | |
2673 | assert(zvrf); | |
2674 | ||
2675 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2676 | zlog_debug( | |
2677 | "%u:Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x " | |
2678 | "%s-> VNI %u", | |
2679 | ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)), | |
2680 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, | |
2681 | ifp->ifindex, state, ext_learned ? "ext-learned " : "", | |
2682 | zvni->vni); | |
2683 | ||
2684 | /* If same entry already exists, it might be a change or it might be a | |
2685 | * move from remote to local. | |
2686 | */ | |
2687 | n = zvni_neigh_lookup(zvni, ip); | |
2688 | if (n) { | |
2689 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
2690 | if (memcmp(n->emac.octet, macaddr->octet, | |
ff8b7eb8 | 2691 | ETH_ALEN) |
d62a17ae | 2692 | == 0) { |
2693 | if (n->ifindex == ifp->ifindex) | |
2694 | /* we're not interested in whatever has | |
2695 | * changed. */ | |
2696 | return 0; | |
2697 | /* client doesn't care about a purely local | |
2698 | * change. */ | |
2699 | send_upd = 0; | |
2700 | } else | |
2701 | /* If the MAC has changed, issue a delete first | |
2702 | * as this means a | |
2703 | * different MACIP route. | |
2704 | */ | |
2705 | send_del = 1; | |
2706 | } else if (ext_learned) | |
2707 | /* The neighbor is remote and that is the notification we got. | |
9d303b37 | 2708 | */ |
d62a17ae | 2709 | { |
2710 | /* TODO: Evaluate if we need to do anything here. */ | |
2711 | return 0; | |
2712 | } else | |
2713 | /* Neighbor has moved from remote to local. */ | |
2714 | { | |
2715 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); | |
2716 | n->r_vtep_ip.s_addr = 0; | |
2717 | } | |
2718 | } else { | |
2719 | n = zvni_neigh_add(zvni, ip); | |
2720 | if (!n) { | |
2721 | zlog_err( | |
2722 | "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", | |
2723 | ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)), | |
2724 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
2725 | ifp->name, ifp->ifindex, zvni->vni); | |
2726 | return -1; | |
2727 | } | |
2728 | } | |
2729 | ||
2730 | /* Issue delete for older info, if needed. */ | |
2731 | if (send_del) | |
1a98c087 MK |
2732 | zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, |
2733 | 0); | |
d62a17ae | 2734 | |
2735 | /* Set "local" forwarding info. */ | |
2736 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
ff8b7eb8 | 2737 | memcpy(&n->emac, macaddr, ETH_ALEN); |
d62a17ae | 2738 | n->ifindex = ifp->ifindex; |
2739 | ||
2740 | /* Inform BGP if required. */ | |
2741 | if (send_upd) | |
2742 | return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, | |
1a98c087 | 2743 | macaddr, 0); |
d62a17ae | 2744 | |
2745 | return 0; | |
2232a77c | 2746 | } |
2747 | ||
2748 | /* | |
2749 | * Handle message from client to delete a remote MACIP for a VNI. | |
2750 | */ | |
d62a17ae | 2751 | int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, |
2752 | struct zebra_vrf *zvrf) | |
2753 | { | |
2754 | struct stream *s; | |
2755 | vni_t vni; | |
2756 | struct ethaddr macaddr; | |
2757 | struct ipaddr ip; | |
2758 | struct in_addr vtep_ip; | |
2759 | zebra_vni_t *zvni; | |
2760 | zebra_mac_t *mac; | |
2761 | zebra_neigh_t *n; | |
2762 | u_short l = 0, ipa_len; | |
2763 | char buf[ETHER_ADDR_STRLEN]; | |
2764 | char buf1[INET6_ADDRSTRLEN]; | |
2765 | ||
2766 | s = client->ibuf; | |
2767 | ||
2768 | while (l < length) { | |
2769 | /* Obtain each remote MACIP and process. */ | |
2770 | /* Message contains VNI, followed by MAC followed by IP (if any) | |
2771 | * followed by remote VTEP IP. | |
2772 | */ | |
2773 | mac = NULL; | |
2774 | n = NULL; | |
2775 | memset(&ip, 0, sizeof(ip)); | |
2776 | vni = (vni_t)stream_getl(s); | |
ff8b7eb8 | 2777 | stream_get(&macaddr.octet, s, ETH_ALEN); |
d62a17ae | 2778 | ipa_len = stream_getl(s); |
2779 | if (ipa_len) { | |
2780 | ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 | |
2781 | : IPADDR_V6; | |
2782 | stream_get(&ip.ip.addr, s, ipa_len); | |
2783 | } | |
ff8b7eb8 | 2784 | l += 4 + ETH_ALEN + 4 + ipa_len; |
d62a17ae | 2785 | vtep_ip.s_addr = stream_get_ipv4(s); |
2786 | l += IPV4_MAX_BYTELEN; | |
2787 | ||
2788 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2789 | zlog_debug( | |
2790 | "%u:Recv MACIP Del MAC %s IP %s VNI %u Remote VTEP %s from %s", | |
2791 | zvrf_id(zvrf), | |
2792 | prefix_mac2str(&macaddr, buf, sizeof(buf)), | |
2793 | ipaddr2str(&ip, buf1, sizeof(buf1)), vni, | |
2794 | inet_ntoa(vtep_ip), | |
2795 | zebra_route_string(client->proto)); | |
2796 | ||
2797 | /* Locate VNI hash entry - expected to exist. */ | |
2798 | zvni = zvni_lookup(zvrf, vni); | |
2799 | if (!zvni) { | |
2800 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2801 | zlog_debug( | |
2802 | "Failed to locate VNI hash upon remote MACIP DEL, " | |
2803 | "VRF %d VNI %u", | |
2804 | zvrf_id(zvrf), vni); | |
2805 | continue; | |
2806 | } | |
2807 | if (!zvni->vxlan_if) { | |
2808 | zlog_err( | |
2809 | "VNI %u hash %p doesn't have intf upon remote MACIP DEL", | |
2810 | vni, zvni); | |
2811 | continue; | |
2812 | } | |
2813 | ||
2814 | /* The remote VTEP specified is normally expected to exist, but | |
2815 | * it is | |
2816 | * possible that the peer may delete the VTEP before deleting | |
2817 | * any MACs | |
2818 | * referring to the VTEP, in which case the handler (see | |
2819 | * remote_vtep_del) | |
2820 | * would have already deleted the MACs. | |
2821 | */ | |
2822 | if (!zvni_vtep_find(zvni, &vtep_ip)) | |
2823 | continue; | |
2824 | ||
2825 | /* If the local VxLAN interface is not up (should be a transient | |
2826 | * event), there's nothing more to do. | |
2827 | */ | |
2828 | if (!if_is_operative(zvni->vxlan_if)) | |
2829 | continue; | |
2830 | ||
2831 | mac = zvni_mac_lookup(zvni, &macaddr); | |
2832 | if (ipa_len) | |
2833 | n = zvni_neigh_lookup(zvni, &ip); | |
2834 | ||
2835 | if (n && !mac) { | |
2836 | zlog_err( | |
2837 | "failed to locate MAC %s for neigh %s in VRF %u VNI %u", | |
2838 | prefix_mac2str(&macaddr, buf, sizeof(buf)), | |
2839 | ipaddr2str(&ip, buf1, sizeof(buf1)), | |
2840 | zvrf_id(zvrf), vni); | |
2841 | continue; | |
2842 | } | |
2843 | ||
2844 | /* If the remote mac or neighbor doesn't exist there is nothing | |
2845 | * more | |
2846 | * to do. Otherwise, uninstall the entry and then remove it. | |
2847 | */ | |
2848 | if (!mac && !n) | |
2849 | continue; | |
2850 | ||
2851 | /* Uninstall remote neighbor or MAC. */ | |
2852 | if (n) { | |
2853 | /* When the MAC changes for an IP, it is possible the | |
2854 | * client may | |
2855 | * update the new MAC before trying to delete the "old" | |
2856 | * neighbor | |
2857 | * (as these are two different MACIP routes). Do the | |
2858 | * delete only | |
2859 | * if the MAC matches. | |
2860 | */ | |
2861 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) | |
2862 | && (memcmp(n->emac.octet, macaddr.octet, | |
ff8b7eb8 | 2863 | ETH_ALEN) |
d62a17ae | 2864 | == 0)) { |
2865 | zvni_neigh_uninstall(zvni, n); | |
2866 | zvni_neigh_del(zvni, n); | |
2867 | zvni_deref_ip2mac(zvni, mac, 1); | |
2868 | } | |
2869 | } else { | |
2870 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { | |
2871 | if (!mac->neigh_refcnt) { | |
2872 | zvni_mac_uninstall(zvni, mac, 0); | |
2873 | zvni_mac_del(zvni, mac); | |
2874 | } else | |
2875 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
2876 | } | |
2877 | } | |
2878 | } | |
2879 | ||
2880 | return 0; | |
2232a77c | 2881 | } |
2882 | ||
2883 | /* | |
2884 | * Handle message from client to add a remote MACIP for a VNI. This | |
2885 | * could be just the add of a MAC address or the add of a neighbor | |
2886 | * (IP+MAC). | |
2887 | */ | |
d62a17ae | 2888 | int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, |
2889 | struct zebra_vrf *zvrf) | |
2890 | { | |
2891 | struct stream *s; | |
2892 | vni_t vni; | |
2893 | struct ethaddr macaddr; | |
2894 | struct ipaddr ip; | |
2895 | struct in_addr vtep_ip; | |
2896 | zebra_vni_t *zvni; | |
2897 | zebra_vtep_t *zvtep; | |
2898 | zebra_mac_t *mac, *old_mac; | |
2899 | zebra_neigh_t *n; | |
2900 | u_short l = 0, ipa_len; | |
2901 | int update_mac = 0, update_neigh = 0; | |
2902 | char buf[ETHER_ADDR_STRLEN]; | |
2903 | char buf1[INET6_ADDRSTRLEN]; | |
2904 | u_char sticky; | |
2905 | ||
2906 | assert(EVPN_ENABLED(zvrf)); | |
2907 | ||
2908 | s = client->ibuf; | |
2909 | ||
2910 | while (l < length) { | |
2911 | /* Obtain each remote MACIP and process. */ | |
2912 | /* Message contains VNI, followed by MAC followed by IP (if any) | |
2913 | * followed by remote VTEP IP. | |
2914 | */ | |
2915 | update_mac = update_neigh = 0; | |
2916 | mac = NULL; | |
2917 | n = NULL; | |
2918 | memset(&ip, 0, sizeof(ip)); | |
2919 | vni = (vni_t)stream_getl(s); | |
ff8b7eb8 | 2920 | stream_get(&macaddr.octet, s, ETH_ALEN); |
d62a17ae | 2921 | ipa_len = stream_getl(s); |
2922 | if (ipa_len) { | |
2923 | ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 | |
2924 | : IPADDR_V6; | |
2925 | stream_get(&ip.ip.addr, s, ipa_len); | |
2926 | } | |
ff8b7eb8 | 2927 | l += 4 + ETH_ALEN + 4 + ipa_len; |
d62a17ae | 2928 | vtep_ip.s_addr = stream_get_ipv4(s); |
2929 | l += IPV4_MAX_BYTELEN; | |
2930 | ||
2931 | /* Get 'sticky' flag. */ | |
2932 | sticky = stream_getc(s); | |
2933 | l++; | |
2934 | ||
2935 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2936 | zlog_debug( | |
2937 | "%u:Recv MACIP Add %sMAC %s IP %s VNI %u Remote VTEP %s from %s", | |
2938 | zvrf_id(zvrf), sticky ? "sticky " : "", | |
2939 | prefix_mac2str(&macaddr, buf, sizeof(buf)), | |
2940 | ipaddr2str(&ip, buf1, sizeof(buf1)), vni, | |
2941 | inet_ntoa(vtep_ip), | |
2942 | zebra_route_string(client->proto)); | |
2943 | ||
2944 | /* Locate VNI hash entry - expected to exist. */ | |
2945 | zvni = zvni_lookup(zvrf, vni); | |
2946 | if (!zvni) { | |
2947 | zlog_err( | |
2948 | "Failed to locate VNI hash upon remote MACIP ADD, VRF %d VNI %u", | |
2949 | zvrf_id(zvrf), vni); | |
2950 | continue; | |
2951 | } | |
2952 | if (!zvni->vxlan_if) { | |
2953 | zlog_err( | |
2954 | "VNI %u hash %p doesn't have intf upon remote MACIP add", | |
2955 | vni, zvni); | |
2956 | continue; | |
2957 | } | |
2958 | /* If the local VxLAN interface is not up (should be a transient | |
2959 | * event), there's nothing more to do. | |
2960 | */ | |
2961 | if (!if_is_operative(zvni->vxlan_if)) | |
2962 | continue; | |
2963 | ||
2964 | /* The remote VTEP specified should normally exist, but it is | |
2965 | * possible | |
2966 | * that when peering comes up, peer may advertise MACIP routes | |
2967 | * before | |
2968 | * advertising type-3 routes. | |
2969 | */ | |
2970 | zvtep = zvni_vtep_find(zvni, &vtep_ip); | |
2971 | if (!zvtep) { | |
2972 | if (zvni_vtep_add(zvni, &vtep_ip) == NULL) { | |
2973 | zlog_err( | |
2974 | "Failed to add remote VTEP, VRF %d VNI %u zvni %p", | |
2975 | zvrf_id(zvrf), vni, zvni); | |
2976 | continue; | |
2977 | } | |
2978 | ||
2979 | zvni_vtep_install(zvni, &vtep_ip); | |
2980 | } | |
2981 | ||
2982 | /* First, check if the remote MAC is unknown or has a change. If | |
2983 | * so, | |
2984 | * that needs to be updated first. Note that client could | |
2985 | * install | |
2986 | * MAC and MACIP separately or just install the latter. | |
2987 | */ | |
2988 | mac = zvni_mac_lookup(zvni, &macaddr); | |
2989 | if (!mac || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) | |
2990 | || (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0) | |
2991 | != sticky | |
2992 | || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip)) | |
2993 | update_mac = 1; | |
2994 | ||
2995 | if (update_mac) { | |
2996 | if (!mac) { | |
2997 | mac = zvni_mac_add(zvni, &macaddr); | |
2998 | if (!mac) { | |
2999 | zlog_warn( | |
3000 | "%u:Failed to add MAC %s VNI %u Remote VTEP %s", | |
3001 | zvrf_id(zvrf), | |
3002 | prefix_mac2str(&macaddr, buf, | |
3003 | sizeof(buf)), | |
3004 | vni, inet_ntoa(vtep_ip)); | |
3005 | return -1; | |
3006 | } | |
3007 | ||
3008 | /* Is this MAC created for a MACIP? */ | |
3009 | if (ipa_len) | |
3010 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
3011 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
3012 | /* Moving from local to remote, issue delete. */ | |
3013 | zvni_mac_uninstall(zvni, mac, 1); | |
3014 | } | |
3015 | ||
3016 | /* Set "auto" and "remote" forwarding info. */ | |
3017 | UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); | |
3018 | memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); | |
3019 | SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); | |
3020 | mac->fwd_info.r_vtep_ip = vtep_ip; | |
3021 | ||
3022 | if (sticky) | |
3023 | SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
3024 | else | |
3025 | UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
3026 | ||
3027 | /* Install the entry. */ | |
3028 | zvni_mac_install(zvni, mac); | |
3029 | } | |
3030 | ||
3031 | /* If there is no IP, continue - after clearing AUTO flag of | |
3032 | * MAC. */ | |
3033 | if (!ipa_len) { | |
3034 | UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
3035 | continue; | |
3036 | } | |
3037 | ||
3038 | /* Check if the remote neighbor itself is unknown or has a | |
3039 | * change. | |
3040 | * If so, create or update and then install the entry. | |
3041 | */ | |
3042 | n = zvni_neigh_lookup(zvni, &ip); | |
3043 | if (!n || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) | |
3044 | || (memcmp(&n->emac, &macaddr, sizeof(macaddr)) != 0) | |
3045 | || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip)) | |
3046 | update_neigh = 1; | |
3047 | ||
3048 | if (update_neigh) { | |
3049 | if (!n) { | |
3050 | n = zvni_neigh_add(zvni, &ip); | |
3051 | if (!n) { | |
3052 | zlog_warn( | |
3053 | "%u:Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s", | |
3054 | zvrf_id(zvrf), | |
3055 | ipaddr2str(&ip, buf1, | |
3056 | sizeof(buf1)), | |
3057 | prefix_mac2str(&macaddr, buf, | |
3058 | sizeof(buf)), | |
3059 | vni, inet_ntoa(vtep_ip)); | |
3060 | return -1; | |
3061 | } | |
3062 | ||
3063 | /* New neighbor referring to this MAC. */ | |
3064 | mac->neigh_refcnt++; | |
3065 | } else if (memcmp(&n->emac, &macaddr, sizeof(macaddr)) | |
3066 | != 0) { | |
3067 | /* MAC change, update ref counts for old and new | |
3068 | * MAC. */ | |
3069 | old_mac = zvni_mac_lookup(zvni, &n->emac); | |
3070 | if (old_mac) | |
3071 | zvni_deref_ip2mac(zvni, old_mac, 1); | |
3072 | mac->neigh_refcnt++; | |
3073 | } | |
3074 | ||
3075 | /* Set "remote" forwarding info. */ | |
3076 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
3077 | /* TODO: Handle MAC change. */ | |
ff8b7eb8 | 3078 | memcpy(&n->emac, &macaddr, ETH_ALEN); |
d62a17ae | 3079 | n->r_vtep_ip = vtep_ip; |
3080 | SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); | |
3081 | ||
3082 | /* Install the entry. */ | |
3083 | zvni_neigh_install(zvni, n); | |
3084 | } | |
3085 | } | |
3086 | ||
3087 | return 0; | |
13d60d35 | 3088 | } |
3089 | ||
3090 | /* | |
2232a77c | 3091 | * Handle notification of MAC add/update over VxLAN. If the kernel is notifying |
3092 | * us, this must involve a multihoming scenario. Treat this as implicit delete | |
3093 | * of any prior local MAC. | |
13d60d35 | 3094 | */ |
d62a17ae | 3095 | int zebra_vxlan_check_del_local_mac(struct interface *ifp, |
3096 | struct interface *br_if, | |
3097 | struct ethaddr *macaddr, vlanid_t vid) | |
13d60d35 | 3098 | { |
d62a17ae | 3099 | struct zebra_if *zif; |
3100 | struct zebra_vrf *zvrf; | |
3101 | struct zebra_l2info_vxlan *vxl; | |
3102 | vni_t vni; | |
3103 | zebra_vni_t *zvni; | |
3104 | zebra_mac_t *mac; | |
3105 | char buf[ETHER_ADDR_STRLEN]; | |
3106 | u_char sticky; | |
13d60d35 | 3107 | |
d62a17ae | 3108 | zif = ifp->info; |
3109 | assert(zif); | |
3110 | vxl = &zif->l2info.vxl; | |
3111 | vni = vxl->vni; | |
13d60d35 | 3112 | |
d62a17ae | 3113 | /* Locate VRF corresponding to interface. */ |
3114 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
3115 | assert(zvrf); | |
13d60d35 | 3116 | |
d62a17ae | 3117 | /* If EVPN is not enabled, nothing to do. */ |
3118 | if (!EVPN_ENABLED(zvrf)) | |
3119 | return 0; | |
13d60d35 | 3120 | |
d62a17ae | 3121 | /* Locate hash entry; it is expected to exist. */ |
3122 | zvni = zvni_lookup(zvrf, vni); | |
3123 | if (!zvni) | |
3124 | return 0; | |
13d60d35 | 3125 | |
d62a17ae | 3126 | /* If entry doesn't exist, nothing to do. */ |
3127 | mac = zvni_mac_lookup(zvni, macaddr); | |
3128 | if (!mac) | |
3129 | return 0; | |
13d60d35 | 3130 | |
d62a17ae | 3131 | /* Is it a local entry? */ |
3132 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) | |
3133 | return 0; | |
13d60d35 | 3134 | |
d62a17ae | 3135 | if (IS_ZEBRA_DEBUG_VXLAN) |
3136 | zlog_debug( | |
3137 | "%u:Add/update remote MAC %s intf %s(%u) VNI %u - del local", | |
3138 | ifp->vrf_id, prefix_mac2str(macaddr, buf, sizeof(buf)), | |
3139 | ifp->name, ifp->ifindex, vni); | |
13d60d35 | 3140 | |
d62a17ae | 3141 | /* Remove MAC from BGP. */ |
3142 | sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; | |
1a98c087 MK |
3143 | zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, |
3144 | (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); | |
13d60d35 | 3145 | |
d62a17ae | 3146 | /* Delete this MAC entry. */ |
3147 | zvni_mac_del(zvni, mac); | |
13d60d35 | 3148 | |
d62a17ae | 3149 | return 0; |
13d60d35 | 3150 | } |
3151 | ||
3152 | /* | |
2232a77c | 3153 | * Handle remote MAC delete by kernel; readd the remote MAC if we have it. |
3154 | * This can happen because the remote MAC entries are also added as "dynamic", | |
3155 | * so the kernel can ageout the entry. | |
13d60d35 | 3156 | */ |
d62a17ae | 3157 | int zebra_vxlan_check_readd_remote_mac(struct interface *ifp, |
3158 | struct interface *br_if, | |
3159 | struct ethaddr *macaddr, vlanid_t vid) | |
13d60d35 | 3160 | { |
d62a17ae | 3161 | struct zebra_if *zif; |
3162 | struct zebra_vrf *zvrf; | |
3163 | struct zebra_l2info_vxlan *vxl; | |
3164 | vni_t vni; | |
3165 | zebra_vni_t *zvni; | |
3166 | zebra_mac_t *mac; | |
3167 | char buf[ETHER_ADDR_STRLEN]; | |
2232a77c | 3168 | |
d62a17ae | 3169 | zif = ifp->info; |
3170 | assert(zif); | |
3171 | vxl = &zif->l2info.vxl; | |
3172 | vni = vxl->vni; | |
2232a77c | 3173 | |
d62a17ae | 3174 | /* Locate VRF corresponding to interface. */ |
3175 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
3176 | assert(zvrf); | |
13d60d35 | 3177 | |
d62a17ae | 3178 | /* If EVPN is not enabled, nothing to do. */ |
3179 | if (!EVPN_ENABLED(zvrf)) | |
3180 | return 0; | |
2232a77c | 3181 | |
d62a17ae | 3182 | /* Locate hash entry; it is expected to exist. */ |
3183 | zvni = zvni_lookup(zvrf, vni); | |
3184 | if (!zvni) | |
3185 | return 0; | |
13d60d35 | 3186 | |
d62a17ae | 3187 | /* If entry doesn't exist, nothing to do. */ |
3188 | mac = zvni_mac_lookup(zvni, macaddr); | |
3189 | if (!mac) | |
3190 | return 0; | |
2232a77c | 3191 | |
d62a17ae | 3192 | /* Is it a remote entry? */ |
3193 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) | |
3194 | return 0; | |
2232a77c | 3195 | |
d62a17ae | 3196 | if (IS_ZEBRA_DEBUG_VXLAN) |
3197 | zlog_debug("%u:Del remote MAC %s intf %s(%u) VNI %u - readd", | |
3198 | ifp->vrf_id, | |
3199 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, | |
3200 | ifp->ifindex, vni); | |
13d60d35 | 3201 | |
d62a17ae | 3202 | zvni_mac_install(zvni, mac); |
3203 | return 0; | |
13d60d35 | 3204 | } |
3205 | ||
3206 | /* | |
2232a77c | 3207 | * Handle local MAC delete (on a port or VLAN corresponding to this VNI). |
13d60d35 | 3208 | */ |
d62a17ae | 3209 | int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, |
3210 | struct ethaddr *macaddr, vlanid_t vid) | |
13d60d35 | 3211 | { |
d62a17ae | 3212 | zebra_vni_t *zvni; |
3213 | zebra_mac_t *mac; | |
3214 | struct zebra_vrf *zvrf; | |
3215 | char buf[ETHER_ADDR_STRLEN]; | |
3216 | u_char sticky; | |
13d60d35 | 3217 | |
d62a17ae | 3218 | /* We are interested in MACs only on ports or (port, VLAN) that |
3219 | * map to a VNI. | |
3220 | */ | |
3221 | zvni = zvni_map_vlan(ifp, br_if, vid); | |
3222 | if (!zvni) | |
3223 | return 0; | |
3224 | if (!zvni->vxlan_if) { | |
3225 | zlog_err("VNI %u hash %p doesn't have intf upon local MAC DEL", | |
3226 | zvni->vni, zvni); | |
3227 | return -1; | |
3228 | } | |
13d60d35 | 3229 | |
d62a17ae | 3230 | if (IS_ZEBRA_DEBUG_VXLAN) |
3231 | zlog_debug("%u:Del MAC %s intf %s(%u) VID %u -> VNI %u", | |
3232 | ifp->vrf_id, | |
3233 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, | |
3234 | ifp->ifindex, vid, zvni->vni); | |
2232a77c | 3235 | |
d62a17ae | 3236 | /* If entry doesn't exist, nothing to do. */ |
3237 | mac = zvni_mac_lookup(zvni, macaddr); | |
3238 | if (!mac) | |
3239 | return 0; | |
2232a77c | 3240 | |
d62a17ae | 3241 | /* Is it a local entry? */ |
3242 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) | |
3243 | return 0; | |
2232a77c | 3244 | |
d62a17ae | 3245 | /* Locate VRF corresponding to interface. */ |
3246 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); | |
3247 | assert(zvrf); | |
2232a77c | 3248 | |
d62a17ae | 3249 | /* Remove MAC from BGP. */ |
3250 | sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; | |
1a98c087 MK |
3251 | zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, |
3252 | (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); | |
2232a77c | 3253 | |
d62a17ae | 3254 | /* Delete this MAC entry. */ |
3255 | zvni_mac_del(zvni, mac); | |
2232a77c | 3256 | |
d62a17ae | 3257 | return 0; |
13d60d35 | 3258 | } |
3259 | ||
3260 | /* | |
2232a77c | 3261 | * Handle local MAC add (on a port or VLAN corresponding to this VNI). |
13d60d35 | 3262 | */ |
d62a17ae | 3263 | int zebra_vxlan_local_mac_add_update(struct interface *ifp, |
3264 | struct interface *br_if, | |
3265 | struct ethaddr *macaddr, vlanid_t vid, | |
3266 | u_char sticky) | |
3267 | { | |
3268 | zebra_vni_t *zvni; | |
3269 | zebra_mac_t *mac; | |
3270 | struct zebra_vrf *zvrf; | |
3271 | char buf[ETHER_ADDR_STRLEN]; | |
3272 | int add = 1; | |
3273 | u_char mac_sticky; | |
3274 | ||
3275 | /* We are interested in MACs only on ports or (port, VLAN) that | |
3276 | * map to a VNI. | |
3277 | */ | |
3278 | zvni = zvni_map_vlan(ifp, br_if, vid); | |
3279 | if (!zvni) { | |
3280 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3281 | zlog_debug( | |
3282 | "%u:Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI", | |
3283 | ifp->vrf_id, sticky ? "sticky " : "", | |
3284 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
3285 | ifp->name, ifp->ifindex, vid); | |
3286 | return 0; | |
3287 | } | |
3288 | ||
3289 | if (!zvni->vxlan_if) { | |
3290 | zlog_err("VNI %u hash %p doesn't have intf upon local MAC ADD", | |
3291 | zvni->vni, zvni); | |
3292 | return -1; | |
3293 | } | |
3294 | ||
3295 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3296 | zlog_debug( | |
3297 | "%u:Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u", | |
3298 | ifp->vrf_id, sticky ? "sticky " : "", | |
3299 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, | |
3300 | ifp->ifindex, vid, zvni->vni); | |
3301 | ||
3302 | /* If same entry already exists, nothing to do. */ | |
3303 | mac = zvni_mac_lookup(zvni, macaddr); | |
3304 | if (mac) { | |
3305 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
3306 | mac_sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) | |
3307 | ? 1 | |
3308 | : 0; | |
3309 | ||
b8ce75a5 MK |
3310 | /* |
3311 | * return if nothing has changed. | |
3312 | * inform bgp if sticky flag has changed | |
3313 | * update locally and do not inform bgp if local | |
3314 | * parameters like interface has changed | |
3315 | */ | |
d62a17ae | 3316 | if (mac_sticky == sticky |
3317 | && mac->fwd_info.local.ifindex == ifp->ifindex | |
3318 | && mac->fwd_info.local.vid == vid) { | |
3319 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3320 | zlog_debug( | |
3321 | "%u:Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, " | |
3322 | "entry exists and has not changed ", | |
3323 | ifp->vrf_id, | |
3324 | sticky ? "sticky " : "", | |
3325 | prefix_mac2str(macaddr, buf, | |
3326 | sizeof(buf)), | |
3327 | ifp->name, ifp->ifindex, vid, | |
3328 | zvni->vni); | |
3329 | return 0; | |
b8ce75a5 MK |
3330 | } else if (mac_sticky != sticky) |
3331 | add = 1; | |
3332 | else | |
3333 | add = 0; /* This is an update of local | |
3334 | interface. */ | |
421bb26a MK |
3335 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { |
3336 | /* | |
3337 | * If we have already learned the MAC as a remote sticky | |
3338 | * MAC, | |
3339 | * this is a operator error and we must log a warning | |
3340 | */ | |
8f4b98ee | 3341 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) { |
421bb26a MK |
3342 | zlog_warn( |
3343 | "MAC %s is already learnt as a remote sticky mac behind VTEP %s VNI %d", | |
3344 | prefix_mac2str(macaddr, buf, | |
3345 | sizeof(buf)), | |
3346 | inet_ntoa(mac->fwd_info.r_vtep_ip), | |
3347 | zvni->vni); | |
8f4b98ee MK |
3348 | return 0; |
3349 | } | |
d62a17ae | 3350 | } |
3351 | } | |
3352 | ||
3353 | /* Locate VRF corresponding to interface. */ | |
3354 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); | |
3355 | assert(zvrf); | |
3356 | ||
3357 | if (!mac) { | |
3358 | mac = zvni_mac_add(zvni, macaddr); | |
3359 | if (!mac) { | |
3360 | zlog_err("%u:Failed to add MAC %s intf %s(%u) VID %u", | |
3361 | ifp->vrf_id, | |
3362 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
3363 | ifp->name, ifp->ifindex, vid); | |
3364 | return -1; | |
3365 | } | |
3366 | } | |
3367 | ||
3368 | /* Set "local" forwarding info. */ | |
3369 | UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); | |
3370 | memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); | |
3371 | SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); | |
3372 | mac->fwd_info.local.ifindex = ifp->ifindex; | |
3373 | mac->fwd_info.local.vid = vid; | |
3374 | ||
3375 | if (sticky) | |
3376 | SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
3377 | else | |
3378 | UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
3379 | ||
3380 | /* Inform BGP if required. */ | |
3381 | if (add) | |
1a98c087 MK |
3382 | return zvni_mac_send_add_to_client( |
3383 | zvrf, zvni->vni, macaddr, | |
3384 | (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); | |
d62a17ae | 3385 | |
3386 | return 0; | |
2232a77c | 3387 | } |
13d60d35 | 3388 | |
3389 | /* | |
3390 | * Handle message from client to delete a remote VTEP for a VNI. | |
3391 | */ | |
d62a17ae | 3392 | int zebra_vxlan_remote_vtep_del(struct zserv *client, int sock, u_short length, |
3393 | struct zebra_vrf *zvrf) | |
3394 | { | |
3395 | struct stream *s; | |
3396 | u_short l = 0; | |
3397 | vni_t vni; | |
3398 | struct in_addr vtep_ip; | |
3399 | zebra_vni_t *zvni; | |
3400 | zebra_vtep_t *zvtep; | |
3401 | ||
3402 | s = client->ibuf; | |
3403 | ||
3404 | while (l < length) { | |
3405 | /* Obtain each remote VTEP and process. */ | |
3406 | vni = (vni_t)stream_getl(s); | |
3407 | l += 4; | |
3408 | vtep_ip.s_addr = stream_get_ipv4(s); | |
3409 | l += IPV4_MAX_BYTELEN; | |
3410 | ||
3411 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3412 | zlog_debug("%u:Recv VTEP_DEL %s VNI %u from %s", | |
3413 | zvrf_id(zvrf), inet_ntoa(vtep_ip), vni, | |
3414 | zebra_route_string(client->proto)); | |
3415 | ||
3416 | /* Locate VNI hash entry - expected to exist. */ | |
3417 | zvni = zvni_lookup(zvrf, vni); | |
3418 | if (!zvni) { | |
3419 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3420 | zlog_debug( | |
3421 | "Failed to locate VNI hash upon remote VTEP DEL, " | |
3422 | "VRF %d VNI %u", | |
3423 | zvrf_id(zvrf), vni); | |
3424 | continue; | |
3425 | } | |
3426 | ||
3427 | /* If the remote VTEP does not exist, there's nothing more to | |
3428 | * do. | |
3429 | * Otherwise, uninstall any remote MACs pointing to this VTEP | |
3430 | * and | |
3431 | * then, the VTEP entry itself and remove it. | |
3432 | */ | |
3433 | zvtep = zvni_vtep_find(zvni, &vtep_ip); | |
3434 | if (!zvtep) | |
3435 | continue; | |
3436 | ||
3437 | zvni_neigh_del_from_vtep(zvni, 1, &vtep_ip); | |
3438 | zvni_mac_del_from_vtep(zvni, 1, &vtep_ip); | |
3439 | zvni_vtep_uninstall(zvni, &vtep_ip); | |
3440 | zvni_vtep_del(zvni, zvtep); | |
3441 | } | |
3442 | ||
3443 | return 0; | |
13d60d35 | 3444 | } |
3445 | ||
3446 | /* | |
3447 | * Handle message from client to add a remote VTEP for a VNI. | |
3448 | */ | |
d62a17ae | 3449 | int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock, u_short length, |
3450 | struct zebra_vrf *zvrf) | |
3451 | { | |
3452 | struct stream *s; | |
3453 | u_short l = 0; | |
3454 | vni_t vni; | |
3455 | struct in_addr vtep_ip; | |
3456 | zebra_vni_t *zvni; | |
3457 | ||
3458 | assert(EVPN_ENABLED(zvrf)); | |
3459 | ||
3460 | s = client->ibuf; | |
3461 | ||
3462 | while (l < length) { | |
3463 | /* Obtain each remote VTEP and process. */ | |
3464 | vni = (vni_t)stream_getl(s); | |
3465 | l += 4; | |
3466 | vtep_ip.s_addr = stream_get_ipv4(s); | |
3467 | l += IPV4_MAX_BYTELEN; | |
3468 | ||
3469 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3470 | zlog_debug("%u:Recv VTEP_ADD %s VNI %u from %s", | |
3471 | zvrf_id(zvrf), inet_ntoa(vtep_ip), vni, | |
3472 | zebra_route_string(client->proto)); | |
3473 | ||
3474 | /* Locate VNI hash entry - expected to exist. */ | |
3475 | zvni = zvni_lookup(zvrf, vni); | |
3476 | if (!zvni) { | |
3477 | zlog_err( | |
3478 | "Failed to locate VNI hash upon remote VTEP ADD, VRF %d VNI %u", | |
3479 | zvrf_id(zvrf), vni); | |
3480 | continue; | |
3481 | } | |
3482 | if (!zvni->vxlan_if) { | |
3483 | zlog_err( | |
3484 | "VNI %u hash %p doesn't have intf upon remote VTEP ADD", | |
3485 | zvni->vni, zvni); | |
3486 | continue; | |
3487 | } | |
3488 | ||
3489 | ||
3490 | /* If the remote VTEP already exists, or the local VxLAN | |
3491 | * interface is | |
3492 | * not up (should be a transient event), there's nothing more | |
3493 | * to do. | |
3494 | * Otherwise, add and install the entry. | |
3495 | */ | |
3496 | if (zvni_vtep_find(zvni, &vtep_ip)) | |
3497 | continue; | |
3498 | ||
3499 | if (!if_is_operative(zvni->vxlan_if)) | |
3500 | continue; | |
3501 | ||
3502 | if (zvni_vtep_add(zvni, &vtep_ip) == NULL) { | |
3503 | zlog_err( | |
3504 | "Failed to add remote VTEP, VRF %d VNI %u zvni %p", | |
3505 | zvrf_id(zvrf), vni, zvni); | |
3506 | continue; | |
3507 | } | |
3508 | ||
3509 | zvni_vtep_install(zvni, &vtep_ip); | |
3510 | } | |
3511 | ||
3512 | return 0; | |
13d60d35 | 3513 | } |
3514 | ||
1a98c087 MK |
3515 | /* |
3516 | * Add/Del gateway macip to evpn | |
3517 | * g/w can be: | |
3518 | * 1. SVI interface on a vlan aware bridge | |
3519 | * 2. SVI interface on a vlan unaware bridge | |
3520 | * 3. vrr interface (MACVLAN) associated to a SVI | |
3521 | * We advertise macip routes for an interface if it is associated to VxLan vlan | |
3522 | */ | |
3523 | int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, | |
3524 | int add) | |
3525 | { | |
3526 | struct ipaddr ip; | |
3527 | struct ethaddr macaddr; | |
3528 | zebra_vni_t *zvni = NULL; | |
3529 | struct zebra_vrf *zvrf = NULL; | |
3530 | ||
3531 | memset(&ip, 0, sizeof(struct ipaddr)); | |
3532 | memset(&macaddr, 0, sizeof(struct ethaddr)); | |
3533 | ||
3534 | if (IS_ZEBRA_IF_MACVLAN(ifp)) { | |
3535 | struct interface *svi_if = | |
3536 | NULL; /* SVI corresponding to the MACVLAN */ | |
3537 | struct zebra_if *ifp_zif = | |
3538 | NULL; /* Zebra daemon specific info for MACVLAN */ | |
3539 | struct zebra_if *svi_if_zif = | |
3540 | NULL; /* Zebra daemon specific info for SVI*/ | |
3541 | ||
3542 | ifp_zif = ifp->info; | |
3543 | if (!ifp_zif) | |
3544 | return -1; | |
3545 | ||
3546 | svi_if = ifp_zif->link; | |
3547 | if (!svi_if) { | |
3548 | zlog_err("%u:MACVLAN %s(%u) without link information", | |
3549 | ifp->vrf_id, ifp->name, ifp->ifindex); | |
3550 | return -1; | |
3551 | } | |
3552 | ||
3553 | if (IS_ZEBRA_IF_VLAN(svi_if)) { | |
3554 | svi_if_zif = svi_if->info; | |
3555 | if (svi_if_zif) | |
3556 | zvni = zvni_map_svi(svi_if, svi_if_zif->link); | |
3557 | } else if (IS_ZEBRA_IF_BRIDGE(svi_if)) { | |
3558 | zvni = zvni_map_svi(svi_if, svi_if); | |
3559 | } | |
3560 | } else if (IS_ZEBRA_IF_VLAN(ifp)) { | |
3561 | struct zebra_if *svi_if_zif = | |
3562 | NULL; /* Zebra daemon specific info for SVI*/ | |
3563 | ||
3564 | svi_if_zif = ifp->info; | |
3565 | if (svi_if_zif) | |
3566 | zvni = zvni_map_svi(ifp, svi_if_zif->link); | |
3567 | } else if (IS_ZEBRA_IF_BRIDGE(ifp)) { | |
3568 | zvni = zvni_map_svi(ifp, ifp); | |
3569 | } | |
3570 | ||
3571 | if (!zvni) | |
3572 | return 0; | |
3573 | ||
3574 | if (!zvni->vxlan_if) { | |
3575 | zlog_err("VNI %u hash %p doesn't have intf upon MACVLAN up", | |
3576 | zvni->vni, zvni); | |
3577 | return -1; | |
3578 | } | |
3579 | ||
3580 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); | |
3581 | if (!zvrf) | |
3582 | return -1; | |
3583 | ||
3584 | /* check if we are advertising gw macip routes */ | |
3585 | if (!advertise_gw_macip_enabled(zvrf, zvni)) | |
3586 | return 0; | |
3587 | ||
3588 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); | |
3589 | ||
3590 | if (p->family == AF_INET) { | |
3591 | ip.ipa_type = IPADDR_V4; | |
3592 | memcpy(&(ip.ipaddr_v4), &(p->u.prefix4), | |
3593 | sizeof(struct in_addr)); | |
3594 | } else if (p->family == AF_INET6) { | |
3595 | ip.ipa_type = IPADDR_V6; | |
3596 | memcpy(&(ip.ipaddr_v6), &(p->u.prefix6), | |
3597 | sizeof(struct in6_addr)); | |
3598 | } | |
3599 | ||
3600 | ||
3601 | if (add) | |
3602 | zvni_gw_macip_add(ifp, zvni, &macaddr, &ip); | |
3603 | else | |
3604 | zvni_gw_macip_del(ifp, zvni, &ip); | |
3605 | ||
3606 | return 0; | |
3607 | } | |
3608 | ||
2232a77c | 3609 | /* |
3610 | * Handle SVI interface going down. At this point, this is a NOP since | |
3611 | * the kernel deletes the neighbor entries on this SVI (if any). | |
3612 | */ | |
d62a17ae | 3613 | int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if) |
2232a77c | 3614 | { |
d62a17ae | 3615 | return 0; |
2232a77c | 3616 | } |
3617 | ||
3618 | /* | |
3619 | * Handle SVI interface coming up. This may or may not be of interest, | |
3620 | * but if this is a SVI on a VxLAN bridge, we need to install any remote | |
3621 | * neighbor entries (which will be used for EVPN ARP suppression). | |
3622 | */ | |
d62a17ae | 3623 | int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) |
2232a77c | 3624 | { |
d62a17ae | 3625 | zebra_vni_t *zvni; |
3626 | struct neigh_walk_ctx n_wctx; | |
2232a77c | 3627 | |
d62a17ae | 3628 | zvni = zvni_map_svi(ifp, link_if); |
3629 | if (!zvni) | |
3630 | return 0; | |
2232a77c | 3631 | |
d62a17ae | 3632 | if (!zvni->vxlan_if) { |
3633 | zlog_err("VNI %u hash %p doesn't have intf upon SVI up", | |
3634 | zvni->vni, zvni); | |
3635 | return -1; | |
3636 | } | |
2232a77c | 3637 | |
d62a17ae | 3638 | if (IS_ZEBRA_DEBUG_VXLAN) |
3639 | zlog_debug("%u:SVI %s(%u) VNI %u is UP, installing neighbors", | |
3640 | ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni); | |
2232a77c | 3641 | |
d62a17ae | 3642 | /* Install any remote neighbors for this VNI. */ |
3643 | memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); | |
3644 | n_wctx.zvni = zvni; | |
3645 | hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, &n_wctx); | |
2232a77c | 3646 | |
d62a17ae | 3647 | return 0; |
2232a77c | 3648 | } |
3649 | ||
13d60d35 | 3650 | /* |
3651 | * Handle VxLAN interface down - update BGP if required, and do | |
3652 | * internal cleanup. | |
3653 | */ | |
d62a17ae | 3654 | int zebra_vxlan_if_down(struct interface *ifp) |
13d60d35 | 3655 | { |
d62a17ae | 3656 | struct zebra_if *zif; |
3657 | struct zebra_vrf *zvrf; | |
3658 | zebra_vni_t *zvni; | |
3659 | struct zebra_l2info_vxlan *vxl; | |
3660 | vni_t vni; | |
13d60d35 | 3661 | |
d62a17ae | 3662 | /* Locate VRF corresponding to interface. */ |
3663 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
3664 | assert(zvrf); | |
13d60d35 | 3665 | |
d62a17ae | 3666 | /* If EVPN is not enabled, nothing further to be done. */ |
3667 | if (!EVPN_ENABLED(zvrf)) | |
3668 | return 0; | |
13d60d35 | 3669 | |
d62a17ae | 3670 | zif = ifp->info; |
3671 | assert(zif); | |
3672 | vxl = &zif->l2info.vxl; | |
3673 | vni = vxl->vni; | |
13d60d35 | 3674 | |
d62a17ae | 3675 | if (IS_ZEBRA_DEBUG_VXLAN) |
3676 | zlog_debug("%u:Intf %s(%u) VNI %u is DOWN", ifp->vrf_id, | |
3677 | ifp->name, ifp->ifindex, vni); | |
13d60d35 | 3678 | |
d62a17ae | 3679 | /* Locate hash entry; it is expected to exist. */ |
3680 | zvni = zvni_lookup(zvrf, vni); | |
3681 | if (!zvni) { | |
3682 | zlog_err( | |
3683 | "Failed to locate VNI hash at DOWN, VRF %d IF %s(%u) VNI %u", | |
3684 | ifp->vrf_id, ifp->name, ifp->ifindex, vni); | |
3685 | return -1; | |
3686 | } | |
13d60d35 | 3687 | |
d62a17ae | 3688 | assert(zvni->vxlan_if == ifp); |
13d60d35 | 3689 | |
d62a17ae | 3690 | /* Delete this VNI from BGP. */ |
3691 | zvni_send_del_to_client(zvrf, zvni->vni); | |
13d60d35 | 3692 | |
d62a17ae | 3693 | /* Free up all neighbors and MACs, if any. */ |
3694 | zvni_neigh_del_all(zvrf, zvni, 1, 0, DEL_ALL_NEIGH); | |
3695 | zvni_mac_del_all(zvrf, zvni, 1, 0, DEL_ALL_MAC); | |
2232a77c | 3696 | |
d62a17ae | 3697 | /* Free up all remote VTEPs, if any. */ |
3698 | zvni_vtep_del_all(zvni, 1); | |
13d60d35 | 3699 | |
d62a17ae | 3700 | return 0; |
13d60d35 | 3701 | } |
3702 | ||
3703 | /* | |
3704 | * Handle VxLAN interface up - update BGP if required. | |
3705 | */ | |
d62a17ae | 3706 | int zebra_vxlan_if_up(struct interface *ifp) |
13d60d35 | 3707 | { |
d62a17ae | 3708 | struct zebra_if *zif; |
3709 | struct zebra_vrf *zvrf; | |
3710 | zebra_vni_t *zvni; | |
3711 | struct zebra_l2info_vxlan *vxl; | |
3712 | vni_t vni; | |
13d60d35 | 3713 | |
d62a17ae | 3714 | /* Locate VRF corresponding to interface. */ |
3715 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
3716 | assert(zvrf); | |
13d60d35 | 3717 | |
d62a17ae | 3718 | /* If EVPN is not enabled, nothing further to be done. */ |
3719 | if (!EVPN_ENABLED(zvrf)) | |
3720 | return 0; | |
13d60d35 | 3721 | |
d62a17ae | 3722 | zif = ifp->info; |
3723 | assert(zif); | |
3724 | vxl = &zif->l2info.vxl; | |
3725 | vni = vxl->vni; | |
13d60d35 | 3726 | |
d62a17ae | 3727 | if (IS_ZEBRA_DEBUG_VXLAN) |
3728 | zlog_debug("%u:Intf %s(%u) VNI %u is UP", ifp->vrf_id, | |
3729 | ifp->name, ifp->ifindex, vni); | |
13d60d35 | 3730 | |
d62a17ae | 3731 | /* Locate hash entry; it is expected to exist. */ |
3732 | zvni = zvni_lookup(zvrf, vni); | |
3733 | if (!zvni) { | |
3734 | zlog_err( | |
3735 | "Failed to locate VNI hash at UP, VRF %d IF %s(%u) VNI %u", | |
3736 | ifp->vrf_id, ifp->name, ifp->ifindex, vni); | |
3737 | return -1; | |
3738 | } | |
13d60d35 | 3739 | |
d62a17ae | 3740 | assert(zvni->vxlan_if == ifp); |
13d60d35 | 3741 | |
d62a17ae | 3742 | /* If part of a bridge, inform BGP about this VNI. */ |
3743 | /* Also, read and populate local MACs and neighbors. */ | |
3744 | if (zif->brslave_info.br_if) { | |
3745 | zvni_send_add_to_client(zvrf, zvni); | |
3746 | zvni_read_mac_neigh(zvrf, zvni, ifp); | |
3747 | } | |
13d60d35 | 3748 | |
d62a17ae | 3749 | return 0; |
13d60d35 | 3750 | } |
3751 | ||
3752 | /* | |
3753 | * Handle VxLAN interface delete. Locate and remove entry in hash table | |
3754 | * and update BGP, if required. | |
3755 | */ | |
d62a17ae | 3756 | int zebra_vxlan_if_del(struct interface *ifp) |
13d60d35 | 3757 | { |
d62a17ae | 3758 | struct zebra_if *zif; |
3759 | struct zebra_vrf *zvrf; | |
3760 | zebra_vni_t *zvni; | |
3761 | struct zebra_l2info_vxlan *vxl; | |
3762 | vni_t vni; | |
13d60d35 | 3763 | |
d62a17ae | 3764 | /* Locate VRF corresponding to interface. */ |
3765 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
3766 | assert(zvrf); | |
13d60d35 | 3767 | |
d62a17ae | 3768 | /* If EVPN is not enabled, nothing further to be done. */ |
3769 | if (!EVPN_ENABLED(zvrf)) | |
3770 | return 0; | |
13d60d35 | 3771 | |
d62a17ae | 3772 | zif = ifp->info; |
3773 | assert(zif); | |
3774 | vxl = &zif->l2info.vxl; | |
3775 | vni = vxl->vni; | |
13d60d35 | 3776 | |
d62a17ae | 3777 | if (IS_ZEBRA_DEBUG_VXLAN) |
3778 | zlog_debug("%u:Del VNI %u intf %s(%u)", ifp->vrf_id, vni, | |
3779 | ifp->name, ifp->ifindex); | |
13d60d35 | 3780 | |
d62a17ae | 3781 | /* Locate hash entry; it is expected to exist. */ |
3782 | zvni = zvni_lookup(zvrf, vni); | |
3783 | if (!zvni) { | |
3784 | zlog_err( | |
3785 | "Failed to locate VNI hash at del, VRF %d IF %s(%u) VNI %u", | |
3786 | ifp->vrf_id, ifp->name, ifp->ifindex, vni); | |
3787 | return 0; | |
3788 | } | |
13d60d35 | 3789 | |
d62a17ae | 3790 | /* Delete VNI from BGP. */ |
3791 | zvni_send_del_to_client(zvrf, zvni->vni); | |
13d60d35 | 3792 | |
d62a17ae | 3793 | /* Free up all neighbors and MAC, if any. */ |
3794 | zvni_neigh_del_all(zvrf, zvni, 0, 0, DEL_ALL_NEIGH); | |
3795 | zvni_mac_del_all(zvrf, zvni, 0, 0, DEL_ALL_MAC); | |
2232a77c | 3796 | |
d62a17ae | 3797 | /* Free up all remote VTEPs, if any. */ |
3798 | zvni_vtep_del_all(zvni, 0); | |
13d60d35 | 3799 | |
d62a17ae | 3800 | /* Delete the hash entry. */ |
3801 | if (zvni_del(zvrf, zvni)) { | |
3802 | zlog_err("Failed to del VNI hash %p, VRF %d IF %s(%u) VNI %u", | |
3803 | zvni, ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni); | |
3804 | return -1; | |
3805 | } | |
13d60d35 | 3806 | |
d62a17ae | 3807 | return 0; |
13d60d35 | 3808 | } |
3809 | ||
3810 | /* | |
3811 | * Handle VxLAN interface update - change to tunnel IP, master or VLAN. | |
3812 | */ | |
d62a17ae | 3813 | int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags) |
3814 | { | |
3815 | struct zebra_if *zif; | |
3816 | struct zebra_vrf *zvrf; | |
3817 | zebra_vni_t *zvni; | |
3818 | struct zebra_l2info_vxlan *vxl; | |
3819 | vni_t vni; | |
3820 | ||
3821 | /* Locate VRF corresponding to interface. */ | |
3822 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
3823 | assert(zvrf); | |
3824 | ||
3825 | /* If EVPN is not enabled, nothing further to be done. */ | |
3826 | if (!EVPN_ENABLED(zvrf)) | |
3827 | return 0; | |
3828 | ||
3829 | zif = ifp->info; | |
3830 | assert(zif); | |
3831 | vxl = &zif->l2info.vxl; | |
3832 | vni = vxl->vni; | |
3833 | ||
3834 | /* Update VNI hash. */ | |
3835 | zvni = zvni_lookup(zvrf, vni); | |
3836 | if (!zvni) { | |
3837 | zlog_err( | |
3838 | "Failed to find VNI hash on update, VRF %d IF %s(%u) VNI %u", | |
3839 | ifp->vrf_id, ifp->name, ifp->ifindex, vni); | |
3840 | return -1; | |
3841 | } | |
3842 | ||
3843 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3844 | zlog_debug( | |
3845 | "%u:Update VNI %u intf %s(%u) VLAN %u local IP %s " | |
3846 | "master %u chg 0x%x", | |
3847 | ifp->vrf_id, vni, ifp->name, ifp->ifindex, | |
3848 | vxl->access_vlan, inet_ntoa(vxl->vtep_ip), | |
3849 | zif->brslave_info.bridge_ifindex, chgflags); | |
3850 | ||
3851 | /* Removed from bridge? */ | |
3852 | if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) | |
3853 | && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { | |
3854 | /* Delete from client, remove all remote VTEPs */ | |
3855 | /* Also, free up all MACs and neighbors. */ | |
3856 | zvni_send_del_to_client(zvrf, zvni->vni); | |
3857 | zvni_neigh_del_all(zvrf, zvni, 1, 0, DEL_ALL_NEIGH); | |
3858 | zvni_mac_del_all(zvrf, zvni, 1, 0, DEL_ALL_MAC); | |
3859 | zvni_vtep_del_all(zvni, 1); | |
3860 | } else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { | |
3861 | /* Remove all existing local neighbors and MACs for this VNI | |
3862 | * (including from BGP) | |
3863 | */ | |
3864 | zvni_neigh_del_all(zvrf, zvni, 0, 1, DEL_LOCAL_MAC); | |
3865 | zvni_mac_del_all(zvrf, zvni, 0, 1, DEL_LOCAL_MAC); | |
3866 | } | |
3867 | ||
3868 | zvni->local_vtep_ip = vxl->vtep_ip; | |
3869 | zvni->vxlan_if = ifp; | |
3870 | ||
3871 | /* Take further actions needed. Note that if we are here, there is a | |
3872 | * change of interest. | |
3873 | */ | |
3874 | /* If down or not mapped to a bridge, we're done. */ | |
3875 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
3876 | return 0; | |
3877 | ||
3878 | /* Inform BGP, if there is a change of interest. */ | |
3879 | if (chgflags | |
3880 | & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE)) | |
3881 | zvni_send_add_to_client(zvrf, zvni); | |
3882 | ||
3883 | /* If there is a valid new master or a VLAN mapping change, read and | |
3884 | * populate local MACs and neighbors. Also, reinstall any remote MACs | |
3885 | * and neighbors for this VNI (based on new VLAN). | |
3886 | */ | |
3887 | if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) | |
3888 | zvni_read_mac_neigh(zvrf, zvni, ifp); | |
3889 | else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { | |
3890 | struct mac_walk_ctx m_wctx; | |
3891 | struct neigh_walk_ctx n_wctx; | |
3892 | ||
3893 | zvni_read_mac_neigh(zvrf, zvni, ifp); | |
3894 | ||
3895 | memset(&m_wctx, 0, sizeof(struct mac_walk_ctx)); | |
3896 | m_wctx.zvni = zvni; | |
3897 | hash_iterate(zvni->mac_table, zvni_install_mac_hash, &m_wctx); | |
3898 | ||
3899 | memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); | |
3900 | n_wctx.zvni = zvni; | |
3901 | hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, | |
3902 | &n_wctx); | |
3903 | } | |
3904 | ||
3905 | return 0; | |
13d60d35 | 3906 | } |
3907 | ||
3908 | /* | |
3909 | * Handle VxLAN interface add. | |
3910 | */ | |
d62a17ae | 3911 | int zebra_vxlan_if_add(struct interface *ifp) |
13d60d35 | 3912 | { |
d62a17ae | 3913 | struct zebra_if *zif; |
3914 | struct zebra_vrf *zvrf; | |
3915 | zebra_vni_t *zvni; | |
3916 | struct zebra_l2info_vxlan *vxl; | |
3917 | vni_t vni; | |
13d60d35 | 3918 | |
d62a17ae | 3919 | /* Locate VRF corresponding to interface. */ |
3920 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
3921 | assert(zvrf); | |
13d60d35 | 3922 | |
d62a17ae | 3923 | /* If EVPN is not enabled, nothing further to be done. */ |
3924 | if (!EVPN_ENABLED(zvrf)) | |
3925 | return 0; | |
13d60d35 | 3926 | |
d62a17ae | 3927 | zif = ifp->info; |
3928 | assert(zif); | |
3929 | vxl = &zif->l2info.vxl; | |
3930 | vni = vxl->vni; | |
13d60d35 | 3931 | |
d62a17ae | 3932 | if (IS_ZEBRA_DEBUG_VXLAN) |
3933 | zlog_debug( | |
3934 | "%u:Add VNI %u intf %s(%u) VLAN %u local IP %s master %u", | |
3935 | ifp->vrf_id, vni, ifp->name, ifp->ifindex, | |
3936 | vxl->access_vlan, inet_ntoa(vxl->vtep_ip), | |
3937 | zif->brslave_info.bridge_ifindex); | |
13d60d35 | 3938 | |
d62a17ae | 3939 | /* Create or update VNI hash. */ |
3940 | zvni = zvni_lookup(zvrf, vni); | |
3941 | if (!zvni) { | |
3942 | zvni = zvni_add(zvrf, vni); | |
3943 | if (!zvni) { | |
3944 | zlog_err( | |
3945 | "Failed to add VNI hash, VRF %d IF %s(%u) VNI %u", | |
3946 | ifp->vrf_id, ifp->name, ifp->ifindex, vni); | |
3947 | return -1; | |
3948 | } | |
3949 | } | |
13d60d35 | 3950 | |
d62a17ae | 3951 | zvni->local_vtep_ip = vxl->vtep_ip; |
3952 | zvni->vxlan_if = ifp; | |
13d60d35 | 3953 | |
d62a17ae | 3954 | /* If down or not mapped to a bridge, we're done. */ |
3955 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
3956 | return 0; | |
13d60d35 | 3957 | |
d62a17ae | 3958 | /* Inform BGP */ |
3959 | zvni_send_add_to_client(zvrf, zvni); | |
13d60d35 | 3960 | |
d62a17ae | 3961 | /* Read and populate local MACs and neighbors */ |
3962 | zvni_read_mac_neigh(zvrf, zvni, ifp); | |
2232a77c | 3963 | |
d62a17ae | 3964 | return 0; |
13d60d35 | 3965 | } |
3966 | ||
1a98c087 MK |
3967 | /* |
3968 | * Handle message from client to enable/disable advertisement of g/w macip | |
3969 | * routes | |
3970 | */ | |
3971 | int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock, | |
3972 | u_short length, struct zebra_vrf *zvrf) | |
3973 | { | |
3974 | struct stream *s; | |
3975 | int advertise; | |
3976 | vni_t vni = 0; | |
3977 | zebra_vni_t *zvni = NULL; | |
3978 | ||
3979 | s = client->ibuf; | |
3980 | advertise = stream_getc(s); | |
3981 | vni = stream_get3(s); | |
3982 | ||
3983 | if (!vni) { | |
3984 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3985 | zlog_debug("%u:EVPN gateway macip Adv %s, currently %s", | |
3986 | zvrf_id(zvrf), | |
3987 | advertise ? "enabled" : "disabled", | |
3988 | advertise_gw_macip_enabled(zvrf, NULL) | |
3989 | ? "enabled" | |
3990 | : "disabled"); | |
3991 | ||
3992 | if (zvrf->advertise_gw_macip == advertise) | |
3993 | return 0; | |
3994 | ||
3995 | zvrf->advertise_gw_macip = advertise; | |
3996 | ||
3997 | if (advertise_gw_macip_enabled(zvrf, zvni)) | |
3998 | hash_iterate(zvrf->vni_table, | |
3999 | zvni_gw_macip_add_for_vni_hash, zvrf); | |
4000 | else | |
4001 | hash_iterate(zvrf->vni_table, | |
4002 | zvni_gw_macip_del_for_vni_hash, zvrf); | |
4003 | ||
4004 | } else { | |
4005 | struct zebra_if *zif = NULL; | |
4006 | struct zebra_l2info_vxlan zl2_info; | |
4007 | struct interface *vlan_if = NULL; | |
4008 | struct interface *vrr_if = NULL; | |
4009 | ||
4010 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4011 | zlog_debug( | |
4012 | "%u:EVPN gateway macip Adv %s on VNI %d , currently %s", | |
4013 | zvrf_id(zvrf), | |
4014 | advertise ? "enabled" : "disabled", vni, | |
4015 | advertise_gw_macip_enabled(zvrf, zvni) | |
4016 | ? "enabled" | |
4017 | : "disabled"); | |
4018 | ||
4019 | zvni = zvni_lookup(zvrf, vni); | |
4020 | if (!zvni) | |
4021 | return 0; | |
4022 | ||
4023 | if (zvni->advertise_gw_macip == advertise) | |
4024 | return 0; | |
4025 | ||
4026 | zvni->advertise_gw_macip = advertise; | |
4027 | ||
4028 | zif = zvni->vxlan_if->info; | |
4029 | zl2_info = zif->l2info.vxl; | |
4030 | ||
4031 | vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan, | |
4032 | zif->brslave_info.br_if); | |
4033 | if (!vlan_if) | |
4034 | return 0; | |
4035 | ||
4036 | if (advertise_gw_macip_enabled(zvrf, zvni)) { | |
4037 | /* Add primary SVI MAC-IP */ | |
4038 | zvni_add_macip_for_intf(vlan_if, zvni); | |
4039 | ||
4040 | /* Add VRR MAC-IP - if any*/ | |
4041 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
4042 | if (vrr_if) | |
4043 | zvni_add_macip_for_intf(vrr_if, zvni); | |
4044 | } else { | |
4045 | /* Del primary MAC-IP */ | |
4046 | zvni_del_macip_for_intf(vlan_if, zvni); | |
4047 | ||
4048 | /* Del VRR MAC-IP - if any*/ | |
4049 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
4050 | if (vrr_if) | |
4051 | zvni_del_macip_for_intf(vrr_if, zvni); | |
4052 | } | |
4053 | } | |
4054 | ||
4055 | return 0; | |
4056 | } | |
4057 | ||
4058 | ||
13d60d35 | 4059 | /* |
4060 | * Handle message from client to learn (or stop learning) about VNIs and MACs. | |
4061 | * When enabled, the VNI hash table will be built and MAC FDB table read; | |
4062 | * when disabled, the entries should be deleted and remote VTEPs and MACs | |
4063 | * uninstalled from the kernel. | |
4064 | */ | |
d62a17ae | 4065 | int zebra_vxlan_advertise_all_vni(struct zserv *client, int sock, |
4066 | u_short length, struct zebra_vrf *zvrf) | |
13d60d35 | 4067 | { |
d62a17ae | 4068 | struct stream *s; |
4069 | int advertise; | |
13d60d35 | 4070 | |
d62a17ae | 4071 | s = client->ibuf; |
4072 | advertise = stream_getc(s); | |
13d60d35 | 4073 | |
d62a17ae | 4074 | if (IS_ZEBRA_DEBUG_VXLAN) |
4075 | zlog_debug("%u:EVPN VNI Adv %s, currently %s", zvrf_id(zvrf), | |
4076 | advertise ? "enabled" : "disabled", | |
4077 | EVPN_ENABLED(zvrf) ? "enabled" : "disabled"); | |
13d60d35 | 4078 | |
d62a17ae | 4079 | if (zvrf->advertise_all_vni == advertise) |
4080 | return 0; | |
13d60d35 | 4081 | |
d62a17ae | 4082 | zvrf->advertise_all_vni = advertise; |
4083 | if (EVPN_ENABLED(zvrf)) { | |
4084 | /* Build VNI hash table and inform BGP. */ | |
4085 | zvni_build_hash_table(zvrf); | |
2232a77c | 4086 | |
1a98c087 MK |
4087 | /* Add all SVI (L3 GW) MACs to BGP*/ |
4088 | hash_iterate(zvrf->vni_table, zvni_gw_macip_add_for_vni_hash, | |
4089 | zvrf); | |
4090 | ||
d62a17ae | 4091 | /* Read the MAC FDB */ |
4092 | macfdb_read(zvrf->zns); | |
2232a77c | 4093 | |
d62a17ae | 4094 | /* Read neighbors */ |
4095 | neigh_read(zvrf->zns); | |
4096 | } else { | |
4097 | /* Cleanup VTEPs for all VNIs - uninstall from | |
4098 | * kernel and free entries. | |
4099 | */ | |
4100 | hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf); | |
4101 | } | |
13d60d35 | 4102 | |
d62a17ae | 4103 | return 0; |
13d60d35 | 4104 | } |
4105 | ||
4106 | /* | |
4107 | * Allocate VNI hash table for this VRF and do other initialization. | |
4108 | * NOTE: Currently supported only for default VRF. | |
4109 | */ | |
d62a17ae | 4110 | void zebra_vxlan_init_tables(struct zebra_vrf *zvrf) |
13d60d35 | 4111 | { |
d62a17ae | 4112 | if (!zvrf) |
4113 | return; | |
4114 | zvrf->vni_table = hash_create(vni_hash_keymake, vni_hash_cmp, | |
4115 | "Zebra VRF VNI Table"); | |
13d60d35 | 4116 | } |
4117 | ||
4118 | /* Close all VNI handling */ | |
d62a17ae | 4119 | void zebra_vxlan_close_tables(struct zebra_vrf *zvrf) |
13d60d35 | 4120 | { |
d62a17ae | 4121 | hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf); |
9b67b514 | 4122 | hash_free(zvrf->vni_table); |
13d60d35 | 4123 | } |