]>
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 | ||
43e52561 | 25 | #include "hash.h" |
13d60d35 | 26 | #include "if.h" |
43e52561 | 27 | #include "jhash.h" |
13d60d35 | 28 | #include "linklist.h" |
43e52561 QY |
29 | #include "log.h" |
30 | #include "memory.h" | |
31 | #include "prefix.h" | |
13d60d35 | 32 | #include "stream.h" |
43e52561 | 33 | #include "table.h" |
13d60d35 | 34 | #include "vlan.h" |
35 | #include "vxlan.h" | |
68e33151 CS |
36 | #ifdef GNU_LINUX |
37 | #include <linux/neighbour.h> | |
38 | #endif | |
13d60d35 | 39 | |
89272910 | 40 | #include "zebra/zebra_router.h" |
43e52561 QY |
41 | #include "zebra/debug.h" |
42 | #include "zebra/interface.h" | |
13d60d35 | 43 | #include "zebra/rib.h" |
44 | #include "zebra/rt.h" | |
43e52561 QY |
45 | #include "zebra/rt_netlink.h" |
46 | #include "zebra/zebra_errors.h" | |
47 | #include "zebra/zebra_l2.h" | |
48 | #include "zebra/zebra_memory.h" | |
13d60d35 | 49 | #include "zebra/zebra_ns.h" |
13d60d35 | 50 | #include "zebra/zebra_vrf.h" |
13d60d35 | 51 | #include "zebra/zebra_vxlan.h" |
43e52561 QY |
52 | #include "zebra/zebra_vxlan_private.h" |
53 | #include "zebra/zserv.h" | |
13d60d35 | 54 | |
6134fd82 | 55 | DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix"); |
d62a17ae | 56 | DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash"); |
b7cfce93 | 57 | DEFINE_MTYPE_STATIC(ZEBRA, ZL3VNI, "L3 VNI hash"); |
13d60d35 | 58 | DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP"); |
d62a17ae | 59 | DEFINE_MTYPE_STATIC(ZEBRA, MAC, "VNI MAC"); |
60 | DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); | |
13d60d35 | 61 | |
62 | /* definitions */ | |
63 | ||
13d60d35 | 64 | /* static function declarations */ |
996c9314 LB |
65 | static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, |
66 | uint16_t cmd); | |
cd233079 | 67 | static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json); |
d62a17ae | 68 | static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt); |
1374d4db | 69 | static void zvni_print_dad_neigh_hash(struct hash_backet *backet, void *ctxt); |
d62a17ae | 70 | static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, |
cd233079 | 71 | void **args); |
c0e519d3 MK |
72 | static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty, |
73 | json_object *json); | |
316f4ca4 MK |
74 | static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, |
75 | json_object *json); | |
24cdbd0d | 76 | static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json); |
d62a17ae | 77 | static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt); |
78 | static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt); | |
cd233079 CS |
79 | static void zvni_print(zebra_vni_t *zvni, void **ctxt); |
80 | static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]); | |
d62a17ae | 81 | |
996c9314 | 82 | static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, |
d7c0a89a | 83 | struct ipaddr *ip, uint8_t flags, |
f07e1c99 | 84 | uint32_t seq, uint16_t cmd); |
d62a17ae | 85 | static unsigned int neigh_hash_keymake(void *p); |
d62a17ae | 86 | static void *zvni_neigh_alloc(void *p); |
b6938a74 MK |
87 | static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip, |
88 | struct ethaddr *mac); | |
d62a17ae | 89 | static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n); |
d62a17ae | 90 | static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall, |
91 | struct in_addr *r_vtep_ip); | |
996c9314 | 92 | static void zvni_neigh_del_all(zebra_vni_t *zvni, int uninstall, int upd_client, |
d7c0a89a | 93 | uint32_t flags); |
d62a17ae | 94 | static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip); |
996c9314 | 95 | static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, |
d7c0a89a | 96 | struct ethaddr *macaddr, |
f07e1c99 | 97 | uint8_t flags, uint32_t seq); |
996c9314 | 98 | static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip, |
d7c0a89a QY |
99 | struct ethaddr *macaddr, |
100 | uint8_t flags); | |
d62a17ae | 101 | static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n); |
102 | static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n); | |
b7cfce93 | 103 | static zebra_vni_t *zvni_from_svi(struct interface *ifp, |
996c9314 LB |
104 | struct interface *br_if); |
105 | static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if); | |
d62a17ae | 106 | |
b7cfce93 | 107 | /* l3-vni next-hop neigh related APIs */ |
2dbad57f | 108 | static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, |
b7cfce93 MK |
109 | struct ipaddr *ip); |
110 | static void *zl3vni_nh_alloc(void *p); | |
111 | static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, | |
112 | struct ipaddr *vtep_ip, | |
113 | struct ethaddr *rmac); | |
114 | static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); | |
115 | static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); | |
2dbad57f | 116 | static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n); |
b7cfce93 MK |
117 | |
118 | /* l3-vni rmac related APIs */ | |
119 | static void zl3vni_print_rmac_hash(struct hash_backet *, void *); | |
2dbad57f | 120 | static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, |
b7cfce93 MK |
121 | struct ethaddr *rmac); |
122 | static void *zl3vni_rmac_alloc(void *p); | |
123 | static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, | |
124 | struct ethaddr *rmac); | |
125 | static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); | |
126 | static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); | |
996c9314 | 127 | static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac); |
b7cfce93 MK |
128 | |
129 | /* l3-vni related APIs*/ | |
b7cfce93 MK |
130 | static zebra_l3vni_t *zl3vni_lookup(vni_t vni); |
131 | static void *zl3vni_alloc(void *p); | |
132 | static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id); | |
133 | static int zl3vni_del(zebra_l3vni_t *zl3vni); | |
134 | static zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t); | |
b7cfce93 MK |
135 | static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni); |
136 | static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni); | |
b7cfce93 MK |
137 | static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni); |
138 | static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni); | |
139 | ||
d62a17ae | 140 | static unsigned int mac_hash_keymake(void *p); |
74df8d6d | 141 | static bool mac_cmp(const void *p1, const void *p2); |
d62a17ae | 142 | static void *zvni_mac_alloc(void *p); |
143 | static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr); | |
144 | static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac); | |
d62a17ae | 145 | static void zvni_mac_del_from_vtep(zebra_vni_t *zvni, int uninstall, |
146 | struct in_addr *r_vtep_ip); | |
996c9314 | 147 | static void zvni_mac_del_all(zebra_vni_t *zvni, int uninstall, int upd_client, |
d7c0a89a | 148 | uint32_t flags); |
d62a17ae | 149 | static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr); |
996c9314 | 150 | static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, |
f07e1c99 | 151 | uint8_t flags, uint32_t seq); |
e98e4b88 | 152 | static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr); |
d62a17ae | 153 | static zebra_vni_t *zvni_map_vlan(struct interface *ifp, |
154 | struct interface *br_if, vlanid_t vid); | |
155 | static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac); | |
d63c1b18 | 156 | static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac); |
d62a17ae | 157 | static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt); |
158 | ||
159 | static unsigned int vni_hash_keymake(void *p); | |
d62a17ae | 160 | static void *zvni_alloc(void *p); |
2853fed6 | 161 | static zebra_vni_t *zvni_lookup(vni_t vni); |
162 | static zebra_vni_t *zvni_add(vni_t vni); | |
163 | static int zvni_del(zebra_vni_t *zvni); | |
164 | static int zvni_send_add_to_client(zebra_vni_t *zvni); | |
165 | static int zvni_send_del_to_client(vni_t vni); | |
166 | static void zvni_build_hash_table(); | |
d62a17ae | 167 | static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep); |
168 | static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip); | |
169 | static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip); | |
170 | static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep); | |
171 | static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall); | |
172 | static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip); | |
173 | static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip); | |
1a98c087 MK |
174 | static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni); |
175 | static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni); | |
176 | static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, | |
177 | struct ethaddr *macaddr, struct ipaddr *ip); | |
178 | static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, | |
179 | struct ipaddr *ip); | |
180 | struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp); | |
2853fed6 | 181 | static int advertise_gw_macip_enabled(zebra_vni_t *zvni); |
e22a946a CS |
182 | static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf, |
183 | zebra_mac_t *old_zmac, | |
184 | zebra_mac_t *new_zmac, | |
185 | zebra_neigh_t *nbr); | |
fe697c6b | 186 | static int remote_neigh_count(zebra_mac_t *zmac); |
187 | static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac); | |
c80a972c CS |
188 | static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t); |
189 | static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t); | |
13d60d35 | 190 | |
191 | /* Private functions */ | |
5e1b0650 | 192 | static int host_rb_entry_compare(const struct host_rb_entry *hle1, |
85442b09 | 193 | const struct host_rb_entry *hle2) |
5e1b0650 DS |
194 | { |
195 | if (hle1->p.family < hle2->p.family) | |
196 | return -1; | |
197 | ||
198 | if (hle1->p.family > hle2->p.family) | |
199 | return 1; | |
200 | ||
201 | if (hle1->p.prefixlen < hle2->p.prefixlen) | |
202 | return -1; | |
203 | ||
204 | if (hle1->p.prefixlen > hle2->p.prefixlen) | |
205 | return 1; | |
206 | ||
207 | if (hle1->p.family == AF_INET) { | |
208 | if (hle1->p.u.prefix4.s_addr < hle2->p.u.prefix4.s_addr) | |
209 | return -1; | |
210 | ||
211 | if (hle1->p.u.prefix4.s_addr > hle2->p.u.prefix4.s_addr) | |
212 | return 1; | |
213 | ||
214 | return 0; | |
2acc2310 DS |
215 | } else if (hle1->p.family == AF_INET6) { |
216 | return memcmp(&hle1->p.u.prefix6, &hle2->p.u.prefix6, | |
217 | IPV6_MAX_BYTELEN); | |
5e1b0650 | 218 | } else { |
9df414fe QY |
219 | zlog_debug("%s: Unexpected family type: %d", |
220 | __PRETTY_FUNCTION__, hle1->p.family); | |
5e1b0650 DS |
221 | return 0; |
222 | } | |
223 | } | |
85442b09 | 224 | RB_GENERATE(host_rb_tree_entry, host_rb_entry, hl_entry, host_rb_entry_compare); |
5e1b0650 | 225 | |
85442b09 | 226 | static uint32_t rb_host_count(struct host_rb_tree_entry *hrbe) |
5e1b0650 DS |
227 | { |
228 | struct host_rb_entry *hle; | |
229 | uint32_t count = 0; | |
230 | ||
85442b09 | 231 | RB_FOREACH (hle, host_rb_tree_entry, hrbe) |
5e1b0650 DS |
232 | count++; |
233 | ||
234 | return count; | |
235 | } | |
13d60d35 | 236 | |
790f8dc5 | 237 | /* |
238 | * Return number of valid MACs in a VNI's MAC hash table - all | |
239 | * remote MACs and non-internal (auto) local MACs count. | |
240 | */ | |
d7c0a89a | 241 | static uint32_t num_valid_macs(zebra_vni_t *zvni) |
790f8dc5 | 242 | { |
243 | unsigned int i; | |
d7c0a89a | 244 | uint32_t num_macs = 0; |
790f8dc5 | 245 | struct hash *hash; |
246 | struct hash_backet *hb; | |
247 | zebra_mac_t *mac; | |
248 | ||
249 | hash = zvni->mac_table; | |
250 | if (!hash) | |
251 | return num_macs; | |
252 | for (i = 0; i < hash->size; i++) { | |
253 | for (hb = hash->index[i]; hb; hb = hb->next) { | |
254 | mac = (zebra_mac_t *)hb->data; | |
255 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) | |
63ce2ee7 | 256 | || CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) |
790f8dc5 | 257 | || !CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) |
258 | num_macs++; | |
259 | } | |
260 | } | |
261 | ||
262 | return num_macs; | |
263 | } | |
264 | ||
1374d4db CS |
265 | static uint32_t num_dup_detected_macs(zebra_vni_t *zvni) |
266 | { | |
267 | unsigned int i; | |
268 | uint32_t num_macs = 0; | |
269 | struct hash *hash; | |
270 | struct hash_backet *hb; | |
271 | zebra_mac_t *mac; | |
272 | ||
273 | hash = zvni->mac_table; | |
274 | if (!hash) | |
275 | return num_macs; | |
276 | for (i = 0; i < hash->size; i++) { | |
277 | for (hb = hash->index[i]; hb; hb = hb->next) { | |
278 | mac = (zebra_mac_t *)hb->data; | |
279 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) | |
280 | num_macs++; | |
281 | } | |
282 | } | |
283 | ||
284 | return num_macs; | |
285 | } | |
286 | ||
287 | static uint32_t num_dup_detected_neighs(zebra_vni_t *zvni) | |
288 | { | |
289 | unsigned int i; | |
290 | uint32_t num_neighs = 0; | |
291 | struct hash *hash; | |
292 | struct hash_backet *hb; | |
293 | zebra_neigh_t *nbr; | |
294 | ||
295 | hash = zvni->neigh_table; | |
296 | if (!hash) | |
297 | return num_neighs; | |
298 | for (i = 0; i < hash->size; i++) { | |
299 | for (hb = hash->index[i]; hb; hb = hb->next) { | |
300 | nbr = (zebra_neigh_t *)hb->data; | |
301 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) | |
302 | num_neighs++; | |
303 | } | |
304 | } | |
305 | ||
306 | return num_neighs; | |
307 | } | |
308 | ||
2853fed6 | 309 | static int advertise_gw_macip_enabled(zebra_vni_t *zvni) |
1a98c087 | 310 | { |
2853fed6 | 311 | struct zebra_vrf *zvrf; |
312 | ||
313 | zvrf = vrf_info_lookup(VRF_DEFAULT); | |
1a98c087 MK |
314 | if (zvrf && zvrf->advertise_gw_macip) |
315 | return 1; | |
316 | ||
317 | if (zvni && zvni->advertise_gw_macip) | |
318 | return 1; | |
319 | ||
320 | return 0; | |
321 | } | |
322 | ||
e22a946a CS |
323 | /* As part Duplicate Address Detection (DAD) for IP mobility |
324 | * MAC binding changes, ensure to inheirt duplicate flag | |
325 | */ | |
326 | static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf, | |
327 | zebra_mac_t *old_zmac, | |
328 | zebra_mac_t *new_zmac, | |
329 | zebra_neigh_t *nbr) | |
330 | { | |
331 | bool is_old_mac_dup = false; | |
332 | bool is_new_mac_dup = false; | |
333 | ||
334 | if (!zvrf->dup_addr_detect) | |
335 | return 0; | |
336 | /* Check old or new MAC is detected as duplicate | |
337 | * mark this neigh as duplicate | |
338 | */ | |
339 | if (old_zmac) | |
340 | is_old_mac_dup = CHECK_FLAG(old_zmac->flags, | |
341 | ZEBRA_MAC_DUPLICATE); | |
342 | if (new_zmac) | |
343 | is_new_mac_dup = CHECK_FLAG(new_zmac->flags, | |
344 | ZEBRA_MAC_DUPLICATE); | |
345 | /* Old and/or new MAC can be in duplicate state, | |
346 | * based on that IP/Neigh Inherits the flag. | |
347 | * If New MAC is marked duplicate, inherit to the IP. | |
348 | * If old MAC is duplicate but new MAC is not, clear | |
349 | * duplicate flag for IP and reset detection params | |
350 | * and let IP DAD retrigger. | |
351 | */ | |
352 | if (is_new_mac_dup && !CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) { | |
353 | SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
354 | /* Capture Duplicate detection time */ | |
355 | nbr->dad_dup_detect_time = monotime(NULL); | |
356 | return 1; | |
357 | } else if (is_old_mac_dup && !is_new_mac_dup) { | |
358 | UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
359 | nbr->dad_count = 0; | |
360 | nbr->detect_start_time.tv_sec = 0; | |
361 | nbr->detect_start_time.tv_usec = 0; | |
362 | } | |
363 | return 0; | |
364 | } | |
365 | ||
cec2e17d | 366 | /* |
367 | * Helper function to determine maximum width of neighbor IP address for | |
368 | * display - just because we're dealing with IPv6 addresses that can | |
369 | * widely vary. | |
370 | */ | |
d62a17ae | 371 | static void zvni_find_neigh_addr_width(struct hash_backet *backet, void *ctxt) |
cec2e17d | 372 | { |
d62a17ae | 373 | zebra_neigh_t *n; |
374 | char buf[INET6_ADDRSTRLEN]; | |
375 | struct neigh_walk_ctx *wctx = ctxt; | |
376 | int width; | |
cec2e17d | 377 | |
d62a17ae | 378 | n = (zebra_neigh_t *)backet->data; |
cec2e17d | 379 | |
1445b43c A |
380 | ipaddr2str(&n->ip, buf, sizeof(buf)); |
381 | width = strlen(buf); | |
d62a17ae | 382 | if (width > wctx->addr_width) |
383 | wctx->addr_width = width; | |
68e33151 | 384 | |
cec2e17d | 385 | } |
386 | ||
387 | /* | |
388 | * Print a specific neighbor entry. | |
389 | */ | |
cd233079 | 390 | static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) |
cec2e17d | 391 | { |
d62a17ae | 392 | struct vty *vty; |
393 | char buf1[ETHER_ADDR_STRLEN]; | |
394 | char buf2[INET6_ADDRSTRLEN]; | |
1a8c5c38 | 395 | const char *type_str; |
396 | const char *state_str; | |
397 | bool flags_present = false; | |
87454e6b CS |
398 | struct zebra_vrf *zvrf; |
399 | struct timeval detect_start_time = {0, 0}; | |
cec2e17d | 400 | |
87454e6b | 401 | zvrf = zebra_vrf_lookup_by_id(n->zvni->vrf_id); |
cd233079 CS |
402 | ipaddr2str(&n->ip, buf2, sizeof(buf2)); |
403 | prefix_mac2str(&n->emac, buf1, sizeof(buf1)); | |
1a8c5c38 | 404 | type_str = CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) ? |
405 | "local" : "remote"; | |
406 | state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive"; | |
cd233079 CS |
407 | vty = (struct vty *)ctxt; |
408 | if (json == NULL) { | |
409 | vty_out(vty, "IP: %s\n", | |
410 | ipaddr2str(&n->ip, buf2, sizeof(buf2))); | |
1a8c5c38 | 411 | vty_out(vty, " Type: %s\n", type_str); |
412 | vty_out(vty, " State: %s\n", state_str); | |
413 | vty_out(vty, " MAC: %s\n", | |
cd233079 CS |
414 | prefix_mac2str(&n->emac, buf1, sizeof(buf1))); |
415 | } else { | |
416 | json_object_string_add(json, "ip", buf2); | |
1a8c5c38 | 417 | json_object_string_add(json, "type", type_str); |
418 | json_object_string_add(json, "state", state_str); | |
cd233079 CS |
419 | json_object_string_add(json, "mac", buf1); |
420 | } | |
421 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
b6938a74 | 422 | if (json == NULL) { |
1a8c5c38 | 423 | vty_out(vty, " Remote VTEP: %s\n", |
cd233079 | 424 | inet_ntoa(n->r_vtep_ip)); |
b6938a74 | 425 | } else |
cd233079 CS |
426 | json_object_string_add(json, "remoteVtep", |
427 | inet_ntoa(n->r_vtep_ip)); | |
428 | } | |
ead40654 | 429 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) { |
1a8c5c38 | 430 | if (!json) { |
431 | vty_out(vty, " Flags: Default-gateway"); | |
432 | flags_present = true; | |
433 | } else | |
ead40654 MK |
434 | json_object_boolean_true_add(json, "defaultGateway"); |
435 | } | |
68e33151 | 436 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)) { |
1a8c5c38 | 437 | if (!json) { |
438 | vty_out(vty, | |
439 | flags_present ? " ,Router" : " Flags: Router"); | |
440 | flags_present = true; | |
441 | } | |
68e33151 | 442 | } |
f07e1c99 | 443 | if (json == NULL) { |
1a8c5c38 | 444 | if (flags_present) |
445 | vty_out(vty, "\n"); | |
446 | vty_out(vty, " Local Seq: %u Remote Seq: %u\n", | |
f07e1c99 | 447 | n->loc_seq, n->rem_seq); |
87454e6b CS |
448 | |
449 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) { | |
450 | vty_out(vty, " Duplicate, detected at %s", | |
451 | time_to_string(n->dad_dup_detect_time)); | |
452 | } else if (n->dad_count) { | |
453 | monotime_since(&n->detect_start_time, | |
454 | &detect_start_time); | |
455 | if (detect_start_time.tv_sec <= zvrf->dad_time) { | |
456 | char *buf = time_to_string(n-> | |
457 | detect_start_time.tv_sec); | |
458 | char tmp_buf[30]; | |
459 | ||
460 | memset(tmp_buf, 0, 30); | |
461 | strncpy(tmp_buf, buf, strlen(buf) - 1); | |
462 | vty_out(vty, | |
463 | " Duplicate detection started at %s, detection count %u\n", | |
464 | tmp_buf, n->dad_count); | |
465 | } | |
466 | } | |
1a8c5c38 | 467 | } else { |
468 | json_object_int_add(json, "localSequence", n->loc_seq); | |
469 | json_object_int_add(json, "remoteSequence", n->rem_seq); | |
87454e6b CS |
470 | json_object_int_add(json, "detectionCount", |
471 | n->dad_count); | |
472 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) | |
473 | json_object_boolean_true_add(json, "isDuplicate"); | |
474 | else | |
475 | json_object_boolean_false_add(json, "isDuplicate"); | |
476 | ||
477 | ||
68e33151 | 478 | } |
cec2e17d | 479 | } |
480 | ||
481 | /* | |
482 | * Print neighbor hash entry - called for display of all neighbors. | |
483 | */ | |
d62a17ae | 484 | static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt) |
485 | { | |
486 | struct vty *vty; | |
cd233079 | 487 | json_object *json_vni = NULL, *json_row = NULL; |
d62a17ae | 488 | zebra_neigh_t *n; |
489 | char buf1[ETHER_ADDR_STRLEN]; | |
490 | char buf2[INET6_ADDRSTRLEN]; | |
491 | struct neigh_walk_ctx *wctx = ctxt; | |
1a8c5c38 | 492 | const char *state_str; |
d62a17ae | 493 | |
494 | vty = wctx->vty; | |
cd233079 | 495 | json_vni = wctx->json; |
d62a17ae | 496 | n = (zebra_neigh_t *)backet->data; |
d62a17ae | 497 | |
cd233079 CS |
498 | if (json_vni) |
499 | json_row = json_object_new_object(); | |
500 | ||
d62a17ae | 501 | prefix_mac2str(&n->emac, buf1, sizeof(buf1)); |
502 | ipaddr2str(&n->ip, buf2, sizeof(buf2)); | |
1a8c5c38 | 503 | state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive"; |
504 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
505 | if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) | |
506 | return; | |
507 | ||
cd233079 | 508 | if (json_vni == NULL) { |
1a8c5c38 | 509 | vty_out(vty, "%*s %-6s %-8s %-17s\n", |
510 | -wctx->addr_width, buf2, "local", | |
511 | state_str, buf1); | |
cd233079 CS |
512 | } else { |
513 | json_object_string_add(json_row, "type", "local"); | |
1a8c5c38 | 514 | json_object_string_add(json_row, "state", state_str); |
cd233079 | 515 | json_object_string_add(json_row, "mac", buf1); |
1a8c5c38 | 516 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) |
517 | json_object_boolean_true_add( | |
518 | json_row, "defaultGateway"); | |
519 | json_object_int_add(json_row, "localSequence", | |
520 | n->loc_seq); | |
521 | json_object_int_add(json_row, "remoteSequence", | |
522 | n->rem_seq); | |
87454e6b CS |
523 | json_object_int_add(json_row, "detectionCount", |
524 | n->dad_count); | |
525 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) | |
526 | json_object_boolean_true_add(json_row, | |
527 | "isDuplicate"); | |
528 | else | |
529 | json_object_boolean_false_add(json_row, | |
530 | "isDuplicate"); | |
cd233079 | 531 | } |
d62a17ae | 532 | wctx->count++; |
1a8c5c38 | 533 | } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { |
534 | if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) && | |
535 | !IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip)) | |
536 | return; | |
537 | ||
538 | if (json_vni == NULL) { | |
539 | if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) && | |
540 | (wctx->count == 0)) | |
541 | vty_out(vty, | |
542 | "%*s %-6s %-8s %-17s %-21s\n", | |
543 | -wctx->addr_width, "Neighbor", "Type", | |
544 | "State", "MAC", "Remote VTEP"); | |
545 | vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n", | |
546 | -wctx->addr_width, buf2, "remote", state_str, | |
547 | buf1, inet_ntoa(n->r_vtep_ip)); | |
cd233079 | 548 | } else { |
1a8c5c38 | 549 | json_object_string_add(json_row, "type", "remote"); |
550 | json_object_string_add(json_row, "state", state_str); | |
551 | json_object_string_add(json_row, "mac", buf1); | |
552 | json_object_string_add(json_row, "remoteVtep", | |
553 | inet_ntoa(n->r_vtep_ip)); | |
554 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) | |
555 | json_object_boolean_true_add(json_row, | |
556 | "defaultGateway"); | |
557 | json_object_int_add(json_row, "localSequence", | |
558 | n->loc_seq); | |
559 | json_object_int_add(json_row, "remoteSequence", | |
560 | n->rem_seq); | |
87454e6b CS |
561 | json_object_int_add(json_row, "detectionCount", |
562 | n->dad_count); | |
563 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) | |
564 | json_object_boolean_true_add(json_row, | |
565 | "isDuplicate"); | |
566 | else | |
567 | json_object_boolean_false_add(json_row, | |
568 | "isDuplicate"); | |
d62a17ae | 569 | } |
1a8c5c38 | 570 | wctx->count++; |
d62a17ae | 571 | } |
cd233079 CS |
572 | |
573 | if (json_vni) | |
574 | json_object_object_add(json_vni, buf2, json_row); | |
cec2e17d | 575 | } |
576 | ||
577 | /* | |
578 | * Print neighbors for all VNI. | |
579 | */ | |
d62a17ae | 580 | static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, |
cd233079 | 581 | void **args) |
cec2e17d | 582 | { |
d62a17ae | 583 | struct vty *vty; |
cd233079 | 584 | json_object *json = NULL, *json_vni = NULL; |
d62a17ae | 585 | zebra_vni_t *zvni; |
d7c0a89a | 586 | uint32_t num_neigh; |
d62a17ae | 587 | struct neigh_walk_ctx wctx; |
cd233079 | 588 | char vni_str[VNI_STR_LEN]; |
1374d4db | 589 | uint32_t print_dup; |
cd233079 CS |
590 | |
591 | vty = (struct vty *)args[0]; | |
592 | json = (json_object *)args[1]; | |
1374d4db | 593 | print_dup = (uint32_t)(uintptr_t)args[2]; |
cec2e17d | 594 | |
d62a17ae | 595 | zvni = (zebra_vni_t *)backet->data; |
9ea660be | 596 | |
d62a17ae | 597 | num_neigh = hashcount(zvni->neigh_table); |
1374d4db CS |
598 | |
599 | if (print_dup) | |
600 | num_neigh = num_dup_detected_neighs(zvni); | |
601 | ||
68e33151 | 602 | if (json == NULL) { |
cd233079 CS |
603 | vty_out(vty, |
604 | "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n", | |
605 | zvni->vni, num_neigh); | |
68e33151 | 606 | } else { |
cd233079 CS |
607 | json_vni = json_object_new_object(); |
608 | json_object_int_add(json_vni, "numArpNd", num_neigh); | |
609 | snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); | |
610 | } | |
1374d4db | 611 | |
cd233079 CS |
612 | if (!num_neigh) { |
613 | if (json) | |
614 | json_object_object_add(json, vni_str, json_vni); | |
d62a17ae | 615 | return; |
cd233079 | 616 | } |
cec2e17d | 617 | |
d62a17ae | 618 | /* Since we have IPv6 addresses to deal with which can vary widely in |
619 | * size, we try to be a bit more elegant in display by first computing | |
620 | * the maximum width. | |
621 | */ | |
622 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); | |
623 | wctx.zvni = zvni; | |
624 | wctx.vty = vty; | |
625 | wctx.addr_width = 15; | |
cd233079 | 626 | wctx.json = json_vni; |
d62a17ae | 627 | hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); |
cec2e17d | 628 | |
68e33151 | 629 | if (json == NULL) { |
1a8c5c38 | 630 | vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n", |
631 | -wctx.addr_width, "IP", "Type", | |
632 | "State", "MAC", "Remote VTEP"); | |
68e33151 | 633 | } |
1374d4db CS |
634 | if (print_dup) |
635 | hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash, | |
636 | &wctx); | |
637 | else | |
638 | hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); | |
cd233079 CS |
639 | |
640 | if (json) | |
641 | json_object_object_add(json, vni_str, json_vni); | |
cec2e17d | 642 | } |
643 | ||
1374d4db CS |
644 | static void zvni_print_dad_neigh_hash(struct hash_backet *backet, void *ctxt) |
645 | { | |
646 | zebra_neigh_t *nbr; | |
647 | ||
648 | nbr = (zebra_neigh_t *)backet->data; | |
649 | if (!nbr) | |
650 | return; | |
651 | ||
652 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) | |
653 | zvni_print_neigh_hash(backet, ctxt); | |
654 | } | |
655 | ||
9aa741ea | 656 | /* print a specific next hop for an l3vni */ |
996c9314 | 657 | static void zl3vni_print_nh(zebra_neigh_t *n, struct vty *vty, |
c0e519d3 | 658 | json_object *json) |
9aa741ea MK |
659 | { |
660 | char buf1[ETHER_ADDR_STRLEN]; | |
661 | char buf2[INET6_ADDRSTRLEN]; | |
c0e519d3 | 662 | json_object *json_hosts = NULL; |
f2a503f0 | 663 | struct host_rb_entry *hle; |
9aa741ea | 664 | |
c0e519d3 MK |
665 | if (!json) { |
666 | vty_out(vty, "Ip: %s\n", | |
667 | ipaddr2str(&n->ip, buf2, sizeof(buf2))); | |
668 | vty_out(vty, " RMAC: %s\n", | |
996c9314 | 669 | prefix_mac2str(&n->emac, buf1, sizeof(buf1))); |
f2a503f0 DS |
670 | vty_out(vty, " Refcount: %d\n", |
671 | rb_host_count(&n->host_rb)); | |
4cce389e | 672 | vty_out(vty, " Prefixes:\n"); |
85442b09 | 673 | RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb) |
c0e519d3 | 674 | vty_out(vty, " %s\n", |
f2a503f0 | 675 | prefix2str(&hle->p, buf2, sizeof(buf2))); |
c0e519d3 MK |
676 | } else { |
677 | json_hosts = json_object_new_array(); | |
996c9314 LB |
678 | json_object_string_add( |
679 | json, "ip", ipaddr2str(&(n->ip), buf2, sizeof(buf2))); | |
680 | json_object_string_add( | |
681 | json, "routerMac", | |
682 | prefix_mac2str(&n->emac, buf2, sizeof(buf2))); | |
f2a503f0 DS |
683 | json_object_int_add(json, "refCount", |
684 | rb_host_count(&n->host_rb)); | |
85442b09 | 685 | RB_FOREACH (hle, host_rb_tree_entry, &n->host_rb) |
c0e519d3 | 686 | json_object_array_add(json_hosts, |
996c9314 | 687 | json_object_new_string(prefix2str( |
f2a503f0 | 688 | &hle->p, buf2, sizeof(buf2)))); |
4cce389e | 689 | json_object_object_add(json, "prefixList", json_hosts); |
c0e519d3 | 690 | } |
9aa741ea MK |
691 | } |
692 | ||
693 | /* Print a specific RMAC entry */ | |
996c9314 | 694 | static void zl3vni_print_rmac(zebra_mac_t *zrmac, struct vty *vty, |
316f4ca4 | 695 | json_object *json) |
9aa741ea MK |
696 | { |
697 | char buf1[ETHER_ADDR_STRLEN]; | |
698 | char buf2[PREFIX_STRLEN]; | |
316f4ca4 | 699 | json_object *json_hosts = NULL; |
5e1b0650 | 700 | struct host_rb_entry *hle; |
9aa741ea | 701 | |
316f4ca4 MK |
702 | if (!json) { |
703 | vty_out(vty, "MAC: %s\n", | |
704 | prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); | |
705 | vty_out(vty, " Remote VTEP: %s\n", | |
706 | inet_ntoa(zrmac->fwd_info.r_vtep_ip)); | |
41db76c2 | 707 | vty_out(vty, " Refcount: %d\n", rb_host_count(&zrmac->host_rb)); |
4cce389e | 708 | vty_out(vty, " Prefixes:\n"); |
85442b09 | 709 | RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb) |
316f4ca4 | 710 | vty_out(vty, " %s\n", |
5e1b0650 | 711 | prefix2str(&hle->p, buf2, sizeof(buf2))); |
316f4ca4 MK |
712 | } else { |
713 | json_hosts = json_object_new_array(); | |
996c9314 LB |
714 | json_object_string_add( |
715 | json, "routerMac", | |
716 | prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); | |
4cce389e | 717 | json_object_string_add(json, "vtepIp", |
316f4ca4 | 718 | inet_ntoa(zrmac->fwd_info.r_vtep_ip)); |
41db76c2 DS |
719 | json_object_int_add(json, "refCount", |
720 | rb_host_count(&zrmac->host_rb)); | |
1a8c5c38 | 721 | json_object_int_add(json, "localSequence", zrmac->loc_seq); |
722 | json_object_int_add(json, "remoteSequence", zrmac->rem_seq); | |
85442b09 | 723 | RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb) |
5e1b0650 DS |
724 | json_object_array_add( |
725 | json_hosts, | |
726 | json_object_new_string(prefix2str( | |
727 | &hle->p, buf2, sizeof(buf2)))); | |
4cce389e | 728 | json_object_object_add(json, "prefixList", json_hosts); |
316f4ca4 | 729 | } |
9aa741ea MK |
730 | } |
731 | ||
cec2e17d | 732 | /* |
733 | * Print a specific MAC entry. | |
734 | */ | |
24cdbd0d | 735 | static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) |
d62a17ae | 736 | { |
737 | struct vty *vty; | |
b6938a74 MK |
738 | zebra_neigh_t *n = NULL; |
739 | struct listnode *node = NULL; | |
d62a17ae | 740 | char buf1[20]; |
b6938a74 | 741 | char buf2[INET6_ADDRSTRLEN]; |
87454e6b CS |
742 | struct zebra_vrf *zvrf; |
743 | struct timeval detect_start_time = {0, 0}; | |
744 | ||
745 | zvrf = zebra_vrf_lookup_by_id(mac->zvni->vrf_id); | |
d62a17ae | 746 | |
747 | vty = (struct vty *)ctxt; | |
24cdbd0d | 748 | prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1)); |
d62a17ae | 749 | |
24cdbd0d DS |
750 | if (json) { |
751 | json_object *json_mac = json_object_new_object(); | |
752 | ||
753 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
754 | struct zebra_ns *zns; | |
755 | struct interface *ifp; | |
756 | ifindex_t ifindex; | |
757 | ||
758 | ifindex = mac->fwd_info.local.ifindex; | |
759 | zns = zebra_ns_lookup(NS_DEFAULT); | |
760 | ifp = if_lookup_by_index_per_ns(zns, ifindex); | |
761 | if (!ifp) | |
762 | return; | |
763 | json_object_string_add(json_mac, "type", "local"); | |
764 | json_object_string_add(json_mac, "intf", ifp->name); | |
765 | json_object_int_add(json_mac, "ifindex", ifindex); | |
766 | if (mac->fwd_info.local.vid) | |
767 | json_object_int_add(json_mac, "vlan", | |
768 | mac->fwd_info.local.vid); | |
769 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { | |
770 | json_object_string_add(json_mac, "type", "remote"); | |
771 | json_object_string_add( | |
772 | json_mac, "remoteVtep", | |
773 | inet_ntoa(mac->fwd_info.r_vtep_ip)); | |
774 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) | |
29611019 | 775 | json_object_string_add(json_mac, "type", "auto"); |
b6938a74 | 776 | |
24cdbd0d DS |
777 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) |
778 | json_object_boolean_true_add(json_mac, "stickyMac"); | |
ead40654 | 779 | |
24cdbd0d DS |
780 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) |
781 | json_object_boolean_true_add(json_mac, | |
782 | "defaultGateway"); | |
ead40654 | 783 | |
24cdbd0d DS |
784 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)) |
785 | json_object_boolean_true_add(json_mac, | |
786 | "remoteGatewayMac"); | |
51f4dab4 | 787 | |
24cdbd0d DS |
788 | json_object_int_add(json_mac, "localSequence", mac->loc_seq); |
789 | json_object_int_add(json_mac, "remoteSequence", mac->rem_seq); | |
f07e1c99 | 790 | |
87454e6b CS |
791 | json_object_int_add(json_mac, "detectionCount", mac->dad_count); |
792 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) | |
793 | json_object_boolean_true_add(json_mac, "isDuplicate"); | |
794 | else | |
795 | json_object_boolean_false_add(json_mac, "isDuplicate"); | |
796 | ||
24cdbd0d DS |
797 | /* print all the associated neigh */ |
798 | if (!listcount(mac->neigh_list)) | |
799 | json_object_string_add(json_mac, "neighbors", "none"); | |
800 | else { | |
801 | json_object *json_active_nbrs = json_object_new_array(); | |
802 | json_object *json_inactive_nbrs = | |
803 | json_object_new_array(); | |
804 | json_object *json_nbrs = json_object_new_object(); | |
805 | ||
806 | for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) { | |
807 | if (IS_ZEBRA_NEIGH_ACTIVE(n)) | |
808 | json_object_array_add( | |
809 | json_active_nbrs, | |
810 | json_object_new_string( | |
811 | ipaddr2str( | |
812 | &n->ip, buf2, | |
813 | sizeof(buf2)))); | |
814 | else | |
815 | json_object_array_add( | |
816 | json_inactive_nbrs, | |
817 | json_object_new_string( | |
818 | ipaddr2str( | |
819 | &n->ip, buf2, | |
820 | sizeof(buf2)))); | |
821 | } | |
822 | ||
823 | json_object_object_add(json_nbrs, "active", | |
824 | json_active_nbrs); | |
825 | json_object_object_add(json_nbrs, "inactive", | |
826 | json_inactive_nbrs); | |
827 | json_object_object_add(json_mac, "neighbors", | |
828 | json_nbrs); | |
b6938a74 | 829 | } |
b6938a74 | 830 | |
24cdbd0d DS |
831 | json_object_object_add(json, buf1, json_mac); |
832 | vty_out(vty, "%s\n", | |
833 | json_object_to_json_string_ext( | |
834 | json, JSON_C_TO_STRING_PRETTY)); | |
835 | json_object_free(json); | |
836 | } else { | |
837 | vty_out(vty, "MAC: %s\n", buf1); | |
838 | ||
839 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
840 | struct zebra_ns *zns; | |
841 | struct interface *ifp; | |
842 | ifindex_t ifindex; | |
843 | ||
844 | ifindex = mac->fwd_info.local.ifindex; | |
845 | zns = zebra_ns_lookup(NS_DEFAULT); | |
846 | ifp = if_lookup_by_index_per_ns(zns, ifindex); | |
847 | if (!ifp) | |
848 | return; | |
849 | vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex); | |
850 | if (mac->fwd_info.local.vid) | |
851 | vty_out(vty, " VLAN: %u", | |
852 | mac->fwd_info.local.vid); | |
853 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { | |
854 | vty_out(vty, " Remote VTEP: %s", | |
855 | inet_ntoa(mac->fwd_info.r_vtep_ip)); | |
856 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { | |
857 | vty_out(vty, " Auto Mac "); | |
858 | } | |
859 | ||
860 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) | |
861 | vty_out(vty, " Sticky Mac "); | |
862 | ||
863 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) | |
864 | vty_out(vty, " Default-gateway Mac "); | |
865 | ||
866 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW)) | |
867 | vty_out(vty, " Remote-gateway Mac "); | |
868 | ||
869 | vty_out(vty, "\n"); | |
870 | vty_out(vty, " Local Seq: %u Remote Seq: %u", mac->loc_seq, | |
871 | mac->rem_seq); | |
872 | vty_out(vty, "\n"); | |
873 | ||
87454e6b CS |
874 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { |
875 | vty_out(vty, " Duplicate, detected at %s", | |
876 | time_to_string(mac->dad_dup_detect_time)); | |
877 | } else if (mac->dad_count) { | |
878 | monotime_since(&mac->detect_start_time, | |
879 | &detect_start_time); | |
880 | if (detect_start_time.tv_sec <= zvrf->dad_time) { | |
881 | char *buf = time_to_string(mac-> | |
882 | detect_start_time.tv_sec); | |
883 | char tmp_buf[30]; | |
884 | ||
885 | memset(tmp_buf, 0, 30); | |
886 | strncpy(tmp_buf, buf, strlen(buf) - 1); | |
887 | vty_out(vty, | |
888 | " Duplicate detection started at %s, detection count %u\n", | |
889 | tmp_buf, mac->dad_count); | |
890 | } | |
891 | } | |
892 | ||
24cdbd0d DS |
893 | /* print all the associated neigh */ |
894 | vty_out(vty, " Neighbors:\n"); | |
895 | if (!listcount(mac->neigh_list)) | |
896 | vty_out(vty, " No Neighbors\n"); | |
897 | else { | |
898 | for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) { | |
899 | vty_out(vty, " %s %s\n", | |
900 | ipaddr2str(&n->ip, buf2, sizeof(buf2)), | |
901 | (IS_ZEBRA_NEIGH_ACTIVE(n) | |
902 | ? "Active" | |
903 | : "Inactive")); | |
904 | } | |
905 | } | |
906 | ||
907 | vty_out(vty, "\n"); | |
908 | } | |
cec2e17d | 909 | } |
910 | ||
911 | /* | |
912 | * Print MAC hash entry - called for display of all MACs. | |
913 | */ | |
d62a17ae | 914 | static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) |
915 | { | |
916 | struct vty *vty; | |
cd233079 | 917 | json_object *json_mac_hdr = NULL, *json_mac = NULL; |
d62a17ae | 918 | zebra_mac_t *mac; |
919 | char buf1[20]; | |
920 | struct mac_walk_ctx *wctx = ctxt; | |
921 | ||
922 | vty = wctx->vty; | |
cd233079 | 923 | json_mac_hdr = wctx->json; |
d62a17ae | 924 | mac = (zebra_mac_t *)backet->data; |
d62a17ae | 925 | |
926 | prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1)); | |
cd233079 CS |
927 | |
928 | if (json_mac_hdr) | |
929 | json_mac = json_object_new_object(); | |
930 | ||
1a8c5c38 | 931 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { |
d62a17ae | 932 | struct zebra_ns *zns; |
933 | ifindex_t ifindex; | |
934 | struct interface *ifp; | |
935 | vlanid_t vid; | |
936 | ||
1a8c5c38 | 937 | if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) |
938 | return; | |
939 | ||
d62a17ae | 940 | zns = zebra_ns_lookup(NS_DEFAULT); |
941 | ifindex = mac->fwd_info.local.ifindex; | |
942 | ifp = if_lookup_by_index_per_ns(zns, ifindex); | |
943 | if (!ifp) // unexpected | |
944 | return; | |
945 | vid = mac->fwd_info.local.vid; | |
cd233079 CS |
946 | if (json_mac_hdr == NULL) |
947 | vty_out(vty, "%-17s %-6s %-21s", buf1, "local", | |
948 | ifp->name); | |
949 | else { | |
950 | json_object_string_add(json_mac, "type", "local"); | |
951 | json_object_string_add(json_mac, "intf", ifp->name); | |
952 | } | |
953 | if (vid) { | |
954 | if (json_mac_hdr == NULL) | |
955 | vty_out(vty, " %-5u", vid); | |
956 | else | |
957 | json_object_int_add(json_mac, "vlan", vid); | |
958 | } | |
1a8c5c38 | 959 | if (json_mac_hdr == NULL) { |
cd233079 | 960 | vty_out(vty, "\n"); |
1a8c5c38 | 961 | } else { |
962 | json_object_int_add(json_mac, "localSequence", | |
963 | mac->loc_seq); | |
964 | json_object_int_add(json_mac, "remoteSequence", | |
965 | mac->rem_seq); | |
87454e6b CS |
966 | json_object_int_add(json_mac, "detectionCount", |
967 | mac->dad_count); | |
968 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) | |
969 | json_object_boolean_true_add(json_mac, | |
970 | "isDuplicate"); | |
971 | else | |
972 | json_object_boolean_false_add(json_mac, | |
973 | "isDuplicate"); | |
cd233079 | 974 | json_object_object_add(json_mac_hdr, buf1, json_mac); |
1a8c5c38 | 975 | } |
976 | ||
d62a17ae | 977 | wctx->count++; |
1a8c5c38 | 978 | |
b6938a74 | 979 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { |
1a8c5c38 | 980 | |
981 | if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) && | |
982 | !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, | |
983 | &wctx->r_vtep_ip)) | |
984 | return; | |
985 | ||
986 | if (json_mac_hdr == NULL) { | |
987 | if ((wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) && | |
988 | (wctx->count == 0)) { | |
989 | vty_out(vty, "\nVNI %u\n\n", wctx->zvni->vni); | |
990 | vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", | |
991 | "Type", "Intf/Remote VTEP", "VLAN"); | |
d62a17ae | 992 | } |
1a8c5c38 | 993 | vty_out(vty, "%-17s %-6s %-21s\n", buf1, "remote", |
994 | inet_ntoa(mac->fwd_info.r_vtep_ip)); | |
d62a17ae | 995 | } else { |
1a8c5c38 | 996 | json_object_string_add(json_mac, "type", "remote"); |
997 | json_object_string_add(json_mac, "remoteVtep", | |
cd233079 | 998 | inet_ntoa(mac->fwd_info.r_vtep_ip)); |
1a8c5c38 | 999 | json_object_object_add(json_mac_hdr, buf1, json_mac); |
1000 | json_object_int_add(json_mac, "localSequence", | |
1001 | mac->loc_seq); | |
1002 | json_object_int_add(json_mac, "remoteSequence", | |
1003 | mac->rem_seq); | |
87454e6b CS |
1004 | json_object_int_add(json_mac, "detectionCount", |
1005 | mac->dad_count); | |
1006 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) | |
1007 | json_object_boolean_true_add(json_mac, | |
1008 | "isDuplicate"); | |
1009 | else | |
1010 | json_object_boolean_false_add(json_mac, | |
1011 | "isDuplicate"); | |
1012 | ||
d62a17ae | 1013 | } |
1a8c5c38 | 1014 | |
1015 | wctx->count++; | |
d62a17ae | 1016 | } |
cec2e17d | 1017 | } |
1018 | ||
1374d4db CS |
1019 | /* Print Duplicate MAC */ |
1020 | static void zvni_print_dad_mac_hash(struct hash_backet *backet, void *ctxt) | |
1021 | { | |
1022 | zebra_mac_t *mac; | |
1023 | ||
1024 | mac = (zebra_mac_t *)backet->data; | |
1025 | if (!mac) | |
1026 | return; | |
1027 | ||
1028 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) | |
1029 | zvni_print_mac_hash(backet, ctxt); | |
1030 | } | |
1031 | ||
cec2e17d | 1032 | /* |
1033 | * Print MACs for all VNI. | |
1034 | */ | |
d62a17ae | 1035 | static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) |
cec2e17d | 1036 | { |
d62a17ae | 1037 | struct vty *vty; |
cd233079 CS |
1038 | json_object *json = NULL, *json_vni = NULL; |
1039 | json_object *json_mac = NULL; | |
d62a17ae | 1040 | zebra_vni_t *zvni; |
d7c0a89a | 1041 | uint32_t num_macs; |
d62a17ae | 1042 | struct mac_walk_ctx *wctx = ctxt; |
cd233079 | 1043 | char vni_str[VNI_STR_LEN]; |
cec2e17d | 1044 | |
d62a17ae | 1045 | vty = (struct vty *)wctx->vty; |
cd233079 | 1046 | json = (struct json_object *)wctx->json; |
cec2e17d | 1047 | |
d62a17ae | 1048 | zvni = (zebra_vni_t *)backet->data; |
d62a17ae | 1049 | wctx->zvni = zvni; |
cec2e17d | 1050 | |
d62a17ae | 1051 | /*We are iterating over a new VNI, set the count to 0*/ |
1052 | wctx->count = 0; | |
cec2e17d | 1053 | |
790f8dc5 | 1054 | num_macs = num_valid_macs(zvni); |
d62a17ae | 1055 | if (!num_macs) |
1056 | return; | |
cd233079 | 1057 | |
1374d4db CS |
1058 | if (wctx->print_dup) |
1059 | num_macs = num_dup_detected_macs(zvni); | |
1060 | ||
cd233079 CS |
1061 | if (json) { |
1062 | json_vni = json_object_new_object(); | |
1063 | json_mac = json_object_new_object(); | |
1064 | snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); | |
d62a17ae | 1065 | } |
cec2e17d | 1066 | |
cd233079 CS |
1067 | if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) { |
1068 | if (json == NULL) { | |
1069 | vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n", | |
1070 | zvni->vni, num_macs); | |
1071 | vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", | |
1072 | "Intf/Remote VTEP", "VLAN"); | |
1073 | } else | |
1074 | json_object_int_add(json_vni, "numMacs", num_macs); | |
1075 | } | |
1374d4db CS |
1076 | |
1077 | if (!num_macs) { | |
1078 | if (json) { | |
1079 | json_object_int_add(json_vni, "numMacs", num_macs); | |
1080 | json_object_object_add(json, vni_str, json_vni); | |
1081 | } | |
1082 | return; | |
1083 | } | |
1084 | ||
cd233079 CS |
1085 | /* assign per-vni to wctx->json object to fill macs |
1086 | * under the vni. Re-assign primary json object to fill | |
1087 | * next vni information. | |
1088 | */ | |
1089 | wctx->json = json_mac; | |
1374d4db CS |
1090 | if (wctx->print_dup) |
1091 | hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash, wctx); | |
1092 | else | |
1093 | hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx); | |
cd233079 CS |
1094 | wctx->json = json; |
1095 | if (json) { | |
1096 | if (wctx->count) | |
1097 | json_object_object_add(json_vni, "macs", json_mac); | |
1098 | json_object_object_add(json, vni_str, json_vni); | |
1099 | } | |
cec2e17d | 1100 | } |
1101 | ||
996c9314 | 1102 | static void zl3vni_print_nh_hash(struct hash_backet *backet, void *ctx) |
b7cfce93 MK |
1103 | { |
1104 | struct nh_walk_ctx *wctx = NULL; | |
1105 | struct vty *vty = NULL; | |
32798965 | 1106 | struct json_object *json_vni = NULL; |
b7cfce93 MK |
1107 | struct json_object *json_nh = NULL; |
1108 | zebra_neigh_t *n = NULL; | |
1109 | char buf1[ETHER_ADDR_STRLEN]; | |
2dbad57f | 1110 | char buf2[INET6_ADDRSTRLEN]; |
b7cfce93 MK |
1111 | |
1112 | wctx = (struct nh_walk_ctx *)ctx; | |
1113 | vty = wctx->vty; | |
32798965 MK |
1114 | json_vni = wctx->json; |
1115 | if (json_vni) | |
b7cfce93 MK |
1116 | json_nh = json_object_new_object(); |
1117 | n = (zebra_neigh_t *)backet->data; | |
b7cfce93 | 1118 | |
32798965 | 1119 | if (!json_vni) { |
4cce389e | 1120 | vty_out(vty, "%-15s %-17s\n", |
2dbad57f | 1121 | ipaddr2str(&(n->ip), buf2, sizeof(buf2)), |
4cce389e | 1122 | prefix_mac2str(&n->emac, buf1, sizeof(buf1))); |
b7cfce93 | 1123 | } else { |
4cce389e | 1124 | json_object_string_add(json_nh, "nexthopIp", |
32798965 | 1125 | ipaddr2str(&n->ip, buf2, sizeof(buf2))); |
996c9314 LB |
1126 | json_object_string_add( |
1127 | json_nh, "routerMac", | |
1128 | prefix_mac2str(&n->emac, buf1, sizeof(buf1))); | |
32798965 MK |
1129 | json_object_object_add(json_vni, |
1130 | ipaddr2str(&(n->ip), buf2, sizeof(buf2)), | |
1131 | json_nh); | |
b7cfce93 MK |
1132 | } |
1133 | } | |
1134 | ||
2dbad57f | 1135 | static void zl3vni_print_nh_hash_all_vni(struct hash_backet *backet, |
32798965 | 1136 | void **args) |
2dbad57f | 1137 | { |
1138 | struct vty *vty = NULL; | |
1139 | json_object *json = NULL; | |
1140 | json_object *json_vni = NULL; | |
2dbad57f | 1141 | zebra_l3vni_t *zl3vni = NULL; |
1142 | uint32_t num_nh = 0; | |
32798965 | 1143 | struct nh_walk_ctx wctx; |
2dbad57f | 1144 | char vni_str[VNI_STR_LEN]; |
1145 | ||
32798965 MK |
1146 | vty = (struct vty *)args[0]; |
1147 | json = (struct json_object *)args[1]; | |
2dbad57f | 1148 | |
1149 | zl3vni = (zebra_l3vni_t *)backet->data; | |
2dbad57f | 1150 | |
1151 | num_nh = hashcount(zl3vni->nh_table); | |
1152 | if (!num_nh) | |
1153 | return; | |
1154 | ||
1155 | if (json) { | |
1156 | json_vni = json_object_new_object(); | |
2dbad57f | 1157 | snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni); |
1158 | } | |
1159 | ||
1160 | if (json == NULL) { | |
996c9314 | 1161 | vty_out(vty, "\nVNI %u #Next-Hops %u\n\n", zl3vni->vni, num_nh); |
4cce389e | 1162 | vty_out(vty, "%-15s %-17s\n", "IP", "RMAC"); |
2dbad57f | 1163 | } else |
4cce389e | 1164 | json_object_int_add(json_vni, "numNextHops", num_nh); |
2dbad57f | 1165 | |
32798965 MK |
1166 | memset(&wctx, 0, sizeof(struct nh_walk_ctx)); |
1167 | wctx.vty = vty; | |
1168 | wctx.json = json_vni; | |
1169 | hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx); | |
1170 | if (json) | |
2dbad57f | 1171 | json_object_object_add(json, vni_str, json_vni); |
2dbad57f | 1172 | } |
1173 | ||
b7cfce93 | 1174 | static void zl3vni_print_rmac_hash_all_vni(struct hash_backet *backet, |
c0b4eaa4 | 1175 | void **args) |
b7cfce93 MK |
1176 | { |
1177 | struct vty *vty = NULL; | |
1178 | json_object *json = NULL; | |
1179 | json_object *json_vni = NULL; | |
b7cfce93 | 1180 | zebra_l3vni_t *zl3vni = NULL; |
d7c0a89a | 1181 | uint32_t num_rmacs; |
c0b4eaa4 | 1182 | struct rmac_walk_ctx wctx; |
b7cfce93 MK |
1183 | char vni_str[VNI_STR_LEN]; |
1184 | ||
c0b4eaa4 MK |
1185 | vty = (struct vty *)args[0]; |
1186 | json = (struct json_object *)args[1]; | |
b7cfce93 MK |
1187 | |
1188 | zl3vni = (zebra_l3vni_t *)backet->data; | |
b7cfce93 MK |
1189 | |
1190 | num_rmacs = hashcount(zl3vni->rmac_table); | |
1191 | if (!num_rmacs) | |
1192 | return; | |
1193 | ||
1194 | if (json) { | |
1195 | json_vni = json_object_new_object(); | |
b7cfce93 MK |
1196 | snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni); |
1197 | } | |
1198 | ||
1199 | if (json == NULL) { | |
996c9314 | 1200 | vty_out(vty, "\nVNI %u #RMACs %u\n\n", zl3vni->vni, num_rmacs); |
4cce389e | 1201 | vty_out(vty, "%-17s %-21s\n", "RMAC", "Remote VTEP"); |
b7cfce93 MK |
1202 | } else |
1203 | json_object_int_add(json_vni, "numRmacs", num_rmacs); | |
1204 | ||
1205 | /* assign per-vni to wctx->json object to fill macs | |
1206 | * under the vni. Re-assign primary json object to fill | |
1207 | * next vni information. | |
1208 | */ | |
c0b4eaa4 MK |
1209 | memset(&wctx, 0, sizeof(struct rmac_walk_ctx)); |
1210 | wctx.vty = vty; | |
1211 | wctx.json = json_vni; | |
1212 | hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx); | |
1213 | if (json) | |
b7cfce93 | 1214 | json_object_object_add(json, vni_str, json_vni); |
b7cfce93 MK |
1215 | } |
1216 | ||
996c9314 | 1217 | static void zl3vni_print_rmac_hash(struct hash_backet *backet, void *ctx) |
b7cfce93 MK |
1218 | { |
1219 | zebra_mac_t *zrmac = NULL; | |
1220 | struct rmac_walk_ctx *wctx = NULL; | |
1221 | struct vty *vty = NULL; | |
1222 | struct json_object *json = NULL; | |
1223 | struct json_object *json_rmac = NULL; | |
1224 | char buf[ETHER_ADDR_STRLEN]; | |
1225 | ||
1226 | wctx = (struct rmac_walk_ctx *)ctx; | |
1227 | vty = wctx->vty; | |
1228 | json = wctx->json; | |
1229 | if (json) | |
1230 | json_rmac = json_object_new_object(); | |
1231 | zrmac = (zebra_mac_t *)backet->data; | |
b7cfce93 MK |
1232 | |
1233 | if (!json) { | |
4cce389e | 1234 | vty_out(vty, "%-17s %-21s\n", |
b7cfce93 | 1235 | prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), |
996c9314 | 1236 | inet_ntoa(zrmac->fwd_info.r_vtep_ip)); |
b7cfce93 | 1237 | } else { |
996c9314 LB |
1238 | json_object_string_add( |
1239 | json_rmac, "routerMac", | |
1240 | prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf))); | |
4cce389e | 1241 | json_object_string_add(json_rmac, "vtepIp", |
b7cfce93 | 1242 | inet_ntoa(zrmac->fwd_info.r_vtep_ip)); |
996c9314 LB |
1243 | json_object_object_add( |
1244 | json, prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), | |
1245 | json_rmac); | |
b7cfce93 MK |
1246 | } |
1247 | } | |
1248 | ||
1249 | /* print a specific L3 VNI entry */ | |
1250 | static void zl3vni_print(zebra_l3vni_t *zl3vni, void **ctx) | |
1251 | { | |
1252 | char buf[ETHER_ADDR_STRLEN]; | |
1253 | struct vty *vty = NULL; | |
1254 | json_object *json = NULL; | |
1255 | zebra_vni_t *zvni = NULL; | |
1256 | json_object *json_vni_list = NULL; | |
1257 | struct listnode *node = NULL, *nnode = NULL; | |
1258 | ||
1259 | vty = ctx[0]; | |
1260 | json = ctx[1]; | |
1261 | ||
1262 | if (!json) { | |
1263 | vty_out(vty, "VNI: %u\n", zl3vni->vni); | |
4cce389e | 1264 | vty_out(vty, " Type: %s\n", "L3"); |
996c9314 | 1265 | vty_out(vty, " Tenant VRF: %s\n", zl3vni_vrf_name(zl3vni)); |
4cce389e | 1266 | vty_out(vty, " Local Vtep Ip: %s\n", |
b67a60d2 | 1267 | inet_ntoa(zl3vni->local_vtep_ip)); |
b7cfce93 MK |
1268 | vty_out(vty, " Vxlan-Intf: %s\n", |
1269 | zl3vni_vxlan_if_name(zl3vni)); | |
996c9314 LB |
1270 | vty_out(vty, " SVI-If: %s\n", zl3vni_svi_if_name(zl3vni)); |
1271 | vty_out(vty, " State: %s\n", zl3vni_state2str(zl3vni)); | |
c48d9f5f | 1272 | vty_out(vty, " VNI Filter: %s\n", |
996c9314 LB |
1273 | CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) |
1274 | ? "prefix-routes-only" | |
1275 | : "none"); | |
4cce389e | 1276 | vty_out(vty, " Router MAC: %s\n", |
b7cfce93 | 1277 | zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); |
4cce389e | 1278 | vty_out(vty, " L2 VNIs: "); |
b7cfce93 MK |
1279 | for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) |
1280 | vty_out(vty, "%u ", zvni->vni); | |
1281 | vty_out(vty, "\n"); | |
1282 | } else { | |
1283 | json_vni_list = json_object_new_array(); | |
1284 | json_object_int_add(json, "vni", zl3vni->vni); | |
4cce389e MK |
1285 | json_object_string_add(json, "type", "L3"); |
1286 | json_object_string_add(json, "localVtepIp", | |
b67a60d2 | 1287 | inet_ntoa(zl3vni->local_vtep_ip)); |
4cce389e | 1288 | json_object_string_add(json, "vxlanIntf", |
b7cfce93 | 1289 | zl3vni_vxlan_if_name(zl3vni)); |
4cce389e | 1290 | json_object_string_add(json, "sviIntf", |
b7cfce93 | 1291 | zl3vni_svi_if_name(zl3vni)); |
996c9314 LB |
1292 | json_object_string_add(json, "state", zl3vni_state2str(zl3vni)); |
1293 | json_object_string_add(json, "vrf", zl3vni_vrf_name(zl3vni)); | |
1294 | json_object_string_add( | |
1295 | json, "routerMac", | |
1296 | zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); | |
1297 | json_object_string_add( | |
1298 | json, "vniFilter", | |
1299 | CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) | |
1300 | ? "prefix-routes-only" | |
1301 | : "none"); | |
b7cfce93 MK |
1302 | for (ALL_LIST_ELEMENTS(zl3vni->l2vnis, node, nnode, zvni)) { |
1303 | json_object_array_add(json_vni_list, | |
1304 | json_object_new_int(zvni->vni)); | |
1305 | } | |
4cce389e | 1306 | json_object_object_add(json, "l2Vnis", json_vni_list); |
b7cfce93 MK |
1307 | } |
1308 | } | |
1309 | ||
cec2e17d | 1310 | /* |
1311 | * Print a specific VNI entry. | |
1312 | */ | |
cd233079 | 1313 | static void zvni_print(zebra_vni_t *zvni, void **ctxt) |
d62a17ae | 1314 | { |
1315 | struct vty *vty; | |
1316 | zebra_vtep_t *zvtep; | |
d7c0a89a QY |
1317 | uint32_t num_macs; |
1318 | uint32_t num_neigh; | |
cd233079 CS |
1319 | json_object *json = NULL; |
1320 | json_object *json_vtep_list = NULL; | |
1321 | json_object *json_ip_str = NULL; | |
d62a17ae | 1322 | |
cd233079 CS |
1323 | vty = ctxt[0]; |
1324 | json = ctxt[1]; | |
1325 | ||
b7cfce93 | 1326 | if (json == NULL) { |
cd233079 | 1327 | vty_out(vty, "VNI: %u\n", zvni->vni); |
4cce389e MK |
1328 | vty_out(vty, " Type: %s\n", "L2"); |
1329 | vty_out(vty, " Tenant VRF: %s\n", vrf_id_to_name(zvni->vrf_id)); | |
b7cfce93 | 1330 | } else { |
cd233079 | 1331 | json_object_int_add(json, "vni", zvni->vni); |
4cce389e | 1332 | json_object_string_add(json, "type", "L2"); |
b7cfce93 MK |
1333 | json_object_string_add(json, "vrf", |
1334 | vrf_id_to_name(zvni->vrf_id)); | |
1335 | } | |
d62a17ae | 1336 | |
d62a17ae | 1337 | if (!zvni->vxlan_if) { // unexpected |
cd233079 CS |
1338 | if (json == NULL) |
1339 | vty_out(vty, " VxLAN interface: unknown\n"); | |
d62a17ae | 1340 | return; |
1341 | } | |
790f8dc5 | 1342 | num_macs = num_valid_macs(zvni); |
cd233079 | 1343 | num_neigh = hashcount(zvni->neigh_table); |
4cce389e | 1344 | if (json == NULL) { |
996c9314 | 1345 | vty_out(vty, " VxLAN interface: %s\n", zvni->vxlan_if->name); |
4cce389e | 1346 | vty_out(vty, " VxLAN ifIndex: %u\n", zvni->vxlan_if->ifindex); |
996c9314 | 1347 | vty_out(vty, " Local VTEP IP: %s\n", |
cd233079 | 1348 | inet_ntoa(zvni->local_vtep_ip)); |
4cce389e | 1349 | } else { |
cd233079 CS |
1350 | json_object_string_add(json, "vxlanInterface", |
1351 | zvni->vxlan_if->name); | |
1352 | json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex); | |
1353 | json_object_string_add(json, "vtepIp", | |
1354 | inet_ntoa(zvni->local_vtep_ip)); | |
ddd16ed5 MK |
1355 | json_object_string_add(json, "advertiseGatewayMacip", |
1356 | zvni->advertise_gw_macip ? "Yes" : "No"); | |
cd233079 CS |
1357 | json_object_int_add(json, "numMacs", num_macs); |
1358 | json_object_int_add(json, "numArpNd", num_neigh); | |
1359 | } | |
d62a17ae | 1360 | if (!zvni->vteps) { |
cd233079 CS |
1361 | if (json == NULL) |
1362 | vty_out(vty, " No remote VTEPs known for this VNI\n"); | |
d62a17ae | 1363 | } else { |
cd233079 CS |
1364 | if (json == NULL) |
1365 | vty_out(vty, " Remote VTEPs for this VNI:\n"); | |
1366 | else | |
1367 | json_vtep_list = json_object_new_array(); | |
1368 | for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { | |
1369 | if (json == NULL) | |
1370 | vty_out(vty, " %s\n", | |
1371 | inet_ntoa(zvtep->vtep_ip)); | |
1372 | else { | |
1373 | json_ip_str = json_object_new_string( | |
1374 | inet_ntoa(zvtep->vtep_ip)); | |
1375 | json_object_array_add(json_vtep_list, | |
1376 | json_ip_str); | |
1377 | } | |
1378 | } | |
1379 | if (json) | |
1380 | json_object_object_add(json, "numRemoteVteps", | |
1381 | json_vtep_list); | |
1382 | } | |
1383 | if (json == NULL) { | |
1384 | vty_out(vty, | |
1385 | " Number of MACs (local and remote) known for this VNI: %u\n", | |
1386 | num_macs); | |
1387 | vty_out(vty, | |
1388 | " Number of ARPs (IPv4 and IPv6, local and remote) " | |
1389 | "known for this VNI: %u\n", | |
1390 | num_neigh); | |
ddd16ed5 MK |
1391 | vty_out(vty, " Advertise-gw-macip: %s\n", |
1392 | zvni->advertise_gw_macip ? "Yes" : "No"); | |
d62a17ae | 1393 | } |
cec2e17d | 1394 | } |
1395 | ||
b7cfce93 | 1396 | /* print a L3 VNI hash entry */ |
996c9314 | 1397 | static void zl3vni_print_hash(struct hash_backet *backet, void *ctx[]) |
b7cfce93 | 1398 | { |
b7cfce93 MK |
1399 | struct vty *vty = NULL; |
1400 | json_object *json = NULL; | |
51d8de8f | 1401 | json_object *json_vni = NULL; |
b7cfce93 MK |
1402 | zebra_l3vni_t *zl3vni = NULL; |
1403 | ||
51d8de8f MK |
1404 | vty = (struct vty *)ctx[0]; |
1405 | json = (json_object *)ctx[1]; | |
b7cfce93 MK |
1406 | |
1407 | zl3vni = (zebra_l3vni_t *)backet->data; | |
b7cfce93 MK |
1408 | |
1409 | if (!json) { | |
996c9314 LB |
1410 | vty_out(vty, "%-10u %-4s %-21s %-8lu %-8lu %-15s %-37s\n", |
1411 | zl3vni->vni, "L3", zl3vni_vxlan_if_name(zl3vni), | |
4cce389e | 1412 | hashcount(zl3vni->rmac_table), |
996c9314 | 1413 | hashcount(zl3vni->nh_table), "n/a", |
4cce389e | 1414 | zl3vni_vrf_name(zl3vni)); |
b7cfce93 | 1415 | } else { |
51d8de8f MK |
1416 | char vni_str[VNI_STR_LEN]; |
1417 | ||
1418 | snprintf(vni_str, VNI_STR_LEN, "%u", zl3vni->vni); | |
1419 | json_vni = json_object_new_object(); | |
1420 | json_object_int_add(json_vni, "vni", zl3vni->vni); | |
4cce389e | 1421 | json_object_string_add(json_vni, "vxlanIf", |
b7cfce93 | 1422 | zl3vni_vxlan_if_name(zl3vni)); |
4cce389e MK |
1423 | json_object_int_add(json_vni, "numMacs", |
1424 | hashcount(zl3vni->rmac_table)); | |
1425 | json_object_int_add(json_vni, "numArpNd", | |
1426 | hashcount(zl3vni->nh_table)); | |
1427 | json_object_string_add(json_vni, "numRemoteVteps", "n/a"); | |
1428 | json_object_string_add(json_vni, "type", "L3"); | |
1429 | json_object_string_add(json_vni, "tenantVrf", | |
b7cfce93 | 1430 | zl3vni_vrf_name(zl3vni)); |
51d8de8f | 1431 | json_object_object_add(json, vni_str, json_vni); |
b7cfce93 | 1432 | } |
b7cfce93 MK |
1433 | } |
1434 | ||
cec2e17d | 1435 | /* |
1436 | * Print a VNI hash entry - called for display of all VNIs. | |
1437 | */ | |
cd233079 | 1438 | static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) |
cec2e17d | 1439 | { |
d62a17ae | 1440 | struct vty *vty; |
1441 | zebra_vni_t *zvni; | |
1442 | zebra_vtep_t *zvtep; | |
d7c0a89a QY |
1443 | uint32_t num_vteps = 0; |
1444 | uint32_t num_macs = 0; | |
1445 | uint32_t num_neigh = 0; | |
cd233079 CS |
1446 | json_object *json = NULL; |
1447 | json_object *json_vni = NULL; | |
1448 | json_object *json_ip_str = NULL; | |
1449 | json_object *json_vtep_list = NULL; | |
1450 | ||
1451 | vty = ctxt[0]; | |
1452 | json = ctxt[1]; | |
cec2e17d | 1453 | |
d62a17ae | 1454 | zvni = (zebra_vni_t *)backet->data; |
cec2e17d | 1455 | |
d62a17ae | 1456 | zvtep = zvni->vteps; |
1457 | while (zvtep) { | |
1458 | num_vteps++; | |
1459 | zvtep = zvtep->next; | |
1460 | } | |
cec2e17d | 1461 | |
790f8dc5 | 1462 | num_macs = num_valid_macs(zvni); |
d62a17ae | 1463 | num_neigh = hashcount(zvni->neigh_table); |
cd233079 | 1464 | if (json == NULL) |
996c9314 | 1465 | vty_out(vty, "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n", |
4cce389e | 1466 | zvni->vni, "L2", |
cd233079 | 1467 | zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", |
996c9314 | 1468 | num_macs, num_neigh, num_vteps, |
b7cfce93 | 1469 | vrf_id_to_name(zvni->vrf_id)); |
cd233079 CS |
1470 | else { |
1471 | char vni_str[VNI_STR_LEN]; | |
1472 | snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); | |
1473 | json_vni = json_object_new_object(); | |
4cce389e MK |
1474 | json_object_int_add(json_vni, "vni", zvni->vni); |
1475 | json_object_string_add(json_vni, "type", "L2"); | |
cd233079 CS |
1476 | json_object_string_add(json_vni, "vxlanIf", |
1477 | zvni->vxlan_if ? zvni->vxlan_if->name | |
1478 | : "unknown"); | |
cd233079 CS |
1479 | json_object_int_add(json_vni, "numMacs", num_macs); |
1480 | json_object_int_add(json_vni, "numArpNd", num_neigh); | |
1481 | json_object_int_add(json_vni, "numRemoteVteps", num_vteps); | |
4cce389e MK |
1482 | json_object_string_add(json_vni, "tenantVrf", |
1483 | vrf_id_to_name(zvni->vrf_id)); | |
cd233079 CS |
1484 | if (num_vteps) { |
1485 | json_vtep_list = json_object_new_array(); | |
1486 | for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { | |
1487 | json_ip_str = json_object_new_string( | |
1488 | inet_ntoa(zvtep->vtep_ip)); | |
1489 | json_object_array_add(json_vtep_list, | |
1490 | json_ip_str); | |
1491 | } | |
1492 | json_object_object_add(json_vni, "remoteVteps", | |
1493 | json_vtep_list); | |
1494 | } | |
1495 | json_object_object_add(json, vni_str, json_vni); | |
1496 | } | |
cec2e17d | 1497 | } |
1498 | ||
13d60d35 | 1499 | /* |
2232a77c | 1500 | * Inform BGP about local MACIP. |
1501 | */ | |
996c9314 | 1502 | static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr, |
d7c0a89a | 1503 | struct ipaddr *ip, uint8_t flags, |
f07e1c99 | 1504 | uint32_t seq, uint16_t cmd) |
d62a17ae | 1505 | { |
d62a17ae | 1506 | char buf[ETHER_ADDR_STRLEN]; |
1507 | char buf2[INET6_ADDRSTRLEN]; | |
b7cfce93 MK |
1508 | int ipa_len; |
1509 | struct zserv *client = NULL; | |
1510 | struct stream *s = NULL; | |
d62a17ae | 1511 | |
21ccc0cf | 1512 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); |
d62a17ae | 1513 | /* BGP may not be running. */ |
1514 | if (!client) | |
1515 | return 0; | |
1516 | ||
1002497a | 1517 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
d62a17ae | 1518 | |
7cf15b25 | 1519 | zclient_create_header(s, cmd, VRF_DEFAULT); |
d62a17ae | 1520 | stream_putl(s, vni); |
ff8b7eb8 | 1521 | stream_put(s, macaddr->octet, ETH_ALEN); |
d62a17ae | 1522 | if (ip) { |
1523 | ipa_len = 0; | |
1524 | if (IS_IPADDR_V4(ip)) | |
1525 | ipa_len = IPV4_MAX_BYTELEN; | |
1526 | else if (IS_IPADDR_V6(ip)) | |
1527 | ipa_len = IPV6_MAX_BYTELEN; | |
1528 | ||
1529 | stream_putl(s, ipa_len); /* IP address length */ | |
1530 | if (ipa_len) | |
1531 | stream_put(s, &ip->ip.addr, ipa_len); /* IP address */ | |
1532 | } else | |
1533 | stream_putl(s, 0); /* Just MAC. */ | |
1534 | ||
f07e1c99 | 1535 | if (cmd == ZEBRA_MACIP_ADD) { |
1536 | stream_putc(s, flags); /* sticky mac/gateway mac */ | |
1537 | stream_putl(s, seq); /* sequence number */ | |
1538 | } | |
d62a17ae | 1539 | |
b7cfce93 | 1540 | |
d62a17ae | 1541 | /* Write packet size. */ |
1542 | stream_putw_at(s, 0, stream_get_endp(s)); | |
1543 | ||
1544 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1a98c087 | 1545 | zlog_debug( |
f07e1c99 | 1546 | "Send MACIP %s flags 0x%x MAC %s IP %s seq %u L2-VNI %u to %s", |
996c9314 LB |
1547 | (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags, |
1548 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
f07e1c99 | 1549 | ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni, |
1a98c087 | 1550 | zebra_route_string(client->proto)); |
d62a17ae | 1551 | |
1552 | if (cmd == ZEBRA_MACIP_ADD) | |
1553 | client->macipadd_cnt++; | |
1554 | else | |
1555 | client->macipdel_cnt++; | |
1556 | ||
21ccc0cf | 1557 | return zserv_send_message(client, s); |
2232a77c | 1558 | } |
1559 | ||
1560 | /* | |
1561 | * Make hash key for neighbors. | |
13d60d35 | 1562 | */ |
d62a17ae | 1563 | static unsigned int neigh_hash_keymake(void *p) |
13d60d35 | 1564 | { |
d62a17ae | 1565 | zebra_neigh_t *n = p; |
1566 | struct ipaddr *ip = &n->ip; | |
13d60d35 | 1567 | |
d62a17ae | 1568 | if (IS_IPADDR_V4(ip)) |
1569 | return jhash_1word(ip->ipaddr_v4.s_addr, 0); | |
2232a77c | 1570 | |
d62a17ae | 1571 | return jhash2(ip->ipaddr_v6.s6_addr32, |
1572 | ZEBRA_NUM_OF(ip->ipaddr_v6.s6_addr32), 0); | |
13d60d35 | 1573 | } |
1574 | ||
1575 | /* | |
2232a77c | 1576 | * Compare two neighbor hash structures. |
13d60d35 | 1577 | */ |
74df8d6d | 1578 | static bool neigh_cmp(const void *p1, const void *p2) |
13d60d35 | 1579 | { |
d62a17ae | 1580 | const zebra_neigh_t *n1 = p1; |
1581 | const zebra_neigh_t *n2 = p2; | |
13d60d35 | 1582 | |
d62a17ae | 1583 | if (n1 == NULL && n2 == NULL) |
74df8d6d | 1584 | return true; |
2232a77c | 1585 | |
d62a17ae | 1586 | if (n1 == NULL || n2 == NULL) |
74df8d6d | 1587 | return false; |
2232a77c | 1588 | |
d62a17ae | 1589 | return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0); |
13d60d35 | 1590 | } |
1591 | ||
27fa3398 DS |
1592 | static int neigh_list_cmp(void *p1, void *p2) |
1593 | { | |
1594 | const zebra_neigh_t *n1 = p1; | |
1595 | const zebra_neigh_t *n2 = p2; | |
1596 | ||
1597 | return memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)); | |
1598 | } | |
1599 | ||
13d60d35 | 1600 | /* |
2232a77c | 1601 | * Callback to allocate neighbor hash entry. |
13d60d35 | 1602 | */ |
d62a17ae | 1603 | static void *zvni_neigh_alloc(void *p) |
13d60d35 | 1604 | { |
d62a17ae | 1605 | const zebra_neigh_t *tmp_n = p; |
1606 | zebra_neigh_t *n; | |
13d60d35 | 1607 | |
d62a17ae | 1608 | n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t)); |
1609 | *n = *tmp_n; | |
2232a77c | 1610 | |
d62a17ae | 1611 | return ((void *)n); |
13d60d35 | 1612 | } |
1613 | ||
1614 | /* | |
2232a77c | 1615 | * Add neighbor entry. |
13d60d35 | 1616 | */ |
b6938a74 MK |
1617 | static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip, |
1618 | struct ethaddr *mac) | |
13d60d35 | 1619 | { |
d62a17ae | 1620 | zebra_neigh_t tmp_n; |
1621 | zebra_neigh_t *n = NULL; | |
b6938a74 | 1622 | zebra_mac_t *zmac = NULL; |
13d60d35 | 1623 | |
d62a17ae | 1624 | memset(&tmp_n, 0, sizeof(zebra_neigh_t)); |
1625 | memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr)); | |
1626 | n = hash_get(zvni->neigh_table, &tmp_n, zvni_neigh_alloc); | |
1627 | assert(n); | |
13d60d35 | 1628 | |
b6938a74 MK |
1629 | memcpy(&n->emac, mac, ETH_ALEN); |
1630 | n->state = ZEBRA_NEIGH_INACTIVE; | |
1631 | ||
1632 | /* Associate the neigh to mac */ | |
1633 | zmac = zvni_mac_lookup(zvni, mac); | |
1634 | if (zmac) | |
1635 | listnode_add_sort(zmac->neigh_list, n); | |
1636 | ||
d62a17ae | 1637 | return n; |
13d60d35 | 1638 | } |
1639 | ||
1640 | /* | |
2232a77c | 1641 | * Delete neighbor entry. |
13d60d35 | 1642 | */ |
d62a17ae | 1643 | static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n) |
13d60d35 | 1644 | { |
d62a17ae | 1645 | zebra_neigh_t *tmp_n; |
b6938a74 MK |
1646 | zebra_mac_t *zmac = NULL; |
1647 | ||
1648 | zmac = zvni_mac_lookup(zvni, &n->emac); | |
1649 | if (zmac) | |
1650 | listnode_delete(zmac->neigh_list, n); | |
13d60d35 | 1651 | |
d62a17ae | 1652 | /* Free the VNI hash entry and allocated memory. */ |
1653 | tmp_n = hash_release(zvni->neigh_table, n); | |
1654 | if (tmp_n) | |
1655 | XFREE(MTYPE_NEIGH, tmp_n); | |
13d60d35 | 1656 | |
d62a17ae | 1657 | return 0; |
13d60d35 | 1658 | } |
1659 | ||
1660 | /* | |
2232a77c | 1661 | * Free neighbor hash entry (callback) |
13d60d35 | 1662 | */ |
b1599bb6 | 1663 | static void zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg) |
13d60d35 | 1664 | { |
d62a17ae | 1665 | struct neigh_walk_ctx *wctx = arg; |
1666 | zebra_neigh_t *n = backet->data; | |
2232a77c | 1667 | |
d62a17ae | 1668 | if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL)) |
1669 | || ((wctx->flags & DEL_REMOTE_NEIGH) | |
1670 | && (n->flags & ZEBRA_NEIGH_REMOTE)) | |
1671 | || ((wctx->flags & DEL_REMOTE_NEIGH_FROM_VTEP) | |
1672 | && (n->flags & ZEBRA_NEIGH_REMOTE) | |
1673 | && IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) { | |
1674 | if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL)) | |
2853fed6 | 1675 | zvni_neigh_send_del_to_client(wctx->zvni->vni, &n->ip, |
1a98c087 | 1676 | &n->emac, 0); |
13d60d35 | 1677 | |
d62a17ae | 1678 | if (wctx->uninstall) |
1679 | zvni_neigh_uninstall(wctx->zvni, n); | |
13d60d35 | 1680 | |
b1599bb6 | 1681 | zvni_neigh_del(wctx->zvni, n); |
d62a17ae | 1682 | } |
13d60d35 | 1683 | |
b1599bb6 | 1684 | return; |
13d60d35 | 1685 | } |
1686 | ||
1687 | /* | |
2232a77c | 1688 | * Delete all neighbor entries from specific VTEP for a particular VNI. |
13d60d35 | 1689 | */ |
d62a17ae | 1690 | static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall, |
1691 | struct in_addr *r_vtep_ip) | |
13d60d35 | 1692 | { |
d62a17ae | 1693 | struct neigh_walk_ctx wctx; |
13d60d35 | 1694 | |
d62a17ae | 1695 | if (!zvni->neigh_table) |
1696 | return; | |
13d60d35 | 1697 | |
d62a17ae | 1698 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); |
1699 | wctx.zvni = zvni; | |
1700 | wctx.uninstall = uninstall; | |
1701 | wctx.flags = DEL_REMOTE_NEIGH_FROM_VTEP; | |
1702 | wctx.r_vtep_ip = *r_vtep_ip; | |
13d60d35 | 1703 | |
b1599bb6 | 1704 | hash_iterate(zvni->neigh_table, zvni_neigh_del_hash_entry, &wctx); |
2232a77c | 1705 | } |
13d60d35 | 1706 | |
2232a77c | 1707 | /* |
1708 | * Delete all neighbor entries for this VNI. | |
1709 | */ | |
996c9314 | 1710 | static void zvni_neigh_del_all(zebra_vni_t *zvni, int uninstall, int upd_client, |
d7c0a89a | 1711 | uint32_t flags) |
2232a77c | 1712 | { |
d62a17ae | 1713 | struct neigh_walk_ctx wctx; |
13d60d35 | 1714 | |
d62a17ae | 1715 | if (!zvni->neigh_table) |
1716 | return; | |
13d60d35 | 1717 | |
d62a17ae | 1718 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); |
1719 | wctx.zvni = zvni; | |
d62a17ae | 1720 | wctx.uninstall = uninstall; |
1721 | wctx.upd_client = upd_client; | |
1722 | wctx.flags = flags; | |
2232a77c | 1723 | |
b1599bb6 | 1724 | hash_iterate(zvni->neigh_table, zvni_neigh_del_hash_entry, &wctx); |
13d60d35 | 1725 | } |
1726 | ||
1727 | /* | |
2232a77c | 1728 | * Look up neighbor hash entry. |
1729 | */ | |
d62a17ae | 1730 | static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip) |
2232a77c | 1731 | { |
d62a17ae | 1732 | zebra_neigh_t tmp; |
1733 | zebra_neigh_t *n; | |
2232a77c | 1734 | |
d62a17ae | 1735 | memset(&tmp, 0, sizeof(tmp)); |
1736 | memcpy(&tmp.ip, ip, sizeof(struct ipaddr)); | |
1737 | n = hash_lookup(zvni->neigh_table, &tmp); | |
2232a77c | 1738 | |
d62a17ae | 1739 | return n; |
2232a77c | 1740 | } |
1741 | ||
f07e1c99 | 1742 | /* |
1743 | * Process all neighbors associated with a MAC upon the MAC being learnt | |
1744 | * locally or undergoing any other change (such as sequence number). | |
1745 | */ | |
1746 | static void zvni_process_neigh_on_local_mac_change(zebra_vni_t *zvni, | |
1747 | zebra_mac_t *zmac, | |
1748 | bool seq_change) | |
b6938a74 MK |
1749 | { |
1750 | zebra_neigh_t *n = NULL; | |
1751 | struct listnode *node = NULL; | |
c80a972c | 1752 | struct zebra_vrf *zvrf = NULL; |
b6938a74 | 1753 | char buf[ETHER_ADDR_STRLEN]; |
b6938a74 | 1754 | |
c80a972c CS |
1755 | zvrf = vrf_info_lookup(zvni->vrf_id); |
1756 | ||
f07e1c99 | 1757 | if (IS_ZEBRA_DEBUG_VXLAN) |
1758 | zlog_debug("Processing neighbors on local MAC %s %s, VNI %u", | |
1759 | prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)), | |
1760 | seq_change ? "CHANGE" : "ADD", zvni->vni); | |
1761 | ||
1762 | /* Walk all neighbors and mark any inactive local neighbors as | |
1763 | * active and/or update sequence number upon a move, and inform BGP. | |
1764 | * The action for remote neighbors is TBD. | |
1765 | * NOTE: We can't simply uninstall remote neighbors as the kernel may | |
1766 | * accidentally end up deleting a just-learnt local neighbor. | |
1767 | */ | |
b6938a74 MK |
1768 | for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { |
1769 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
f07e1c99 | 1770 | if (IS_ZEBRA_NEIGH_INACTIVE(n) || seq_change) { |
b6938a74 | 1771 | ZEBRA_NEIGH_SET_ACTIVE(n); |
f07e1c99 | 1772 | n->loc_seq = zmac->loc_seq; |
c80a972c CS |
1773 | if (!(zvrf->dup_addr_detect && |
1774 | zvrf->dad_freeze && !!CHECK_FLAG(n->flags, | |
1775 | ZEBRA_NEIGH_DUPLICATE))) | |
1776 | zvni_neigh_send_add_to_client( | |
1777 | zvni->vni, &n->ip, &n->emac, | |
1778 | n->flags, n->loc_seq); | |
b6938a74 | 1779 | } |
b6938a74 MK |
1780 | } |
1781 | } | |
1782 | } | |
1783 | ||
f07e1c99 | 1784 | /* |
1785 | * Process all neighbors associated with a local MAC upon the MAC being | |
1786 | * deleted. | |
1787 | */ | |
2853fed6 | 1788 | static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni, |
b6938a74 MK |
1789 | zebra_mac_t *zmac) |
1790 | { | |
1791 | zebra_neigh_t *n = NULL; | |
1792 | struct listnode *node = NULL; | |
1793 | char buf[ETHER_ADDR_STRLEN]; | |
b6938a74 | 1794 | |
f07e1c99 | 1795 | if (IS_ZEBRA_DEBUG_VXLAN) |
1796 | zlog_debug("Processing neighbors on local MAC %s DEL, VNI %u", | |
1797 | prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)), | |
1798 | zvni->vni); | |
1799 | ||
1800 | /* Walk all local neighbors and mark as inactive and inform | |
1801 | * BGP, if needed. | |
1802 | * TBD: There is currently no handling for remote neighbors. We | |
1803 | * don't expect them to exist, if they do, do we install the MAC | |
1804 | * as a remote MAC and the neighbor as remote? | |
1805 | */ | |
b6938a74 MK |
1806 | for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { |
1807 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
1808 | if (IS_ZEBRA_NEIGH_ACTIVE(n)) { | |
b6938a74 | 1809 | ZEBRA_NEIGH_SET_INACTIVE(n); |
f07e1c99 | 1810 | n->loc_seq = 0; |
996c9314 LB |
1811 | zvni_neigh_send_del_to_client(zvni->vni, &n->ip, |
1812 | &n->emac, 0); | |
b6938a74 | 1813 | } |
b6938a74 MK |
1814 | } |
1815 | } | |
1816 | } | |
1817 | ||
f07e1c99 | 1818 | /* |
1819 | * Process all neighbors associated with a MAC upon the MAC being remotely | |
1820 | * learnt. | |
1821 | */ | |
2853fed6 | 1822 | static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni, |
b6938a74 MK |
1823 | zebra_mac_t *zmac) |
1824 | { | |
1825 | zebra_neigh_t *n = NULL; | |
1826 | struct listnode *node = NULL; | |
1827 | char buf[ETHER_ADDR_STRLEN]; | |
b6938a74 | 1828 | |
f07e1c99 | 1829 | if (IS_ZEBRA_DEBUG_VXLAN) |
1830 | zlog_debug("Processing neighbors on remote MAC %s ADD, VNI %u", | |
1831 | prefix_mac2str(&zmac->macaddr, buf, sizeof(buf)), | |
1832 | zvni->vni); | |
1833 | ||
1834 | /* Walk all local neighbors and mark as inactive and inform | |
1835 | * BGP, if needed. | |
1836 | */ | |
b6938a74 MK |
1837 | for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { |
1838 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
1839 | if (IS_ZEBRA_NEIGH_ACTIVE(n)) { | |
b6938a74 | 1840 | ZEBRA_NEIGH_SET_INACTIVE(n); |
f07e1c99 | 1841 | n->loc_seq = 0; |
996c9314 LB |
1842 | zvni_neigh_send_del_to_client(zvni->vni, &n->ip, |
1843 | &n->emac, 0); | |
b6938a74 MK |
1844 | } |
1845 | } | |
1846 | } | |
1847 | } | |
1848 | ||
f07e1c99 | 1849 | /* |
1850 | * Process all neighbors associated with a remote MAC upon the MAC being | |
1851 | * deleted. | |
1852 | */ | |
2853fed6 | 1853 | static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni, |
b6938a74 MK |
1854 | zebra_mac_t *zmac) |
1855 | { | |
f07e1c99 | 1856 | /* NOTE: Currently a NO-OP. */ |
b6938a74 MK |
1857 | } |
1858 | ||
2232a77c | 1859 | /* |
1860 | * Inform BGP about local neighbor addition. | |
13d60d35 | 1861 | */ |
996c9314 | 1862 | static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, |
ead40654 | 1863 | struct ethaddr *macaddr, |
f07e1c99 | 1864 | uint8_t neigh_flags, |
1865 | uint32_t seq) | |
13d60d35 | 1866 | { |
d7c0a89a | 1867 | uint8_t flags = 0; |
ead40654 MK |
1868 | |
1869 | if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW)) | |
1870 | SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); | |
68e33151 CS |
1871 | /* Set router flag (R-bit) based on local neigh entry add */ |
1872 | if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ROUTER_FLAG)) | |
1873 | SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); | |
ead40654 | 1874 | |
2853fed6 | 1875 | return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags, |
f07e1c99 | 1876 | seq, ZEBRA_MACIP_ADD); |
2232a77c | 1877 | } |
13d60d35 | 1878 | |
2232a77c | 1879 | /* |
1880 | * Inform BGP about local neighbor deletion. | |
1881 | */ | |
996c9314 | 1882 | static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip, |
d7c0a89a | 1883 | struct ethaddr *macaddr, uint8_t flags) |
2232a77c | 1884 | { |
2853fed6 | 1885 | return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags, |
f07e1c99 | 1886 | 0, ZEBRA_MACIP_DEL); |
2232a77c | 1887 | } |
1888 | ||
1889 | /* | |
1890 | * Install remote neighbor into the kernel. | |
1891 | */ | |
d62a17ae | 1892 | static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n) |
2232a77c | 1893 | { |
d62a17ae | 1894 | struct zebra_if *zif; |
1895 | struct zebra_l2info_vxlan *vxl; | |
1896 | struct interface *vlan_if; | |
f7dae312 | 1897 | #ifdef GNU_LINUX |
68e33151 | 1898 | uint8_t flags; |
f7dae312 | 1899 | #endif |
68e33151 | 1900 | int ret = 0; |
2232a77c | 1901 | |
d62a17ae | 1902 | if (!(n->flags & ZEBRA_NEIGH_REMOTE)) |
1903 | return 0; | |
13d60d35 | 1904 | |
d62a17ae | 1905 | zif = zvni->vxlan_if->info; |
1906 | if (!zif) | |
1907 | return -1; | |
1908 | vxl = &zif->l2info.vxl; | |
13d60d35 | 1909 | |
2853fed6 | 1910 | vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); |
d62a17ae | 1911 | if (!vlan_if) |
1912 | return -1; | |
68e33151 CS |
1913 | #ifdef GNU_LINUX |
1914 | flags = NTF_EXT_LEARNED; | |
1915 | if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG) | |
1916 | flags |= NTF_ROUTER; | |
f07e1c99 | 1917 | ZEBRA_NEIGH_SET_ACTIVE(n); |
68e33151 CS |
1918 | ret = kernel_add_neigh(vlan_if, &n->ip, &n->emac, flags); |
1919 | #endif | |
1920 | return ret; | |
2232a77c | 1921 | } |
13d60d35 | 1922 | |
2232a77c | 1923 | /* |
1924 | * Uninstall remote neighbor from the kernel. | |
1925 | */ | |
d62a17ae | 1926 | static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n) |
2232a77c | 1927 | { |
d62a17ae | 1928 | struct zebra_if *zif; |
1929 | struct zebra_l2info_vxlan *vxl; | |
1930 | struct interface *vlan_if; | |
13d60d35 | 1931 | |
d62a17ae | 1932 | if (!(n->flags & ZEBRA_NEIGH_REMOTE)) |
1933 | return 0; | |
2232a77c | 1934 | |
d62a17ae | 1935 | if (!zvni->vxlan_if) { |
9df414fe QY |
1936 | zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", |
1937 | zvni->vni, zvni); | |
d62a17ae | 1938 | return -1; |
1939 | } | |
2232a77c | 1940 | |
d62a17ae | 1941 | zif = zvni->vxlan_if->info; |
1942 | if (!zif) | |
1943 | return -1; | |
1944 | vxl = &zif->l2info.vxl; | |
2853fed6 | 1945 | vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); |
d62a17ae | 1946 | if (!vlan_if) |
1947 | return -1; | |
2232a77c | 1948 | |
f07e1c99 | 1949 | ZEBRA_NEIGH_SET_INACTIVE(n); |
1950 | n->loc_seq = 0; | |
d62a17ae | 1951 | return kernel_del_neigh(vlan_if, &n->ip); |
13d60d35 | 1952 | } |
1953 | ||
1954 | /* | |
2232a77c | 1955 | * Install neighbor hash entry - called upon access VLAN change. |
13d60d35 | 1956 | */ |
d62a17ae | 1957 | static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt) |
13d60d35 | 1958 | { |
d62a17ae | 1959 | zebra_neigh_t *n; |
1960 | struct neigh_walk_ctx *wctx = ctxt; | |
13d60d35 | 1961 | |
d62a17ae | 1962 | n = (zebra_neigh_t *)backet->data; |
13d60d35 | 1963 | |
d62a17ae | 1964 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) |
1965 | zvni_neigh_install(wctx->zvni, n); | |
2232a77c | 1966 | } |
13d60d35 | 1967 | |
1a98c087 MK |
1968 | /* Get the VRR interface for SVI if any */ |
1969 | struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp) | |
1970 | { | |
1971 | struct zebra_vrf *zvrf = NULL; | |
1972 | struct interface *tmp_if = NULL; | |
1973 | struct zebra_if *zif = NULL; | |
1a98c087 MK |
1974 | |
1975 | zvrf = vrf_info_lookup(ifp->vrf_id); | |
1976 | assert(zvrf); | |
1977 | ||
451fda4f | 1978 | FOR_ALL_INTERFACES (zvrf->vrf, tmp_if) { |
1a98c087 MK |
1979 | zif = tmp_if->info; |
1980 | if (!zif) | |
1981 | continue; | |
1982 | ||
1983 | if (!IS_ZEBRA_IF_MACVLAN(tmp_if)) | |
1984 | continue; | |
1985 | ||
1986 | if (zif->link == ifp) | |
1987 | return tmp_if; | |
1988 | } | |
1989 | ||
1990 | return NULL; | |
1991 | } | |
1992 | ||
1993 | static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni) | |
1994 | { | |
1a98c087 MK |
1995 | struct listnode *cnode = NULL, *cnnode = NULL; |
1996 | struct connected *c = NULL; | |
1997 | struct ethaddr macaddr; | |
1998 | ||
1a98c087 MK |
1999 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); |
2000 | ||
2001 | for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { | |
2002 | struct ipaddr ip; | |
2003 | ||
2004 | memset(&ip, 0, sizeof(struct ipaddr)); | |
2005 | if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) | |
2006 | continue; | |
2007 | ||
2008 | if (c->address->family == AF_INET) { | |
2009 | ip.ipa_type = IPADDR_V4; | |
2010 | memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), | |
2011 | sizeof(struct in_addr)); | |
2012 | } else if (c->address->family == AF_INET6) { | |
2013 | ip.ipa_type = IPADDR_V6; | |
2014 | memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6), | |
2015 | sizeof(struct in6_addr)); | |
2016 | } else { | |
2017 | continue; | |
2018 | } | |
2019 | ||
2020 | zvni_gw_macip_del(ifp, zvni, &ip); | |
2021 | } | |
2022 | ||
2023 | return 0; | |
2024 | } | |
2025 | ||
2026 | static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni) | |
2027 | { | |
1a98c087 MK |
2028 | struct listnode *cnode = NULL, *cnnode = NULL; |
2029 | struct connected *c = NULL; | |
2030 | struct ethaddr macaddr; | |
2031 | ||
1a98c087 MK |
2032 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); |
2033 | ||
2034 | for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { | |
2035 | struct ipaddr ip; | |
2036 | ||
2037 | memset(&ip, 0, sizeof(struct ipaddr)); | |
2038 | if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) | |
2039 | continue; | |
2040 | ||
2041 | if (c->address->family == AF_INET) { | |
2042 | ip.ipa_type = IPADDR_V4; | |
2043 | memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), | |
2044 | sizeof(struct in_addr)); | |
2045 | } else if (c->address->family == AF_INET6) { | |
2046 | ip.ipa_type = IPADDR_V6; | |
2047 | memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6), | |
2048 | sizeof(struct in6_addr)); | |
2049 | } else { | |
2050 | continue; | |
2051 | } | |
2052 | ||
2053 | zvni_gw_macip_add(ifp, zvni, &macaddr, &ip); | |
2054 | } | |
31310b25 MK |
2055 | return 0; |
2056 | } | |
2057 | ||
2058 | ||
996c9314 | 2059 | static int zvni_advertise_subnet(zebra_vni_t *zvni, struct interface *ifp, |
31310b25 MK |
2060 | int advertise) |
2061 | { | |
2062 | struct listnode *cnode = NULL, *cnnode = NULL; | |
2063 | struct connected *c = NULL; | |
2064 | struct ethaddr macaddr; | |
2065 | ||
2066 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); | |
2067 | ||
2068 | for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { | |
2069 | struct prefix p; | |
1a98c087 | 2070 | |
31310b25 MK |
2071 | memcpy(&p, c->address, sizeof(struct prefix)); |
2072 | ||
2073 | /* skip link local address */ | |
2074 | if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) | |
2075 | continue; | |
2076 | ||
2077 | apply_mask(&p); | |
2078 | if (advertise) | |
2079 | ip_prefix_send_to_client(ifp->vrf_id, &p, | |
996c9314 | 2080 | ZEBRA_IP_PREFIX_ROUTE_ADD); |
31310b25 MK |
2081 | else |
2082 | ip_prefix_send_to_client(ifp->vrf_id, &p, | |
2083 | ZEBRA_IP_PREFIX_ROUTE_DEL); | |
2084 | } | |
1a98c087 MK |
2085 | return 0; |
2086 | } | |
2087 | ||
2088 | /* | |
2089 | * zvni_gw_macip_add_to_client | |
2090 | */ | |
2091 | static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, | |
2092 | struct ethaddr *macaddr, struct ipaddr *ip) | |
2093 | { | |
1a98c087 MK |
2094 | char buf[ETHER_ADDR_STRLEN]; |
2095 | char buf2[INET6_ADDRSTRLEN]; | |
b7cfce93 MK |
2096 | zebra_neigh_t *n = NULL; |
2097 | zebra_mac_t *mac = NULL; | |
2098 | struct zebra_if *zif = NULL; | |
2099 | struct zebra_l2info_vxlan *vxl = NULL; | |
2100 | ||
1a98c087 MK |
2101 | zif = zvni->vxlan_if->info; |
2102 | if (!zif) | |
2103 | return -1; | |
2104 | ||
2105 | vxl = &zif->l2info.vxl; | |
2106 | ||
2107 | mac = zvni_mac_lookup(zvni, macaddr); | |
2108 | if (!mac) { | |
2109 | mac = zvni_mac_add(zvni, macaddr); | |
2110 | if (!mac) { | |
e914ccbe | 2111 | flog_err(EC_ZEBRA_MAC_ADD_FAILED, |
1c50c1c0 QY |
2112 | "Failed to add MAC %s intf %s(%u) VID %u", |
2113 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
2114 | ifp->name, ifp->ifindex, vxl->access_vlan); | |
1a98c087 MK |
2115 | return -1; |
2116 | } | |
2117 | } | |
2118 | ||
2119 | /* Set "local" forwarding info. */ | |
2120 | SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); | |
2121 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
ead40654 | 2122 | SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW); |
1a98c087 MK |
2123 | memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); |
2124 | mac->fwd_info.local.ifindex = ifp->ifindex; | |
2125 | mac->fwd_info.local.vid = vxl->access_vlan; | |
2126 | ||
2127 | n = zvni_neigh_lookup(zvni, ip); | |
2128 | if (!n) { | |
b6938a74 | 2129 | n = zvni_neigh_add(zvni, ip, macaddr); |
1a98c087 | 2130 | if (!n) { |
af4c2728 | 2131 | flog_err( |
e914ccbe | 2132 | EC_ZEBRA_MAC_ADD_FAILED, |
2853fed6 | 2133 | "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", |
2134 | ipaddr2str(ip, buf2, sizeof(buf2)), | |
0af35d90 | 2135 | prefix_mac2str(macaddr, buf, sizeof(buf)), |
1a98c087 MK |
2136 | ifp->name, ifp->ifindex, zvni->vni); |
2137 | return -1; | |
2138 | } | |
2139 | } | |
2140 | ||
2141 | /* Set "local" forwarding info. */ | |
2142 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
ead40654 | 2143 | SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW); |
1a8c5c38 | 2144 | ZEBRA_NEIGH_SET_ACTIVE(n); |
68e33151 CS |
2145 | /* Set Router flag (R-bit) */ |
2146 | if (ip->ipa_type == IPADDR_V6) | |
2147 | SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
1a98c087 MK |
2148 | memcpy(&n->emac, macaddr, ETH_ALEN); |
2149 | n->ifindex = ifp->ifindex; | |
2150 | ||
ead40654 MK |
2151 | /* Only advertise in BGP if the knob is enabled */ |
2152 | if (!advertise_gw_macip_enabled(zvni)) | |
2153 | return 0; | |
2154 | ||
1a98c087 MK |
2155 | if (IS_ZEBRA_DEBUG_VXLAN) |
2156 | zlog_debug( | |
68e33151 | 2157 | "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP with flags 0x%x", |
2853fed6 | 2158 | ifp->name, ifp->ifindex, zvni->vni, |
1e9f448f | 2159 | prefix_mac2str(macaddr, buf, sizeof(buf)), |
68e33151 | 2160 | ipaddr2str(ip, buf2, sizeof(buf2)), n->flags); |
1a98c087 | 2161 | |
f07e1c99 | 2162 | zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, |
2163 | n->flags, n->loc_seq); | |
1a98c087 MK |
2164 | |
2165 | return 0; | |
2166 | } | |
2167 | ||
2168 | /* | |
2169 | * zvni_gw_macip_del_from_client | |
2170 | */ | |
2171 | static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, | |
2172 | struct ipaddr *ip) | |
2173 | { | |
0af35d90 | 2174 | char buf1[ETHER_ADDR_STRLEN]; |
1a98c087 | 2175 | char buf2[INET6_ADDRSTRLEN]; |
b7cfce93 MK |
2176 | zebra_neigh_t *n = NULL; |
2177 | zebra_mac_t *mac = NULL; | |
2178 | ||
1a98c087 MK |
2179 | /* If the neigh entry is not present nothing to do*/ |
2180 | n = zvni_neigh_lookup(zvni, ip); | |
2181 | if (!n) | |
2182 | return 0; | |
2183 | ||
2184 | /* mac entry should be present */ | |
2185 | mac = zvni_mac_lookup(zvni, &n->emac); | |
0af35d90 | 2186 | if (!mac) { |
0437e105 | 2187 | zlog_debug("MAC %s doesn't exist for neigh %s on VNI %u", |
9df414fe QY |
2188 | prefix_mac2str(&n->emac, buf1, sizeof(buf1)), |
2189 | ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni); | |
0af35d90 RW |
2190 | return -1; |
2191 | } | |
1a98c087 MK |
2192 | |
2193 | /* If the entry is not local nothing to do*/ | |
2194 | if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) | |
2195 | return -1; | |
2196 | ||
ead40654 | 2197 | /* only need to delete the entry from bgp if we sent it before */ |
01a6143b | 2198 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
2199 | zlog_debug( |
2200 | "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", | |
2201 | ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni, | |
ee496c3b | 2202 | prefix_mac2str(&(n->emac), buf1, sizeof(buf1)), |
996c9314 | 2203 | ipaddr2str(ip, buf2, sizeof(buf2))); |
01a6143b MK |
2204 | |
2205 | /* Remove neighbor from BGP. */ | |
2206 | zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, | |
2207 | ZEBRA_MACIP_TYPE_GW); | |
1a98c087 MK |
2208 | |
2209 | /* Delete this neighbor entry. */ | |
2210 | zvni_neigh_del(zvni, n); | |
2211 | ||
2212 | /* see if the mac needs to be deleted as well*/ | |
1e9f448f | 2213 | if (mac) |
fe697c6b | 2214 | zvni_deref_ip2mac(zvni, mac); |
1a98c087 MK |
2215 | |
2216 | return 0; | |
2217 | } | |
2218 | ||
2219 | static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, | |
2853fed6 | 2220 | void *ctxt) |
1a98c087 MK |
2221 | { |
2222 | zebra_vni_t *zvni = NULL; | |
2223 | struct zebra_if *zif = NULL; | |
2224 | struct zebra_l2info_vxlan zl2_info; | |
2225 | struct interface *vlan_if = NULL; | |
2226 | struct interface *vrr_if = NULL; | |
b5ebdc9b | 2227 | struct interface *ifp; |
1a98c087 MK |
2228 | |
2229 | /* Add primary SVI MAC*/ | |
2230 | zvni = (zebra_vni_t *)backet->data; | |
1a98c087 | 2231 | |
b5ebdc9b | 2232 | ifp = zvni->vxlan_if; |
2233 | if (!ifp) | |
2234 | return; | |
2235 | zif = ifp->info; | |
2236 | ||
2237 | /* If down or not mapped to a bridge, we're done. */ | |
b682f6de | 2238 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
b5ebdc9b | 2239 | return; |
2240 | ||
1a98c087 MK |
2241 | zl2_info = zif->l2info.vxl; |
2242 | ||
996c9314 LB |
2243 | vlan_if = |
2244 | zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); | |
1a98c087 MK |
2245 | if (!vlan_if) |
2246 | return; | |
2247 | ||
2248 | /* Del primary MAC-IP */ | |
2249 | zvni_del_macip_for_intf(vlan_if, zvni); | |
2250 | ||
2251 | /* Del VRR MAC-IP - if any*/ | |
2252 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
2253 | if (vrr_if) | |
2254 | zvni_del_macip_for_intf(vrr_if, zvni); | |
2255 | ||
2256 | return; | |
2257 | } | |
2258 | ||
2259 | static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, | |
2853fed6 | 2260 | void *ctxt) |
1a98c087 MK |
2261 | { |
2262 | zebra_vni_t *zvni = NULL; | |
2263 | struct zebra_if *zif = NULL; | |
2264 | struct zebra_l2info_vxlan zl2_info; | |
2265 | struct interface *vlan_if = NULL; | |
2266 | struct interface *vrr_if = NULL; | |
b5ebdc9b | 2267 | struct interface *ifp = NULL; |
1a98c087 MK |
2268 | |
2269 | zvni = (zebra_vni_t *)backet->data; | |
1a98c087 | 2270 | |
b5ebdc9b | 2271 | ifp = zvni->vxlan_if; |
2272 | if (!ifp) | |
2273 | return; | |
2274 | zif = ifp->info; | |
2275 | ||
2276 | /* If down or not mapped to a bridge, we're done. */ | |
b682f6de | 2277 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
b5ebdc9b | 2278 | return; |
1a98c087 MK |
2279 | zl2_info = zif->l2info.vxl; |
2280 | ||
996c9314 LB |
2281 | vlan_if = |
2282 | zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); | |
1a98c087 MK |
2283 | if (!vlan_if) |
2284 | return; | |
2285 | ||
1a98c087 MK |
2286 | /* Add primary SVI MAC-IP */ |
2287 | zvni_add_macip_for_intf(vlan_if, zvni); | |
2288 | ||
2289 | /* Add VRR MAC-IP - if any*/ | |
2290 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
2291 | if (vrr_if) | |
2292 | zvni_add_macip_for_intf(vrr_if, zvni); | |
2293 | ||
2294 | return; | |
2295 | } | |
2296 | ||
ee69da27 MK |
2297 | static int zvni_local_neigh_update(zebra_vni_t *zvni, |
2298 | struct interface *ifp, | |
2299 | struct ipaddr *ip, | |
68e33151 | 2300 | struct ethaddr *macaddr, |
a37f4598 | 2301 | bool is_router) |
ee69da27 MK |
2302 | { |
2303 | char buf[ETHER_ADDR_STRLEN]; | |
2304 | char buf2[INET6_ADDRSTRLEN]; | |
e22a946a | 2305 | struct zebra_vrf *zvrf; |
ee69da27 MK |
2306 | zebra_neigh_t *n = NULL; |
2307 | zebra_mac_t *zmac = NULL, *old_zmac = NULL; | |
f07e1c99 | 2308 | uint32_t old_mac_seq = 0, mac_new_seq = 0; |
2309 | bool upd_mac_seq = false; | |
2310 | bool neigh_mac_change = false; | |
e22a946a CS |
2311 | bool neigh_on_hold = false; |
2312 | bool neigh_was_remote = false; | |
2313 | struct in_addr vtep_ip = {.s_addr = 0}; | |
2314 | struct timeval elapsed = {0, 0}; | |
ee69da27 | 2315 | |
f07e1c99 | 2316 | /* Check if the MAC exists. */ |
ee69da27 MK |
2317 | zmac = zvni_mac_lookup(zvni, macaddr); |
2318 | if (!zmac) { | |
f07e1c99 | 2319 | /* create a dummy MAC if the MAC is not already present */ |
ee69da27 MK |
2320 | if (IS_ZEBRA_DEBUG_VXLAN) |
2321 | zlog_debug( | |
2322 | "AUTO MAC %s created for neigh %s on VNI %u", | |
2323 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
2324 | ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni); | |
2325 | ||
2326 | zmac = zvni_mac_add(zvni, macaddr); | |
2327 | if (!zmac) { | |
9df414fe QY |
2328 | zlog_debug("Failed to add MAC %s VNI %u", |
2329 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
2330 | zvni->vni); | |
ee69da27 MK |
2331 | return -1; |
2332 | } | |
2333 | ||
2334 | memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info)); | |
2335 | memset(&zmac->flags, 0, sizeof(uint32_t)); | |
2336 | SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO); | |
f07e1c99 | 2337 | } else { |
2338 | if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) { | |
2339 | /* | |
2340 | * We don't change the MAC to local upon a neighbor | |
2341 | * learn event, we wait for the explicit local MAC | |
2342 | * learn. However, we have to compute its sequence | |
2343 | * number in preparation for when it actually turns | |
2344 | * local. | |
2345 | */ | |
2346 | upd_mac_seq = true; | |
2347 | } | |
ee69da27 MK |
2348 | } |
2349 | ||
e22a946a CS |
2350 | zvrf = vrf_info_lookup(zvni->vrf_id); |
2351 | if (!zvrf) | |
2352 | return -1; | |
2353 | ||
f07e1c99 | 2354 | /* Check if the neighbor exists. */ |
ee69da27 | 2355 | n = zvni_neigh_lookup(zvni, ip); |
f07e1c99 | 2356 | if (!n) { |
2357 | /* New neighbor - create */ | |
2358 | n = zvni_neigh_add(zvni, ip, macaddr); | |
2359 | if (!n) { | |
2360 | flog_err( | |
e914ccbe | 2361 | EC_ZEBRA_MAC_ADD_FAILED, |
f07e1c99 | 2362 | "Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", |
2363 | ipaddr2str(ip, buf2, sizeof(buf2)), | |
2364 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
2365 | ifp->name, ifp->ifindex, zvni->vni); | |
2366 | return -1; | |
2367 | } | |
2368 | /* Set "local" forwarding info. */ | |
2369 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
2370 | n->ifindex = ifp->ifindex; | |
2371 | } else { | |
ee69da27 | 2372 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { |
66e37987 | 2373 | bool mac_different; |
2374 | bool cur_is_router; | |
2375 | ||
2376 | /* Note any changes and see if of interest to BGP. */ | |
2377 | mac_different = (memcmp(n->emac.octet, | |
2378 | macaddr->octet, ETH_ALEN) != 0) ? 1 : 0; | |
2379 | cur_is_router = !!CHECK_FLAG(n->flags, | |
2380 | ZEBRA_NEIGH_ROUTER_FLAG); | |
2381 | if (!mac_different && is_router == cur_is_router) { | |
ee69da27 | 2382 | n->ifindex = ifp->ifindex; |
66e37987 | 2383 | return 0; |
2384 | } | |
ee69da27 | 2385 | |
66e37987 | 2386 | if (!mac_different) { |
e22a946a CS |
2387 | bool is_neigh_freezed = false; |
2388 | ||
66e37987 | 2389 | /* Only the router flag has changed. */ |
2390 | if (is_router) | |
2391 | SET_FLAG(n->flags, | |
2392 | ZEBRA_NEIGH_ROUTER_FLAG); | |
2393 | else | |
2394 | UNSET_FLAG(n->flags, | |
2395 | ZEBRA_NEIGH_ROUTER_FLAG); | |
ee69da27 | 2396 | |
e22a946a CS |
2397 | /* Neigh is in freeze state and freeze action |
2398 | * is enabled, do not send update to client. | |
2399 | */ | |
2400 | is_neigh_freezed = (zvrf->dup_addr_detect && | |
2401 | zvrf->dad_freeze && | |
2402 | CHECK_FLAG(n->flags, | |
2403 | ZEBRA_NEIGH_DUPLICATE)); | |
2404 | ||
2405 | if (IS_ZEBRA_NEIGH_ACTIVE(n) && | |
2406 | !is_neigh_freezed) | |
66e37987 | 2407 | return zvni_neigh_send_add_to_client( |
2408 | zvni->vni, ip, macaddr, | |
2409 | n->flags, n->loc_seq); | |
2410 | return 0; | |
2411 | } | |
2412 | ||
2413 | /* The MAC has changed, need to issue a delete | |
2414 | * first as this means a different MACIP route. | |
2415 | * Also, need to do some unlinking/relinking. | |
2416 | * We also need to update the MAC's sequence number | |
2417 | * in different situations. | |
2418 | */ | |
2419 | if (IS_ZEBRA_NEIGH_ACTIVE(n)) | |
2420 | zvni_neigh_send_del_to_client(zvni->vni, &n->ip, | |
2421 | &n->emac, 0); | |
2422 | old_zmac = zvni_mac_lookup(zvni, &n->emac); | |
2423 | if (old_zmac) { | |
2424 | old_mac_seq = CHECK_FLAG(old_zmac->flags, | |
2425 | ZEBRA_MAC_REMOTE) ? | |
2426 | old_zmac->rem_seq : old_zmac->loc_seq; | |
2427 | neigh_mac_change = upd_mac_seq = true; | |
2428 | listnode_delete(old_zmac->neigh_list, n); | |
2429 | zvni_deref_ip2mac(zvni, old_zmac); | |
29c2ce7c | 2430 | } |
ee69da27 | 2431 | |
66e37987 | 2432 | /* Update the forwarding info. */ |
2433 | n->ifindex = ifp->ifindex; | |
2434 | memcpy(&n->emac, macaddr, ETH_ALEN); | |
2435 | ||
2436 | /* Link to new MAC */ | |
2437 | listnode_add_sort(zmac->neigh_list, n); | |
f07e1c99 | 2438 | } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { |
2439 | /* | |
2440 | * Neighbor has moved from remote to local. Its | |
2441 | * MAC could have also changed as part of the move. | |
2442 | */ | |
ee69da27 MK |
2443 | if (memcmp(n->emac.octet, macaddr->octet, |
2444 | ETH_ALEN) != 0) { | |
2445 | old_zmac = zvni_mac_lookup(zvni, &n->emac); | |
2446 | if (old_zmac) { | |
9df2b997 | 2447 | old_mac_seq = CHECK_FLAG( |
2448 | old_zmac->flags, | |
2449 | ZEBRA_MAC_REMOTE) ? | |
f07e1c99 | 2450 | old_zmac->rem_seq : |
2451 | old_zmac->loc_seq; | |
2452 | neigh_mac_change = upd_mac_seq = true; | |
9fc1522c DS |
2453 | listnode_delete(old_zmac->neigh_list, |
2454 | n); | |
fe697c6b | 2455 | zvni_deref_ip2mac(zvni, old_zmac); |
ee69da27 MK |
2456 | } |
2457 | ||
2458 | /* Link to new MAC */ | |
2459 | memcpy(&n->emac, macaddr, ETH_ALEN); | |
2460 | listnode_add_sort(zmac->neigh_list, n); | |
2461 | } | |
e22a946a CS |
2462 | /* Based on Mobility event Scenario-B from the |
2463 | * draft, neigh's previous state was remote treat this | |
2464 | * event for DAD. | |
2465 | */ | |
2466 | neigh_was_remote = true; | |
2467 | vtep_ip = n->r_vtep_ip; | |
ee69da27 MK |
2468 | /* Mark appropriately */ |
2469 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); | |
2470 | n->r_vtep_ip.s_addr = 0; | |
2471 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
2472 | n->ifindex = ifp->ifindex; | |
2473 | } | |
f07e1c99 | 2474 | } |
2475 | ||
2476 | /* If MAC was previously remote, or the neighbor had a different | |
2477 | * MAC earlier, recompute the sequence number. | |
2478 | */ | |
2479 | if (upd_mac_seq) { | |
2480 | uint32_t seq1, seq2; | |
2481 | ||
2482 | seq1 = CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE) ? | |
2483 | zmac->rem_seq + 1 : zmac->loc_seq; | |
2484 | seq2 = neigh_mac_change ? old_mac_seq + 1 : 0; | |
2485 | mac_new_seq = zmac->loc_seq < MAX(seq1, seq2) ? | |
2486 | MAX(seq1, seq2) : zmac->loc_seq; | |
ee69da27 MK |
2487 | } |
2488 | ||
e22a946a | 2489 | /* Mark Router flag (R-bit) */ |
a37f4598 | 2490 | if (is_router) |
54c17425 CS |
2491 | SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); |
2492 | else | |
2493 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
2494 | ||
e22a946a CS |
2495 | /* Check old and/or new MAC detected as duplicate mark |
2496 | * the neigh as duplicate | |
2497 | */ | |
2498 | if (zebra_vxlan_ip_inherit_dad_from_mac(zvrf, old_zmac, zmac, n)) { | |
2499 | flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED, | |
2500 | "VNI %u: MAC %s IP %s detected as duplicate during local update, inherit duplicate from MAC", | |
2501 | zvni->vni, | |
2502 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
2503 | ipaddr2str(&n->ip, buf2, sizeof(buf2))); | |
2504 | } | |
2505 | ||
2506 | /* Duplicate Address Detection (DAD) is enabled. | |
2507 | * Based on Mobility event Scenario-B from the | |
2508 | * draft, IP/Neigh's MAC binding changed and | |
2509 | * neigh's previous state was remote, trigger DAD. | |
2510 | */ | |
2511 | if (zvrf->dup_addr_detect) { | |
2512 | /* Neigh could have inherit dup flag or IP DAD | |
2513 | * detected earlier | |
2514 | */ | |
2515 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) { | |
2516 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2517 | zlog_debug( | |
2518 | "%s: duplicate addr MAC %s IP %s skip update to client, learn count %u recover time %u", | |
2519 | __PRETTY_FUNCTION__, | |
2520 | prefix_mac2str(macaddr, | |
2521 | buf, sizeof(buf)), | |
2522 | ipaddr2str(ip, buf2, sizeof(buf2)), | |
2523 | n->dad_count, | |
2524 | zvrf->dad_freeze_time); | |
2525 | ||
2526 | /* In case of warn-only, inform client and update neigh | |
2527 | */ | |
2528 | if (zvrf->dad_freeze) | |
2529 | neigh_on_hold = true; | |
2530 | ||
2531 | goto send_notif; | |
2532 | } | |
c80a972c | 2533 | |
e22a946a CS |
2534 | /* MAC binding changed and previous state was remote */ |
2535 | if (!(neigh_mac_change && neigh_was_remote)) | |
2536 | goto send_notif; | |
2537 | ||
2538 | /* First check if neigh is already marked duplicate via | |
2539 | * MAC dup detection, before firing M Seconds | |
2540 | * duplicate detection. | |
2541 | * RFC-7432: A PE/VTEP that detects a MAC mobility | |
2542 | * event via local learning starts an M-second timer. | |
2543 | * | |
2544 | * Check if detection time (M-secs) expired. | |
2545 | * Reset learn count and detection start time. | |
2546 | */ | |
2547 | monotime_since(&n->detect_start_time, &elapsed); | |
2548 | if (n->dad_count == 0 || elapsed.tv_sec > zvrf->dad_time) { | |
2549 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2550 | zlog_debug("%s: duplicate addr MAC %s detection time passed, reset learn count %u", | |
2551 | __PRETTY_FUNCTION__, | |
2552 | prefix_mac2str(macaddr, buf, | |
2553 | sizeof(buf)), | |
2554 | n->dad_count); | |
2555 | n->dad_count = 0; | |
2556 | /* Start dup. detection time */ | |
2557 | monotime(&n->detect_start_time); | |
2558 | } | |
2559 | ||
2560 | n->dad_count++; | |
2561 | ||
2562 | if (n->dad_count >= zvrf->dad_max_moves) { | |
2563 | flog_warn(EC_ZEBRA_DUP_IP_DETECTED, | |
2564 | "VNI %u: MAC %s IP %s detected as duplicate during local update, last VTEP %s", | |
2565 | zvni->vni, | |
2566 | prefix_mac2str(&n->emac, buf, sizeof(buf)), | |
2567 | ipaddr2str(ip, buf2, sizeof(buf2)), | |
2568 | inet_ntoa(vtep_ip)); | |
2569 | ||
2570 | /* Mark Duplicate */ | |
2571 | SET_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE); | |
2572 | ||
2573 | /* Capture Duplicate detection time */ | |
2574 | n->dad_dup_detect_time = monotime(NULL); | |
2575 | ||
c80a972c CS |
2576 | /* Start auto recovery timer for this IP */ |
2577 | THREAD_OFF(n->dad_ip_auto_recovery_timer); | |
2578 | if (zvrf->dad_freeze && zvrf->dad_freeze_time) { | |
2579 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2580 | zlog_debug( | |
2581 | "%s: duplicate addr MAC %s IP %s flags 0x%x auto recovery time %u start", | |
2582 | __PRETTY_FUNCTION__, | |
2583 | prefix_mac2str(macaddr, buf, | |
2584 | sizeof(buf)), | |
2585 | ipaddr2str(ip, buf2, sizeof(buf2)), | |
2586 | n->flags, | |
2587 | zvrf->dad_freeze_time); | |
2588 | ||
2589 | thread_add_timer(zebrad.master, | |
2590 | zebra_vxlan_dad_ip_auto_recovery_exp, | |
2591 | n, | |
2592 | zvrf->dad_freeze_time, | |
2593 | &n->dad_ip_auto_recovery_timer); | |
2594 | } | |
2595 | ||
e22a946a CS |
2596 | if (zvrf->dad_freeze) |
2597 | neigh_on_hold = true; | |
2598 | } | |
2599 | } | |
2600 | ||
2601 | send_notif: | |
c80a972c | 2602 | |
ee69da27 | 2603 | /* Before we program this in BGP, we need to check if MAC is locally |
f07e1c99 | 2604 | * learnt. If not, force neighbor to be inactive and reset its seq. |
ee69da27 MK |
2605 | */ |
2606 | if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) { | |
8b44d564 | 2607 | ZEBRA_NEIGH_SET_INACTIVE(n); |
f07e1c99 | 2608 | n->loc_seq = 0; |
2609 | zmac->loc_seq = mac_new_seq; | |
ee69da27 MK |
2610 | return 0; |
2611 | } | |
2612 | ||
f07e1c99 | 2613 | /* If the MAC's sequence number has changed, inform the MAC and all |
2614 | * neighbors associated with the MAC to BGP, else just inform this | |
2615 | * neighbor. | |
2616 | */ | |
2617 | if (upd_mac_seq && zmac->loc_seq != mac_new_seq) { | |
29c2ce7c | 2618 | if (IS_ZEBRA_DEBUG_VXLAN) |
f07e1c99 | 2619 | zlog_debug("Seq changed for MAC %s VNI %u - old %u new %u", |
2620 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
2621 | zvni->vni, zmac->loc_seq, mac_new_seq); | |
2622 | zmac->loc_seq = mac_new_seq; | |
2623 | if (zvni_mac_send_add_to_client(zvni->vni, macaddr, | |
2624 | zmac->flags, zmac->loc_seq)) | |
2625 | return -1; | |
2626 | zvni_process_neigh_on_local_mac_change(zvni, zmac, 1); | |
29c2ce7c CS |
2627 | return 0; |
2628 | } | |
2629 | ||
ee69da27 | 2630 | ZEBRA_NEIGH_SET_ACTIVE(n); |
f07e1c99 | 2631 | n->loc_seq = zmac->loc_seq; |
ee69da27 | 2632 | |
e22a946a CS |
2633 | if (!neigh_on_hold) |
2634 | return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, | |
f07e1c99 | 2635 | n->flags, n->loc_seq); |
e22a946a | 2636 | return 0; |
ee69da27 MK |
2637 | } |
2638 | ||
2639 | static int zvni_remote_neigh_update(zebra_vni_t *zvni, | |
2640 | struct interface *ifp, | |
2641 | struct ipaddr *ip, | |
2642 | struct ethaddr *macaddr, | |
2643 | uint16_t state) | |
2644 | { | |
2645 | char buf[ETHER_ADDR_STRLEN]; | |
2646 | char buf2[INET6_ADDRSTRLEN]; | |
2647 | zebra_neigh_t *n = NULL; | |
2648 | zebra_mac_t *zmac = NULL; | |
2649 | ||
2650 | /* If the neighbor is unknown, there is no further action. */ | |
2651 | n = zvni_neigh_lookup(zvni, ip); | |
2652 | if (!n) | |
2653 | return 0; | |
2654 | ||
2655 | /* If a remote entry, see if it needs to be refreshed */ | |
2656 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
e9d2cbde | 2657 | #ifdef GNU_LINUX |
ee69da27 MK |
2658 | if (state & NUD_STALE) |
2659 | zvni_neigh_install(zvni, n); | |
e9d2cbde | 2660 | #endif |
ee69da27 MK |
2661 | } else { |
2662 | /* We got a "remote" neighbor notification for an entry | |
2663 | * we think is local. This can happen in a multihoming | |
2664 | * scenario - but only if the MAC is already "remote". | |
2665 | * Just mark our entry as "remote". | |
2666 | */ | |
2667 | zmac = zvni_mac_lookup(zvni, macaddr); | |
2668 | if (!zmac || !CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) { | |
9df414fe | 2669 | zlog_debug( |
43e52561 QY |
2670 | "Ignore remote neigh %s (MAC %s) on L2-VNI %u - MAC unknown or local", |
2671 | ipaddr2str(&n->ip, buf2, sizeof(buf2)), | |
2672 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
2673 | zvni->vni); | |
ee69da27 MK |
2674 | return -1; |
2675 | } | |
2676 | ||
2677 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
2678 | SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); | |
4fd5ea4b | 2679 | ZEBRA_NEIGH_SET_ACTIVE(n); |
ee69da27 MK |
2680 | n->r_vtep_ip = zmac->fwd_info.r_vtep_ip; |
2681 | } | |
2682 | ||
2683 | return 0; | |
2684 | } | |
2685 | ||
2232a77c | 2686 | /* |
2687 | * Make hash key for MAC. | |
2688 | */ | |
d62a17ae | 2689 | static unsigned int mac_hash_keymake(void *p) |
2232a77c | 2690 | { |
d62a17ae | 2691 | zebra_mac_t *pmac = p; |
25331def DS |
2692 | const void *pnt = (void *)pmac->macaddr.octet; |
2693 | ||
ff8b7eb8 | 2694 | return jhash(pnt, ETH_ALEN, 0xa5a5a55a); |
2232a77c | 2695 | } |
13d60d35 | 2696 | |
2232a77c | 2697 | /* |
2698 | * Compare two MAC addresses. | |
2699 | */ | |
74df8d6d | 2700 | static bool mac_cmp(const void *p1, const void *p2) |
2232a77c | 2701 | { |
d62a17ae | 2702 | const zebra_mac_t *pmac1 = p1; |
2703 | const zebra_mac_t *pmac2 = p2; | |
2232a77c | 2704 | |
d62a17ae | 2705 | if (pmac1 == NULL && pmac2 == NULL) |
74df8d6d | 2706 | return true; |
2232a77c | 2707 | |
d62a17ae | 2708 | if (pmac1 == NULL || pmac2 == NULL) |
74df8d6d | 2709 | return false; |
2232a77c | 2710 | |
996c9314 | 2711 | return (memcmp(pmac1->macaddr.octet, pmac2->macaddr.octet, ETH_ALEN) |
d62a17ae | 2712 | == 0); |
2232a77c | 2713 | } |
2714 | ||
2715 | /* | |
2716 | * Callback to allocate MAC hash entry. | |
2717 | */ | |
d62a17ae | 2718 | static void *zvni_mac_alloc(void *p) |
2232a77c | 2719 | { |
d62a17ae | 2720 | const zebra_mac_t *tmp_mac = p; |
2721 | zebra_mac_t *mac; | |
2232a77c | 2722 | |
d62a17ae | 2723 | mac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t)); |
2724 | *mac = *tmp_mac; | |
2232a77c | 2725 | |
d62a17ae | 2726 | return ((void *)mac); |
2232a77c | 2727 | } |
2728 | ||
2729 | /* | |
2730 | * Add MAC entry. | |
2731 | */ | |
d62a17ae | 2732 | static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr) |
2232a77c | 2733 | { |
d62a17ae | 2734 | zebra_mac_t tmp_mac; |
2735 | zebra_mac_t *mac = NULL; | |
2232a77c | 2736 | |
d62a17ae | 2737 | memset(&tmp_mac, 0, sizeof(zebra_mac_t)); |
ff8b7eb8 | 2738 | memcpy(&tmp_mac.macaddr, macaddr, ETH_ALEN); |
d62a17ae | 2739 | mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc); |
2740 | assert(mac); | |
2232a77c | 2741 | |
b6938a74 | 2742 | mac->neigh_list = list_new(); |
27fa3398 | 2743 | mac->neigh_list->cmp = neigh_list_cmp; |
b6938a74 | 2744 | |
d62a17ae | 2745 | return mac; |
2232a77c | 2746 | } |
2747 | ||
2748 | /* | |
2749 | * Delete MAC entry. | |
2750 | */ | |
d62a17ae | 2751 | static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) |
2232a77c | 2752 | { |
d62a17ae | 2753 | zebra_mac_t *tmp_mac; |
2232a77c | 2754 | |
6a154c88 | 2755 | list_delete(&mac->neigh_list); |
b6938a74 | 2756 | |
d62a17ae | 2757 | /* Free the VNI hash entry and allocated memory. */ |
2758 | tmp_mac = hash_release(zvni->mac_table, mac); | |
2759 | if (tmp_mac) | |
2760 | XFREE(MTYPE_MAC, tmp_mac); | |
2232a77c | 2761 | |
d62a17ae | 2762 | return 0; |
2232a77c | 2763 | } |
2764 | ||
2765 | /* | |
2766 | * Free MAC hash entry (callback) | |
2767 | */ | |
b1599bb6 | 2768 | static void zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) |
2232a77c | 2769 | { |
d62a17ae | 2770 | struct mac_walk_ctx *wctx = arg; |
2771 | zebra_mac_t *mac = backet->data; | |
2232a77c | 2772 | |
d62a17ae | 2773 | if (((wctx->flags & DEL_LOCAL_MAC) && (mac->flags & ZEBRA_MAC_LOCAL)) |
2774 | || ((wctx->flags & DEL_REMOTE_MAC) | |
2775 | && (mac->flags & ZEBRA_MAC_REMOTE)) | |
2776 | || ((wctx->flags & DEL_REMOTE_MAC_FROM_VTEP) | |
2777 | && (mac->flags & ZEBRA_MAC_REMOTE) | |
2778 | && IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, | |
2779 | &wctx->r_vtep_ip))) { | |
2780 | if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { | |
996c9314 | 2781 | zvni_mac_send_del_to_client(wctx->zvni->vni, |
e98e4b88 | 2782 | &mac->macaddr); |
d62a17ae | 2783 | } |
2232a77c | 2784 | |
d62a17ae | 2785 | if (wctx->uninstall) |
d63c1b18 | 2786 | zvni_mac_uninstall(wctx->zvni, mac); |
2232a77c | 2787 | |
b1599bb6 | 2788 | zvni_mac_del(wctx->zvni, mac); |
d62a17ae | 2789 | } |
2232a77c | 2790 | |
b1599bb6 | 2791 | return; |
2232a77c | 2792 | } |
2793 | ||
2794 | /* | |
2795 | * Delete all MAC entries from specific VTEP for a particular VNI. | |
2796 | */ | |
d62a17ae | 2797 | static void zvni_mac_del_from_vtep(zebra_vni_t *zvni, int uninstall, |
2798 | struct in_addr *r_vtep_ip) | |
2232a77c | 2799 | { |
d62a17ae | 2800 | struct mac_walk_ctx wctx; |
2232a77c | 2801 | |
d62a17ae | 2802 | if (!zvni->mac_table) |
2803 | return; | |
2232a77c | 2804 | |
d62a17ae | 2805 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
2806 | wctx.zvni = zvni; | |
2807 | wctx.uninstall = uninstall; | |
2808 | wctx.flags = DEL_REMOTE_MAC_FROM_VTEP; | |
2809 | wctx.r_vtep_ip = *r_vtep_ip; | |
2232a77c | 2810 | |
b1599bb6 | 2811 | hash_iterate(zvni->mac_table, zvni_mac_del_hash_entry, &wctx); |
2232a77c | 2812 | } |
2813 | ||
2814 | /* | |
2815 | * Delete all MAC entries for this VNI. | |
2816 | */ | |
996c9314 | 2817 | static void zvni_mac_del_all(zebra_vni_t *zvni, int uninstall, int upd_client, |
d7c0a89a | 2818 | uint32_t flags) |
2232a77c | 2819 | { |
d62a17ae | 2820 | struct mac_walk_ctx wctx; |
2232a77c | 2821 | |
d62a17ae | 2822 | if (!zvni->mac_table) |
2823 | return; | |
2232a77c | 2824 | |
d62a17ae | 2825 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
2826 | wctx.zvni = zvni; | |
d62a17ae | 2827 | wctx.uninstall = uninstall; |
2828 | wctx.upd_client = upd_client; | |
2829 | wctx.flags = flags; | |
2232a77c | 2830 | |
b1599bb6 | 2831 | hash_iterate(zvni->mac_table, zvni_mac_del_hash_entry, &wctx); |
2232a77c | 2832 | } |
2833 | ||
2834 | /* | |
2835 | * Look up MAC hash entry. | |
2836 | */ | |
d62a17ae | 2837 | static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac) |
2232a77c | 2838 | { |
d62a17ae | 2839 | zebra_mac_t tmp; |
2840 | zebra_mac_t *pmac; | |
2232a77c | 2841 | |
d62a17ae | 2842 | memset(&tmp, 0, sizeof(tmp)); |
ff8b7eb8 | 2843 | memcpy(&tmp.macaddr, mac, ETH_ALEN); |
d62a17ae | 2844 | pmac = hash_lookup(zvni->mac_table, &tmp); |
2232a77c | 2845 | |
d62a17ae | 2846 | return pmac; |
2232a77c | 2847 | } |
2848 | ||
2849 | /* | |
2850 | * Inform BGP about local MAC addition. | |
2851 | */ | |
996c9314 | 2852 | static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr, |
f07e1c99 | 2853 | uint8_t mac_flags, uint32_t seq) |
2232a77c | 2854 | { |
d7c0a89a | 2855 | uint8_t flags = 0; |
ead40654 MK |
2856 | |
2857 | if (CHECK_FLAG(mac_flags, ZEBRA_MAC_STICKY)) | |
2858 | SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); | |
2859 | if (CHECK_FLAG(mac_flags, ZEBRA_MAC_DEF_GW)) | |
2860 | SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); | |
2861 | ||
2853fed6 | 2862 | return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags, |
f07e1c99 | 2863 | seq, ZEBRA_MACIP_ADD); |
2232a77c | 2864 | } |
2865 | ||
2866 | /* | |
2867 | * Inform BGP about local MAC deletion. | |
2868 | */ | |
e98e4b88 | 2869 | static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr) |
2232a77c | 2870 | { |
e98e4b88 AK |
2871 | return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */, |
2872 | 0 /* seq */, ZEBRA_MACIP_DEL); | |
2232a77c | 2873 | } |
2874 | ||
2875 | /* | |
2876 | * Map port or (port, VLAN) to a VNI. This is invoked upon getting MAC | |
2853fed6 | 2877 | * notifications, to see if they are of interest. |
2232a77c | 2878 | */ |
d62a17ae | 2879 | static zebra_vni_t *zvni_map_vlan(struct interface *ifp, |
2880 | struct interface *br_if, vlanid_t vid) | |
2232a77c | 2881 | { |
2853fed6 | 2882 | struct zebra_ns *zns; |
2883 | struct route_node *rn; | |
2884 | struct interface *tmp_if = NULL; | |
d62a17ae | 2885 | struct zebra_if *zif; |
2886 | struct zebra_l2info_bridge *br; | |
2853fed6 | 2887 | struct zebra_l2info_vxlan *vxl = NULL; |
d7c0a89a | 2888 | uint8_t bridge_vlan_aware; |
d62a17ae | 2889 | zebra_vni_t *zvni; |
2853fed6 | 2890 | int found = 0; |
2232a77c | 2891 | |
d62a17ae | 2892 | /* Determine if bridge is VLAN-aware or not */ |
2893 | zif = br_if->info; | |
2894 | assert(zif); | |
2895 | br = &zif->l2info.br; | |
2896 | bridge_vlan_aware = br->vlan_aware; | |
2232a77c | 2897 | |
d62a17ae | 2898 | /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ |
2899 | /* TODO: Optimize with a hash. */ | |
2853fed6 | 2900 | zns = zebra_ns_lookup(NS_DEFAULT); |
2901 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { | |
2902 | tmp_if = (struct interface *)rn->info; | |
2903 | if (!tmp_if) | |
2904 | continue; | |
d62a17ae | 2905 | zif = tmp_if->info; |
2906 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
2907 | continue; | |
2908 | if (!if_is_operative(tmp_if)) | |
2909 | continue; | |
2910 | vxl = &zif->l2info.vxl; | |
2232a77c | 2911 | |
d62a17ae | 2912 | if (zif->brslave_info.br_if != br_if) |
2913 | continue; | |
2232a77c | 2914 | |
2853fed6 | 2915 | if (!bridge_vlan_aware || vxl->access_vlan == vid) { |
2916 | found = 1; | |
d62a17ae | 2917 | break; |
2853fed6 | 2918 | } |
d62a17ae | 2919 | } |
2232a77c | 2920 | |
2853fed6 | 2921 | if (!found) |
d62a17ae | 2922 | return NULL; |
2232a77c | 2923 | |
2853fed6 | 2924 | zvni = zvni_lookup(vxl->vni); |
d62a17ae | 2925 | return zvni; |
2232a77c | 2926 | } |
2927 | ||
2928 | /* | |
2929 | * Map SVI and associated bridge to a VNI. This is invoked upon getting | |
2930 | * neighbor notifications, to see if they are of interest. | |
2232a77c | 2931 | */ |
b7cfce93 MK |
2932 | static zebra_vni_t *zvni_from_svi(struct interface *ifp, |
2933 | struct interface *br_if) | |
d62a17ae | 2934 | { |
2853fed6 | 2935 | struct zebra_ns *zns; |
2936 | struct route_node *rn; | |
2937 | struct interface *tmp_if = NULL; | |
d62a17ae | 2938 | struct zebra_if *zif; |
2939 | struct zebra_l2info_bridge *br; | |
2853fed6 | 2940 | struct zebra_l2info_vxlan *vxl = NULL; |
d7c0a89a | 2941 | uint8_t bridge_vlan_aware; |
d62a17ae | 2942 | vlanid_t vid = 0; |
2943 | zebra_vni_t *zvni; | |
2853fed6 | 2944 | int found = 0; |
d62a17ae | 2945 | |
71349e03 MK |
2946 | if (!br_if) |
2947 | return NULL; | |
2948 | ||
d62a17ae | 2949 | /* Make sure the linked interface is a bridge. */ |
2950 | if (!IS_ZEBRA_IF_BRIDGE(br_if)) | |
2951 | return NULL; | |
2952 | ||
d62a17ae | 2953 | /* Determine if bridge is VLAN-aware or not */ |
2954 | zif = br_if->info; | |
2955 | assert(zif); | |
2956 | br = &zif->l2info.br; | |
2957 | bridge_vlan_aware = br->vlan_aware; | |
2958 | if (bridge_vlan_aware) { | |
2959 | struct zebra_l2info_vlan *vl; | |
2960 | ||
2961 | if (!IS_ZEBRA_IF_VLAN(ifp)) | |
2962 | return NULL; | |
2963 | ||
2964 | zif = ifp->info; | |
2965 | assert(zif); | |
2966 | vl = &zif->l2info.vl; | |
2967 | vid = vl->vid; | |
2968 | } | |
2969 | ||
2970 | /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ | |
2971 | /* TODO: Optimize with a hash. */ | |
2853fed6 | 2972 | zns = zebra_ns_lookup(NS_DEFAULT); |
2973 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { | |
2974 | tmp_if = (struct interface *)rn->info; | |
2975 | if (!tmp_if) | |
2976 | continue; | |
d62a17ae | 2977 | zif = tmp_if->info; |
2978 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
2979 | continue; | |
2980 | if (!if_is_operative(tmp_if)) | |
2981 | continue; | |
2982 | vxl = &zif->l2info.vxl; | |
2983 | ||
2984 | if (zif->brslave_info.br_if != br_if) | |
2985 | continue; | |
2986 | ||
2853fed6 | 2987 | if (!bridge_vlan_aware || vxl->access_vlan == vid) { |
2988 | found = 1; | |
d62a17ae | 2989 | break; |
2853fed6 | 2990 | } |
d62a17ae | 2991 | } |
2992 | ||
2853fed6 | 2993 | if (!found) |
d62a17ae | 2994 | return NULL; |
2995 | ||
2853fed6 | 2996 | zvni = zvni_lookup(vxl->vni); |
d62a17ae | 2997 | return zvni; |
2232a77c | 2998 | } |
2999 | ||
3000 | /* Map to SVI on bridge corresponding to specified VLAN. This can be one | |
3001 | * of two cases: | |
3002 | * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface | |
3003 | * linked to the bridge | |
3004 | * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface | |
3005 | * itself | |
3006 | */ | |
2853fed6 | 3007 | static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if) |
d62a17ae | 3008 | { |
2853fed6 | 3009 | struct zebra_ns *zns; |
3010 | struct route_node *rn; | |
3011 | struct interface *tmp_if = NULL; | |
d62a17ae | 3012 | struct zebra_if *zif; |
3013 | struct zebra_l2info_bridge *br; | |
3014 | struct zebra_l2info_vlan *vl; | |
d7c0a89a | 3015 | uint8_t bridge_vlan_aware; |
2853fed6 | 3016 | int found = 0; |
d62a17ae | 3017 | |
b5ebdc9b | 3018 | /* Defensive check, caller expected to invoke only with valid bridge. */ |
3019 | if (!br_if) | |
3020 | return NULL; | |
3021 | ||
d62a17ae | 3022 | /* Determine if bridge is VLAN-aware or not */ |
3023 | zif = br_if->info; | |
3024 | assert(zif); | |
3025 | br = &zif->l2info.br; | |
3026 | bridge_vlan_aware = br->vlan_aware; | |
3027 | ||
3028 | /* Check oper status of the SVI. */ | |
3029 | if (!bridge_vlan_aware) | |
3030 | return if_is_operative(br_if) ? br_if : NULL; | |
3031 | ||
3032 | /* Identify corresponding VLAN interface. */ | |
3033 | /* TODO: Optimize with a hash. */ | |
2853fed6 | 3034 | zns = zebra_ns_lookup(NS_DEFAULT); |
3035 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { | |
3036 | tmp_if = (struct interface *)rn->info; | |
d62a17ae | 3037 | /* Check oper status of the SVI. */ |
2853fed6 | 3038 | if (!tmp_if || !if_is_operative(tmp_if)) |
d62a17ae | 3039 | continue; |
3040 | zif = tmp_if->info; | |
3041 | if (!zif || zif->zif_type != ZEBRA_IF_VLAN | |
3042 | || zif->link != br_if) | |
3043 | continue; | |
3044 | vl = (struct zebra_l2info_vlan *)&zif->l2info.vl; | |
3045 | ||
2853fed6 | 3046 | if (vl->vid == vid) { |
3047 | found = 1; | |
d62a17ae | 3048 | break; |
2853fed6 | 3049 | } |
d62a17ae | 3050 | } |
3051 | ||
2853fed6 | 3052 | return found ? tmp_if : NULL; |
2232a77c | 3053 | } |
3054 | ||
3055 | /* | |
3056 | * Install remote MAC into the kernel. | |
3057 | */ | |
d62a17ae | 3058 | static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac) |
2232a77c | 3059 | { |
d62a17ae | 3060 | struct zebra_if *zif; |
3061 | struct zebra_l2info_vxlan *vxl; | |
a37f4598 | 3062 | bool sticky; |
2232a77c | 3063 | |
d62a17ae | 3064 | if (!(mac->flags & ZEBRA_MAC_REMOTE)) |
3065 | return 0; | |
2232a77c | 3066 | |
d62a17ae | 3067 | zif = zvni->vxlan_if->info; |
3068 | if (!zif) | |
3069 | return -1; | |
3070 | vxl = &zif->l2info.vxl; | |
2232a77c | 3071 | |
a37f4598 | 3072 | sticky = !!CHECK_FLAG(mac->flags, |
3073 | (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)); | |
c85c03c7 | 3074 | |
d62a17ae | 3075 | return kernel_add_mac(zvni->vxlan_if, vxl->access_vlan, &mac->macaddr, |
3076 | mac->fwd_info.r_vtep_ip, sticky); | |
2232a77c | 3077 | } |
3078 | ||
3079 | /* | |
d63c1b18 | 3080 | * Uninstall remote MAC from the kernel. |
2232a77c | 3081 | */ |
d63c1b18 | 3082 | static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac) |
2232a77c | 3083 | { |
d62a17ae | 3084 | struct zebra_if *zif; |
3085 | struct zebra_l2info_vxlan *vxl; | |
98efddf1 | 3086 | struct in_addr vtep_ip; |
d62a17ae | 3087 | struct interface *ifp; |
2232a77c | 3088 | |
d63c1b18 | 3089 | if (!(mac->flags & ZEBRA_MAC_REMOTE)) |
d62a17ae | 3090 | return 0; |
2232a77c | 3091 | |
d62a17ae | 3092 | if (!zvni->vxlan_if) { |
9df414fe QY |
3093 | zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", |
3094 | zvni->vni, zvni); | |
d62a17ae | 3095 | return -1; |
3096 | } | |
2232a77c | 3097 | |
d62a17ae | 3098 | zif = zvni->vxlan_if->info; |
3099 | if (!zif) | |
3100 | return -1; | |
3101 | vxl = &zif->l2info.vxl; | |
2232a77c | 3102 | |
d63c1b18 | 3103 | ifp = zvni->vxlan_if; |
3104 | vtep_ip = mac->fwd_info.r_vtep_ip; | |
2232a77c | 3105 | |
d63c1b18 | 3106 | return kernel_del_mac(ifp, vxl->access_vlan, &mac->macaddr, vtep_ip); |
2232a77c | 3107 | } |
3108 | ||
3109 | /* | |
3110 | * Install MAC hash entry - called upon access VLAN change. | |
3111 | */ | |
d62a17ae | 3112 | static void zvni_install_mac_hash(struct hash_backet *backet, void *ctxt) |
2232a77c | 3113 | { |
d62a17ae | 3114 | zebra_mac_t *mac; |
3115 | struct mac_walk_ctx *wctx = ctxt; | |
2232a77c | 3116 | |
d62a17ae | 3117 | mac = (zebra_mac_t *)backet->data; |
2232a77c | 3118 | |
d62a17ae | 3119 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) |
3120 | zvni_mac_install(wctx->zvni, mac); | |
2232a77c | 3121 | } |
3122 | ||
fe697c6b | 3123 | /* |
3124 | * Count of remote neighbors referencing this MAC. | |
3125 | */ | |
3126 | static int remote_neigh_count(zebra_mac_t *zmac) | |
3127 | { | |
3128 | zebra_neigh_t *n = NULL; | |
3129 | struct listnode *node = NULL; | |
3130 | int count = 0; | |
3131 | ||
3132 | for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { | |
3133 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) | |
3134 | count++; | |
3135 | } | |
3136 | ||
3137 | return count; | |
3138 | } | |
3139 | ||
2232a77c | 3140 | /* |
3141 | * Decrement neighbor refcount of MAC; uninstall and free it if | |
3142 | * appropriate. | |
3143 | */ | |
fe697c6b | 3144 | static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac) |
2232a77c | 3145 | { |
fe697c6b | 3146 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) |
d62a17ae | 3147 | return; |
2232a77c | 3148 | |
fe697c6b | 3149 | /* If all remote neighbors referencing a remote MAC go away, |
3150 | * we need to uninstall the MAC. | |
3151 | */ | |
3152 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) && | |
3153 | remote_neigh_count(mac) == 0) { | |
d63c1b18 | 3154 | zvni_mac_uninstall(zvni, mac); |
fe697c6b | 3155 | UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); |
3156 | } | |
2232a77c | 3157 | |
fe697c6b | 3158 | /* If no neighbors, delete the MAC. */ |
3159 | if (list_isempty(mac->neigh_list)) | |
3160 | zvni_mac_del(zvni, mac); | |
2232a77c | 3161 | } |
3162 | ||
3163 | /* | |
3164 | * Read and populate local MACs and neighbors corresponding to this VNI. | |
3165 | */ | |
996c9314 | 3166 | static void zvni_read_mac_neigh(zebra_vni_t *zvni, struct interface *ifp) |
2232a77c | 3167 | { |
2853fed6 | 3168 | struct zebra_ns *zns; |
d62a17ae | 3169 | struct zebra_if *zif; |
3170 | struct interface *vlan_if; | |
3171 | struct zebra_l2info_vxlan *vxl; | |
1a98c087 | 3172 | struct interface *vrr_if; |
2232a77c | 3173 | |
d62a17ae | 3174 | zif = ifp->info; |
3175 | vxl = &zif->l2info.vxl; | |
2853fed6 | 3176 | zns = zebra_ns_lookup(NS_DEFAULT); |
2232a77c | 3177 | |
d62a17ae | 3178 | if (IS_ZEBRA_DEBUG_VXLAN) |
3179 | zlog_debug( | |
2853fed6 | 3180 | "Reading MAC FDB and Neighbors for intf %s(%u) VNI %u master %u", |
3181 | ifp->name, ifp->ifindex, zvni->vni, | |
d62a17ae | 3182 | zif->brslave_info.bridge_ifindex); |
2232a77c | 3183 | |
2853fed6 | 3184 | macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if); |
3185 | vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); | |
1a98c087 MK |
3186 | if (vlan_if) { |
3187 | ||
ead40654 MK |
3188 | /* Add SVI MAC-IP */ |
3189 | zvni_add_macip_for_intf(vlan_if, zvni); | |
1a98c087 | 3190 | |
ead40654 MK |
3191 | /* Add VRR MAC-IP - if any*/ |
3192 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
3193 | if (vrr_if) | |
3194 | zvni_add_macip_for_intf(vrr_if, zvni); | |
1a98c087 | 3195 | |
2853fed6 | 3196 | neigh_read_for_vlan(zns, vlan_if); |
1a98c087 | 3197 | } |
2232a77c | 3198 | } |
3199 | ||
3200 | /* | |
3201 | * Hash function for VNI. | |
3202 | */ | |
d62a17ae | 3203 | static unsigned int vni_hash_keymake(void *p) |
2232a77c | 3204 | { |
d62a17ae | 3205 | const zebra_vni_t *zvni = p; |
2232a77c | 3206 | |
d62a17ae | 3207 | return (jhash_1word(zvni->vni, 0)); |
2232a77c | 3208 | } |
3209 | ||
3210 | /* | |
3211 | * Compare 2 VNI hash entries. | |
3212 | */ | |
74df8d6d | 3213 | static bool vni_hash_cmp(const void *p1, const void *p2) |
2232a77c | 3214 | { |
d62a17ae | 3215 | const zebra_vni_t *zvni1 = p1; |
3216 | const zebra_vni_t *zvni2 = p2; | |
2232a77c | 3217 | |
d62a17ae | 3218 | return (zvni1->vni == zvni2->vni); |
2232a77c | 3219 | } |
3220 | ||
27fa3398 DS |
3221 | static int vni_list_cmp(void *p1, void *p2) |
3222 | { | |
3223 | const zebra_vni_t *zvni1 = p1; | |
3224 | const zebra_vni_t *zvni2 = p2; | |
3225 | ||
3226 | if (zvni1->vni == zvni2->vni) | |
3227 | return 0; | |
3228 | return (zvni1->vni < zvni2->vni) ? -1 : 1; | |
3229 | } | |
3230 | ||
2232a77c | 3231 | /* |
3232 | * Callback to allocate VNI hash entry. | |
3233 | */ | |
d62a17ae | 3234 | static void *zvni_alloc(void *p) |
2232a77c | 3235 | { |
d62a17ae | 3236 | const zebra_vni_t *tmp_vni = p; |
3237 | zebra_vni_t *zvni; | |
2232a77c | 3238 | |
d62a17ae | 3239 | zvni = XCALLOC(MTYPE_ZVNI, sizeof(zebra_vni_t)); |
3240 | zvni->vni = tmp_vni->vni; | |
3241 | return ((void *)zvni); | |
2232a77c | 3242 | } |
3243 | ||
3244 | /* | |
3245 | * Look up VNI hash entry. | |
3246 | */ | |
2853fed6 | 3247 | static zebra_vni_t *zvni_lookup(vni_t vni) |
2232a77c | 3248 | { |
2853fed6 | 3249 | struct zebra_vrf *zvrf; |
d62a17ae | 3250 | zebra_vni_t tmp_vni; |
3251 | zebra_vni_t *zvni = NULL; | |
2232a77c | 3252 | |
2853fed6 | 3253 | zvrf = vrf_info_lookup(VRF_DEFAULT); |
3254 | assert(zvrf); | |
d62a17ae | 3255 | memset(&tmp_vni, 0, sizeof(zebra_vni_t)); |
3256 | tmp_vni.vni = vni; | |
3257 | zvni = hash_lookup(zvrf->vni_table, &tmp_vni); | |
2232a77c | 3258 | |
d62a17ae | 3259 | return zvni; |
2232a77c | 3260 | } |
3261 | ||
3262 | /* | |
3263 | * Add VNI hash entry. | |
3264 | */ | |
2853fed6 | 3265 | static zebra_vni_t *zvni_add(vni_t vni) |
2232a77c | 3266 | { |
2853fed6 | 3267 | struct zebra_vrf *zvrf; |
d62a17ae | 3268 | zebra_vni_t tmp_zvni; |
3269 | zebra_vni_t *zvni = NULL; | |
2232a77c | 3270 | |
2853fed6 | 3271 | zvrf = vrf_info_lookup(VRF_DEFAULT); |
3272 | assert(zvrf); | |
d62a17ae | 3273 | memset(&tmp_zvni, 0, sizeof(zebra_vni_t)); |
3274 | tmp_zvni.vni = vni; | |
3275 | zvni = hash_get(zvrf->vni_table, &tmp_zvni, zvni_alloc); | |
3276 | assert(zvni); | |
2232a77c | 3277 | |
d62a17ae | 3278 | /* Create hash table for MAC */ |
3279 | zvni->mac_table = | |
3280 | hash_create(mac_hash_keymake, mac_cmp, "Zebra VNI MAC Table"); | |
2232a77c | 3281 | |
d62a17ae | 3282 | /* Create hash table for neighbors */ |
3283 | zvni->neigh_table = hash_create(neigh_hash_keymake, neigh_cmp, | |
3284 | "Zebra VNI Neighbor Table"); | |
2232a77c | 3285 | |
d62a17ae | 3286 | return zvni; |
2232a77c | 3287 | } |
3288 | ||
3289 | /* | |
3290 | * Delete VNI hash entry. | |
3291 | */ | |
2853fed6 | 3292 | static int zvni_del(zebra_vni_t *zvni) |
2232a77c | 3293 | { |
2853fed6 | 3294 | struct zebra_vrf *zvrf; |
d62a17ae | 3295 | zebra_vni_t *tmp_zvni; |
2232a77c | 3296 | |
2853fed6 | 3297 | zvrf = vrf_info_lookup(VRF_DEFAULT); |
3298 | assert(zvrf); | |
3299 | ||
d62a17ae | 3300 | zvni->vxlan_if = NULL; |
2232a77c | 3301 | |
d62a17ae | 3302 | /* Free the neighbor hash table. */ |
3303 | hash_free(zvni->neigh_table); | |
3304 | zvni->neigh_table = NULL; | |
2232a77c | 3305 | |
d62a17ae | 3306 | /* Free the MAC hash table. */ |
3307 | hash_free(zvni->mac_table); | |
3308 | zvni->mac_table = NULL; | |
2232a77c | 3309 | |
d62a17ae | 3310 | /* Free the VNI hash entry and allocated memory. */ |
3311 | tmp_zvni = hash_release(zvrf->vni_table, zvni); | |
3312 | if (tmp_zvni) | |
3313 | XFREE(MTYPE_ZVNI, tmp_zvni); | |
2232a77c | 3314 | |
d62a17ae | 3315 | return 0; |
2232a77c | 3316 | } |
3317 | ||
3318 | /* | |
3319 | * Inform BGP about local VNI addition. | |
3320 | */ | |
2853fed6 | 3321 | static int zvni_send_add_to_client(zebra_vni_t *zvni) |
2232a77c | 3322 | { |
d62a17ae | 3323 | struct zserv *client; |
3324 | struct stream *s; | |
2232a77c | 3325 | |
21ccc0cf | 3326 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); |
d62a17ae | 3327 | /* BGP may not be running. */ |
3328 | if (!client) | |
3329 | return 0; | |
2232a77c | 3330 | |
1002497a | 3331 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
2232a77c | 3332 | |
7cf15b25 | 3333 | zclient_create_header(s, ZEBRA_VNI_ADD, VRF_DEFAULT); |
d62a17ae | 3334 | stream_putl(s, zvni->vni); |
3335 | stream_put_in_addr(s, &zvni->local_vtep_ip); | |
b7cfce93 | 3336 | stream_put(s, &zvni->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */ |
2232a77c | 3337 | |
d62a17ae | 3338 | /* Write packet size. */ |
3339 | stream_putw_at(s, 0, stream_get_endp(s)); | |
2232a77c | 3340 | |
d62a17ae | 3341 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
3342 | zlog_debug("Send VNI_ADD %u %s tenant vrf %s to %s", zvni->vni, |
3343 | inet_ntoa(zvni->local_vtep_ip), | |
b7cfce93 | 3344 | vrf_id_to_name(zvni->vrf_id), |
d62a17ae | 3345 | zebra_route_string(client->proto)); |
2232a77c | 3346 | |
d62a17ae | 3347 | client->vniadd_cnt++; |
21ccc0cf | 3348 | return zserv_send_message(client, s); |
2232a77c | 3349 | } |
3350 | ||
3351 | /* | |
3352 | * Inform BGP about local VNI deletion. | |
3353 | */ | |
2853fed6 | 3354 | static int zvni_send_del_to_client(vni_t vni) |
2232a77c | 3355 | { |
d62a17ae | 3356 | struct zserv *client; |
3357 | struct stream *s; | |
2232a77c | 3358 | |
21ccc0cf | 3359 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); |
d62a17ae | 3360 | /* BGP may not be running. */ |
3361 | if (!client) | |
3362 | return 0; | |
2232a77c | 3363 | |
1002497a | 3364 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
d62a17ae | 3365 | stream_reset(s); |
2232a77c | 3366 | |
7cf15b25 | 3367 | zclient_create_header(s, ZEBRA_VNI_DEL, VRF_DEFAULT); |
d62a17ae | 3368 | stream_putl(s, vni); |
2232a77c | 3369 | |
d62a17ae | 3370 | /* Write packet size. */ |
3371 | stream_putw_at(s, 0, stream_get_endp(s)); | |
2232a77c | 3372 | |
d62a17ae | 3373 | if (IS_ZEBRA_DEBUG_VXLAN) |
2853fed6 | 3374 | zlog_debug("Send VNI_DEL %u to %s", vni, |
d62a17ae | 3375 | zebra_route_string(client->proto)); |
2232a77c | 3376 | |
d62a17ae | 3377 | client->vnidel_cnt++; |
21ccc0cf | 3378 | return zserv_send_message(client, s); |
2232a77c | 3379 | } |
3380 | ||
3381 | /* | |
3382 | * Build the VNI hash table by going over the VxLAN interfaces. This | |
3383 | * is called when EVPN (advertise-all-vni) is enabled. | |
3384 | */ | |
2853fed6 | 3385 | static void zvni_build_hash_table() |
2232a77c | 3386 | { |
2853fed6 | 3387 | struct zebra_ns *zns; |
3388 | struct route_node *rn; | |
d62a17ae | 3389 | struct interface *ifp; |
2232a77c | 3390 | |
d62a17ae | 3391 | /* Walk VxLAN interfaces and create VNI hash. */ |
2853fed6 | 3392 | zns = zebra_ns_lookup(NS_DEFAULT); |
3393 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { | |
b7cfce93 | 3394 | vni_t vni; |
643215ce | 3395 | zebra_vni_t *zvni = NULL; |
3396 | zebra_l3vni_t *zl3vni = NULL; | |
d62a17ae | 3397 | struct zebra_if *zif; |
3398 | struct zebra_l2info_vxlan *vxl; | |
2232a77c | 3399 | |
2853fed6 | 3400 | ifp = (struct interface *)rn->info; |
3401 | if (!ifp) | |
3402 | continue; | |
d62a17ae | 3403 | zif = ifp->info; |
3404 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
3405 | continue; | |
2232a77c | 3406 | |
b7cfce93 | 3407 | vxl = &zif->l2info.vxl; |
d62a17ae | 3408 | vni = vxl->vni; |
2232a77c | 3409 | |
643215ce | 3410 | /* L3-VNI and L2-VNI are handled seperately */ |
3411 | zl3vni = zl3vni_lookup(vni); | |
3412 | if (zl3vni) { | |
2232a77c | 3413 | |
b7cfce93 | 3414 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
3415 | zlog_debug( |
3416 | "create L3-VNI hash for Intf %s(%u) L3-VNI %u", | |
3417 | ifp->name, ifp->ifindex, vni); | |
2232a77c | 3418 | |
b7cfce93 | 3419 | /* associate with vxlan_if */ |
b67a60d2 | 3420 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
b7cfce93 | 3421 | zl3vni->vxlan_if = ifp; |
2232a77c | 3422 | |
523cafc4 | 3423 | /* |
3424 | * we need to associate with SVI. | |
b7cfce93 | 3425 | * we can associate with svi-if only after association |
523cafc4 | 3426 | * with vxlan-intf is complete |
3427 | */ | |
b7cfce93 MK |
3428 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); |
3429 | ||
3430 | if (is_l3vni_oper_up(zl3vni)) | |
3431 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
3432 | ||
3433 | } else { | |
b7cfce93 MK |
3434 | struct interface *vlan_if = NULL; |
3435 | ||
3436 | if (IS_ZEBRA_DEBUG_VXLAN) | |
3437 | zlog_debug( | |
3438 | "Create L2-VNI hash for intf %s(%u) L2-VNI %u local IP %s", | |
3439 | ifp->name, ifp->ifindex, vni, | |
3440 | inet_ntoa(vxl->vtep_ip)); | |
3441 | ||
3442 | /* VNI hash entry is not expected to exist. */ | |
3443 | zvni = zvni_lookup(vni); | |
3444 | if (zvni) { | |
9df414fe | 3445 | zlog_debug( |
b7cfce93 MK |
3446 | "VNI hash already present for IF %s(%u) L2-VNI %u", |
3447 | ifp->name, ifp->ifindex, vni); | |
3448 | continue; | |
3449 | } | |
3450 | ||
3451 | zvni = zvni_add(vni); | |
3452 | if (!zvni) { | |
9df414fe | 3453 | zlog_debug( |
b7cfce93 MK |
3454 | "Failed to add VNI hash, IF %s(%u) L2-VNI %u", |
3455 | ifp->name, ifp->ifindex, vni); | |
3456 | return; | |
3457 | } | |
3458 | ||
3459 | zvni->local_vtep_ip = vxl->vtep_ip; | |
3460 | zvni->vxlan_if = ifp; | |
3461 | vlan_if = zvni_map_to_svi(vxl->access_vlan, | |
3462 | zif->brslave_info.br_if); | |
3463 | if (vlan_if) { | |
3464 | zvni->vrf_id = vlan_if->vrf_id; | |
3465 | zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); | |
3466 | if (zl3vni) | |
3467 | listnode_add_sort(zl3vni->l2vnis, zvni); | |
3468 | } | |
3469 | ||
3470 | ||
3471 | /* Inform BGP if intf is up and mapped to bridge. */ | |
3472 | if (if_is_operative(ifp) && zif->brslave_info.br_if) | |
3473 | zvni_send_add_to_client(zvni); | |
3474 | } | |
d62a17ae | 3475 | } |
2232a77c | 3476 | } |
3477 | ||
3478 | /* | |
3479 | * See if remote VTEP matches with prefix. | |
3480 | */ | |
d62a17ae | 3481 | static int zvni_vtep_match(struct in_addr *vtep_ip, zebra_vtep_t *zvtep) |
2232a77c | 3482 | { |
d62a17ae | 3483 | return (IPV4_ADDR_SAME(vtep_ip, &zvtep->vtep_ip)); |
2232a77c | 3484 | } |
3485 | ||
3486 | /* | |
3487 | * Locate remote VTEP in VNI hash table. | |
3488 | */ | |
d62a17ae | 3489 | static zebra_vtep_t *zvni_vtep_find(zebra_vni_t *zvni, struct in_addr *vtep_ip) |
2232a77c | 3490 | { |
d62a17ae | 3491 | zebra_vtep_t *zvtep; |
2232a77c | 3492 | |
d62a17ae | 3493 | if (!zvni) |
3494 | return NULL; | |
2232a77c | 3495 | |
d62a17ae | 3496 | for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { |
3497 | if (zvni_vtep_match(vtep_ip, zvtep)) | |
3498 | break; | |
3499 | } | |
2232a77c | 3500 | |
d62a17ae | 3501 | return zvtep; |
2232a77c | 3502 | } |
3503 | ||
3504 | /* | |
3505 | * Add remote VTEP to VNI hash table. | |
3506 | */ | |
d62a17ae | 3507 | static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip) |
2232a77c | 3508 | { |
d62a17ae | 3509 | zebra_vtep_t *zvtep; |
2232a77c | 3510 | |
d62a17ae | 3511 | zvtep = XCALLOC(MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t)); |
2232a77c | 3512 | |
d62a17ae | 3513 | zvtep->vtep_ip = *vtep_ip; |
2232a77c | 3514 | |
d62a17ae | 3515 | if (zvni->vteps) |
3516 | zvni->vteps->prev = zvtep; | |
3517 | zvtep->next = zvni->vteps; | |
3518 | zvni->vteps = zvtep; | |
2232a77c | 3519 | |
d62a17ae | 3520 | return zvtep; |
2232a77c | 3521 | } |
3522 | ||
3523 | /* | |
3524 | * Remove remote VTEP from VNI hash table. | |
3525 | */ | |
d62a17ae | 3526 | static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep) |
2232a77c | 3527 | { |
d62a17ae | 3528 | if (zvtep->next) |
3529 | zvtep->next->prev = zvtep->prev; | |
3530 | if (zvtep->prev) | |
3531 | zvtep->prev->next = zvtep->next; | |
3532 | else | |
3533 | zvni->vteps = zvtep->next; | |
2232a77c | 3534 | |
d62a17ae | 3535 | zvtep->prev = zvtep->next = NULL; |
3536 | XFREE(MTYPE_ZVNI_VTEP, zvtep); | |
2232a77c | 3537 | |
d62a17ae | 3538 | return 0; |
2232a77c | 3539 | } |
3540 | ||
3541 | /* | |
3542 | * Delete all remote VTEPs for this VNI (upon VNI delete). Also | |
3543 | * uninstall from kernel if asked to. | |
3544 | */ | |
d62a17ae | 3545 | static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall) |
2232a77c | 3546 | { |
d62a17ae | 3547 | zebra_vtep_t *zvtep, *zvtep_next; |
2232a77c | 3548 | |
d62a17ae | 3549 | if (!zvni) |
3550 | return -1; | |
2232a77c | 3551 | |
d62a17ae | 3552 | for (zvtep = zvni->vteps; zvtep; zvtep = zvtep_next) { |
3553 | zvtep_next = zvtep->next; | |
3554 | if (uninstall) | |
3555 | zvni_vtep_uninstall(zvni, &zvtep->vtep_ip); | |
3556 | zvni_vtep_del(zvni, zvtep); | |
3557 | } | |
2232a77c | 3558 | |
d62a17ae | 3559 | return 0; |
2232a77c | 3560 | } |
3561 | ||
3562 | /* | |
3563 | * Install remote VTEP into the kernel. | |
3564 | */ | |
d62a17ae | 3565 | static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip) |
2232a77c | 3566 | { |
fbac9605 DS |
3567 | if (is_vxlan_flooding_head_end()) |
3568 | return kernel_add_vtep(zvni->vni, zvni->vxlan_if, vtep_ip); | |
3569 | return 0; | |
2232a77c | 3570 | } |
3571 | ||
3572 | /* | |
3573 | * Uninstall remote VTEP from the kernel. | |
3574 | */ | |
d62a17ae | 3575 | static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip) |
2232a77c | 3576 | { |
d62a17ae | 3577 | if (!zvni->vxlan_if) { |
9df414fe QY |
3578 | zlog_debug("VNI %u hash %p couldn't be uninstalled - no intf", |
3579 | zvni->vni, zvni); | |
d62a17ae | 3580 | return -1; |
3581 | } | |
2232a77c | 3582 | |
d62a17ae | 3583 | return kernel_del_vtep(zvni->vni, zvni->vxlan_if, vtep_ip); |
2232a77c | 3584 | } |
3585 | ||
fbac9605 DS |
3586 | /* |
3587 | * Install or uninstall flood entries in the kernel corresponding to | |
3588 | * remote VTEPs. This is invoked upon change to BUM handling. | |
3589 | */ | |
3590 | static void zvni_handle_flooding_remote_vteps(struct hash_backet *backet, | |
3591 | void *zvrf) | |
3592 | { | |
3593 | zebra_vni_t *zvni; | |
3594 | zebra_vtep_t *zvtep; | |
3595 | ||
3596 | zvni = (zebra_vni_t *)backet->data; | |
3597 | if (!zvni) | |
3598 | return; | |
3599 | ||
3600 | for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { | |
3601 | if (is_vxlan_flooding_head_end()) | |
3602 | zvni_vtep_install(zvni, &zvtep->vtep_ip); | |
3603 | else | |
3604 | zvni_vtep_uninstall(zvni, &zvtep->vtep_ip); | |
3605 | } | |
3606 | } | |
3607 | ||
2232a77c | 3608 | /* |
3609 | * Cleanup VNI/VTEP and update kernel | |
3610 | */ | |
84915b0a | 3611 | static void zvni_cleanup_all(struct hash_backet *backet, void *arg) |
2232a77c | 3612 | { |
b7cfce93 MK |
3613 | zebra_vni_t *zvni = NULL; |
3614 | zebra_l3vni_t *zl3vni = NULL; | |
84915b0a | 3615 | struct zebra_vrf *zvrf = (struct zebra_vrf *)arg; |
2232a77c | 3616 | |
d62a17ae | 3617 | zvni = (zebra_vni_t *)backet->data; |
2232a77c | 3618 | |
b7cfce93 | 3619 | /* remove from l3-vni list */ |
84915b0a | 3620 | if (zvrf->l3vni) |
3621 | zl3vni = zl3vni_lookup(zvrf->l3vni); | |
b7cfce93 MK |
3622 | if (zl3vni) |
3623 | listnode_delete(zl3vni->l2vnis, zvni); | |
3624 | ||
d62a17ae | 3625 | /* Free up all neighbors and MACs, if any. */ |
2853fed6 | 3626 | zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH); |
3627 | zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC); | |
2232a77c | 3628 | |
d62a17ae | 3629 | /* Free up all remote VTEPs, if any. */ |
3630 | zvni_vtep_del_all(zvni, 1); | |
2232a77c | 3631 | |
d62a17ae | 3632 | /* Delete the hash entry. */ |
2853fed6 | 3633 | zvni_del(zvni); |
2232a77c | 3634 | } |
3635 | ||
655b04d1 | 3636 | /* cleanup L3VNI */ |
996c9314 | 3637 | static void zl3vni_cleanup_all(struct hash_backet *backet, void *args) |
655b04d1 MK |
3638 | { |
3639 | zebra_l3vni_t *zl3vni = NULL; | |
3640 | ||
3641 | zl3vni = (zebra_l3vni_t *)backet->data; | |
655b04d1 MK |
3642 | |
3643 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
3644 | } | |
3645 | ||
85442b09 | 3646 | static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe, |
41db76c2 | 3647 | struct prefix *host) |
5e1b0650 DS |
3648 | { |
3649 | struct host_rb_entry lookup; | |
3650 | struct host_rb_entry *hle; | |
3651 | ||
3652 | memset(&lookup, 0, sizeof(lookup)); | |
3653 | memcpy(&lookup.p, host, sizeof(*host)); | |
3654 | ||
85442b09 | 3655 | hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup); |
5e1b0650 DS |
3656 | if (hle) |
3657 | return; | |
3658 | ||
3659 | hle = XCALLOC(MTYPE_HOST_PREFIX, sizeof(struct host_rb_entry)); | |
3660 | memcpy(hle, &lookup, sizeof(lookup)); | |
3661 | ||
85442b09 | 3662 | RB_INSERT(host_rb_tree_entry, hrbe, hle); |
5e1b0650 DS |
3663 | } |
3664 | ||
85442b09 | 3665 | static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host) |
5e1b0650 DS |
3666 | { |
3667 | struct host_rb_entry lookup; | |
3668 | struct host_rb_entry *hle; | |
3669 | ||
3670 | memset(&lookup, 0, sizeof(lookup)); | |
3671 | memcpy(&lookup.p, host, sizeof(*host)); | |
3672 | ||
85442b09 | 3673 | hle = RB_FIND(host_rb_tree_entry, hrbe, &lookup); |
10ac2516 | 3674 | if (hle) { |
85442b09 | 3675 | RB_REMOVE(host_rb_tree_entry, hrbe, hle); |
10ac2516 DS |
3676 | XFREE(MTYPE_HOST_PREFIX, hle); |
3677 | } | |
5e1b0650 DS |
3678 | |
3679 | return; | |
3680 | } | |
3681 | ||
b7cfce93 MK |
3682 | /* |
3683 | * Look up MAC hash entry. | |
3684 | */ | |
2dbad57f | 3685 | static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni, |
b7cfce93 MK |
3686 | struct ethaddr *rmac) |
3687 | { | |
3688 | zebra_mac_t tmp; | |
3689 | zebra_mac_t *pmac; | |
3690 | ||
3691 | memset(&tmp, 0, sizeof(tmp)); | |
3692 | memcpy(&tmp.macaddr, rmac, ETH_ALEN); | |
3693 | pmac = hash_lookup(zl3vni->rmac_table, &tmp); | |
2232a77c | 3694 | |
b7cfce93 | 3695 | return pmac; |
2dbad57f | 3696 | } |
2232a77c | 3697 | |
cec2e17d | 3698 | /* |
b7cfce93 | 3699 | * Callback to allocate RMAC hash entry. |
cec2e17d | 3700 | */ |
2dbad57f | 3701 | static void *zl3vni_rmac_alloc(void *p) |
d62a17ae | 3702 | { |
b7cfce93 MK |
3703 | const zebra_mac_t *tmp_rmac = p; |
3704 | zebra_mac_t *zrmac; | |
d62a17ae | 3705 | |
b7cfce93 MK |
3706 | zrmac = XCALLOC(MTYPE_MAC, sizeof(zebra_mac_t)); |
3707 | *zrmac = *tmp_rmac; | |
d62a17ae | 3708 | |
b7cfce93 | 3709 | return ((void *)zrmac); |
2dbad57f | 3710 | } |
cd233079 | 3711 | |
b7cfce93 MK |
3712 | /* |
3713 | * Add RMAC entry to l3-vni | |
3714 | */ | |
996c9314 | 3715 | static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac) |
b7cfce93 MK |
3716 | { |
3717 | zebra_mac_t tmp_rmac; | |
3718 | zebra_mac_t *zrmac = NULL; | |
d62a17ae | 3719 | |
b7cfce93 MK |
3720 | memset(&tmp_rmac, 0, sizeof(zebra_mac_t)); |
3721 | memcpy(&tmp_rmac.macaddr, rmac, ETH_ALEN); | |
3722 | zrmac = hash_get(zl3vni->rmac_table, &tmp_rmac, zl3vni_rmac_alloc); | |
3723 | assert(zrmac); | |
d62a17ae | 3724 | |
85442b09 | 3725 | RB_INIT(host_rb_tree_entry, &zrmac->host_rb); |
b7cfce93 | 3726 | |
2dbad57f | 3727 | SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE); |
3728 | SET_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC); | |
3729 | ||
b7cfce93 | 3730 | return zrmac; |
2dbad57f | 3731 | } |
cec2e17d | 3732 | |
3733 | /* | |
b7cfce93 | 3734 | * Delete MAC entry. |
cec2e17d | 3735 | */ |
996c9314 | 3736 | static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) |
cec2e17d | 3737 | { |
b7cfce93 | 3738 | zebra_mac_t *tmp_rmac; |
5e1b0650 | 3739 | struct host_rb_entry *hle; |
cd233079 | 3740 | |
85442b09 DS |
3741 | while (!RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) { |
3742 | hle = RB_ROOT(host_rb_tree_entry, &zrmac->host_rb); | |
5e1b0650 | 3743 | |
85442b09 | 3744 | RB_REMOVE(host_rb_tree_entry, &zrmac->host_rb, hle); |
5e1b0650 DS |
3745 | XFREE(MTYPE_HOST_PREFIX, hle); |
3746 | } | |
cd233079 | 3747 | |
b7cfce93 MK |
3748 | tmp_rmac = hash_release(zl3vni->rmac_table, zrmac); |
3749 | if (tmp_rmac) | |
3750 | XFREE(MTYPE_MAC, tmp_rmac); | |
cd233079 | 3751 | |
b7cfce93 | 3752 | return 0; |
2dbad57f | 3753 | } |
cec2e17d | 3754 | |
3755 | /* | |
b7cfce93 | 3756 | * Install remote RMAC into the kernel. |
cec2e17d | 3757 | */ |
996c9314 | 3758 | static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) |
cec2e17d | 3759 | { |
b7cfce93 MK |
3760 | struct zebra_if *zif = NULL; |
3761 | struct zebra_l2info_vxlan *vxl = NULL; | |
cec2e17d | 3762 | |
996c9314 LB |
3763 | if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) |
3764 | || !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) | |
b7cfce93 MK |
3765 | return 0; |
3766 | ||
3767 | zif = zl3vni->vxlan_if->info; | |
3768 | if (!zif) | |
3769 | return -1; | |
3770 | ||
3771 | vxl = &zif->l2info.vxl; | |
3772 | ||
3773 | return kernel_add_mac(zl3vni->vxlan_if, vxl->access_vlan, | |
996c9314 | 3774 | &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, 0); |
2dbad57f | 3775 | } |
b7cfce93 MK |
3776 | |
3777 | /* | |
3778 | * Uninstall remote RMAC from the kernel. | |
3779 | */ | |
996c9314 | 3780 | static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac) |
b7cfce93 MK |
3781 | { |
3782 | char buf[ETHER_ADDR_STRLEN]; | |
3783 | struct zebra_if *zif = NULL; | |
3784 | struct zebra_l2info_vxlan *vxl = NULL; | |
3785 | ||
996c9314 LB |
3786 | if (!(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE)) |
3787 | || !(CHECK_FLAG(zrmac->flags, ZEBRA_MAC_REMOTE_RMAC))) | |
b7cfce93 MK |
3788 | return 0; |
3789 | ||
3790 | if (!zl3vni->vxlan_if) { | |
9df414fe | 3791 | zlog_debug( |
996c9314 LB |
3792 | "RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if", |
3793 | prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), | |
3794 | zl3vni->vni, zl3vni); | |
b7cfce93 MK |
3795 | return -1; |
3796 | } | |
3797 | ||
3798 | zif = zl3vni->vxlan_if->info; | |
3799 | if (!zif) | |
3800 | return -1; | |
3801 | ||
3802 | vxl = &zif->l2info.vxl; | |
3803 | ||
3804 | return kernel_del_mac(zl3vni->vxlan_if, vxl->access_vlan, | |
d63c1b18 | 3805 | &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip); |
2dbad57f | 3806 | } |
3807 | ||
3808 | /* handle rmac add */ | |
996c9314 | 3809 | static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, |
6134fd82 | 3810 | struct ipaddr *vtep_ip, |
3811 | struct prefix *host_prefix) | |
2dbad57f | 3812 | { |
3813 | char buf[ETHER_ADDR_STRLEN]; | |
3814 | char buf1[INET6_ADDRSTRLEN]; | |
3815 | zebra_mac_t *zrmac = NULL; | |
3816 | ||
3817 | zrmac = zl3vni_rmac_lookup(zl3vni, rmac); | |
3818 | if (!zrmac) { | |
3819 | ||
3820 | zrmac = zl3vni_rmac_add(zl3vni, rmac); | |
3821 | if (!zrmac) { | |
9df414fe | 3822 | zlog_debug( |
2dbad57f | 3823 | "Failed to add RMAC %s L3VNI %u Remote VTEP %s", |
996c9314 LB |
3824 | prefix_mac2str(rmac, buf, sizeof(buf)), |
3825 | zl3vni->vni, | |
3826 | ipaddr2str(vtep_ip, buf1, sizeof(buf1))); | |
2dbad57f | 3827 | return -1; |
3828 | } | |
3829 | memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); | |
3830 | zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; | |
3831 | ||
3832 | /* install rmac in kernel */ | |
3833 | zl3vni_rmac_install(zl3vni, zrmac); | |
3834 | } | |
6134fd82 | 3835 | |
41db76c2 | 3836 | rb_find_or_add_host(&zrmac->host_rb, host_prefix); |
5e1b0650 | 3837 | |
2dbad57f | 3838 | return 0; |
3839 | } | |
3840 | ||
3841 | ||
3842 | /* handle rmac delete */ | |
22e63104 | 3843 | static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac, |
6134fd82 | 3844 | struct prefix *host_prefix) |
2dbad57f | 3845 | { |
41db76c2 | 3846 | rb_delete_host(&zrmac->host_rb, host_prefix); |
2dbad57f | 3847 | |
85442b09 | 3848 | if (RB_EMPTY(host_rb_tree_entry, &zrmac->host_rb)) { |
2dbad57f | 3849 | /* uninstall from kernel */ |
3850 | zl3vni_rmac_uninstall(zl3vni, zrmac); | |
3851 | ||
3852 | /* del the rmac entry */ | |
3853 | zl3vni_rmac_del(zl3vni, zrmac); | |
3854 | } | |
2dbad57f | 3855 | } |
b7cfce93 MK |
3856 | |
3857 | /* | |
3858 | * Look up nh hash entry on a l3-vni. | |
3859 | */ | |
996c9314 | 3860 | static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, struct ipaddr *ip) |
b7cfce93 MK |
3861 | { |
3862 | zebra_neigh_t tmp; | |
3863 | zebra_neigh_t *n; | |
3864 | ||
3865 | memset(&tmp, 0, sizeof(tmp)); | |
3866 | memcpy(&tmp.ip, ip, sizeof(struct ipaddr)); | |
3867 | n = hash_lookup(zl3vni->nh_table, &tmp); | |
3868 | ||
3869 | return n; | |
2dbad57f | 3870 | } |
b7cfce93 MK |
3871 | |
3872 | ||
3873 | /* | |
3874 | * Callback to allocate NH hash entry on L3-VNI. | |
3875 | */ | |
2dbad57f | 3876 | static void *zl3vni_nh_alloc(void *p) |
b7cfce93 MK |
3877 | { |
3878 | const zebra_neigh_t *tmp_n = p; | |
3879 | zebra_neigh_t *n; | |
3880 | ||
3881 | n = XCALLOC(MTYPE_NEIGH, sizeof(zebra_neigh_t)); | |
3882 | *n = *tmp_n; | |
3883 | ||
3884 | return ((void *)n); | |
2dbad57f | 3885 | } |
b7cfce93 MK |
3886 | |
3887 | /* | |
3888 | * Add neighbor entry. | |
3889 | */ | |
996c9314 | 3890 | static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip, |
b7cfce93 MK |
3891 | struct ethaddr *mac) |
3892 | { | |
3893 | zebra_neigh_t tmp_n; | |
3894 | zebra_neigh_t *n = NULL; | |
3895 | ||
3896 | memset(&tmp_n, 0, sizeof(zebra_neigh_t)); | |
3897 | memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr)); | |
3898 | n = hash_get(zl3vni->nh_table, &tmp_n, zl3vni_nh_alloc); | |
3899 | assert(n); | |
3900 | ||
85442b09 | 3901 | RB_INIT(host_rb_tree_entry, &n->host_rb); |
6134fd82 | 3902 | |
b7cfce93 | 3903 | memcpy(&n->emac, mac, ETH_ALEN); |
2dbad57f | 3904 | SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); |
3905 | SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE_NH); | |
b7cfce93 MK |
3906 | |
3907 | return n; | |
2dbad57f | 3908 | } |
b7cfce93 MK |
3909 | |
3910 | /* | |
3911 | * Delete neighbor entry. | |
3912 | */ | |
996c9314 | 3913 | static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) |
b7cfce93 MK |
3914 | { |
3915 | zebra_neigh_t *tmp_n; | |
f2a503f0 | 3916 | struct host_rb_entry *hle; |
b7cfce93 | 3917 | |
85442b09 DS |
3918 | while (!RB_EMPTY(host_rb_tree_entry, &n->host_rb)) { |
3919 | hle = RB_ROOT(host_rb_tree_entry, &n->host_rb); | |
f2a503f0 | 3920 | |
85442b09 | 3921 | RB_REMOVE(host_rb_tree_entry, &n->host_rb, hle); |
f2a503f0 DS |
3922 | XFREE(MTYPE_HOST_PREFIX, hle); |
3923 | } | |
55aabf6f | 3924 | |
b7cfce93 MK |
3925 | tmp_n = hash_release(zl3vni->nh_table, n); |
3926 | if (tmp_n) | |
3927 | XFREE(MTYPE_NEIGH, tmp_n); | |
3928 | ||
3929 | return 0; | |
2dbad57f | 3930 | } |
b7cfce93 MK |
3931 | |
3932 | /* | |
3933 | * Install remote nh as neigh into the kernel. | |
3934 | */ | |
996c9314 | 3935 | static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) |
b7cfce93 | 3936 | { |
f7dae312 | 3937 | #ifdef GNU_LINUX |
68e33151 | 3938 | uint8_t flags; |
f7dae312 | 3939 | #endif |
68e33151 CS |
3940 | int ret = 0; |
3941 | ||
b7cfce93 MK |
3942 | if (!is_l3vni_oper_up(zl3vni)) |
3943 | return -1; | |
3944 | ||
996c9314 LB |
3945 | if (!(n->flags & ZEBRA_NEIGH_REMOTE) |
3946 | || !(n->flags & ZEBRA_NEIGH_REMOTE_NH)) | |
b7cfce93 | 3947 | return 0; |
68e33151 CS |
3948 | #ifdef GNU_LINUX |
3949 | flags = NTF_EXT_LEARNED; | |
3950 | if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG) | |
3951 | flags |= NTF_ROUTER; | |
3952 | ret = kernel_add_neigh(zl3vni->svi_if, &n->ip, &n->emac, flags); | |
3953 | #endif | |
3954 | return ret; | |
2dbad57f | 3955 | } |
b7cfce93 MK |
3956 | |
3957 | /* | |
3958 | * Uninstall remote nh from the kernel. | |
3959 | */ | |
996c9314 | 3960 | static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) |
b7cfce93 | 3961 | { |
996c9314 LB |
3962 | if (!(n->flags & ZEBRA_NEIGH_REMOTE) |
3963 | || !(n->flags & ZEBRA_NEIGH_REMOTE_NH)) | |
b7cfce93 MK |
3964 | return 0; |
3965 | ||
fa409e1e | 3966 | if (!zl3vni->svi_if || !if_is_operative(zl3vni->svi_if)) |
3967 | return 0; | |
3968 | ||
b7cfce93 | 3969 | return kernel_del_neigh(zl3vni->svi_if, &n->ip); |
2dbad57f | 3970 | } |
3971 | ||
3972 | /* add remote vtep as a neigh entry */ | |
996c9314 | 3973 | static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip, |
6134fd82 | 3974 | struct ethaddr *rmac, |
3975 | struct prefix *host_prefix) | |
2dbad57f | 3976 | { |
3977 | char buf[ETHER_ADDR_STRLEN]; | |
3978 | char buf1[INET6_ADDRSTRLEN]; | |
3979 | zebra_neigh_t *nh = NULL; | |
3980 | ||
3981 | nh = zl3vni_nh_lookup(zl3vni, vtep_ip); | |
3982 | if (!nh) { | |
3983 | nh = zl3vni_nh_add(zl3vni, vtep_ip, rmac); | |
3984 | if (!nh) { | |
3985 | ||
9df414fe | 3986 | zlog_debug( |
2dbad57f | 3987 | "Failed to add NH as Neigh (IP %s MAC %s L3-VNI %u)", |
996c9314 LB |
3988 | ipaddr2str(vtep_ip, buf1, sizeof(buf1)), |
3989 | prefix_mac2str(rmac, buf, sizeof(buf)), | |
2dbad57f | 3990 | zl3vni->vni); |
3991 | return -1; | |
3992 | } | |
3993 | ||
3994 | /* install the nh neigh in kernel */ | |
3995 | zl3vni_nh_install(zl3vni, nh); | |
3996 | } | |
6134fd82 | 3997 | |
f2a503f0 | 3998 | rb_find_or_add_host(&nh->host_rb, host_prefix); |
6134fd82 | 3999 | |
2dbad57f | 4000 | return 0; |
4001 | } | |
4002 | ||
4003 | /* handle nh neigh delete */ | |
22e63104 | 4004 | static void zl3vni_remote_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *nh, |
4005 | struct prefix *host_prefix) | |
2dbad57f | 4006 | { |
f2a503f0 | 4007 | rb_delete_host(&nh->host_rb, host_prefix); |
2dbad57f | 4008 | |
85442b09 | 4009 | if (RB_EMPTY(host_rb_tree_entry, &nh->host_rb)) { |
2dbad57f | 4010 | /* uninstall from kernel */ |
4011 | zl3vni_nh_uninstall(zl3vni, nh); | |
4012 | ||
4013 | /* delete the nh entry */ | |
4014 | zl3vni_nh_del(zl3vni, nh); | |
4015 | } | |
2dbad57f | 4016 | } |
b7cfce93 | 4017 | |
3bcbba10 | 4018 | /* handle neigh update from kernel - the only thing of interest is to |
4019 | * readd stale entries. | |
4020 | */ | |
996c9314 | 4021 | static int zl3vni_local_nh_add_update(zebra_l3vni_t *zl3vni, struct ipaddr *ip, |
d7c0a89a | 4022 | uint16_t state) |
3bcbba10 | 4023 | { |
c05a738b | 4024 | #ifdef GNU_LINUX |
3bcbba10 | 4025 | zebra_neigh_t *n = NULL; |
4026 | ||
4027 | n = zl3vni_nh_lookup(zl3vni, ip); | |
4028 | if (!n) | |
4029 | return 0; | |
4030 | ||
4031 | /* all next hop neigh are remote and installed by frr. | |
4032 | * If the kernel has aged this entry, re-install. | |
4033 | */ | |
4034 | if (state & NUD_STALE) | |
4035 | zl3vni_nh_install(zl3vni, n); | |
c05a738b | 4036 | #endif |
3bcbba10 | 4037 | return 0; |
4038 | } | |
4039 | ||
8c9b80b9 | 4040 | /* handle neigh delete from kernel */ |
996c9314 | 4041 | static int zl3vni_local_nh_del(zebra_l3vni_t *zl3vni, struct ipaddr *ip) |
8c9b80b9 MK |
4042 | { |
4043 | zebra_neigh_t *n = NULL; | |
4044 | ||
4045 | n = zl3vni_nh_lookup(zl3vni, ip); | |
4046 | if (!n) | |
4047 | return 0; | |
4048 | ||
4049 | /* all next hop neigh are remote and installed by frr. | |
4050 | * If we get an age out notification for these neigh entries, we have to | |
523cafc4 | 4051 | * install it back |
4052 | */ | |
8c9b80b9 MK |
4053 | zl3vni_nh_install(zl3vni, n); |
4054 | ||
4055 | return 0; | |
4056 | } | |
4057 | ||
b7cfce93 MK |
4058 | /* |
4059 | * Hash function for L3 VNI. | |
4060 | */ | |
4061 | static unsigned int l3vni_hash_keymake(void *p) | |
4062 | { | |
4063 | const zebra_l3vni_t *zl3vni = p; | |
4064 | ||
4065 | return jhash_1word(zl3vni->vni, 0); | |
4066 | } | |
4067 | ||
4068 | /* | |
4069 | * Compare 2 L3 VNI hash entries. | |
4070 | */ | |
74df8d6d | 4071 | static bool l3vni_hash_cmp(const void *p1, const void *p2) |
b7cfce93 MK |
4072 | { |
4073 | const zebra_l3vni_t *zl3vni1 = p1; | |
4074 | const zebra_l3vni_t *zl3vni2 = p2; | |
4075 | ||
4076 | return (zl3vni1->vni == zl3vni2->vni); | |
4077 | } | |
4078 | ||
4079 | /* | |
4080 | * Callback to allocate L3 VNI hash entry. | |
4081 | */ | |
4082 | static void *zl3vni_alloc(void *p) | |
4083 | { | |
4084 | zebra_l3vni_t *zl3vni = NULL; | |
4085 | const zebra_l3vni_t *tmp_l3vni = p; | |
4086 | ||
4087 | zl3vni = XCALLOC(MTYPE_ZL3VNI, sizeof(zebra_l3vni_t)); | |
4088 | zl3vni->vni = tmp_l3vni->vni; | |
4089 | return ((void *)zl3vni); | |
4090 | } | |
4091 | ||
4092 | /* | |
4093 | * Look up L3 VNI hash entry. | |
4094 | */ | |
4095 | static zebra_l3vni_t *zl3vni_lookup(vni_t vni) | |
4096 | { | |
b7cfce93 MK |
4097 | zebra_l3vni_t tmp_l3vni; |
4098 | zebra_l3vni_t *zl3vni = NULL; | |
4099 | ||
b7cfce93 MK |
4100 | memset(&tmp_l3vni, 0, sizeof(zebra_l3vni_t)); |
4101 | tmp_l3vni.vni = vni; | |
89272910 | 4102 | zl3vni = hash_lookup(zrouter.l3vni_table, &tmp_l3vni); |
b7cfce93 MK |
4103 | |
4104 | return zl3vni; | |
4105 | } | |
4106 | ||
4107 | /* | |
4108 | * Add L3 VNI hash entry. | |
4109 | */ | |
4110 | static zebra_l3vni_t *zl3vni_add(vni_t vni, vrf_id_t vrf_id) | |
4111 | { | |
4112 | zebra_l3vni_t tmp_zl3vni; | |
b7cfce93 MK |
4113 | zebra_l3vni_t *zl3vni = NULL; |
4114 | ||
b7cfce93 MK |
4115 | memset(&tmp_zl3vni, 0, sizeof(zebra_l3vni_t)); |
4116 | tmp_zl3vni.vni = vni; | |
4117 | ||
89272910 | 4118 | zl3vni = hash_get(zrouter.l3vni_table, &tmp_zl3vni, zl3vni_alloc); |
b7cfce93 MK |
4119 | assert(zl3vni); |
4120 | ||
4121 | zl3vni->vrf_id = vrf_id; | |
4122 | zl3vni->svi_if = NULL; | |
4123 | zl3vni->vxlan_if = NULL; | |
4124 | zl3vni->l2vnis = list_new(); | |
27fa3398 | 4125 | zl3vni->l2vnis->cmp = vni_list_cmp; |
b7cfce93 MK |
4126 | |
4127 | /* Create hash table for remote RMAC */ | |
996c9314 LB |
4128 | zl3vni->rmac_table = hash_create(mac_hash_keymake, mac_cmp, |
4129 | "Zebra L3-VNI RMAC-Table"); | |
b7cfce93 MK |
4130 | |
4131 | /* Create hash table for neighbors */ | |
4132 | zl3vni->nh_table = hash_create(neigh_hash_keymake, neigh_cmp, | |
996c9314 | 4133 | "Zebra L3-VNI next-hop table"); |
b7cfce93 MK |
4134 | |
4135 | return zl3vni; | |
4136 | } | |
4137 | ||
4138 | /* | |
4139 | * Delete L3 VNI hash entry. | |
4140 | */ | |
4141 | static int zl3vni_del(zebra_l3vni_t *zl3vni) | |
4142 | { | |
b7cfce93 MK |
4143 | zebra_l3vni_t *tmp_zl3vni; |
4144 | ||
b7cfce93 | 4145 | /* free the list of l2vnis */ |
6a154c88 | 4146 | list_delete(&zl3vni->l2vnis); |
b7cfce93 MK |
4147 | zl3vni->l2vnis = NULL; |
4148 | ||
4149 | /* Free the rmac table */ | |
4150 | hash_free(zl3vni->rmac_table); | |
4151 | zl3vni->rmac_table = NULL; | |
4152 | ||
4153 | /* Free the nh table */ | |
4154 | hash_free(zl3vni->nh_table); | |
4155 | zl3vni->nh_table = NULL; | |
4156 | ||
4157 | /* Free the VNI hash entry and allocated memory. */ | |
89272910 | 4158 | tmp_zl3vni = hash_release(zrouter.l3vni_table, zl3vni); |
b7cfce93 MK |
4159 | if (tmp_zl3vni) |
4160 | XFREE(MTYPE_ZL3VNI, tmp_zl3vni); | |
4161 | ||
4162 | return 0; | |
4163 | } | |
4164 | ||
b7cfce93 MK |
4165 | static struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni) |
4166 | { | |
4167 | struct zebra_ns *zns = NULL; | |
4168 | struct route_node *rn = NULL; | |
4169 | struct interface *ifp = NULL; | |
4170 | ||
4171 | /* loop through all vxlan-interface */ | |
4172 | zns = zebra_ns_lookup(NS_DEFAULT); | |
4173 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { | |
4174 | ||
4175 | struct zebra_if *zif = NULL; | |
4176 | struct zebra_l2info_vxlan *vxl = NULL; | |
4177 | ||
4178 | ifp = (struct interface *)rn->info; | |
4179 | if (!ifp) | |
4180 | continue; | |
4181 | ||
4182 | zif = ifp->info; | |
4183 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
4184 | continue; | |
4185 | ||
4186 | vxl = &zif->l2info.vxl; | |
b67a60d2 | 4187 | if (vxl->vni == zl3vni->vni) { |
4188 | zl3vni->local_vtep_ip = vxl->vtep_ip; | |
b7cfce93 | 4189 | return ifp; |
b67a60d2 | 4190 | } |
b7cfce93 MK |
4191 | } |
4192 | ||
4193 | return NULL; | |
4194 | } | |
4195 | ||
4196 | static struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni) | |
4197 | { | |
996c9314 | 4198 | struct zebra_if *zif = NULL; /* zebra_if for vxlan_if */ |
b7cfce93 MK |
4199 | struct zebra_l2info_vxlan *vxl = NULL; /* l2 info for vxlan_if */ |
4200 | ||
2aeb403d | 4201 | if (!zl3vni) |
4202 | return NULL; | |
4203 | ||
b7cfce93 MK |
4204 | if (!zl3vni->vxlan_if) |
4205 | return NULL; | |
4206 | ||
4207 | zif = zl3vni->vxlan_if->info; | |
4208 | if (!zif) | |
4209 | return NULL; | |
4210 | ||
4211 | vxl = &zif->l2info.vxl; | |
4212 | ||
4213 | return zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); | |
4214 | } | |
4215 | ||
4216 | static zebra_l3vni_t *zl3vni_from_vrf(vrf_id_t vrf_id) | |
4217 | { | |
4218 | struct zebra_vrf *zvrf = NULL; | |
4219 | ||
4220 | zvrf = zebra_vrf_lookup_by_id(vrf_id); | |
4221 | if (!zvrf) | |
4222 | return NULL; | |
4223 | ||
4224 | return zl3vni_lookup(zvrf->l3vni); | |
4225 | } | |
4226 | ||
4227 | /* | |
4228 | * Map SVI and associated bridge to a VNI. This is invoked upon getting | |
4229 | * neighbor notifications, to see if they are of interest. | |
4230 | */ | |
4231 | static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp, | |
4232 | struct interface *br_if) | |
4233 | { | |
4234 | int found = 0; | |
4235 | vlanid_t vid = 0; | |
d7c0a89a | 4236 | uint8_t bridge_vlan_aware = 0; |
b7cfce93 MK |
4237 | zebra_l3vni_t *zl3vni = NULL; |
4238 | struct zebra_ns *zns = NULL; | |
4239 | struct route_node *rn = NULL; | |
4240 | struct zebra_if *zif = NULL; | |
4241 | struct interface *tmp_if = NULL; | |
4242 | struct zebra_l2info_bridge *br = NULL; | |
4243 | struct zebra_l2info_vxlan *vxl = NULL; | |
4244 | ||
4245 | if (!br_if) | |
4246 | return NULL; | |
4247 | ||
4248 | /* Make sure the linked interface is a bridge. */ | |
4249 | if (!IS_ZEBRA_IF_BRIDGE(br_if)) | |
4250 | return NULL; | |
4251 | ||
4252 | /* Determine if bridge is VLAN-aware or not */ | |
4253 | zif = br_if->info; | |
4254 | assert(zif); | |
4255 | br = &zif->l2info.br; | |
4256 | bridge_vlan_aware = br->vlan_aware; | |
4257 | if (bridge_vlan_aware) { | |
4258 | struct zebra_l2info_vlan *vl; | |
4259 | ||
4260 | if (!IS_ZEBRA_IF_VLAN(ifp)) | |
4261 | return NULL; | |
4262 | ||
4263 | zif = ifp->info; | |
4264 | assert(zif); | |
4265 | vl = &zif->l2info.vl; | |
4266 | vid = vl->vid; | |
4267 | } | |
4268 | ||
4269 | /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */ | |
4270 | /* TODO: Optimize with a hash. */ | |
4271 | zns = zebra_ns_lookup(NS_DEFAULT); | |
4272 | for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) { | |
4273 | tmp_if = (struct interface *)rn->info; | |
4274 | if (!tmp_if) | |
4275 | continue; | |
4276 | zif = tmp_if->info; | |
4277 | if (!zif || zif->zif_type != ZEBRA_IF_VXLAN) | |
4278 | continue; | |
4279 | if (!if_is_operative(tmp_if)) | |
4280 | continue; | |
4281 | vxl = &zif->l2info.vxl; | |
4282 | ||
4283 | if (zif->brslave_info.br_if != br_if) | |
4284 | continue; | |
4285 | ||
4286 | if (!bridge_vlan_aware || vxl->access_vlan == vid) { | |
4287 | found = 1; | |
4288 | break; | |
4289 | } | |
4290 | } | |
4291 | ||
4292 | if (!found) | |
4293 | return NULL; | |
4294 | ||
4295 | zl3vni = zl3vni_lookup(vxl->vni); | |
4296 | return zl3vni; | |
4297 | } | |
4298 | ||
4299 | /* | |
4300 | * Inform BGP about l3-vni. | |
4301 | */ | |
4302 | static int zl3vni_send_add_to_client(zebra_l3vni_t *zl3vni) | |
4303 | { | |
4304 | struct stream *s = NULL; | |
4305 | struct zserv *client = NULL; | |
4306 | struct ethaddr rmac; | |
4307 | char buf[ETHER_ADDR_STRLEN]; | |
4308 | ||
21ccc0cf | 4309 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); |
b7cfce93 MK |
4310 | /* BGP may not be running. */ |
4311 | if (!client) | |
4312 | return 0; | |
4313 | ||
4314 | /* get the rmac */ | |
4315 | memset(&rmac, 0, sizeof(struct ethaddr)); | |
4316 | zl3vni_get_rmac(zl3vni, &rmac); | |
4317 | ||
1002497a | 4318 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
b7cfce93 | 4319 | |
996c9314 | 4320 | zclient_create_header(s, ZEBRA_L3VNI_ADD, zl3vni_vrf_id(zl3vni)); |
b7cfce93 MK |
4321 | stream_putl(s, zl3vni->vni); |
4322 | stream_put(s, &rmac, sizeof(struct ethaddr)); | |
b67a60d2 | 4323 | stream_put_in_addr(s, &zl3vni->local_vtep_ip); |
c48d9f5f | 4324 | stream_put(s, &zl3vni->filter, sizeof(int)); |
b7cfce93 MK |
4325 | |
4326 | /* Write packet size. */ | |
4327 | stream_putw_at(s, 0, stream_get_endp(s)); | |
4328 | ||
4329 | if (IS_ZEBRA_DEBUG_VXLAN) | |
c48d9f5f | 4330 | zlog_debug( |
996c9314 LB |
4331 | "Send L3_VNI_ADD %u VRF %s RMAC %s local-ip %s filter %s to %s", |
4332 | zl3vni->vni, vrf_id_to_name(zl3vni_vrf_id(zl3vni)), | |
4333 | prefix_mac2str(&rmac, buf, sizeof(buf)), | |
4334 | inet_ntoa(zl3vni->local_vtep_ip), | |
4335 | CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) | |
4336 | ? "prefix-routes-only" | |
4337 | : "none", | |
4338 | zebra_route_string(client->proto)); | |
b7cfce93 MK |
4339 | |
4340 | client->l3vniadd_cnt++; | |
21ccc0cf | 4341 | return zserv_send_message(client, s); |
b7cfce93 MK |
4342 | } |
4343 | ||
4344 | /* | |
4345 | * Inform BGP about local l3-VNI deletion. | |
4346 | */ | |
4347 | static int zl3vni_send_del_to_client(zebra_l3vni_t *zl3vni) | |
4348 | { | |
4349 | struct stream *s = NULL; | |
4350 | struct zserv *client = NULL; | |
4351 | ||
21ccc0cf | 4352 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); |
b7cfce93 MK |
4353 | /* BGP may not be running. */ |
4354 | if (!client) | |
4355 | return 0; | |
4356 | ||
1002497a | 4357 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
b7cfce93 | 4358 | |
996c9314 | 4359 | zclient_create_header(s, ZEBRA_L3VNI_DEL, zl3vni_vrf_id(zl3vni)); |
b7cfce93 MK |
4360 | stream_putl(s, zl3vni->vni); |
4361 | ||
4362 | /* Write packet size. */ | |
4363 | stream_putw_at(s, 0, stream_get_endp(s)); | |
4364 | ||
4365 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 | 4366 | zlog_debug("Send L3_VNI_DEL %u VRF %s to %s", zl3vni->vni, |
b7cfce93 MK |
4367 | vrf_id_to_name(zl3vni_vrf_id(zl3vni)), |
4368 | zebra_route_string(client->proto)); | |
4369 | ||
4370 | client->l3vnidel_cnt++; | |
21ccc0cf | 4371 | return zserv_send_message(client, s); |
b7cfce93 MK |
4372 | } |
4373 | ||
4374 | static void zebra_vxlan_process_l3vni_oper_up(zebra_l3vni_t *zl3vni) | |
4375 | { | |
2aeb403d | 4376 | if (!zl3vni) |
4377 | return; | |
4378 | ||
b7cfce93 MK |
4379 | /* send l3vni add to BGP */ |
4380 | zl3vni_send_add_to_client(zl3vni); | |
4381 | } | |
4382 | ||
4383 | static void zebra_vxlan_process_l3vni_oper_down(zebra_l3vni_t *zl3vni) | |
4384 | { | |
2aeb403d | 4385 | if (!zl3vni) |
4386 | return; | |
4387 | ||
b7cfce93 MK |
4388 | /* send l3-vni del to BGP*/ |
4389 | zl3vni_send_del_to_client(zl3vni); | |
4390 | } | |
4391 | ||
996c9314 | 4392 | static void zvni_add_to_l3vni_list(struct hash_backet *backet, void *ctxt) |
b7cfce93 | 4393 | { |
996c9314 LB |
4394 | zebra_vni_t *zvni = (zebra_vni_t *)backet->data; |
4395 | zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)ctxt; | |
b7cfce93 MK |
4396 | |
4397 | if (zvni->vrf_id == zl3vni_vrf_id(zl3vni)) | |
4398 | listnode_add_sort(zl3vni->l2vnis, zvni); | |
4399 | } | |
4400 | ||
b7cfce93 MK |
4401 | /* |
4402 | * handle transition of vni from l2 to l3 and vice versa | |
4403 | */ | |
996c9314 LB |
4404 | static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni, |
4405 | int add) | |
b7cfce93 MK |
4406 | { |
4407 | zebra_vni_t *zvni = NULL; | |
4408 | ||
4409 | /* There is a possibility that VNI notification was already received | |
4410 | * from kernel and we programmed it as L2-VNI | |
4411 | * In such a case we need to delete this L2-VNI first, so | |
4412 | * that it can be reprogrammed as L3-VNI in the system. It is also | |
4413 | * possible that the vrf-vni mapping is removed from FRR while the vxlan | |
4414 | * interface is still present in kernel. In this case to keep it | |
523cafc4 | 4415 | * symmetric, we will delete the l3-vni and reprogram it as l2-vni |
4416 | */ | |
b7cfce93 MK |
4417 | if (add) { |
4418 | /* Locate hash entry */ | |
4419 | zvni = zvni_lookup(vni); | |
4420 | if (!zvni) | |
4421 | return 0; | |
4422 | ||
4423 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 | 4424 | zlog_debug("Del L2-VNI %u - transition to L3-VNI", vni); |
b7cfce93 MK |
4425 | |
4426 | /* Delete VNI from BGP. */ | |
4427 | zvni_send_del_to_client(zvni->vni); | |
4428 | ||
4429 | /* Free up all neighbors and MAC, if any. */ | |
4430 | zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH); | |
4431 | zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC); | |
4432 | ||
4433 | /* Free up all remote VTEPs, if any. */ | |
4434 | zvni_vtep_del_all(zvni, 0); | |
4435 | ||
4436 | /* Delete the hash entry. */ | |
4437 | if (zvni_del(zvni)) { | |
e914ccbe | 4438 | flog_err(EC_ZEBRA_VNI_DEL_FAILED, |
1c50c1c0 QY |
4439 | "Failed to del VNI hash %p, VNI %u", zvni, |
4440 | zvni->vni); | |
b7cfce93 MK |
4441 | return -1; |
4442 | } | |
4443 | } else { | |
4444 | /* TODO_MITESH: This needs to be thought through. We don't have | |
4445 | * enough information at this point to reprogram the vni as | |
4446 | * l2-vni. One way is to store the required info in l3-vni and | |
523cafc4 | 4447 | * used it solely for this purpose |
4448 | */ | |
b7cfce93 MK |
4449 | } |
4450 | ||
4451 | return 0; | |
4452 | } | |
4453 | ||
5e06422c | 4454 | /* delete and uninstall rmac hash entry */ |
996c9314 | 4455 | static void zl3vni_del_rmac_hash_entry(struct hash_backet *backet, void *ctx) |
5e06422c MK |
4456 | { |
4457 | zebra_mac_t *zrmac = NULL; | |
4458 | zebra_l3vni_t *zl3vni = NULL; | |
4459 | ||
4460 | zrmac = (zebra_mac_t *)backet->data; | |
4461 | zl3vni = (zebra_l3vni_t *)ctx; | |
4462 | zl3vni_rmac_uninstall(zl3vni, zrmac); | |
4463 | zl3vni_rmac_del(zl3vni, zrmac); | |
4464 | } | |
4465 | ||
4466 | /* delete and uninstall nh hash entry */ | |
996c9314 | 4467 | static void zl3vni_del_nh_hash_entry(struct hash_backet *backet, void *ctx) |
5e06422c MK |
4468 | { |
4469 | zebra_neigh_t *n = NULL; | |
4470 | zebra_l3vni_t *zl3vni = NULL; | |
4471 | ||
4472 | n = (zebra_neigh_t *)backet->data; | |
4473 | zl3vni = (zebra_l3vni_t *)ctx; | |
4474 | zl3vni_nh_uninstall(zl3vni, n); | |
4475 | zl3vni_nh_del(zl3vni, n); | |
4476 | } | |
4477 | ||
996c9314 LB |
4478 | static int ip_prefix_send_to_client(vrf_id_t vrf_id, struct prefix *p, |
4479 | uint16_t cmd) | |
31310b25 MK |
4480 | { |
4481 | struct zserv *client = NULL; | |
4482 | struct stream *s = NULL; | |
4483 | char buf[PREFIX_STRLEN]; | |
4484 | ||
21ccc0cf | 4485 | client = zserv_find_client(ZEBRA_ROUTE_BGP, 0); |
31310b25 MK |
4486 | /* BGP may not be running. */ |
4487 | if (!client) | |
4488 | return 0; | |
4489 | ||
1002497a | 4490 | s = stream_new(ZEBRA_MAX_PACKET_SIZ); |
31310b25 | 4491 | |
22bd3e94 | 4492 | zclient_create_header(s, cmd, vrf_id); |
31310b25 MK |
4493 | stream_put(s, p, sizeof(struct prefix)); |
4494 | ||
4495 | /* Write packet size. */ | |
4496 | stream_putw_at(s, 0, stream_get_endp(s)); | |
4497 | ||
4498 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 | 4499 | zlog_debug("Send ip prefix %s %s on vrf %s", |
31310b25 MK |
4500 | prefix2str(p, buf, sizeof(buf)), |
4501 | (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) ? "ADD" : "DEL", | |
4502 | vrf_id_to_name(vrf_id)); | |
4503 | ||
4504 | if (cmd == ZEBRA_IP_PREFIX_ROUTE_ADD) | |
4505 | client->prefixadd_cnt++; | |
4506 | else | |
4507 | client->prefixdel_cnt++; | |
4508 | ||
21ccc0cf | 4509 | return zserv_send_message(client, s); |
31310b25 MK |
4510 | } |
4511 | ||
a9a76262 MK |
4512 | /* re-add remote rmac if needed */ |
4513 | static int zebra_vxlan_readd_remote_rmac(zebra_l3vni_t *zl3vni, | |
996c9314 | 4514 | struct ethaddr *rmac) |
a9a76262 MK |
4515 | { |
4516 | char buf[ETHER_ADDR_STRLEN]; | |
4517 | zebra_mac_t *zrmac = NULL; | |
4518 | ||
4519 | zrmac = zl3vni_rmac_lookup(zl3vni, rmac); | |
4520 | if (!zrmac) | |
4521 | return 0; | |
4522 | ||
4523 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4524 | zlog_debug("Del remote RMAC %s L3VNI %u - readd", | |
996c9314 | 4525 | prefix_mac2str(rmac, buf, sizeof(buf)), zl3vni->vni); |
a9a76262 MK |
4526 | |
4527 | zl3vni_rmac_install(zl3vni, zrmac); | |
4528 | return 0; | |
4529 | } | |
4530 | ||
f07e1c99 | 4531 | /* Process a remote MACIP add from BGP. */ |
4532 | static void process_remote_macip_add(vni_t vni, | |
4533 | struct ethaddr *macaddr, | |
9df2b997 | 4534 | uint16_t ipa_len, |
f07e1c99 | 4535 | struct ipaddr *ipaddr, |
9df2b997 | 4536 | uint8_t flags, |
f07e1c99 | 4537 | uint32_t seq, |
4538 | struct in_addr vtep_ip) | |
c48d9f5f | 4539 | { |
f07e1c99 | 4540 | zebra_vni_t *zvni; |
4541 | zebra_vtep_t *zvtep; | |
e22a946a | 4542 | zebra_mac_t *mac = NULL, *old_mac = NULL; |
f07e1c99 | 4543 | zebra_neigh_t *n = NULL; |
4544 | int update_mac = 0, update_neigh = 0; | |
4545 | char buf[ETHER_ADDR_STRLEN]; | |
4546 | char buf1[INET6_ADDRSTRLEN]; | |
4547 | struct interface *ifp = NULL; | |
4548 | struct zebra_if *zif = NULL; | |
e22a946a | 4549 | struct zebra_vrf *zvrf; |
f07e1c99 | 4550 | uint32_t tmp_seq; |
a37f4598 | 4551 | bool sticky; |
4552 | bool remote_gw; | |
4553 | bool is_router; | |
e22a946a CS |
4554 | bool do_dad = false; |
4555 | bool is_dup_detect = false; | |
4556 | struct listnode *node = NULL; | |
4557 | struct timeval elapsed = {0, 0}; | |
c48d9f5f | 4558 | |
f07e1c99 | 4559 | /* Locate VNI hash entry - expected to exist. */ |
4560 | zvni = zvni_lookup(vni); | |
4561 | if (!zvni) { | |
4562 | zlog_warn("Unknown VNI %u upon remote MACIP ADD", vni); | |
4563 | return; | |
4564 | } | |
2dbad57f | 4565 | |
f07e1c99 | 4566 | ifp = zvni->vxlan_if; |
4567 | if (ifp) | |
4568 | zif = ifp->info; | |
4569 | if (!ifp || | |
4570 | !if_is_operative(ifp) || | |
4571 | !zif || | |
4572 | !zif->brslave_info.br_if) { | |
4573 | zlog_warn("Ignoring remote MACIP ADD VNI %u, invalid interface state or info", | |
4574 | vni); | |
2dbad57f | 4575 | return; |
f07e1c99 | 4576 | } |
2dbad57f | 4577 | |
f07e1c99 | 4578 | /* The remote VTEP specified should normally exist, but it is |
4579 | * possible that when peering comes up, peer may advertise MACIP | |
4580 | * routes before advertising type-3 routes. | |
f50dc5e6 | 4581 | */ |
f07e1c99 | 4582 | zvtep = zvni_vtep_find(zvni, &vtep_ip); |
4583 | if (!zvtep) { | |
4584 | if (zvni_vtep_add(zvni, &vtep_ip) == NULL) { | |
4585 | flog_err( | |
e914ccbe | 4586 | EC_ZEBRA_VTEP_ADD_FAILED, |
f07e1c99 | 4587 | "Failed to add remote VTEP, VNI %u zvni %p upon remote MACIP ADD", |
4588 | vni, zvni); | |
4589 | return; | |
4590 | } | |
2dbad57f | 4591 | |
f07e1c99 | 4592 | zvni_vtep_install(zvni, &vtep_ip); |
4593 | } | |
f50dc5e6 | 4594 | |
a37f4598 | 4595 | sticky = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); |
4596 | remote_gw = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW); | |
4597 | is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); | |
2dbad57f | 4598 | |
f07e1c99 | 4599 | mac = zvni_mac_lookup(zvni, macaddr); |
2dbad57f | 4600 | |
f07e1c99 | 4601 | /* Ignore if the mac is already present as a gateway mac */ |
4602 | if (mac && | |
4603 | CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) && | |
4604 | CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) { | |
4605 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4606 | zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as MAC is already configured as gateway MAC", | |
4607 | vni, | |
4608 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
4609 | ipa_len ? " IP " : "", | |
4610 | ipa_len ? | |
4611 | ipaddr2str(ipaddr, buf1, sizeof(buf1)) : ""); | |
2dbad57f | 4612 | return; |
f07e1c99 | 4613 | } |
2dbad57f | 4614 | |
e22a946a CS |
4615 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); |
4616 | if (!zvrf) | |
4617 | return; | |
4618 | ||
f07e1c99 | 4619 | /* check if the remote MAC is unknown or has a change. |
4620 | * If so, that needs to be updated first. Note that client could | |
4621 | * install MAC and MACIP separately or just install the latter. | |
4622 | */ | |
4623 | if (!mac | |
4624 | || !CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) | |
a37f4598 | 4625 | || sticky != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) |
4626 | || remote_gw != !!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) | |
f07e1c99 | 4627 | || !IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &vtep_ip) |
4628 | || seq != mac->rem_seq) | |
4629 | update_mac = 1; | |
4630 | ||
4631 | if (update_mac) { | |
4632 | if (!mac) { | |
4633 | mac = zvni_mac_add(zvni, macaddr); | |
4634 | if (!mac) { | |
4635 | zlog_warn( | |
4636 | "Failed to add MAC %s VNI %u Remote VTEP %s", | |
4637 | prefix_mac2str(macaddr, buf, | |
4638 | sizeof(buf)), | |
4639 | vni, inet_ntoa(vtep_ip)); | |
4640 | return; | |
4641 | } | |
4642 | ||
4643 | /* Is this MAC created for a MACIP? */ | |
4644 | if (ipa_len) | |
4645 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
4646 | } else { | |
4647 | const char *mac_type; | |
4648 | ||
4649 | /* When host moves but changes its (MAC,IP) | |
4650 | * binding, BGP may install a MACIP entry that | |
4651 | * corresponds to "older" location of the host | |
4652 | * in transient situations (because {IP1,M1} | |
4653 | * is a different route from {IP1,M2}). Check | |
4654 | * the sequence number and ignore this update | |
4655 | * if appropriate. | |
4656 | */ | |
4657 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
4658 | tmp_seq = mac->loc_seq; | |
4659 | mac_type = "local"; | |
4660 | } else { | |
4661 | tmp_seq = mac->rem_seq; | |
4662 | mac_type = "remote"; | |
4663 | } | |
4664 | if (seq < tmp_seq) { | |
4665 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4666 | zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s MAC has higher seq %u", | |
4667 | vni, | |
4668 | prefix_mac2str(macaddr, | |
4669 | buf, sizeof(buf)), | |
4670 | ipa_len ? " IP " : "", | |
4671 | ipa_len ? | |
4672 | ipaddr2str(ipaddr, | |
4673 | buf1, sizeof(buf1)) : "", | |
4674 | mac_type, | |
4675 | tmp_seq); | |
4676 | return; | |
4677 | } | |
4678 | } | |
4679 | ||
e22a946a CS |
4680 | /* Check MAC's curent state is local (this is the case |
4681 | * where MAC has moved from L->R) and check previous | |
4682 | * detection started via local learning. | |
4683 | * RFC-7432: A PE/VTEP that detects a MAC mobility | |
4684 | * event via local learning starts an M-second timer. | |
4685 | * | |
4686 | * VTEP-IP or seq. change along is not considered | |
4687 | * for dup. detection. | |
4688 | */ | |
4689 | if ((!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) && | |
4690 | mac->dad_count) | |
4691 | do_dad = true; | |
4692 | ||
e98e4b88 AK |
4693 | /* Remove local MAC from BGP. */ |
4694 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) | |
4695 | zvni_mac_send_del_to_client(zvni->vni, macaddr); | |
4696 | ||
f07e1c99 | 4697 | /* Set "auto" and "remote" forwarding info. */ |
4698 | UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); | |
4699 | memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); | |
4700 | SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); | |
4701 | mac->fwd_info.r_vtep_ip = vtep_ip; | |
4702 | ||
4703 | if (sticky) | |
4704 | SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
4705 | else | |
4706 | UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
4707 | ||
4708 | if (remote_gw) | |
4709 | SET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); | |
4710 | else | |
4711 | UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW); | |
4712 | ||
e22a946a CS |
4713 | if (zvrf->dup_addr_detect && do_dad) { |
4714 | /* MAC is detected as duplicate, hold on to | |
4715 | * install as remote entry. | |
4716 | */ | |
4717 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) { | |
4718 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4719 | zlog_debug( | |
4720 | "%s: duplicate addr MAC %s skip installing, learn count %u recover time %u", | |
4721 | __PRETTY_FUNCTION__, | |
4722 | prefix_mac2str(macaddr, | |
4723 | buf, sizeof(buf)), | |
4724 | mac->dad_count, | |
4725 | zvrf->dad_freeze_time); | |
4726 | /* Do not install MAC but process neigh | |
4727 | * due to the remote MAC add. | |
4728 | */ | |
4729 | goto process_neigh; | |
4730 | } | |
4731 | ||
4732 | /* Check if detection time (M-secs) expired. | |
4733 | * Reset learn count and detection start time. | |
4734 | */ | |
4735 | monotime_since(&mac->detect_start_time, &elapsed); | |
4736 | if (elapsed.tv_sec > zvrf->dad_time) { | |
4737 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4738 | zlog_debug("%s: duplicate addr MAC %s flags 0%x detection time passed, reset learn count %u", | |
4739 | __PRETTY_FUNCTION__, | |
4740 | prefix_mac2str(macaddr, buf, | |
4741 | sizeof(buf)), | |
4742 | mac->flags, mac->dad_count); | |
4743 | /* Reset learn count but do not start detection | |
4744 | * during remote learn. | |
4745 | * Next local learn event start time wil be | |
4746 | * resetted. | |
4747 | */ | |
4748 | mac->dad_count = 0; | |
4749 | } else { | |
4750 | /* Increment detection count while in probe | |
4751 | * window | |
4752 | */ | |
4753 | mac->dad_count++; | |
4754 | } | |
4755 | ||
4756 | if (mac->dad_count >= zvrf->dad_max_moves) { | |
4757 | flog_warn(EC_ZEBRA_DUP_MAC_DETECTED, | |
4758 | "VNI %u: MAC %s detected as duplicate during remote update, from VTEP %s", | |
4759 | zvni->vni, | |
4760 | prefix_mac2str(&mac->macaddr, | |
4761 | buf, sizeof(buf)), | |
4762 | inet_ntoa(mac->fwd_info.r_vtep_ip)); | |
4763 | ||
4764 | SET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE); | |
4765 | ||
4766 | /* Capture Duplicate detection time */ | |
4767 | mac->dad_dup_detect_time = monotime(NULL); | |
4768 | ||
4769 | /* Mark all IPs/Neighs as duplicate associcated | |
4770 | * with this MAC | |
4771 | */ | |
4772 | for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, | |
4773 | node, n)) { | |
4774 | /* Ony Mark IPs which are Remote */ | |
4775 | if (!CHECK_FLAG(n->flags, | |
4776 | ZEBRA_NEIGH_REMOTE)) | |
4777 | continue; | |
4778 | ||
4779 | SET_FLAG(n->flags, | |
4780 | ZEBRA_NEIGH_DUPLICATE); | |
4781 | ||
4782 | /* Capture Duplicate detection time */ | |
4783 | n->dad_dup_detect_time = monotime(NULL); | |
4784 | ||
4785 | flog_warn( | |
4786 | EC_ZEBRA_DUP_IP_INHERIT_DETECTED, | |
4787 | "VNI %u: MAC %s IP %s detected as duplicate during remote update, inherit duplicate from MAC", | |
4788 | zvni->vni, | |
4789 | prefix_mac2str(&mac->macaddr, | |
4790 | buf, sizeof(buf)), | |
4791 | ipaddr2str(&n->ip, buf1, | |
4792 | sizeof(buf1))); | |
4793 | } | |
4794 | ||
c80a972c CS |
4795 | /* Start auto recovery timer for this |
4796 | * MAC | |
4797 | */ | |
4798 | THREAD_OFF(mac->dad_mac_auto_recovery_timer); | |
4799 | if (zvrf->dad_freeze && zvrf->dad_freeze_time) { | |
4800 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4801 | zlog_debug("%s: duplicate addr MAC %s flags 0%x auto recovery time %u start", | |
4802 | __PRETTY_FUNCTION__, | |
4803 | prefix_mac2str(&mac->macaddr, | |
4804 | buf, sizeof(buf)), | |
4805 | mac->flags, | |
4806 | zvrf->dad_freeze_time); | |
4807 | ||
4808 | thread_add_timer(zebrad.master, | |
4809 | zebra_vxlan_dad_mac_auto_recovery_exp, | |
4810 | mac, | |
4811 | zvrf->dad_freeze_time, | |
4812 | &mac->dad_mac_auto_recovery_timer); | |
4813 | } | |
4814 | ||
e22a946a CS |
4815 | if (zvrf->dad_freeze) |
4816 | is_dup_detect = true; | |
4817 | } | |
4818 | ||
4819 | } | |
4820 | process_neigh: | |
f07e1c99 | 4821 | zvni_process_neigh_on_remote_mac_add(zvni, mac); |
4822 | ||
4823 | /* Install the entry. */ | |
e22a946a CS |
4824 | if (!is_dup_detect) |
4825 | zvni_mac_install(zvni, mac); | |
f07e1c99 | 4826 | } |
4827 | ||
4828 | /* Update seq number. */ | |
4829 | mac->rem_seq = seq; | |
4830 | ||
4831 | /* If there is no IP, return after clearing AUTO flag of MAC. */ | |
4832 | if (!ipa_len) { | |
4833 | UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
4834 | return; | |
4835 | } | |
4836 | ||
e22a946a CS |
4837 | /* Reset flag */ |
4838 | do_dad = false; | |
4839 | ||
f07e1c99 | 4840 | /* Check if the remote neighbor itself is unknown or has a |
4841 | * change. If so, create or update and then install the entry. | |
4842 | */ | |
4843 | n = zvni_neigh_lookup(zvni, ipaddr); | |
4844 | if (!n | |
4845 | || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) | |
a37f4598 | 4846 | || is_router != !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) |
f07e1c99 | 4847 | || (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0) |
4848 | || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip) | |
4849 | || seq != n->rem_seq) | |
4850 | update_neigh = 1; | |
4851 | ||
4852 | if (update_neigh) { | |
4853 | if (!n) { | |
4854 | n = zvni_neigh_add(zvni, ipaddr, macaddr); | |
4855 | if (!n) { | |
4856 | zlog_warn( | |
4857 | "Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s", | |
4858 | ipaddr2str(ipaddr, buf1, | |
4859 | sizeof(buf1)), | |
4860 | prefix_mac2str(macaddr, buf, | |
4861 | sizeof(buf)), | |
4862 | vni, inet_ntoa(vtep_ip)); | |
4863 | return; | |
4864 | } | |
4865 | ||
4866 | } else { | |
4867 | const char *n_type; | |
4868 | ||
4869 | /* When host moves but changes its (MAC,IP) | |
4870 | * binding, BGP may install a MACIP entry that | |
4871 | * corresponds to "older" location of the host | |
4872 | * in transient situations (because {IP1,M1} | |
4873 | * is a different route from {IP1,M2}). Check | |
4874 | * the sequence number and ignore this update | |
4875 | * if appropriate. | |
4876 | */ | |
4877 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
4878 | tmp_seq = n->loc_seq; | |
4879 | n_type = "local"; | |
4880 | } else { | |
4881 | tmp_seq = n->rem_seq; | |
4882 | n_type = "remote"; | |
4883 | } | |
4884 | if (seq < tmp_seq) { | |
4885 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4886 | zlog_debug("Ignore remote MACIP ADD VNI %u MAC %s%s%s as existing %s Neigh has higher seq %u", | |
4887 | vni, | |
4888 | prefix_mac2str(macaddr, | |
4889 | buf, sizeof(buf)), | |
4848ef74 A |
4890 | " IP ", |
4891 | ipaddr2str(ipaddr, buf1, sizeof(buf1)), | |
f07e1c99 | 4892 | n_type, |
4893 | tmp_seq); | |
4894 | return; | |
4895 | } | |
4896 | if (memcmp(&n->emac, macaddr, sizeof(*macaddr)) != 0) { | |
4897 | /* MAC change, send a delete for old | |
4898 | * neigh if learnt locally. | |
4899 | */ | |
4900 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) && | |
4901 | IS_ZEBRA_NEIGH_ACTIVE(n)) | |
4902 | zvni_neigh_send_del_to_client( | |
4903 | zvni->vni, &n->ip, | |
4904 | &n->emac, 0); | |
4905 | ||
4906 | /* update neigh list for macs */ | |
4907 | old_mac = zvni_mac_lookup(zvni, &n->emac); | |
4908 | if (old_mac) { | |
4909 | listnode_delete(old_mac->neigh_list, n); | |
fe697c6b | 4910 | zvni_deref_ip2mac(zvni, old_mac); |
f07e1c99 | 4911 | } |
4912 | listnode_add_sort(mac->neigh_list, n); | |
4913 | memcpy(&n->emac, macaddr, ETH_ALEN); | |
e22a946a CS |
4914 | |
4915 | /* Check Neigh's curent state is local | |
4916 | * (this is the case where neigh/host has moved | |
4917 | * from L->R) and check previous detction | |
4918 | * started via local learning. | |
4919 | * | |
4920 | * RFC-7432: A PE/VTEP that detects a MAC | |
4921 | * mobilit event via local learning starts | |
4922 | * an M-second timer. | |
4923 | * VTEP-IP or seq. change along is not | |
4924 | * considered for dup. detection. | |
4925 | * | |
4926 | * Mobilty event scenario-B IP-MAC binding | |
4927 | * changed. | |
4928 | */ | |
4929 | if ((!CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) | |
4930 | && n->dad_count) | |
4931 | do_dad = true; | |
4932 | ||
f07e1c99 | 4933 | } |
4934 | } | |
4935 | ||
4936 | /* Set "remote" forwarding info. */ | |
4937 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
4938 | n->r_vtep_ip = vtep_ip; | |
4939 | SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); | |
4940 | ||
4941 | /* Set router flag (R-bit) to this Neighbor entry */ | |
4942 | if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) | |
4943 | SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
f190902f | 4944 | else |
4945 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
f07e1c99 | 4946 | |
e22a946a CS |
4947 | /* Check old or new MAC detected as duplicate, |
4948 | * inherit duplicate flag to this neigh. | |
4949 | */ | |
4950 | if (zebra_vxlan_ip_inherit_dad_from_mac(zvrf, old_mac, | |
4951 | mac, n)) { | |
4952 | flog_warn(EC_ZEBRA_DUP_IP_INHERIT_DETECTED, | |
4953 | "VNI %u: MAC %s IP %s detected as duplicate during remote update, inherit duplicate from MAC", | |
4954 | zvni->vni, | |
4955 | prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), | |
4956 | ipaddr2str(&n->ip, buf1, sizeof(buf1))); | |
4957 | } | |
4958 | ||
4959 | if (zvrf->dup_addr_detect) { | |
4960 | /* IP is detected as duplicate or inherit dup | |
4961 | * state, hold on to install as remote entry | |
4962 | * only if freeze is enabled. | |
4963 | */ | |
4964 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) { | |
4965 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4966 | zlog_debug( | |
4967 | "%s: duplicate addr MAC %s IP %s skip installing, learn count %u recover time %u", | |
4968 | __PRETTY_FUNCTION__, | |
4969 | prefix_mac2str(macaddr, | |
4970 | buf, sizeof(buf)), | |
4971 | ipaddr2str(ipaddr, buf1, | |
4972 | sizeof(buf1)), | |
4973 | n->dad_count, | |
4974 | zvrf->dad_freeze_time); | |
4975 | ||
4976 | if (zvrf->dad_freeze) | |
4977 | is_dup_detect = true; | |
4978 | /* warn-only action, neigh will be installed. | |
4979 | * freeze action, it wil not be installed. | |
4980 | */ | |
4981 | goto install_neigh; | |
4982 | } | |
4983 | ||
4984 | if (!do_dad) | |
4985 | goto install_neigh; | |
4986 | ||
4987 | /* Check if detection time (M-secs) expired. | |
4988 | * Reset learn count and detection start time. | |
4989 | * During remote mac add, count should already be 1 | |
4990 | * via local learning. | |
4991 | */ | |
4992 | monotime_since(&n->detect_start_time, &elapsed); | |
4993 | if (elapsed.tv_sec > zvrf->dad_time) { | |
4994 | if (IS_ZEBRA_DEBUG_VXLAN) | |
4995 | zlog_debug("%s: duplicate addr MAC %s IP %s flags 0x%x detection time passed, reset learn count %u", | |
4996 | __PRETTY_FUNCTION__, | |
4997 | prefix_mac2str(macaddr, buf, | |
4998 | sizeof(buf)), | |
4999 | ipaddr2str(ipaddr, buf1, | |
5000 | sizeof(buf1)), | |
5001 | n->flags, | |
5002 | n->dad_count); | |
5003 | /* Reset learn count but do not start detection | |
5004 | * during remote learn event. | |
5005 | */ | |
5006 | n->dad_count = 0; | |
5007 | } else { | |
5008 | /* Increment detection count while in probe | |
5009 | * window | |
5010 | */ | |
5011 | n->dad_count++; | |
5012 | } | |
5013 | ||
5014 | if (n->dad_count >= zvrf->dad_max_moves) { | |
5015 | flog_warn(EC_ZEBRA_DUP_IP_DETECTED, | |
5016 | "VNI %u: MAC %s IP %s detected as duplicate during remote update, from VTEP %s", | |
5017 | zvni->vni, | |
5018 | prefix_mac2str(&mac->macaddr, | |
5019 | buf, sizeof(buf)), | |
5020 | ipaddr2str(ipaddr, buf1, | |
5021 | sizeof(buf1)), | |
5022 | inet_ntoa(n->r_vtep_ip)); | |
5023 | ||
5024 | SET_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE); | |
5025 | ||
5026 | /* Capture Duplicate detection time */ | |
5027 | n->dad_dup_detect_time = monotime(NULL); | |
5028 | ||
c80a972c CS |
5029 | /* Start auto recovery timer for this IP */ |
5030 | THREAD_OFF(n->dad_ip_auto_recovery_timer); | |
5031 | if (zvrf->dad_freeze && zvrf->dad_freeze_time) { | |
5032 | if (IS_ZEBRA_DEBUG_VXLAN) | |
5033 | zlog_debug( | |
5034 | "%s: duplicate addr MAC %s IP %s flags 0x%x auto recovery time %u start", | |
5035 | __PRETTY_FUNCTION__, | |
5036 | prefix_mac2str(&mac->macaddr, | |
5037 | buf, | |
5038 | sizeof(buf)), | |
5039 | ipaddr2str(ipaddr, buf1, | |
5040 | sizeof(buf1)), | |
5041 | mac->flags, | |
5042 | zvrf->dad_freeze_time); | |
5043 | ||
5044 | thread_add_timer(zebrad.master, | |
5045 | zebra_vxlan_dad_ip_auto_recovery_exp, | |
5046 | n, | |
5047 | zvrf->dad_freeze_time, | |
5048 | &n->dad_ip_auto_recovery_timer); | |
5049 | } | |
e22a946a CS |
5050 | if (zvrf->dad_freeze) |
5051 | is_dup_detect = true; | |
5052 | } | |
5053 | } | |
5054 | install_neigh: | |
f07e1c99 | 5055 | /* Install the entry. */ |
e22a946a CS |
5056 | if (!is_dup_detect) |
5057 | zvni_neigh_install(zvni, n); | |
f07e1c99 | 5058 | } |
5059 | ||
5060 | /* Update seq number. */ | |
5061 | n->rem_seq = seq; | |
5062 | } | |
5063 | ||
5064 | /* Process a remote MACIP delete from BGP. */ | |
5065 | static void process_remote_macip_del(vni_t vni, | |
5066 | struct ethaddr *macaddr, | |
9df2b997 | 5067 | uint16_t ipa_len, |
f07e1c99 | 5068 | struct ipaddr *ipaddr, |
5069 | struct in_addr vtep_ip) | |
5070 | { | |
5071 | zebra_vni_t *zvni; | |
5072 | zebra_mac_t *mac = NULL; | |
5073 | zebra_neigh_t *n = NULL; | |
5074 | struct interface *ifp = NULL; | |
5075 | struct zebra_if *zif = NULL; | |
5076 | char buf[ETHER_ADDR_STRLEN]; | |
5077 | char buf1[INET6_ADDRSTRLEN]; | |
5078 | ||
5079 | /* Locate VNI hash entry - expected to exist. */ | |
5080 | zvni = zvni_lookup(vni); | |
5081 | if (!zvni) { | |
5082 | if (IS_ZEBRA_DEBUG_VXLAN) | |
5083 | zlog_debug("Unknown VNI %u upon remote MACIP DEL", vni); | |
5084 | return; | |
5085 | } | |
5086 | ||
5087 | ifp = zvni->vxlan_if; | |
5088 | if (ifp) | |
5089 | zif = ifp->info; | |
5090 | if (!ifp || | |
5091 | !if_is_operative(ifp) || | |
5092 | !zif || | |
5093 | !zif->brslave_info.br_if) { | |
5094 | if (IS_ZEBRA_DEBUG_VXLAN) | |
5095 | zlog_debug("Ignoring remote MACIP DEL VNI %u, invalid interface state or info", | |
5096 | vni); | |
5097 | return; | |
5098 | } | |
5099 | ||
5100 | /* The remote VTEP specified is normally expected to exist, but | |
5101 | * it is possible that the peer may delete the VTEP before deleting | |
5102 | * any MACs referring to the VTEP, in which case the handler (see | |
5103 | * remote_vtep_del) would have already deleted the MACs. | |
5104 | */ | |
5105 | if (!zvni_vtep_find(zvni, &vtep_ip)) | |
5106 | return; | |
5107 | ||
5108 | mac = zvni_mac_lookup(zvni, macaddr); | |
5109 | if (ipa_len) | |
5110 | n = zvni_neigh_lookup(zvni, ipaddr); | |
5111 | ||
5112 | if (n && !mac) { | |
5113 | zlog_warn("Failed to locate MAC %s for neigh %s VNI %u upon remote MACIP DEL", | |
5114 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
5115 | ipaddr2str(ipaddr, buf1, sizeof(buf1)), vni); | |
5116 | return; | |
5117 | } | |
5118 | ||
5119 | /* If the remote mac or neighbor doesn't exist there is nothing | |
5120 | * more to do. Otherwise, uninstall the entry and then remove it. | |
5121 | */ | |
5122 | if (!mac && !n) | |
5123 | return; | |
5124 | ||
5125 | /* Ignore the delete if this mac is a gateway mac-ip */ | |
5126 | if (mac | |
5127 | && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) | |
5128 | && CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) { | |
5129 | zlog_warn( | |
5130 | "Ignore remote MACIP DEL VNI %u MAC %s%s%s as MAC is already configured as gateway MAC", | |
5131 | vni, | |
5132 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
5133 | ipa_len ? " IP " : "", | |
5134 | ipa_len ? | |
5135 | ipaddr2str(ipaddr, buf1, sizeof(buf1)) : ""); | |
5136 | return; | |
5137 | } | |
5138 | ||
5139 | /* Uninstall remote neighbor or MAC. */ | |
5140 | if (n) { | |
5141 | /* When the MAC changes for an IP, it is possible the | |
5142 | * client may update the new MAC before trying to delete the | |
5143 | * "old" neighbor (as these are two different MACIP routes). | |
5144 | * Do the delete only if the MAC matches. | |
5145 | */ | |
5146 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) | |
5147 | && (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) == 0)) { | |
5148 | zvni_neigh_uninstall(zvni, n); | |
5149 | zvni_neigh_del(zvni, n); | |
fe697c6b | 5150 | zvni_deref_ip2mac(zvni, mac); |
f07e1c99 | 5151 | } |
5152 | } else { | |
5153 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { | |
5154 | zvni_process_neigh_on_remote_mac_del(zvni, mac); | |
f3a930da AK |
5155 | /* |
5156 | * the remote sequence number in the auto mac entry | |
5157 | * needs to be reset to 0 as the mac entry may have | |
5158 | * been removed on all VTEPs (including | |
5159 | * the originating one) | |
5160 | */ | |
5161 | mac->rem_seq = 0; | |
f07e1c99 | 5162 | |
fe697c6b | 5163 | /* If all remote neighbors referencing a remote MAC |
5164 | * go away, we need to uninstall the MAC. | |
5165 | */ | |
5166 | if (remote_neigh_count(mac) == 0) { | |
d63c1b18 | 5167 | zvni_mac_uninstall(zvni, mac); |
fe697c6b | 5168 | UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); |
5169 | } | |
5170 | if (list_isempty(mac->neigh_list)) | |
f07e1c99 | 5171 | zvni_mac_del(zvni, mac); |
fe697c6b | 5172 | else |
f07e1c99 | 5173 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); |
5174 | } | |
5175 | } | |
5176 | } | |
5177 | ||
5178 | ||
b7cfce93 MK |
5179 | /* Public functions */ |
5180 | ||
c48d9f5f MK |
5181 | int is_l3vni_for_prefix_routes_only(vni_t vni) |
5182 | { | |
5183 | zebra_l3vni_t *zl3vni = NULL; | |
5184 | ||
5185 | zl3vni = zl3vni_lookup(vni); | |
5186 | if (!zl3vni) | |
5187 | return 0; | |
5188 | ||
5189 | return CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY) ? 1 : 0; | |
5190 | } | |
5191 | ||
2dbad57f | 5192 | /* handle evpn route in vrf table */ |
996c9314 LB |
5193 | void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac, |
5194 | struct ipaddr *vtep_ip, | |
5195 | struct prefix *host_prefix) | |
2dbad57f | 5196 | { |
5197 | zebra_l3vni_t *zl3vni = NULL; | |
f50dc5e6 | 5198 | struct ipaddr ipv4_vtep; |
2dbad57f | 5199 | |
5200 | zl3vni = zl3vni_from_vrf(vrf_id); | |
5201 | if (!zl3vni || !is_l3vni_oper_up(zl3vni)) | |
5202 | return; | |
5203 | ||
3518f352 | 5204 | /* |
f50dc5e6 MK |
5205 | * add the next hop neighbor - |
5206 | * neigh to be installed is the ipv6 nexthop neigh | |
5207 | */ | |
3518f352 | 5208 | zl3vni_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); |
2dbad57f | 5209 | |
f50dc5e6 MK |
5210 | /* |
5211 | * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 | |
5212 | * address. Rmac is programmed against the ipv4 vtep because we only | |
5213 | * support ipv4 tunnels in the h/w right now | |
5214 | */ | |
5215 | memset(&ipv4_vtep, 0, sizeof(struct ipaddr)); | |
5216 | ipv4_vtep.ipa_type = IPADDR_V4; | |
5217 | if (vtep_ip->ipa_type == IPADDR_V6) | |
5218 | ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, | |
5219 | &(ipv4_vtep.ipaddr_v4)); | |
5220 | else | |
5221 | memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, | |
5222 | sizeof(struct in_addr)); | |
5223 | ||
3518f352 DS |
5224 | /* |
5225 | * add the rmac - remote rmac to be installed is against the ipv4 | |
f50dc5e6 MK |
5226 | * nexthop address |
5227 | */ | |
3518f352 | 5228 | zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep, host_prefix); |
2dbad57f | 5229 | } |
5230 | ||
5231 | /* handle evpn vrf route delete */ | |
22e63104 | 5232 | void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id, |
996c9314 LB |
5233 | struct ipaddr *vtep_ip, |
5234 | struct prefix *host_prefix) | |
2dbad57f | 5235 | { |
5236 | zebra_l3vni_t *zl3vni = NULL; | |
22e63104 | 5237 | zebra_neigh_t *nh = NULL; |
5238 | zebra_mac_t *zrmac = NULL; | |
2dbad57f | 5239 | |
5240 | zl3vni = zl3vni_from_vrf(vrf_id); | |
5e06422c | 5241 | if (!zl3vni) |
2dbad57f | 5242 | return; |
5243 | ||
22e63104 | 5244 | /* find the next hop entry and rmac entry */ |
5245 | nh = zl3vni_nh_lookup(zl3vni, vtep_ip); | |
5246 | if (!nh) | |
5247 | return; | |
5248 | zrmac = zl3vni_rmac_lookup(zl3vni, &nh->emac); | |
5249 | ||
2dbad57f | 5250 | /* delete the next hop entry */ |
22e63104 | 5251 | zl3vni_remote_nh_del(zl3vni, nh, host_prefix); |
2dbad57f | 5252 | |
5253 | /* delete the rmac entry */ | |
22e63104 | 5254 | if (zrmac) |
5255 | zl3vni_remote_rmac_del(zl3vni, zrmac, host_prefix); | |
5256 | ||
2dbad57f | 5257 | } |
5258 | ||
996c9314 | 5259 | void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni, |
9f049418 | 5260 | struct ethaddr *rmac, bool use_json) |
9aa741ea MK |
5261 | { |
5262 | zebra_l3vni_t *zl3vni = NULL; | |
5263 | zebra_mac_t *zrmac = NULL; | |
316f4ca4 | 5264 | json_object *json = NULL; |
9aa741ea | 5265 | |
316f4ca4 MK |
5266 | if (!is_evpn_enabled()) { |
5267 | if (use_json) | |
5268 | vty_out(vty, "{}\n"); | |
9aa741ea | 5269 | return; |
316f4ca4 MK |
5270 | } |
5271 | ||
5272 | if (use_json) | |
5273 | json = json_object_new_object(); | |
9aa741ea MK |
5274 | |
5275 | zl3vni = zl3vni_lookup(l3vni); | |
5276 | if (!zl3vni) { | |
316f4ca4 MK |
5277 | if (use_json) |
5278 | vty_out(vty, "{}\n"); | |
5279 | else | |
0437e105 | 5280 | vty_out(vty, "%% L3-VNI %u doesn't exist\n", l3vni); |
9aa741ea MK |
5281 | return; |
5282 | } | |
5283 | ||
5284 | zrmac = zl3vni_rmac_lookup(zl3vni, rmac); | |
5285 | if (!zrmac) { | |
316f4ca4 MK |
5286 | if (use_json) |
5287 | vty_out(vty, "{}\n"); | |
5288 | else | |
5289 | vty_out(vty, | |
0437e105 | 5290 | "%% Requested RMAC doesn't exist in L3-VNI %u", |
316f4ca4 | 5291 | l3vni); |
9aa741ea MK |
5292 | return; |
5293 | } | |
5294 | ||
316f4ca4 MK |
5295 | zl3vni_print_rmac(zrmac, vty, json); |
5296 | ||
5297 | if (use_json) { | |
5298 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5299 | json, JSON_C_TO_STRING_PRETTY)); | |
5300 | json_object_free(json); | |
5301 | } | |
9aa741ea | 5302 | } |
2dbad57f | 5303 | |
9f049418 | 5304 | void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t l3vni, bool use_json) |
b7cfce93 MK |
5305 | { |
5306 | zebra_l3vni_t *zl3vni; | |
d7c0a89a | 5307 | uint32_t num_rmacs; |
b7cfce93 MK |
5308 | struct rmac_walk_ctx wctx; |
5309 | json_object *json = NULL; | |
b7cfce93 MK |
5310 | |
5311 | if (!is_evpn_enabled()) | |
5312 | return; | |
5313 | ||
5314 | zl3vni = zl3vni_lookup(l3vni); | |
5315 | if (!zl3vni) { | |
5316 | if (use_json) | |
5317 | vty_out(vty, "{}\n"); | |
5318 | else | |
5319 | vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); | |
5320 | return; | |
5321 | } | |
5322 | num_rmacs = hashcount(zl3vni->rmac_table); | |
5323 | if (!num_rmacs) | |
5324 | return; | |
5325 | ||
75223c9e | 5326 | if (use_json) |
b7cfce93 | 5327 | json = json_object_new_object(); |
b7cfce93 MK |
5328 | |
5329 | memset(&wctx, 0, sizeof(struct rmac_walk_ctx)); | |
5330 | wctx.vty = vty; | |
75223c9e | 5331 | wctx.json = json; |
b7cfce93 | 5332 | if (!use_json) { |
996c9314 | 5333 | vty_out(vty, "Number of Remote RMACs known for this VNI: %u\n", |
b7cfce93 | 5334 | num_rmacs); |
4cce389e | 5335 | vty_out(vty, "%-17s %-21s\n", "MAC", "Remote VTEP"); |
b7cfce93 MK |
5336 | } else |
5337 | json_object_int_add(json, "numRmacs", num_rmacs); | |
5338 | ||
5339 | hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx); | |
5340 | ||
5341 | if (use_json) { | |
b7cfce93 MK |
5342 | vty_out(vty, "%s\n", json_object_to_json_string_ext( |
5343 | json, JSON_C_TO_STRING_PRETTY)); | |
5344 | json_object_free(json); | |
5345 | } | |
5346 | } | |
5347 | ||
9f049418 | 5348 | void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json) |
b7cfce93 | 5349 | { |
b7cfce93 | 5350 | json_object *json = NULL; |
c0b4eaa4 | 5351 | void *args[2]; |
b7cfce93 MK |
5352 | |
5353 | if (!is_evpn_enabled()) { | |
5354 | if (use_json) | |
5355 | vty_out(vty, "{}\n"); | |
5356 | return; | |
5357 | } | |
5358 | ||
b7cfce93 MK |
5359 | if (use_json) |
5360 | json = json_object_new_object(); | |
5361 | ||
c0b4eaa4 MK |
5362 | args[0] = vty; |
5363 | args[1] = json; | |
89272910 | 5364 | hash_iterate(zrouter.l3vni_table, |
c0b4eaa4 MK |
5365 | (void (*)(struct hash_backet *, |
5366 | void *))zl3vni_print_rmac_hash_all_vni, | |
5367 | args); | |
b7cfce93 MK |
5368 | |
5369 | if (use_json) { | |
5370 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5371 | json, JSON_C_TO_STRING_PRETTY)); | |
5372 | json_object_free(json); | |
5373 | } | |
5374 | } | |
5375 | ||
996c9314 | 5376 | void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, |
9f049418 | 5377 | struct ipaddr *ip, bool use_json) |
9aa741ea MK |
5378 | { |
5379 | zebra_l3vni_t *zl3vni = NULL; | |
5380 | zebra_neigh_t *n = NULL; | |
c0e519d3 | 5381 | json_object *json = NULL; |
9aa741ea | 5382 | |
c0e519d3 MK |
5383 | if (!is_evpn_enabled()) { |
5384 | if (use_json) | |
5385 | vty_out(vty, "{}\n"); | |
9aa741ea | 5386 | return; |
c0e519d3 MK |
5387 | } |
5388 | ||
5389 | if (use_json) | |
5390 | json = json_object_new_object(); | |
9aa741ea MK |
5391 | |
5392 | zl3vni = zl3vni_lookup(l3vni); | |
5393 | if (!zl3vni) { | |
c0e519d3 MK |
5394 | if (use_json) |
5395 | vty_out(vty, "{}\n"); | |
5396 | else | |
5397 | vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); | |
9aa741ea MK |
5398 | return; |
5399 | } | |
5400 | ||
5401 | n = zl3vni_nh_lookup(zl3vni, ip); | |
5402 | if (!n) { | |
c0e519d3 MK |
5403 | if (use_json) |
5404 | vty_out(vty, "{}\n"); | |
5405 | else | |
5406 | vty_out(vty, | |
5407 | "%% Requested next-hop not present for L3-VNI %u", | |
5408 | l3vni); | |
9aa741ea MK |
5409 | return; |
5410 | } | |
5411 | ||
c0e519d3 MK |
5412 | zl3vni_print_nh(n, vty, json); |
5413 | ||
5414 | if (use_json) { | |
5415 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5416 | json, JSON_C_TO_STRING_PRETTY)); | |
5417 | json_object_free(json); | |
5418 | } | |
9aa741ea MK |
5419 | } |
5420 | ||
9f049418 | 5421 | void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json) |
b7cfce93 | 5422 | { |
d7c0a89a | 5423 | uint32_t num_nh; |
2dbad57f | 5424 | struct nh_walk_ctx wctx; |
b7cfce93 | 5425 | json_object *json = NULL; |
b7cfce93 MK |
5426 | zebra_l3vni_t *zl3vni = NULL; |
5427 | ||
5428 | if (!is_evpn_enabled()) | |
5429 | return; | |
5430 | ||
5431 | zl3vni = zl3vni_lookup(l3vni); | |
5432 | if (!zl3vni) { | |
5433 | if (use_json) | |
5434 | vty_out(vty, "{}\n"); | |
5435 | else | |
5436 | vty_out(vty, "%% L3-VNI %u does not exist\n", l3vni); | |
5437 | return; | |
5438 | } | |
5439 | ||
5440 | num_nh = hashcount(zl3vni->nh_table); | |
5441 | if (!num_nh) | |
5442 | return; | |
5443 | ||
9187f600 | 5444 | if (use_json) |
b7cfce93 | 5445 | json = json_object_new_object(); |
b7cfce93 | 5446 | |
2dbad57f | 5447 | wctx.vty = vty; |
9187f600 | 5448 | wctx.json = json; |
b7cfce93 | 5449 | if (!use_json) { |
996c9314 | 5450 | vty_out(vty, "Number of NH Neighbors known for this VNI: %u\n", |
b7cfce93 | 5451 | num_nh); |
4cce389e | 5452 | vty_out(vty, "%-15s %-17s\n", "IP", "RMAC"); |
b7cfce93 | 5453 | } else |
4cce389e | 5454 | json_object_int_add(json, "numNextHops", num_nh); |
b7cfce93 MK |
5455 | |
5456 | hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx); | |
5457 | ||
5458 | if (use_json) { | |
b7cfce93 MK |
5459 | vty_out(vty, "%s\n", json_object_to_json_string_ext( |
5460 | json, JSON_C_TO_STRING_PRETTY)); | |
5461 | json_object_free(json); | |
5462 | } | |
5463 | } | |
5464 | ||
9f049418 | 5465 | void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json) |
b7cfce93 | 5466 | { |
2dbad57f | 5467 | json_object *json = NULL; |
32798965 | 5468 | void *args[2]; |
2dbad57f | 5469 | |
5470 | if (!is_evpn_enabled()) { | |
5471 | if (use_json) | |
5472 | vty_out(vty, "{}\n"); | |
5473 | return; | |
5474 | } | |
5475 | ||
2dbad57f | 5476 | if (use_json) |
5477 | json = json_object_new_object(); | |
5478 | ||
32798965 MK |
5479 | args[0] = vty; |
5480 | args[1] = json; | |
89272910 | 5481 | hash_iterate(zrouter.l3vni_table, |
32798965 MK |
5482 | (void (*)(struct hash_backet *, |
5483 | void *))zl3vni_print_nh_hash_all_vni, | |
5484 | args); | |
2dbad57f | 5485 | |
5486 | if (use_json) { | |
5487 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5488 | json, JSON_C_TO_STRING_PRETTY)); | |
5489 | json_object_free(json); | |
5490 | } | |
b7cfce93 MK |
5491 | } |
5492 | ||
5493 | /* | |
5494 | * Display L3 VNI information (VTY command handler). | |
5495 | */ | |
9f049418 | 5496 | void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json) |
b7cfce93 MK |
5497 | { |
5498 | void *args[2]; | |
5499 | json_object *json = NULL; | |
5500 | zebra_l3vni_t *zl3vni = NULL; | |
5501 | ||
b2ee5a13 MK |
5502 | if (!is_evpn_enabled()) { |
5503 | if (use_json) | |
5504 | vty_out(vty, "{}\n"); | |
b7cfce93 | 5505 | return; |
b2ee5a13 | 5506 | } |
b7cfce93 MK |
5507 | |
5508 | zl3vni = zl3vni_lookup(vni); | |
5509 | if (!zl3vni) { | |
5510 | if (use_json) | |
5511 | vty_out(vty, "{}\n"); | |
5512 | else | |
5513 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
5514 | return; | |
5515 | } | |
5516 | ||
5517 | if (use_json) | |
5518 | json = json_object_new_object(); | |
5519 | ||
b2ee5a13 MK |
5520 | args[0] = vty; |
5521 | args[1] = json; | |
b7cfce93 MK |
5522 | zl3vni_print(zl3vni, (void *)args); |
5523 | ||
5524 | if (use_json) { | |
5525 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5526 | json, JSON_C_TO_STRING_PRETTY)); | |
5527 | json_object_free(json); | |
5528 | } | |
5529 | } | |
5530 | ||
4cce389e MK |
5531 | void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf, |
5532 | json_object *json_vrfs) | |
b7cfce93 | 5533 | { |
4cce389e MK |
5534 | char buf[ETHER_ADDR_STRLEN]; |
5535 | zebra_l3vni_t *zl3vni = NULL; | |
b7cfce93 | 5536 | |
4cce389e MK |
5537 | zl3vni = zl3vni_lookup(zvrf->l3vni); |
5538 | if (!zl3vni) | |
b7cfce93 | 5539 | return; |
b7cfce93 | 5540 | |
4cce389e MK |
5541 | if (!json_vrfs) { |
5542 | vty_out(vty, "%-37s %-10u %-20s %-20s %-5s %-18s\n", | |
996c9314 | 5543 | zvrf_name(zvrf), zl3vni->vni, |
4cce389e | 5544 | zl3vni_vxlan_if_name(zl3vni), |
996c9314 | 5545 | zl3vni_svi_if_name(zl3vni), zl3vni_state2str(zl3vni), |
4cce389e | 5546 | zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); |
b7cfce93 | 5547 | } else { |
4cce389e | 5548 | json_object *json_vrf = NULL; |
9df2b997 | 5549 | |
4cce389e | 5550 | json_vrf = json_object_new_object(); |
996c9314 | 5551 | json_object_string_add(json_vrf, "vrf", zvrf_name(zvrf)); |
4cce389e MK |
5552 | json_object_int_add(json_vrf, "vni", zl3vni->vni); |
5553 | json_object_string_add(json_vrf, "vxlanIntf", | |
5554 | zl3vni_vxlan_if_name(zl3vni)); | |
5555 | json_object_string_add(json_vrf, "sviIntf", | |
5556 | zl3vni_svi_if_name(zl3vni)); | |
5557 | json_object_string_add(json_vrf, "state", | |
5558 | zl3vni_state2str(zl3vni)); | |
996c9314 LB |
5559 | json_object_string_add( |
5560 | json_vrf, "routerMac", | |
5561 | zl3vni_rmac2str(zl3vni, buf, sizeof(buf))); | |
4cce389e | 5562 | json_object_array_add(json_vrfs, json_vrf); |
b7cfce93 MK |
5563 | } |
5564 | } | |
5565 | ||
5566 | /* | |
5567 | * Display Neighbors for a VNI (VTY command handler). | |
5568 | */ | |
5569 | void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, | |
9f049418 | 5570 | vni_t vni, bool use_json) |
b7cfce93 MK |
5571 | { |
5572 | zebra_vni_t *zvni; | |
d7c0a89a | 5573 | uint32_t num_neigh; |
b7cfce93 MK |
5574 | struct neigh_walk_ctx wctx; |
5575 | json_object *json = NULL; | |
5576 | ||
5577 | if (!is_evpn_enabled()) | |
5578 | return; | |
5579 | zvni = zvni_lookup(vni); | |
5580 | if (!zvni) { | |
5581 | if (use_json) | |
5582 | vty_out(vty, "{}\n"); | |
5583 | else | |
5584 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
5585 | return; | |
5586 | } | |
5587 | num_neigh = hashcount(zvni->neigh_table); | |
5588 | if (!num_neigh) | |
5589 | return; | |
5590 | ||
5591 | if (use_json) | |
5592 | json = json_object_new_object(); | |
5593 | ||
5594 | /* Since we have IPv6 addresses to deal with which can vary widely in | |
5595 | * size, we try to be a bit more elegant in display by first computing | |
5596 | * the maximum width. | |
5597 | */ | |
5598 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); | |
5599 | wctx.zvni = zvni; | |
5600 | wctx.vty = vty; | |
5601 | wctx.addr_width = 15; | |
5602 | wctx.json = json; | |
5603 | hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); | |
5604 | ||
5605 | if (!use_json) { | |
5606 | vty_out(vty, | |
5607 | "Number of ARPs (local and remote) known for this VNI: %u\n", | |
5608 | num_neigh); | |
1a8c5c38 | 5609 | vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n", |
5610 | -wctx.addr_width, "IP", "Type", | |
5611 | "State", "MAC", "Remote VTEP"); | |
b7cfce93 MK |
5612 | } else |
5613 | json_object_int_add(json, "numArpNd", num_neigh); | |
5614 | ||
5615 | hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); | |
5616 | if (use_json) { | |
5617 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5618 | json, JSON_C_TO_STRING_PRETTY)); | |
5619 | json_object_free(json); | |
5620 | } | |
5621 | } | |
5622 | ||
5623 | /* | |
5624 | * Display neighbors across all VNIs (VTY command handler). | |
5625 | */ | |
5626 | void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, | |
1374d4db | 5627 | bool print_dup, bool use_json) |
b7cfce93 MK |
5628 | { |
5629 | json_object *json = NULL; | |
1374d4db | 5630 | void *args[3]; |
b7cfce93 MK |
5631 | |
5632 | if (!is_evpn_enabled()) | |
5633 | return; | |
5634 | ||
5635 | if (use_json) | |
5636 | json = json_object_new_object(); | |
5637 | ||
5638 | args[0] = vty; | |
5639 | args[1] = json; | |
1374d4db CS |
5640 | args[2] = (void *)(ptrdiff_t)print_dup; |
5641 | ||
b7cfce93 MK |
5642 | hash_iterate(zvrf->vni_table, |
5643 | (void (*)(struct hash_backet *, | |
5644 | void *))zvni_print_neigh_hash_all_vni, | |
5645 | args); | |
5646 | if (use_json) { | |
5647 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5648 | json, JSON_C_TO_STRING_PRETTY)); | |
5649 | json_object_free(json); | |
5650 | } | |
5651 | } | |
5652 | ||
5653 | /* | |
5654 | * Display specific neighbor for a VNI, if present (VTY command handler). | |
5655 | */ | |
5656 | void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, | |
5657 | struct zebra_vrf *zvrf, vni_t vni, | |
9f049418 | 5658 | struct ipaddr *ip, bool use_json) |
b7cfce93 MK |
5659 | { |
5660 | zebra_vni_t *zvni; | |
5661 | zebra_neigh_t *n; | |
5662 | json_object *json = NULL; | |
5663 | ||
5664 | if (!is_evpn_enabled()) | |
5665 | return; | |
5666 | zvni = zvni_lookup(vni); | |
5667 | if (!zvni) { | |
5668 | if (use_json) | |
cd233079 CS |
5669 | vty_out(vty, "{}\n"); |
5670 | else | |
5671 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 5672 | return; |
5673 | } | |
5674 | n = zvni_neigh_lookup(zvni, ip); | |
5675 | if (!n) { | |
cd233079 CS |
5676 | if (!use_json) |
5677 | vty_out(vty, | |
5678 | "%% Requested neighbor does not exist in VNI %u\n", | |
5679 | vni); | |
d62a17ae | 5680 | return; |
5681 | } | |
cd233079 CS |
5682 | if (use_json) |
5683 | json = json_object_new_object(); | |
5684 | ||
5685 | zvni_print_neigh(n, vty, json); | |
cec2e17d | 5686 | |
cd233079 CS |
5687 | if (use_json) { |
5688 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5689 | json, JSON_C_TO_STRING_PRETTY)); | |
5690 | json_object_free(json); | |
5691 | } | |
cec2e17d | 5692 | } |
5693 | ||
5694 | /* | |
5695 | * Display neighbors for a VNI from specific VTEP (VTY command handler). | |
5696 | * By definition, these are remote neighbors. | |
5697 | */ | |
d62a17ae | 5698 | void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, |
cd233079 | 5699 | vni_t vni, struct in_addr vtep_ip, |
9f049418 | 5700 | bool use_json) |
cec2e17d | 5701 | { |
d62a17ae | 5702 | zebra_vni_t *zvni; |
d7c0a89a | 5703 | uint32_t num_neigh; |
d62a17ae | 5704 | struct neigh_walk_ctx wctx; |
cd233079 | 5705 | json_object *json = NULL; |
cec2e17d | 5706 | |
2853fed6 | 5707 | if (!is_evpn_enabled()) |
d62a17ae | 5708 | return; |
2853fed6 | 5709 | zvni = zvni_lookup(vni); |
d62a17ae | 5710 | if (!zvni) { |
cd233079 CS |
5711 | if (use_json) |
5712 | vty_out(vty, "{}\n"); | |
5713 | else | |
5714 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 5715 | return; |
5716 | } | |
5717 | num_neigh = hashcount(zvni->neigh_table); | |
5718 | if (!num_neigh) | |
5719 | return; | |
cec2e17d | 5720 | |
d62a17ae | 5721 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); |
5722 | wctx.zvni = zvni; | |
5723 | wctx.vty = vty; | |
68e33151 | 5724 | wctx.addr_width = 15; |
d62a17ae | 5725 | wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP; |
5726 | wctx.r_vtep_ip = vtep_ip; | |
cd233079 | 5727 | wctx.json = json; |
68e33151 | 5728 | hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); |
d62a17ae | 5729 | hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); |
cd233079 CS |
5730 | |
5731 | if (use_json) { | |
5732 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5733 | json, JSON_C_TO_STRING_PRETTY)); | |
5734 | json_object_free(json); | |
5735 | } | |
cec2e17d | 5736 | } |
5737 | ||
1374d4db CS |
5738 | /* |
5739 | * Display Duplicate detected Neighbors for a VNI | |
5740 | * (VTY command handler). | |
5741 | */ | |
5742 | void zebra_vxlan_print_neigh_vni_dad(struct vty *vty, | |
5743 | struct zebra_vrf *zvrf, | |
5744 | vni_t vni, | |
5745 | bool use_json) | |
5746 | { | |
5747 | zebra_vni_t *zvni; | |
5748 | uint32_t num_neigh; | |
5749 | struct neigh_walk_ctx wctx; | |
5750 | json_object *json = NULL; | |
5751 | ||
5752 | if (!is_evpn_enabled()) | |
5753 | return; | |
5754 | ||
5755 | zvni = zvni_lookup(vni); | |
5756 | if (!zvni) { | |
5757 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
5758 | return; | |
5759 | } | |
5760 | ||
5761 | num_neigh = hashcount(zvni->neigh_table); | |
5762 | if (!num_neigh) | |
5763 | return; | |
5764 | ||
5765 | num_neigh = num_dup_detected_neighs(zvni); | |
5766 | if (!num_neigh) | |
5767 | return; | |
5768 | ||
5769 | if (use_json) | |
5770 | json = json_object_new_object(); | |
5771 | ||
5772 | /* Since we have IPv6 addresses to deal with which can vary widely in | |
5773 | * size, we try to be a bit more elegant in display by first computing | |
5774 | * the maximum width. | |
5775 | */ | |
5776 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); | |
5777 | wctx.zvni = zvni; | |
5778 | wctx.vty = vty; | |
5779 | wctx.addr_width = 15; | |
5780 | wctx.json = json; | |
5781 | hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); | |
5782 | ||
5783 | if (!use_json) { | |
5784 | vty_out(vty, | |
5785 | "Number of ARPs (local and remote) known for this VNI: %u\n", | |
5786 | num_neigh); | |
5787 | vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n", | |
5788 | -wctx.addr_width, "IP", "Type", | |
5789 | "State", "MAC", "Remote VTEP"); | |
5790 | } else | |
5791 | json_object_int_add(json, "numArpNd", num_neigh); | |
5792 | ||
5793 | hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash, &wctx); | |
5794 | ||
5795 | if (use_json) { | |
5796 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5797 | json, JSON_C_TO_STRING_PRETTY)); | |
5798 | json_object_free(json); | |
5799 | } | |
5800 | } | |
5801 | ||
cec2e17d | 5802 | /* |
5803 | * Display MACs for a VNI (VTY command handler). | |
5804 | */ | |
d62a17ae | 5805 | void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, |
9f049418 | 5806 | vni_t vni, bool use_json) |
cec2e17d | 5807 | { |
d62a17ae | 5808 | zebra_vni_t *zvni; |
d7c0a89a | 5809 | uint32_t num_macs; |
d62a17ae | 5810 | struct mac_walk_ctx wctx; |
cd233079 CS |
5811 | json_object *json = NULL; |
5812 | json_object *json_mac = NULL; | |
cec2e17d | 5813 | |
2853fed6 | 5814 | if (!is_evpn_enabled()) |
d62a17ae | 5815 | return; |
2853fed6 | 5816 | zvni = zvni_lookup(vni); |
d62a17ae | 5817 | if (!zvni) { |
cd233079 CS |
5818 | if (use_json) |
5819 | vty_out(vty, "{}\n"); | |
5820 | else | |
5821 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 5822 | return; |
5823 | } | |
790f8dc5 | 5824 | num_macs = num_valid_macs(zvni); |
d62a17ae | 5825 | if (!num_macs) |
5826 | return; | |
cec2e17d | 5827 | |
cd233079 CS |
5828 | if (use_json) { |
5829 | json = json_object_new_object(); | |
5830 | json_mac = json_object_new_object(); | |
5831 | } | |
5832 | ||
d62a17ae | 5833 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
5834 | wctx.zvni = zvni; | |
5835 | wctx.vty = vty; | |
cd233079 | 5836 | wctx.json = json_mac; |
cec2e17d | 5837 | |
cd233079 CS |
5838 | if (!use_json) { |
5839 | vty_out(vty, | |
5840 | "Number of MACs (local and remote) known for this VNI: %u\n", | |
5841 | num_macs); | |
5842 | vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", | |
5843 | "Intf/Remote VTEP", "VLAN"); | |
5844 | } else | |
5845 | json_object_int_add(json, "numMacs", num_macs); | |
cec2e17d | 5846 | |
d62a17ae | 5847 | hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx); |
cd233079 CS |
5848 | |
5849 | if (use_json) { | |
5850 | json_object_object_add(json, "macs", json_mac); | |
5851 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5852 | json, JSON_C_TO_STRING_PRETTY)); | |
5853 | json_object_free(json); | |
5854 | } | |
cec2e17d | 5855 | } |
5856 | ||
5857 | /* | |
5858 | * Display MACs for all VNIs (VTY command handler). | |
5859 | */ | |
cd233079 | 5860 | void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf, |
1374d4db | 5861 | bool print_dup, bool use_json) |
cec2e17d | 5862 | { |
d62a17ae | 5863 | struct mac_walk_ctx wctx; |
cd233079 | 5864 | json_object *json = NULL; |
cec2e17d | 5865 | |
2853fed6 | 5866 | if (!is_evpn_enabled()) { |
cd233079 CS |
5867 | if (use_json) |
5868 | vty_out(vty, "{}\n"); | |
d62a17ae | 5869 | return; |
cd233079 CS |
5870 | } |
5871 | if (use_json) | |
5872 | json = json_object_new_object(); | |
5873 | ||
d62a17ae | 5874 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
5875 | wctx.vty = vty; | |
cd233079 | 5876 | wctx.json = json; |
1374d4db | 5877 | wctx.print_dup = print_dup; |
d62a17ae | 5878 | hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx); |
cd233079 CS |
5879 | |
5880 | if (use_json) { | |
5881 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5882 | json, JSON_C_TO_STRING_PRETTY)); | |
5883 | json_object_free(json); | |
5884 | } | |
cec2e17d | 5885 | } |
5886 | ||
5887 | /* | |
5888 | * Display MACs for all VNIs (VTY command handler). | |
5889 | */ | |
d62a17ae | 5890 | void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty, |
5891 | struct zebra_vrf *zvrf, | |
9f049418 | 5892 | struct in_addr vtep_ip, bool use_json) |
cec2e17d | 5893 | { |
d62a17ae | 5894 | struct mac_walk_ctx wctx; |
cd233079 | 5895 | json_object *json = NULL; |
cec2e17d | 5896 | |
2853fed6 | 5897 | if (!is_evpn_enabled()) |
d62a17ae | 5898 | return; |
cd233079 CS |
5899 | |
5900 | if (use_json) | |
5901 | json = json_object_new_object(); | |
5902 | ||
d62a17ae | 5903 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
5904 | wctx.vty = vty; | |
5905 | wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; | |
5906 | wctx.r_vtep_ip = vtep_ip; | |
cd233079 | 5907 | wctx.json = json; |
d62a17ae | 5908 | hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx); |
cd233079 CS |
5909 | |
5910 | if (use_json) { | |
5911 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
5912 | json, JSON_C_TO_STRING_PRETTY)); | |
5913 | json_object_free(json); | |
5914 | } | |
cec2e17d | 5915 | } |
5916 | ||
5917 | /* | |
5918 | * Display specific MAC for a VNI, if present (VTY command handler). | |
5919 | */ | |
d62a17ae | 5920 | void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf, |
24cdbd0d DS |
5921 | vni_t vni, struct ethaddr *macaddr, |
5922 | bool use_json) | |
cec2e17d | 5923 | { |
d62a17ae | 5924 | zebra_vni_t *zvni; |
5925 | zebra_mac_t *mac; | |
24cdbd0d | 5926 | json_object *json = NULL; |
cec2e17d | 5927 | |
2853fed6 | 5928 | if (!is_evpn_enabled()) |
d62a17ae | 5929 | return; |
24cdbd0d | 5930 | |
2853fed6 | 5931 | zvni = zvni_lookup(vni); |
d62a17ae | 5932 | if (!zvni) { |
24cdbd0d DS |
5933 | if (use_json) |
5934 | vty_out(vty, "{}\n"); | |
5935 | else | |
5936 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 5937 | return; |
5938 | } | |
5939 | mac = zvni_mac_lookup(zvni, macaddr); | |
5940 | if (!mac) { | |
24cdbd0d DS |
5941 | if (use_json) |
5942 | vty_out(vty, "{}\n"); | |
5943 | else | |
5944 | vty_out(vty, | |
5945 | "%% Requested MAC does not exist in VNI %u\n", | |
5946 | vni); | |
d62a17ae | 5947 | return; |
5948 | } | |
cec2e17d | 5949 | |
24cdbd0d DS |
5950 | if (use_json) |
5951 | json = json_object_new_object(); | |
5952 | ||
5953 | zvni_print_mac(mac, vty, json); | |
cec2e17d | 5954 | } |
5955 | ||
1374d4db CS |
5956 | /* Print Duplicate MACs per VNI */ |
5957 | void zebra_vxlan_print_macs_vni_dad(struct vty *vty, | |
5958 | struct zebra_vrf *zvrf, | |
5959 | vni_t vni, bool use_json) | |
5960 | { | |
5961 | zebra_vni_t *zvni; | |
5962 | struct mac_walk_ctx wctx; | |
5963 | uint32_t num_macs; | |
5964 | json_object *json = NULL; | |
5965 | json_object *json_mac = NULL; | |
5966 | ||
5967 | if (!is_evpn_enabled()) | |
5968 | return; | |
5969 | ||
5970 | zvni = zvni_lookup(vni); | |
5971 | if (!zvni) { | |
5972 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
5973 | return; | |
5974 | } | |
5975 | ||
5976 | num_macs = num_valid_macs(zvni); | |
5977 | if (!num_macs) | |
5978 | return; | |
5979 | ||
5980 | num_macs = num_dup_detected_macs(zvni); | |
5981 | if (!num_macs) | |
5982 | return; | |
5983 | ||
5984 | if (use_json) { | |
5985 | json = json_object_new_object(); | |
5986 | json_mac = json_object_new_object(); | |
5987 | } | |
5988 | ||
5989 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); | |
5990 | wctx.zvni = zvni; | |
5991 | wctx.vty = vty; | |
5992 | wctx.json = json_mac; | |
5993 | ||
5994 | if (!use_json) { | |
5995 | vty_out(vty, | |
5996 | "Number of MACs (local and remote) known for this VNI: %u\n", | |
5997 | num_macs); | |
5998 | vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", | |
5999 | "Intf/Remote VTEP", "VLAN"); | |
6000 | } else | |
6001 | json_object_int_add(json, "numMacs", num_macs); | |
6002 | ||
6003 | hash_iterate(zvni->mac_table, zvni_print_dad_mac_hash, &wctx); | |
6004 | ||
6005 | if (use_json) { | |
6006 | json_object_object_add(json, "macs", json_mac); | |
6007 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
6008 | json, JSON_C_TO_STRING_PRETTY)); | |
6009 | json_object_free(json); | |
6010 | } | |
6011 | ||
6012 | } | |
6013 | ||
cec2e17d | 6014 | /* |
6015 | * Display MACs for a VNI from specific VTEP (VTY command handler). | |
6016 | */ | |
d62a17ae | 6017 | void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, |
cd233079 | 6018 | vni_t vni, struct in_addr vtep_ip, |
9f049418 | 6019 | bool use_json) |
cec2e17d | 6020 | { |
d62a17ae | 6021 | zebra_vni_t *zvni; |
d7c0a89a | 6022 | uint32_t num_macs; |
d62a17ae | 6023 | struct mac_walk_ctx wctx; |
cd233079 CS |
6024 | json_object *json = NULL; |
6025 | json_object *json_mac = NULL; | |
cec2e17d | 6026 | |
2853fed6 | 6027 | if (!is_evpn_enabled()) |
d62a17ae | 6028 | return; |
2853fed6 | 6029 | zvni = zvni_lookup(vni); |
d62a17ae | 6030 | if (!zvni) { |
cd233079 CS |
6031 | if (use_json) |
6032 | vty_out(vty, "{}\n"); | |
6033 | else | |
6034 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
d62a17ae | 6035 | return; |
6036 | } | |
790f8dc5 | 6037 | num_macs = num_valid_macs(zvni); |
d62a17ae | 6038 | if (!num_macs) |
6039 | return; | |
cd233079 CS |
6040 | |
6041 | if (use_json) { | |
6042 | json = json_object_new_object(); | |
6043 | json_mac = json_object_new_object(); | |
6044 | } | |
6045 | ||
d62a17ae | 6046 | memset(&wctx, 0, sizeof(struct mac_walk_ctx)); |
6047 | wctx.zvni = zvni; | |
6048 | wctx.vty = vty; | |
6049 | wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; | |
6050 | wctx.r_vtep_ip = vtep_ip; | |
cd233079 | 6051 | wctx.json = json_mac; |
d62a17ae | 6052 | hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx); |
cd233079 CS |
6053 | |
6054 | if (use_json) { | |
6055 | json_object_int_add(json, "numMacs", wctx.count); | |
6056 | if (wctx.count) | |
6057 | json_object_object_add(json, "macs", json_mac); | |
6058 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
6059 | json, JSON_C_TO_STRING_PRETTY)); | |
6060 | json_object_free(json); | |
6061 | } | |
cec2e17d | 6062 | } |
6063 | ||
6064 | ||
6065 | /* | |
6066 | * Display VNI information (VTY command handler). | |
6067 | */ | |
cd233079 | 6068 | void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, |
9f049418 | 6069 | bool use_json) |
cec2e17d | 6070 | { |
cd233079 CS |
6071 | json_object *json = NULL; |
6072 | void *args[2]; | |
1f2129ec | 6073 | zebra_l3vni_t *zl3vni = NULL; |
6074 | zebra_vni_t *zvni = NULL; | |
cec2e17d | 6075 | |
2853fed6 | 6076 | if (!is_evpn_enabled()) |
d62a17ae | 6077 | return; |
4cce389e | 6078 | |
cd233079 CS |
6079 | if (use_json) |
6080 | json = json_object_new_object(); | |
6081 | args[0] = vty; | |
6082 | args[1] = json; | |
4cce389e | 6083 | |
1f2129ec | 6084 | zl3vni = zl3vni_lookup(vni); |
6085 | if (zl3vni) { | |
4cce389e MK |
6086 | zl3vni_print(zl3vni, (void *)args); |
6087 | } else { | |
4cce389e MK |
6088 | zvni = zvni_lookup(vni); |
6089 | if (!zvni) { | |
6090 | if (use_json) | |
6091 | vty_out(vty, "{}\n"); | |
6092 | else | |
6093 | vty_out(vty, "%% VNI %u does not exist\n", vni); | |
6094 | return; | |
6095 | } | |
6096 | ||
6097 | zvni_print(zvni, (void *)args); | |
6098 | } | |
6099 | ||
cd233079 CS |
6100 | if (use_json) { |
6101 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
6102 | json, JSON_C_TO_STRING_PRETTY)); | |
6103 | json_object_free(json); | |
6104 | } | |
cec2e17d | 6105 | } |
6106 | ||
4cce389e | 6107 | /* Display all global details for EVPN */ |
088f1098 | 6108 | void zebra_vxlan_print_evpn(struct vty *vty, bool uj) |
cec2e17d | 6109 | { |
4cce389e MK |
6110 | int num_l2vnis = 0; |
6111 | int num_l3vnis = 0; | |
d4454626 | 6112 | int num_vnis = 0; |
cd233079 | 6113 | json_object *json = NULL; |
4cce389e | 6114 | struct zebra_vrf *zvrf = NULL; |
cec2e17d | 6115 | |
2853fed6 | 6116 | if (!is_evpn_enabled()) |
d62a17ae | 6117 | return; |
4cce389e | 6118 | |
4cce389e MK |
6119 | zvrf = vrf_info_lookup(VRF_DEFAULT); |
6120 | if (!zvrf) | |
6121 | return; | |
6122 | ||
89272910 | 6123 | num_l3vnis = hashcount(zrouter.l3vni_table); |
4cce389e | 6124 | num_l2vnis = hashcount(zvrf->vni_table); |
d4454626 | 6125 | num_vnis = num_l2vnis + num_l3vnis; |
4cce389e MK |
6126 | |
6127 | if (uj) { | |
cd233079 | 6128 | json = json_object_new_object(); |
ddd16ed5 MK |
6129 | json_object_string_add(json, "advertiseGatewayMacip", |
6130 | zvrf->advertise_gw_macip ? "Yes" : "No"); | |
d4454626 | 6131 | json_object_int_add(json, "numVnis", num_vnis); |
4cce389e MK |
6132 | json_object_int_add(json, "numL2Vnis", num_l2vnis); |
6133 | json_object_int_add(json, "numL3Vnis", num_l3vnis); | |
cd233079 | 6134 | } else { |
4cce389e MK |
6135 | vty_out(vty, "L2 VNIs: %u\n", num_l2vnis); |
6136 | vty_out(vty, "L3 VNIs: %u\n", num_l3vnis); | |
ddd16ed5 MK |
6137 | vty_out(vty, "Advertise gateway mac-ip: %s\n", |
6138 | zvrf->advertise_gw_macip ? "Yes" : "No"); | |
cd233079 | 6139 | } |
4cce389e MK |
6140 | |
6141 | if (uj) { | |
6142 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
6143 | json, JSON_C_TO_STRING_PRETTY)); | |
6144 | json_object_free(json); | |
6145 | } | |
6146 | } | |
6147 | ||
6148 | /* | |
6149 | * Display VNI hash table (VTY command handler). | |
6150 | */ | |
6151 | void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, | |
9f049418 | 6152 | bool use_json) |
4cce389e MK |
6153 | { |
6154 | json_object *json = NULL; | |
4cce389e MK |
6155 | void *args[2]; |
6156 | ||
6157 | if (!is_evpn_enabled()) | |
6158 | return; | |
6159 | ||
4cce389e MK |
6160 | if (use_json) |
6161 | json = json_object_new_object(); | |
6162 | else | |
996c9314 LB |
6163 | vty_out(vty, "%-10s %-4s %-21s %-8s %-8s %-15s %-37s\n", "VNI", |
6164 | "Type", "VxLAN IF", "# MACs", "# ARPs", | |
6165 | "# Remote VTEPs", "Tenant VRF"); | |
4cce389e | 6166 | |
cd233079 CS |
6167 | args[0] = vty; |
6168 | args[1] = json; | |
6169 | ||
4cce389e | 6170 | /* Display all L2-VNIs */ |
cd233079 CS |
6171 | hash_iterate(zvrf->vni_table, |
6172 | (void (*)(struct hash_backet *, void *))zvni_print_hash, | |
6173 | args); | |
6174 | ||
4cce389e | 6175 | /* Display all L3-VNIs */ |
89272910 | 6176 | hash_iterate(zrouter.l3vni_table, |
4cce389e MK |
6177 | (void (*)(struct hash_backet *, void *))zl3vni_print_hash, |
6178 | args); | |
6179 | ||
cd233079 CS |
6180 | if (use_json) { |
6181 | vty_out(vty, "%s\n", json_object_to_json_string_ext( | |
6182 | json, JSON_C_TO_STRING_PRETTY)); | |
6183 | json_object_free(json); | |
6184 | } | |
cec2e17d | 6185 | } |
6186 | ||
3950b52c CS |
6187 | void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS) |
6188 | { | |
6189 | struct stream *s; | |
6190 | int time = 0; | |
6191 | uint32_t max_moves = 0; | |
6192 | uint32_t freeze_time = 0; | |
6193 | bool dup_addr_detect = false; | |
6194 | bool freeze = false; | |
6195 | ||
6196 | s = msg; | |
6197 | STREAM_GETL(s, dup_addr_detect); | |
6198 | STREAM_GETL(s, time); | |
6199 | STREAM_GETL(s, max_moves); | |
6200 | STREAM_GETL(s, freeze); | |
6201 | STREAM_GETL(s, freeze_time); | |
6202 | ||
6203 | zvrf->dup_addr_detect = dup_addr_detect; | |
6204 | zvrf->dad_time = time; | |
6205 | zvrf->dad_max_moves = max_moves; | |
6206 | zvrf->dad_freeze = freeze; | |
6207 | zvrf->dad_freeze_time = freeze_time; | |
6208 | ||
6209 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6210 | zlog_debug( | |
6211 | "%s: duplicate detect %s max_moves %u timeout %u freeze %s freeze_time %u", | |
6212 | __PRETTY_FUNCTION__, | |
6213 | zvrf->dup_addr_detect ? "enable" : "disable", | |
6214 | zvrf->dad_max_moves, | |
6215 | zvrf->dad_time, | |
6216 | zvrf->dad_freeze ? "enable" : "disable", | |
6217 | zvrf->dad_freeze_time); | |
6218 | ||
6219 | stream_failure: | |
6220 | return; | |
6221 | } | |
6222 | ||
2232a77c | 6223 | /* |
ee69da27 MK |
6224 | * Handle neighbor delete notification from the kernel (on a VLAN device |
6225 | * / L3 interface). This may result in either the neighbor getting deleted | |
6226 | * from our database or being re-added to the kernel (if it is a valid | |
2232a77c | 6227 | * remote neighbor). |
6228 | */ | |
ee69da27 MK |
6229 | int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, |
6230 | struct interface *link_if, | |
6231 | struct ipaddr *ip) | |
d62a17ae | 6232 | { |
d62a17ae | 6233 | char buf[INET6_ADDRSTRLEN]; |
b6938a74 | 6234 | char buf2[ETHER_ADDR_STRLEN]; |
b7cfce93 MK |
6235 | zebra_neigh_t *n = NULL; |
6236 | zebra_vni_t *zvni = NULL; | |
6237 | zebra_mac_t *zmac = NULL; | |
8c9b80b9 | 6238 | zebra_l3vni_t *zl3vni = NULL; |
b7cfce93 | 6239 | |
8c9b80b9 | 6240 | /* check if this is a remote neigh entry corresponding to remote |
523cafc4 | 6241 | * next-hop |
6242 | */ | |
8c9b80b9 MK |
6243 | zl3vni = zl3vni_from_svi(ifp, link_if); |
6244 | if (zl3vni) | |
6245 | return zl3vni_local_nh_del(zl3vni, ip); | |
d62a17ae | 6246 | |
6247 | /* We are only interested in neighbors on an SVI that resides on top | |
6248 | * of a VxLAN bridge. | |
6249 | */ | |
b7cfce93 | 6250 | zvni = zvni_from_svi(ifp, link_if); |
d62a17ae | 6251 | if (!zvni) |
6252 | return 0; | |
8c9b80b9 | 6253 | |
d62a17ae | 6254 | if (!zvni->vxlan_if) { |
9df414fe | 6255 | zlog_debug( |
d62a17ae | 6256 | "VNI %u hash %p doesn't have intf upon local neighbor DEL", |
6257 | zvni->vni, zvni); | |
6258 | return -1; | |
6259 | } | |
6260 | ||
6261 | if (IS_ZEBRA_DEBUG_VXLAN) | |
8c9b80b9 | 6262 | zlog_debug("Del neighbor %s intf %s(%u) -> L2-VNI %u", |
996c9314 LB |
6263 | ipaddr2str(ip, buf, sizeof(buf)), ifp->name, |
6264 | ifp->ifindex, zvni->vni); | |
d62a17ae | 6265 | |
6266 | /* If entry doesn't exist, nothing to do. */ | |
6267 | n = zvni_neigh_lookup(zvni, ip); | |
6268 | if (!n) | |
6269 | return 0; | |
6270 | ||
b6938a74 MK |
6271 | zmac = zvni_mac_lookup(zvni, &n->emac); |
6272 | if (!zmac) { | |
6273 | if (IS_ZEBRA_DEBUG_VXLAN) | |
9df414fe | 6274 | zlog_debug( |
2853fed6 | 6275 | "Trying to del a neigh %s without a mac %s on VNI %u", |
6276 | ipaddr2str(ip, buf, sizeof(buf)), | |
b6938a74 MK |
6277 | prefix_mac2str(&n->emac, buf2, sizeof(buf2)), |
6278 | zvni->vni); | |
6279 | ||
6280 | return 0; | |
6281 | } | |
6282 | ||
d62a17ae | 6283 | /* If it is a remote entry, the kernel has aged this out or someone has |
6284 | * deleted it, it needs to be re-installed as Quagga is the owner. | |
6285 | */ | |
6286 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
6287 | zvni_neigh_install(zvni, n); | |
6288 | return 0; | |
6289 | } | |
6290 | ||
d62a17ae | 6291 | /* Remove neighbor from BGP. */ |
b6938a74 | 6292 | if (IS_ZEBRA_NEIGH_ACTIVE(n)) |
996c9314 | 6293 | zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0); |
d62a17ae | 6294 | |
6295 | /* Delete this neighbor entry. */ | |
6296 | zvni_neigh_del(zvni, n); | |
6297 | ||
b6938a74 MK |
6298 | /* see if the AUTO mac needs to be deleted */ |
6299 | if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO) | |
f51d8a27 | 6300 | && !listcount(zmac->neigh_list)) |
b6938a74 MK |
6301 | zvni_mac_del(zvni, zmac); |
6302 | ||
d62a17ae | 6303 | return 0; |
2232a77c | 6304 | } |
6305 | ||
6306 | /* | |
ee69da27 MK |
6307 | * Handle neighbor add or update notification from the kernel (on a VLAN |
6308 | * device / L3 interface). This is typically for a local neighbor but can | |
6309 | * also be for a remote neighbor (e.g., ageout notification). It could | |
6310 | * also be a "move" scenario. | |
2232a77c | 6311 | */ |
ee69da27 MK |
6312 | int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, |
6313 | struct interface *link_if, | |
6314 | struct ipaddr *ip, | |
6315 | struct ethaddr *macaddr, | |
6316 | uint16_t state, | |
a37f4598 | 6317 | bool is_ext, |
6318 | bool is_router) | |
d62a17ae | 6319 | { |
d62a17ae | 6320 | char buf[ETHER_ADDR_STRLEN]; |
6321 | char buf2[INET6_ADDRSTRLEN]; | |
b7cfce93 | 6322 | zebra_vni_t *zvni = NULL; |
3bcbba10 | 6323 | zebra_l3vni_t *zl3vni = NULL; |
6324 | ||
6325 | /* check if this is a remote neigh entry corresponding to remote | |
6326 | * next-hop | |
6327 | */ | |
6328 | zl3vni = zl3vni_from_svi(ifp, link_if); | |
6329 | if (zl3vni) | |
6330 | return zl3vni_local_nh_add_update(zl3vni, ip, state); | |
b7cfce93 | 6331 | |
d62a17ae | 6332 | /* We are only interested in neighbors on an SVI that resides on top |
6333 | * of a VxLAN bridge. | |
6334 | */ | |
b7cfce93 | 6335 | zvni = zvni_from_svi(ifp, link_if); |
d62a17ae | 6336 | if (!zvni) |
6337 | return 0; | |
6338 | ||
d62a17ae | 6339 | if (IS_ZEBRA_DEBUG_VXLAN) |
6340 | zlog_debug( | |
54c17425 | 6341 | "Add/Update neighbor %s MAC %s intf %s(%u) state 0x%x %s %s-> L2-VNI %u", |
2853fed6 | 6342 | ipaddr2str(ip, buf2, sizeof(buf2)), |
d62a17ae | 6343 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, |
a37f4598 | 6344 | ifp->ifindex, state, is_ext ? "ext-learned " : "", |
6345 | is_router ? "router " : "", | |
8c9b80b9 | 6346 | zvni->vni); |
d62a17ae | 6347 | |
ee69da27 | 6348 | /* Is this about a local neighbor or a remote one? */ |
a37f4598 | 6349 | if (!is_ext) |
68e33151 | 6350 | return zvni_local_neigh_update(zvni, ifp, ip, macaddr, |
a37f4598 | 6351 | is_router); |
b7cfce93 | 6352 | |
ee69da27 | 6353 | return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state); |
2232a77c | 6354 | } |
6355 | ||
b682f6de | 6356 | |
2232a77c | 6357 | /* |
6358 | * Handle message from client to delete a remote MACIP for a VNI. | |
6359 | */ | |
89f4e507 | 6360 | void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS) |
d62a17ae | 6361 | { |
6362 | struct stream *s; | |
6363 | vni_t vni; | |
6364 | struct ethaddr macaddr; | |
6365 | struct ipaddr ip; | |
6366 | struct in_addr vtep_ip; | |
9df2b997 | 6367 | uint16_t l = 0, ipa_len; |
d62a17ae | 6368 | char buf[ETHER_ADDR_STRLEN]; |
6369 | char buf1[INET6_ADDRSTRLEN]; | |
6370 | ||
b7cfce93 | 6371 | memset(&macaddr, 0, sizeof(struct ethaddr)); |
b7cfce93 MK |
6372 | memset(&ip, 0, sizeof(struct ipaddr)); |
6373 | memset(&vtep_ip, 0, sizeof(struct in_addr)); | |
6374 | ||
1002497a | 6375 | s = msg; |
d62a17ae | 6376 | |
89f4e507 | 6377 | while (l < hdr->length) { |
d62a17ae | 6378 | /* Obtain each remote MACIP and process. */ |
6379 | /* Message contains VNI, followed by MAC followed by IP (if any) | |
6380 | * followed by remote VTEP IP. | |
6381 | */ | |
d62a17ae | 6382 | memset(&ip, 0, sizeof(ip)); |
ec93aa12 DS |
6383 | STREAM_GETL(s, vni); |
6384 | STREAM_GET(&macaddr.octet, s, ETH_ALEN); | |
6385 | STREAM_GETL(s, ipa_len); | |
d62a17ae | 6386 | if (ipa_len) { |
6387 | ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 | |
6388 | : IPADDR_V6; | |
ec93aa12 | 6389 | STREAM_GET(&ip.ip.addr, s, ipa_len); |
d62a17ae | 6390 | } |
ff8b7eb8 | 6391 | l += 4 + ETH_ALEN + 4 + ipa_len; |
ec93aa12 | 6392 | STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); |
d62a17ae | 6393 | l += IPV4_MAX_BYTELEN; |
6394 | ||
6395 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6396 | zlog_debug( | |
f07e1c99 | 6397 | "Recv MACIP DEL VNI %u MAC %s%s%s Remote VTEP %s from %s", |
6398 | vni, | |
d62a17ae | 6399 | prefix_mac2str(&macaddr, buf, sizeof(buf)), |
f07e1c99 | 6400 | ipa_len ? " IP " : "", |
6401 | ipa_len ? | |
6402 | ipaddr2str(&ip, buf1, sizeof(buf1)) : "", | |
d62a17ae | 6403 | inet_ntoa(vtep_ip), |
6404 | zebra_route_string(client->proto)); | |
6405 | ||
f07e1c99 | 6406 | process_remote_macip_del(vni, &macaddr, ipa_len, &ip, vtep_ip); |
d62a17ae | 6407 | } |
6408 | ||
ec93aa12 | 6409 | stream_failure: |
8068a649 | 6410 | return; |
2232a77c | 6411 | } |
6412 | ||
6413 | /* | |
6414 | * Handle message from client to add a remote MACIP for a VNI. This | |
6415 | * could be just the add of a MAC address or the add of a neighbor | |
6416 | * (IP+MAC). | |
6417 | */ | |
89f4e507 | 6418 | void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) |
d62a17ae | 6419 | { |
6420 | struct stream *s; | |
6421 | vni_t vni; | |
6422 | struct ethaddr macaddr; | |
6423 | struct ipaddr ip; | |
6424 | struct in_addr vtep_ip; | |
9df2b997 | 6425 | uint16_t l = 0, ipa_len; |
f07e1c99 | 6426 | uint8_t flags = 0; |
6427 | uint32_t seq; | |
d62a17ae | 6428 | char buf[ETHER_ADDR_STRLEN]; |
6429 | char buf1[INET6_ADDRSTRLEN]; | |
d62a17ae | 6430 | |
b7cfce93 | 6431 | memset(&macaddr, 0, sizeof(struct ethaddr)); |
b7cfce93 MK |
6432 | memset(&ip, 0, sizeof(struct ipaddr)); |
6433 | memset(&vtep_ip, 0, sizeof(struct in_addr)); | |
6434 | ||
ec93aa12 | 6435 | if (!EVPN_ENABLED(zvrf)) { |
9df414fe | 6436 | zlog_debug("EVPN not enabled, ignoring remote MACIP ADD"); |
8068a649 | 6437 | return; |
ec93aa12 | 6438 | } |
d62a17ae | 6439 | |
1002497a | 6440 | s = msg; |
d62a17ae | 6441 | |
89f4e507 | 6442 | while (l < hdr->length) { |
d62a17ae | 6443 | /* Obtain each remote MACIP and process. */ |
6444 | /* Message contains VNI, followed by MAC followed by IP (if any) | |
6445 | * followed by remote VTEP IP. | |
6446 | */ | |
d62a17ae | 6447 | memset(&ip, 0, sizeof(ip)); |
ec93aa12 DS |
6448 | STREAM_GETL(s, vni); |
6449 | STREAM_GET(&macaddr.octet, s, ETH_ALEN); | |
6450 | STREAM_GETL(s, ipa_len); | |
d62a17ae | 6451 | if (ipa_len) { |
6452 | ip.ipa_type = (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 | |
6453 | : IPADDR_V6; | |
ec93aa12 | 6454 | STREAM_GET(&ip.ip.addr, s, ipa_len); |
d62a17ae | 6455 | } |
ff8b7eb8 | 6456 | l += 4 + ETH_ALEN + 4 + ipa_len; |
ec93aa12 | 6457 | STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); |
d62a17ae | 6458 | l += IPV4_MAX_BYTELEN; |
6459 | ||
ead40654 | 6460 | /* Get flags - sticky mac and/or gateway mac */ |
2017b3ea | 6461 | STREAM_GETC(s, flags); |
d62a17ae | 6462 | l++; |
f07e1c99 | 6463 | STREAM_GETL(s, seq); |
6464 | l += 4; | |
d62a17ae | 6465 | |
6466 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6467 | zlog_debug( | |
f07e1c99 | 6468 | "Recv MACIP ADD VNI %u MAC %s%s%s flags 0x%x seq %u VTEP %s from %s", |
6469 | vni, | |
d62a17ae | 6470 | prefix_mac2str(&macaddr, buf, sizeof(buf)), |
f07e1c99 | 6471 | ipa_len ? " IP " : "", |
6472 | ipa_len ? | |
6473 | ipaddr2str(&ip, buf1, sizeof(buf1)) : "", | |
6474 | flags, seq, inet_ntoa(vtep_ip), | |
d62a17ae | 6475 | zebra_route_string(client->proto)); |
6476 | ||
f07e1c99 | 6477 | process_remote_macip_add(vni, &macaddr, ipa_len, &ip, |
6478 | flags, seq, vtep_ip); | |
d62a17ae | 6479 | } |
6480 | ||
ec93aa12 | 6481 | stream_failure: |
8068a649 | 6482 | return; |
13d60d35 | 6483 | } |
6484 | ||
6485 | /* | |
2232a77c | 6486 | * Handle notification of MAC add/update over VxLAN. If the kernel is notifying |
6487 | * us, this must involve a multihoming scenario. Treat this as implicit delete | |
6488 | * of any prior local MAC. | |
13d60d35 | 6489 | */ |
d62a17ae | 6490 | int zebra_vxlan_check_del_local_mac(struct interface *ifp, |
6491 | struct interface *br_if, | |
6492 | struct ethaddr *macaddr, vlanid_t vid) | |
13d60d35 | 6493 | { |
d62a17ae | 6494 | struct zebra_if *zif; |
d62a17ae | 6495 | struct zebra_l2info_vxlan *vxl; |
6496 | vni_t vni; | |
6497 | zebra_vni_t *zvni; | |
6498 | zebra_mac_t *mac; | |
6499 | char buf[ETHER_ADDR_STRLEN]; | |
13d60d35 | 6500 | |
d62a17ae | 6501 | zif = ifp->info; |
6502 | assert(zif); | |
6503 | vxl = &zif->l2info.vxl; | |
6504 | vni = vxl->vni; | |
13d60d35 | 6505 | |
2853fed6 | 6506 | /* Check if EVPN is enabled. */ |
6507 | if (!is_evpn_enabled()) | |
d62a17ae | 6508 | return 0; |
13d60d35 | 6509 | |
d62a17ae | 6510 | /* Locate hash entry; it is expected to exist. */ |
2853fed6 | 6511 | zvni = zvni_lookup(vni); |
d62a17ae | 6512 | if (!zvni) |
6513 | return 0; | |
13d60d35 | 6514 | |
d62a17ae | 6515 | /* If entry doesn't exist, nothing to do. */ |
6516 | mac = zvni_mac_lookup(zvni, macaddr); | |
6517 | if (!mac) | |
6518 | return 0; | |
13d60d35 | 6519 | |
d62a17ae | 6520 | /* Is it a local entry? */ |
6521 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) | |
6522 | return 0; | |
13d60d35 | 6523 | |
d62a17ae | 6524 | if (IS_ZEBRA_DEBUG_VXLAN) |
6525 | zlog_debug( | |
2853fed6 | 6526 | "Add/update remote MAC %s intf %s(%u) VNI %u - del local", |
996c9314 LB |
6527 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, |
6528 | ifp->ifindex, vni); | |
13d60d35 | 6529 | |
d62a17ae | 6530 | /* Remove MAC from BGP. */ |
e98e4b88 | 6531 | zvni_mac_send_del_to_client(zvni->vni, macaddr); |
13d60d35 | 6532 | |
b6938a74 MK |
6533 | /* |
6534 | * If there are no neigh associated with the mac delete the mac | |
6535 | * else mark it as AUTO for forward reference | |
6536 | */ | |
6537 | if (!listcount(mac->neigh_list)) { | |
6538 | zvni_mac_del(zvni, mac); | |
6539 | } else { | |
6540 | UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); | |
6541 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
6542 | } | |
13d60d35 | 6543 | |
d62a17ae | 6544 | return 0; |
13d60d35 | 6545 | } |
6546 | ||
6547 | /* | |
2232a77c | 6548 | * Handle remote MAC delete by kernel; readd the remote MAC if we have it. |
6549 | * This can happen because the remote MAC entries are also added as "dynamic", | |
6550 | * so the kernel can ageout the entry. | |
13d60d35 | 6551 | */ |
d62a17ae | 6552 | int zebra_vxlan_check_readd_remote_mac(struct interface *ifp, |
6553 | struct interface *br_if, | |
6554 | struct ethaddr *macaddr, vlanid_t vid) | |
13d60d35 | 6555 | { |
a9a76262 MK |
6556 | struct zebra_if *zif = NULL; |
6557 | struct zebra_l2info_vxlan *vxl = NULL; | |
d62a17ae | 6558 | vni_t vni; |
a9a76262 MK |
6559 | zebra_vni_t *zvni = NULL; |
6560 | zebra_l3vni_t *zl3vni = NULL; | |
6561 | zebra_mac_t *mac = NULL; | |
d62a17ae | 6562 | char buf[ETHER_ADDR_STRLEN]; |
2232a77c | 6563 | |
d62a17ae | 6564 | zif = ifp->info; |
6565 | assert(zif); | |
6566 | vxl = &zif->l2info.vxl; | |
6567 | vni = vxl->vni; | |
2232a77c | 6568 | |
2853fed6 | 6569 | /* Check if EVPN is enabled. */ |
6570 | if (!is_evpn_enabled()) | |
d62a17ae | 6571 | return 0; |
2232a77c | 6572 | |
a9a76262 MK |
6573 | /* check if this is a remote RMAC and readd simillar to remote macs */ |
6574 | zl3vni = zl3vni_lookup(vni); | |
6575 | if (zl3vni) | |
6576 | return zebra_vxlan_readd_remote_rmac(zl3vni, macaddr); | |
6577 | ||
d62a17ae | 6578 | /* Locate hash entry; it is expected to exist. */ |
2853fed6 | 6579 | zvni = zvni_lookup(vni); |
d62a17ae | 6580 | if (!zvni) |
6581 | return 0; | |
13d60d35 | 6582 | |
d62a17ae | 6583 | /* If entry doesn't exist, nothing to do. */ |
6584 | mac = zvni_mac_lookup(zvni, macaddr); | |
6585 | if (!mac) | |
6586 | return 0; | |
2232a77c | 6587 | |
d62a17ae | 6588 | /* Is it a remote entry? */ |
6589 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) | |
6590 | return 0; | |
2232a77c | 6591 | |
d62a17ae | 6592 | if (IS_ZEBRA_DEBUG_VXLAN) |
2853fed6 | 6593 | zlog_debug("Del remote MAC %s intf %s(%u) VNI %u - readd", |
d62a17ae | 6594 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, |
6595 | ifp->ifindex, vni); | |
13d60d35 | 6596 | |
d62a17ae | 6597 | zvni_mac_install(zvni, mac); |
6598 | return 0; | |
13d60d35 | 6599 | } |
6600 | ||
6601 | /* | |
2232a77c | 6602 | * Handle local MAC delete (on a port or VLAN corresponding to this VNI). |
13d60d35 | 6603 | */ |
d62a17ae | 6604 | int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, |
6605 | struct ethaddr *macaddr, vlanid_t vid) | |
13d60d35 | 6606 | { |
d62a17ae | 6607 | zebra_vni_t *zvni; |
6608 | zebra_mac_t *mac; | |
d62a17ae | 6609 | char buf[ETHER_ADDR_STRLEN]; |
13d60d35 | 6610 | |
d62a17ae | 6611 | /* We are interested in MACs only on ports or (port, VLAN) that |
6612 | * map to a VNI. | |
6613 | */ | |
6614 | zvni = zvni_map_vlan(ifp, br_if, vid); | |
6615 | if (!zvni) | |
6616 | return 0; | |
6617 | if (!zvni->vxlan_if) { | |
9df414fe QY |
6618 | zlog_debug( |
6619 | "VNI %u hash %p doesn't have intf upon local MAC DEL", | |
6620 | zvni->vni, zvni); | |
d62a17ae | 6621 | return -1; |
6622 | } | |
13d60d35 | 6623 | |
d62a17ae | 6624 | if (IS_ZEBRA_DEBUG_VXLAN) |
f07e1c99 | 6625 | zlog_debug("DEL MAC %s intf %s(%u) VID %u -> VNI %u", |
d62a17ae | 6626 | prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name, |
6627 | ifp->ifindex, vid, zvni->vni); | |
2232a77c | 6628 | |
d62a17ae | 6629 | /* If entry doesn't exist, nothing to do. */ |
6630 | mac = zvni_mac_lookup(zvni, macaddr); | |
6631 | if (!mac) | |
6632 | return 0; | |
2232a77c | 6633 | |
d62a17ae | 6634 | /* Is it a local entry? */ |
6635 | if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) | |
6636 | return 0; | |
2232a77c | 6637 | |
b6938a74 | 6638 | /* Update all the neigh entries associated with this mac */ |
2853fed6 | 6639 | zvni_process_neigh_on_local_mac_del(zvni, mac); |
b6938a74 | 6640 | |
f07e1c99 | 6641 | /* Remove MAC from BGP. */ |
e98e4b88 | 6642 | zvni_mac_send_del_to_client(zvni->vni, macaddr); |
f07e1c99 | 6643 | |
b6938a74 MK |
6644 | /* |
6645 | * If there are no neigh associated with the mac delete the mac | |
6646 | * else mark it as AUTO for forward reference | |
6647 | */ | |
6648 | if (!listcount(mac->neigh_list)) { | |
6649 | zvni_mac_del(zvni, mac); | |
6650 | } else { | |
6651 | UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); | |
6652 | SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
6653 | } | |
2232a77c | 6654 | |
d62a17ae | 6655 | return 0; |
13d60d35 | 6656 | } |
6657 | ||
6658 | /* | |
2232a77c | 6659 | * Handle local MAC add (on a port or VLAN corresponding to this VNI). |
13d60d35 | 6660 | */ |
d62a17ae | 6661 | int zebra_vxlan_local_mac_add_update(struct interface *ifp, |
6662 | struct interface *br_if, | |
6663 | struct ethaddr *macaddr, vlanid_t vid, | |
a37f4598 | 6664 | bool sticky) |
d62a17ae | 6665 | { |
6666 | zebra_vni_t *zvni; | |
6667 | zebra_mac_t *mac; | |
e22a946a | 6668 | struct zebra_vrf *zvrf; |
d62a17ae | 6669 | char buf[ETHER_ADDR_STRLEN]; |
f07e1c99 | 6670 | bool mac_sticky = false; |
6671 | bool inform_client = false; | |
6672 | bool upd_neigh = false; | |
e22a946a CS |
6673 | zebra_neigh_t *n = NULL; |
6674 | struct listnode *node = NULL; | |
6675 | struct in_addr vtep_ip = {.s_addr = 0}; | |
6676 | struct timeval elapsed = {0, 0}; | |
6677 | char buf2[INET6_ADDRSTRLEN]; | |
d62a17ae | 6678 | |
6679 | /* We are interested in MACs only on ports or (port, VLAN) that | |
6680 | * map to a VNI. | |
6681 | */ | |
6682 | zvni = zvni_map_vlan(ifp, br_if, vid); | |
6683 | if (!zvni) { | |
6684 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6685 | zlog_debug( | |
2853fed6 | 6686 | "Add/Update %sMAC %s intf %s(%u) VID %u, could not find VNI", |
6687 | sticky ? "sticky " : "", | |
d62a17ae | 6688 | prefix_mac2str(macaddr, buf, sizeof(buf)), |
6689 | ifp->name, ifp->ifindex, vid); | |
6690 | return 0; | |
6691 | } | |
6692 | ||
6693 | if (!zvni->vxlan_if) { | |
9df414fe QY |
6694 | zlog_debug( |
6695 | "VNI %u hash %p doesn't have intf upon local MAC ADD", | |
6696 | zvni->vni, zvni); | |
d62a17ae | 6697 | return -1; |
6698 | } | |
6699 | ||
e22a946a CS |
6700 | zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); |
6701 | if (!zvrf) | |
6702 | return -1; | |
6703 | ||
f07e1c99 | 6704 | /* Check if we need to create or update or it is a NO-OP. */ |
d62a17ae | 6705 | mac = zvni_mac_lookup(zvni, macaddr); |
f07e1c99 | 6706 | if (!mac) { |
6707 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6708 | zlog_debug( | |
6709 | "ADD %sMAC %s intf %s(%u) VID %u -> VNI %u", | |
6710 | sticky ? "sticky " : "", | |
6711 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
6712 | ifp->name, ifp->ifindex, vid, zvni->vni); | |
d62a17ae | 6713 | |
f07e1c99 | 6714 | mac = zvni_mac_add(zvni, macaddr); |
6715 | if (!mac) { | |
6716 | flog_err( | |
e914ccbe | 6717 | EC_ZEBRA_MAC_ADD_FAILED, |
f07e1c99 | 6718 | "Failed to add MAC %s intf %s(%u) VID %u VNI %u", |
6719 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
6720 | ifp->name, ifp->ifindex, vid, zvni->vni); | |
6721 | return -1; | |
6722 | } | |
6723 | SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); | |
6724 | mac->fwd_info.local.ifindex = ifp->ifindex; | |
6725 | mac->fwd_info.local.vid = vid; | |
6726 | if (sticky) | |
6727 | SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
6728 | inform_client = true; | |
6729 | ||
6730 | } else { | |
6731 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6732 | zlog_debug( | |
6733 | "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u curFlags 0x%x", | |
6734 | sticky ? "sticky " : "", | |
6735 | prefix_mac2str(macaddr, buf, sizeof(buf)), | |
6736 | ifp->name, ifp->ifindex, vid, zvni->vni, | |
6737 | mac->flags); | |
6738 | ||
6739 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
6740 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) | |
6741 | mac_sticky = true; | |
b6938a74 | 6742 | |
b8ce75a5 | 6743 | /* |
f07e1c99 | 6744 | * Update any changes and if changes are relevant to |
6745 | * BGP, note it. | |
b8ce75a5 | 6746 | */ |
d62a17ae | 6747 | if (mac_sticky == sticky |
6748 | && mac->fwd_info.local.ifindex == ifp->ifindex | |
6749 | && mac->fwd_info.local.vid == vid) { | |
6750 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6751 | zlog_debug( | |
2853fed6 | 6752 | "Add/Update %sMAC %s intf %s(%u) VID %u -> VNI %u, " |
d62a17ae | 6753 | "entry exists and has not changed ", |
d62a17ae | 6754 | sticky ? "sticky " : "", |
6755 | prefix_mac2str(macaddr, buf, | |
6756 | sizeof(buf)), | |
6757 | ifp->name, ifp->ifindex, vid, | |
6758 | zvni->vni); | |
6759 | return 0; | |
b6938a74 | 6760 | } |
f07e1c99 | 6761 | if (mac_sticky != sticky) { |
6762 | if (sticky) | |
6763 | SET_FLAG(mac->flags, | |
6764 | ZEBRA_MAC_STICKY); | |
6765 | else | |
6766 | UNSET_FLAG(mac->flags, | |
6767 | ZEBRA_MAC_STICKY); | |
6768 | inform_client = true; | |
6769 | } | |
6770 | ||
6771 | memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); | |
6772 | mac->fwd_info.local.ifindex = ifp->ifindex; | |
6773 | mac->fwd_info.local.vid = vid; | |
6774 | ||
6775 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) || | |
6776 | CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { | |
e22a946a | 6777 | bool do_dad = false; |
f07e1c99 | 6778 | |
421bb26a | 6779 | /* |
f07e1c99 | 6780 | * MAC has either moved or was "internally" created due |
6781 | * to a neighbor learn and is now actually learnt. If | |
6782 | * it was learnt as a remote sticky MAC, this is an | |
6783 | * operator error. | |
421bb26a | 6784 | */ |
8f4b98ee | 6785 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) { |
9df414fe | 6786 | flog_warn( |
e914ccbe | 6787 | EC_ZEBRA_STICKY_MAC_ALREADY_LEARNT, |
9df414fe | 6788 | "MAC %s already learnt as remote sticky MAC behind VTEP %s VNI %u", |
421bb26a MK |
6789 | prefix_mac2str(macaddr, buf, |
6790 | sizeof(buf)), | |
6791 | inet_ntoa(mac->fwd_info.r_vtep_ip), | |
6792 | zvni->vni); | |
8f4b98ee MK |
6793 | return 0; |
6794 | } | |
d62a17ae | 6795 | |
f07e1c99 | 6796 | /* If an actual move, compute MAC's seq number */ |
e22a946a | 6797 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { |
f07e1c99 | 6798 | mac->loc_seq = MAX(mac->rem_seq + 1, |
6799 | mac->loc_seq); | |
e22a946a CS |
6800 | vtep_ip = mac->fwd_info.r_vtep_ip; |
6801 | /* Trigger DAD for remote MAC */ | |
6802 | do_dad = true; | |
6803 | } | |
6804 | ||
f07e1c99 | 6805 | UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); |
6806 | UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); | |
6807 | SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); | |
6808 | memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); | |
6809 | mac->fwd_info.local.ifindex = ifp->ifindex; | |
6810 | mac->fwd_info.local.vid = vid; | |
6811 | if (sticky) | |
6812 | SET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
6813 | else | |
6814 | UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); | |
6815 | /* | |
6816 | * We have to inform BGP of this MAC as well as process | |
6817 | * all neighbors. | |
6818 | */ | |
6819 | inform_client = true; | |
6820 | upd_neigh = true; | |
e22a946a CS |
6821 | |
6822 | if (zvrf->dup_addr_detect && do_dad) { | |
6823 | /* MAC is detected as duplicate, hold on | |
6824 | * advertising to BGP. | |
6825 | */ | |
6826 | if (CHECK_FLAG(mac->flags, | |
6827 | ZEBRA_MAC_DUPLICATE)) { | |
6828 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6829 | zlog_debug( | |
6830 | "%s: duplicate addr MAC %s skip update to client, learn count %u recover time %u", | |
6831 | __PRETTY_FUNCTION__, | |
6832 | prefix_mac2str(macaddr, | |
6833 | buf, sizeof(buf)), | |
6834 | mac->dad_count, | |
6835 | zvrf->dad_freeze_time); | |
6836 | /* For duplicate MAC do not update | |
6837 | * client but update neigh due to | |
6838 | * this MAC update. | |
6839 | */ | |
6840 | if (zvrf->dad_freeze) | |
6841 | inform_client = false; | |
6842 | ||
6843 | goto send_notif; | |
6844 | } | |
6845 | ||
6846 | /* Check if detection time (M-secs) expired. | |
6847 | * Reset learn count and detection start time. | |
6848 | */ | |
6849 | monotime_since(&mac->detect_start_time, | |
6850 | &elapsed); | |
6851 | if (mac->dad_count == 0 || | |
6852 | elapsed.tv_sec >= zvrf->dad_time) { | |
6853 | ||
6854 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6855 | zlog_debug("%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u", | |
6856 | __PRETTY_FUNCTION__, | |
6857 | prefix_mac2str( | |
6858 | macaddr, buf, | |
6859 | sizeof(buf)), | |
6860 | mac->flags, | |
6861 | mac->dad_count); | |
6862 | ||
6863 | mac->dad_count = 0; | |
6864 | /* Capture start dup. detection time */ | |
6865 | monotime(&mac->detect_start_time); | |
6866 | } | |
6867 | ||
6868 | /* Increment move count */ | |
6869 | mac->dad_count++; | |
6870 | ||
6871 | if (mac->dad_count >= zvrf->dad_max_moves) { | |
6872 | flog_warn(EC_ZEBRA_DUP_MAC_DETECTED, | |
6873 | "VNI %u: MAC %s detected as duplicate during local update, last VTEP %s", | |
6874 | zvni->vni, | |
6875 | prefix_mac2str(&mac->macaddr, | |
6876 | buf, sizeof(buf)), | |
6877 | inet_ntoa(vtep_ip)); | |
6878 | ||
6879 | SET_FLAG(mac->flags, | |
6880 | ZEBRA_MAC_DUPLICATE); | |
6881 | ||
6882 | /* Capture Duplicate detection time */ | |
6883 | mac->dad_dup_detect_time = | |
6884 | monotime(NULL); | |
6885 | ||
6886 | /* Mark all IPs/Neighs as duplicate | |
6887 | * associcated with this MAC | |
6888 | */ | |
6889 | for (ALL_LIST_ELEMENTS_RO( | |
6890 | mac->neigh_list, | |
6891 | node, n)) { | |
6892 | ||
6893 | /* Ony Mark IPs which are Local | |
6894 | */ | |
6895 | if (!CHECK_FLAG(n->flags, | |
6896 | ZEBRA_NEIGH_LOCAL)) | |
6897 | continue; | |
6898 | ||
6899 | SET_FLAG(n->flags, | |
6900 | ZEBRA_NEIGH_DUPLICATE); | |
6901 | ||
6902 | n->dad_dup_detect_time = | |
6903 | monotime(NULL); | |
6904 | ||
6905 | flog_warn( | |
6906 | EC_ZEBRA_DUP_IP_INHERIT_DETECTED | |
6907 | , | |
6908 | "VNI %u: MAC %s IP %s detected as duplicate during local update, inherit duplicate from MAC", | |
6909 | zvni->vni, | |
6910 | prefix_mac2str(&mac->macaddr, | |
6911 | buf, sizeof(buf)), | |
6912 | ipaddr2str(&n->ip, buf2, | |
6913 | sizeof(buf2))); | |
6914 | } | |
6915 | ||
c80a972c CS |
6916 | /* Start auto recovery timer for this |
6917 | * MAC | |
6918 | */ | |
6919 | THREAD_OFF( | |
6920 | mac->dad_mac_auto_recovery_timer); | |
6921 | if (zvrf->dad_freeze && | |
6922 | zvrf->dad_freeze_time) { | |
6923 | if (IS_ZEBRA_DEBUG_VXLAN) | |
6924 | zlog_debug("%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start", | |
6925 | __PRETTY_FUNCTION__, | |
6926 | prefix_mac2str( | |
6927 | &mac->macaddr, | |
6928 | buf, | |
6929 | sizeof(buf)), | |
6930 | mac->flags, | |
6931 | zvrf->dad_freeze_time); | |
6932 | ||
6933 | thread_add_timer(zebrad.master, | |
6934 | zebra_vxlan_dad_mac_auto_recovery_exp, | |
6935 | mac, | |
6936 | zvrf->dad_freeze_time, | |
6937 | &mac-> | |
6938 | dad_mac_auto_recovery_timer); | |
6939 | } | |
6940 | ||
e22a946a CS |
6941 | /* Do not inform to client (BGPd), |
6942 | * upd_neigh for neigh sequence change. | |
6943 | */ | |
6944 | if (zvrf->dad_freeze) | |
6945 | inform_client = false; | |
6946 | } | |
6947 | } | |
d62a17ae | 6948 | } |
6949 | } | |
6950 | ||
e22a946a CS |
6951 | send_notif: |
6952 | ||
d62a17ae | 6953 | /* Inform BGP if required. */ |
f07e1c99 | 6954 | if (inform_client) { |
6955 | if (zvni_mac_send_add_to_client(zvni->vni, macaddr, | |
6956 | mac->flags, mac->loc_seq)) | |
6957 | return -1; | |
b6938a74 | 6958 | } |
d62a17ae | 6959 | |
f07e1c99 | 6960 | /* Process all neighbors associated with this MAC, if required. */ |
6961 | if (upd_neigh) | |
6962 | zvni_process_neigh_on_local_mac_change(zvni, mac, 0); | |
6963 | ||
d62a17ae | 6964 | return 0; |
2232a77c | 6965 | } |
13d60d35 | 6966 | |
6967 | /* | |
6968 | * Handle message from client to delete a remote VTEP for a VNI. | |
6969 | */ | |
89f4e507 | 6970 | void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS) |
d62a17ae | 6971 | { |
6972 | struct stream *s; | |
d7c0a89a | 6973 | unsigned short l = 0; |
d62a17ae | 6974 | vni_t vni; |
6975 | struct in_addr vtep_ip; | |
6976 | zebra_vni_t *zvni; | |
6977 | zebra_vtep_t *zvtep; | |
b5ebdc9b | 6978 | struct interface *ifp; |
6979 | struct zebra_if *zif; | |
d62a17ae | 6980 | |
ec93aa12 | 6981 | if (!is_evpn_enabled()) { |
9df414fe | 6982 | zlog_debug( |
996c9314 LB |
6983 | "%s: EVPN is not enabled yet we have received a vtep del command", |
6984 | __PRETTY_FUNCTION__); | |
8068a649 | 6985 | return; |
ec93aa12 DS |
6986 | } |
6987 | ||
2853fed6 | 6988 | if (zvrf_id(zvrf) != VRF_DEFAULT) { |
9df414fe QY |
6989 | zlog_debug("Recv MACIP DEL for non-default VRF %u", |
6990 | zvrf_id(zvrf)); | |
8068a649 | 6991 | return; |
2853fed6 | 6992 | } |
6993 | ||
1002497a | 6994 | s = msg; |
d62a17ae | 6995 | |
89f4e507 | 6996 | while (l < hdr->length) { |
d62a17ae | 6997 | /* Obtain each remote VTEP and process. */ |
ec93aa12 | 6998 | STREAM_GETL(s, vni); |
d62a17ae | 6999 | l += 4; |
ec93aa12 | 7000 | STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); |
d62a17ae | 7001 | l += IPV4_MAX_BYTELEN; |
7002 | ||
7003 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2853fed6 | 7004 | zlog_debug("Recv VTEP_DEL %s VNI %u from %s", |
7005 | inet_ntoa(vtep_ip), vni, | |
d62a17ae | 7006 | zebra_route_string(client->proto)); |
7007 | ||
7008 | /* Locate VNI hash entry - expected to exist. */ | |
2853fed6 | 7009 | zvni = zvni_lookup(vni); |
d62a17ae | 7010 | if (!zvni) { |
7011 | if (IS_ZEBRA_DEBUG_VXLAN) | |
7012 | zlog_debug( | |
7013 | "Failed to locate VNI hash upon remote VTEP DEL, " | |
2853fed6 | 7014 | "VNI %u", |
7015 | vni); | |
d62a17ae | 7016 | continue; |
7017 | } | |
7018 | ||
b5ebdc9b | 7019 | ifp = zvni->vxlan_if; |
7020 | if (!ifp) { | |
9df414fe | 7021 | zlog_debug( |
60466a63 QY |
7022 | "VNI %u hash %p doesn't have intf upon remote VTEP DEL", |
7023 | zvni->vni, zvni); | |
b682f6de | 7024 | continue; |
b5ebdc9b | 7025 | } |
7026 | zif = ifp->info; | |
7027 | ||
7028 | /* If down or not mapped to a bridge, we're done. */ | |
b682f6de | 7029 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
b5ebdc9b | 7030 | continue; |
7031 | ||
d62a17ae | 7032 | /* If the remote VTEP does not exist, there's nothing more to |
7033 | * do. | |
7034 | * Otherwise, uninstall any remote MACs pointing to this VTEP | |
7035 | * and | |
7036 | * then, the VTEP entry itself and remove it. | |
7037 | */ | |
7038 | zvtep = zvni_vtep_find(zvni, &vtep_ip); | |
7039 | if (!zvtep) | |
7040 | continue; | |
7041 | ||
7042 | zvni_neigh_del_from_vtep(zvni, 1, &vtep_ip); | |
7043 | zvni_mac_del_from_vtep(zvni, 1, &vtep_ip); | |
7044 | zvni_vtep_uninstall(zvni, &vtep_ip); | |
7045 | zvni_vtep_del(zvni, zvtep); | |
7046 | } | |
7047 | ||
ec93aa12 | 7048 | stream_failure: |
8068a649 | 7049 | return; |
13d60d35 | 7050 | } |
7051 | ||
7052 | /* | |
7053 | * Handle message from client to add a remote VTEP for a VNI. | |
7054 | */ | |
89f4e507 | 7055 | void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS) |
d62a17ae | 7056 | { |
7057 | struct stream *s; | |
d7c0a89a | 7058 | unsigned short l = 0; |
d62a17ae | 7059 | vni_t vni; |
7060 | struct in_addr vtep_ip; | |
7061 | zebra_vni_t *zvni; | |
b5ebdc9b | 7062 | struct interface *ifp; |
7063 | struct zebra_if *zif; | |
d62a17ae | 7064 | |
ec93aa12 | 7065 | if (!is_evpn_enabled()) { |
9df414fe | 7066 | zlog_debug( |
996c9314 LB |
7067 | "%s: EVPN not enabled yet we received a vtep_add zapi call", |
7068 | __PRETTY_FUNCTION__); | |
8068a649 | 7069 | return; |
ec93aa12 DS |
7070 | } |
7071 | ||
2853fed6 | 7072 | if (zvrf_id(zvrf) != VRF_DEFAULT) { |
9df414fe QY |
7073 | zlog_debug("Recv MACIP ADD for non-default VRF %u", |
7074 | zvrf_id(zvrf)); | |
8068a649 | 7075 | return; |
2853fed6 | 7076 | } |
d62a17ae | 7077 | |
1002497a | 7078 | s = msg; |
d62a17ae | 7079 | |
89f4e507 | 7080 | while (l < hdr->length) { |
d62a17ae | 7081 | /* Obtain each remote VTEP and process. */ |
ec93aa12 | 7082 | STREAM_GETL(s, vni); |
d62a17ae | 7083 | l += 4; |
ec93aa12 | 7084 | STREAM_GET(&vtep_ip.s_addr, s, IPV4_MAX_BYTELEN); |
d62a17ae | 7085 | l += IPV4_MAX_BYTELEN; |
7086 | ||
7087 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2853fed6 | 7088 | zlog_debug("Recv VTEP_ADD %s VNI %u from %s", |
7089 | inet_ntoa(vtep_ip), vni, | |
d62a17ae | 7090 | zebra_route_string(client->proto)); |
7091 | ||
7092 | /* Locate VNI hash entry - expected to exist. */ | |
2853fed6 | 7093 | zvni = zvni_lookup(vni); |
d62a17ae | 7094 | if (!zvni) { |
af4c2728 | 7095 | flog_err( |
e914ccbe | 7096 | EC_ZEBRA_VTEP_ADD_FAILED, |
2853fed6 | 7097 | "Failed to locate VNI hash upon remote VTEP ADD, VNI %u", |
7098 | vni); | |
d62a17ae | 7099 | continue; |
7100 | } | |
b5ebdc9b | 7101 | |
7102 | ifp = zvni->vxlan_if; | |
7103 | if (!ifp) { | |
af4c2728 | 7104 | flog_err( |
e914ccbe | 7105 | EC_ZEBRA_VTEP_ADD_FAILED, |
d62a17ae | 7106 | "VNI %u hash %p doesn't have intf upon remote VTEP ADD", |
7107 | zvni->vni, zvni); | |
7108 | continue; | |
7109 | } | |
7110 | ||
b5ebdc9b | 7111 | zif = ifp->info; |
d62a17ae | 7112 | |
b5ebdc9b | 7113 | /* If down or not mapped to a bridge, we're done. */ |
b682f6de | 7114 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
d62a17ae | 7115 | continue; |
7116 | ||
b682f6de | 7117 | /* If the remote VTEP already exists, |
7118 | there's nothing more to do. */ | |
b5ebdc9b | 7119 | if (zvni_vtep_find(zvni, &vtep_ip)) |
d62a17ae | 7120 | continue; |
7121 | ||
7122 | if (zvni_vtep_add(zvni, &vtep_ip) == NULL) { | |
e914ccbe | 7123 | flog_err(EC_ZEBRA_VTEP_ADD_FAILED, |
1c50c1c0 QY |
7124 | "Failed to add remote VTEP, VNI %u zvni %p", |
7125 | vni, zvni); | |
d62a17ae | 7126 | continue; |
7127 | } | |
7128 | ||
7129 | zvni_vtep_install(zvni, &vtep_ip); | |
7130 | } | |
7131 | ||
ec93aa12 | 7132 | stream_failure: |
8068a649 | 7133 | return; |
13d60d35 | 7134 | } |
7135 | ||
1a98c087 MK |
7136 | /* |
7137 | * Add/Del gateway macip to evpn | |
7138 | * g/w can be: | |
7139 | * 1. SVI interface on a vlan aware bridge | |
7140 | * 2. SVI interface on a vlan unaware bridge | |
7141 | * 3. vrr interface (MACVLAN) associated to a SVI | |
7142 | * We advertise macip routes for an interface if it is associated to VxLan vlan | |
7143 | */ | |
7144 | int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, | |
7145 | int add) | |
7146 | { | |
7147 | struct ipaddr ip; | |
7148 | struct ethaddr macaddr; | |
7149 | zebra_vni_t *zvni = NULL; | |
1a98c087 MK |
7150 | |
7151 | memset(&ip, 0, sizeof(struct ipaddr)); | |
7152 | memset(&macaddr, 0, sizeof(struct ethaddr)); | |
7153 | ||
2853fed6 | 7154 | /* Check if EVPN is enabled. */ |
7155 | if (!is_evpn_enabled()) | |
297a21b6 MK |
7156 | return 0; |
7157 | ||
1a98c087 MK |
7158 | if (IS_ZEBRA_IF_MACVLAN(ifp)) { |
7159 | struct interface *svi_if = | |
7160 | NULL; /* SVI corresponding to the MACVLAN */ | |
7161 | struct zebra_if *ifp_zif = | |
7162 | NULL; /* Zebra daemon specific info for MACVLAN */ | |
7163 | struct zebra_if *svi_if_zif = | |
7164 | NULL; /* Zebra daemon specific info for SVI*/ | |
7165 | ||
7166 | ifp_zif = ifp->info; | |
7167 | if (!ifp_zif) | |
7168 | return -1; | |
7169 | ||
71349e03 MK |
7170 | /* |
7171 | * for a MACVLAN interface the link represents the svi_if | |
7172 | */ | |
7173 | svi_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), | |
7174 | ifp_zif->link_ifindex); | |
1a98c087 | 7175 | if (!svi_if) { |
9df414fe QY |
7176 | zlog_debug("MACVLAN %s(%u) without link information", |
7177 | ifp->name, ifp->ifindex); | |
1a98c087 MK |
7178 | return -1; |
7179 | } | |
7180 | ||
7181 | if (IS_ZEBRA_IF_VLAN(svi_if)) { | |
71349e03 MK |
7182 | /* |
7183 | * If it is a vlan aware bridge then the link gives the | |
7184 | * bridge information | |
7185 | */ | |
7186 | struct interface *svi_if_link = NULL; | |
7187 | ||
1a98c087 | 7188 | svi_if_zif = svi_if->info; |
71349e03 MK |
7189 | if (svi_if_zif) { |
7190 | svi_if_link = if_lookup_by_index_per_ns( | |
60466a63 QY |
7191 | zebra_ns_lookup(NS_DEFAULT), |
7192 | svi_if_zif->link_ifindex); | |
b7cfce93 | 7193 | zvni = zvni_from_svi(svi_if, svi_if_link); |
71349e03 | 7194 | } |
1a98c087 | 7195 | } else if (IS_ZEBRA_IF_BRIDGE(svi_if)) { |
71349e03 MK |
7196 | /* |
7197 | * If it is a vlan unaware bridge then svi is the bridge | |
7198 | * itself | |
7199 | */ | |
b7cfce93 | 7200 | zvni = zvni_from_svi(svi_if, svi_if); |
1a98c087 MK |
7201 | } |
7202 | } else if (IS_ZEBRA_IF_VLAN(ifp)) { | |
7203 | struct zebra_if *svi_if_zif = | |
71349e03 MK |
7204 | NULL; /* Zebra daemon specific info for SVI */ |
7205 | struct interface *svi_if_link = | |
7206 | NULL; /* link info for the SVI = bridge info */ | |
1a98c087 MK |
7207 | |
7208 | svi_if_zif = ifp->info; | |
e3bb770c IS |
7209 | if (svi_if_zif) { |
7210 | svi_if_link = if_lookup_by_index_per_ns( | |
cef91a18 QY |
7211 | zebra_ns_lookup(NS_DEFAULT), |
7212 | svi_if_zif->link_ifindex); | |
e3bb770c IS |
7213 | if (svi_if_link) |
7214 | zvni = zvni_from_svi(ifp, svi_if_link); | |
7215 | } | |
1a98c087 | 7216 | } else if (IS_ZEBRA_IF_BRIDGE(ifp)) { |
b7cfce93 | 7217 | zvni = zvni_from_svi(ifp, ifp); |
1a98c087 MK |
7218 | } |
7219 | ||
7220 | if (!zvni) | |
7221 | return 0; | |
7222 | ||
7223 | if (!zvni->vxlan_if) { | |
9df414fe QY |
7224 | zlog_debug("VNI %u hash %p doesn't have intf upon MACVLAN up", |
7225 | zvni->vni, zvni); | |
1a98c087 MK |
7226 | return -1; |
7227 | } | |
7228 | ||
1a98c087 | 7229 | |
1a98c087 MK |
7230 | memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); |
7231 | ||
7232 | if (p->family == AF_INET) { | |
7233 | ip.ipa_type = IPADDR_V4; | |
7234 | memcpy(&(ip.ipaddr_v4), &(p->u.prefix4), | |
7235 | sizeof(struct in_addr)); | |
7236 | } else if (p->family == AF_INET6) { | |
7237 | ip.ipa_type = IPADDR_V6; | |
7238 | memcpy(&(ip.ipaddr_v6), &(p->u.prefix6), | |
7239 | sizeof(struct in6_addr)); | |
7240 | } | |
7241 | ||
7242 | ||
7243 | if (add) | |
7244 | zvni_gw_macip_add(ifp, zvni, &macaddr, &ip); | |
7245 | else | |
7246 | zvni_gw_macip_del(ifp, zvni, &ip); | |
7247 | ||
7248 | return 0; | |
7249 | } | |
7250 | ||
2232a77c | 7251 | /* |
b7cfce93 MK |
7252 | * Handle SVI interface going down. |
7253 | * SVI can be associated to either L3-VNI or L2-VNI. | |
7254 | * For L2-VNI: At this point, this is a NOP since | |
7255 | * the kernel deletes the neighbor entries on this SVI (if any). | |
7256 | * We only need to update the vrf corresponding to zvni. | |
7257 | * For L3-VNI: L3-VNI is operationally down, update mac-ip routes and delete | |
7258 | * from bgp | |
2232a77c | 7259 | */ |
d62a17ae | 7260 | int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if) |
2232a77c | 7261 | { |
b7cfce93 MK |
7262 | zebra_l3vni_t *zl3vni = NULL; |
7263 | ||
7264 | zl3vni = zl3vni_from_svi(ifp, link_if); | |
7265 | if (zl3vni) { | |
7266 | ||
7267 | /* process l3-vni down */ | |
7268 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
7269 | ||
7270 | /* remove association with svi-if */ | |
7271 | zl3vni->svi_if = NULL; | |
7272 | } else { | |
7273 | zebra_vni_t *zvni = NULL; | |
7274 | ||
7275 | /* since we dont have svi corresponding to zvni, we associate it | |
7276 | * to default vrf. Note: the corresponding neigh entries on the | |
7277 | * SVI would have already been deleted */ | |
7278 | zvni = zvni_from_svi(ifp, link_if); | |
7279 | if (zvni) { | |
7280 | zvni->vrf_id = VRF_DEFAULT; | |
7281 | ||
7282 | /* update the tenant vrf in BGP */ | |
7283 | zvni_send_add_to_client(zvni); | |
7284 | } | |
7285 | } | |
d62a17ae | 7286 | return 0; |
2232a77c | 7287 | } |
7288 | ||
7289 | /* | |
b7cfce93 MK |
7290 | * Handle SVI interface coming up. |
7291 | * SVI can be associated to L3-VNI (l3vni vxlan interface) or L2-VNI (l2-vni | |
7292 | * vxlan intf). | |
7293 | * For L2-VNI: we need to install any remote neighbors entried (used for | |
7294 | * apr-suppression) | |
7295 | * For L3-VNI: SVI will be used to get the rmac to be used with L3-VNI | |
2232a77c | 7296 | */ |
d62a17ae | 7297 | int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) |
2232a77c | 7298 | { |
b7cfce93 MK |
7299 | zebra_vni_t *zvni = NULL; |
7300 | zebra_l3vni_t *zl3vni = NULL; | |
2232a77c | 7301 | |
b7cfce93 MK |
7302 | zl3vni = zl3vni_from_svi(ifp, link_if); |
7303 | if (zl3vni) { | |
2232a77c | 7304 | |
b7cfce93 MK |
7305 | /* associate with svi */ |
7306 | zl3vni->svi_if = ifp; | |
2232a77c | 7307 | |
b7cfce93 MK |
7308 | /* process oper-up */ |
7309 | if (is_l3vni_oper_up(zl3vni)) | |
7310 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
7311 | } else { | |
7312 | ||
7313 | /* process SVI up for l2-vni */ | |
7314 | struct neigh_walk_ctx n_wctx; | |
7315 | ||
7316 | zvni = zvni_from_svi(ifp, link_if); | |
7317 | if (!zvni) | |
7318 | return 0; | |
7319 | ||
7320 | if (!zvni->vxlan_if) { | |
9df414fe | 7321 | zlog_debug( |
43e52561 QY |
7322 | "VNI %u hash %p doesn't have intf upon SVI up", |
7323 | zvni->vni, zvni); | |
b7cfce93 MK |
7324 | return -1; |
7325 | } | |
7326 | ||
7327 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 LB |
7328 | zlog_debug( |
7329 | "SVI %s(%u) VNI %u VRF %s is UP, installing neighbors", | |
7330 | ifp->name, ifp->ifindex, zvni->vni, | |
7331 | vrf_id_to_name(ifp->vrf_id)); | |
2232a77c | 7332 | |
b7cfce93 MK |
7333 | /* update the vrf information for l2-vni and inform bgp */ |
7334 | zvni->vrf_id = ifp->vrf_id; | |
7335 | zvni_send_add_to_client(zvni); | |
7336 | ||
7337 | /* Install any remote neighbors for this VNI. */ | |
7338 | memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); | |
7339 | n_wctx.zvni = zvni; | |
996c9314 | 7340 | hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, |
b7cfce93 MK |
7341 | &n_wctx); |
7342 | } | |
2232a77c | 7343 | |
d62a17ae | 7344 | return 0; |
2232a77c | 7345 | } |
7346 | ||
13d60d35 | 7347 | /* |
b7cfce93 | 7348 | * Handle VxLAN interface down |
13d60d35 | 7349 | */ |
d62a17ae | 7350 | int zebra_vxlan_if_down(struct interface *ifp) |
13d60d35 | 7351 | { |
d62a17ae | 7352 | vni_t vni; |
b7cfce93 MK |
7353 | struct zebra_if *zif = NULL; |
7354 | struct zebra_l2info_vxlan *vxl = NULL; | |
643215ce | 7355 | zebra_l3vni_t *zl3vni = NULL; |
7356 | zebra_vni_t *zvni; | |
13d60d35 | 7357 | |
2853fed6 | 7358 | /* Check if EVPN is enabled. */ |
7359 | if (!is_evpn_enabled()) | |
d62a17ae | 7360 | return 0; |
13d60d35 | 7361 | |
d62a17ae | 7362 | zif = ifp->info; |
7363 | assert(zif); | |
7364 | vxl = &zif->l2info.vxl; | |
7365 | vni = vxl->vni; | |
13d60d35 | 7366 | |
643215ce | 7367 | zl3vni = zl3vni_lookup(vni); |
7368 | if (zl3vni) { | |
b7cfce93 | 7369 | /* process-if-down for l3-vni */ |
b7cfce93 | 7370 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
7371 | zlog_debug("Intf %s(%u) L3-VNI %u is DOWN", ifp->name, |
7372 | ifp->ifindex, vni); | |
b7cfce93 | 7373 | |
b7cfce93 | 7374 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
b7cfce93 MK |
7375 | } else { |
7376 | /* process if-down for l2-vni */ | |
b7cfce93 | 7377 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
7378 | zlog_debug("Intf %s(%u) L2-VNI %u is DOWN", ifp->name, |
7379 | ifp->ifindex, vni); | |
13d60d35 | 7380 | |
b7cfce93 MK |
7381 | /* Locate hash entry; it is expected to exist. */ |
7382 | zvni = zvni_lookup(vni); | |
7383 | if (!zvni) { | |
9df414fe | 7384 | zlog_debug( |
b7cfce93 MK |
7385 | "Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u", |
7386 | ifp->name, ifp->ifindex, vni); | |
7387 | return -1; | |
7388 | } | |
13d60d35 | 7389 | |
b7cfce93 | 7390 | assert(zvni->vxlan_if == ifp); |
13d60d35 | 7391 | |
b7cfce93 MK |
7392 | /* Delete this VNI from BGP. */ |
7393 | zvni_send_del_to_client(zvni->vni); | |
2232a77c | 7394 | |
b7cfce93 MK |
7395 | /* Free up all neighbors and MACs, if any. */ |
7396 | zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH); | |
7397 | zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC); | |
13d60d35 | 7398 | |
b7cfce93 MK |
7399 | /* Free up all remote VTEPs, if any. */ |
7400 | zvni_vtep_del_all(zvni, 1); | |
7401 | } | |
d62a17ae | 7402 | return 0; |
13d60d35 | 7403 | } |
7404 | ||
7405 | /* | |
7406 | * Handle VxLAN interface up - update BGP if required. | |
7407 | */ | |
d62a17ae | 7408 | int zebra_vxlan_if_up(struct interface *ifp) |
13d60d35 | 7409 | { |
d62a17ae | 7410 | vni_t vni; |
b7cfce93 MK |
7411 | struct zebra_if *zif = NULL; |
7412 | struct zebra_l2info_vxlan *vxl = NULL; | |
643215ce | 7413 | zebra_vni_t *zvni = NULL; |
7414 | zebra_l3vni_t *zl3vni = NULL; | |
13d60d35 | 7415 | |
2853fed6 | 7416 | /* Check if EVPN is enabled. */ |
7417 | if (!is_evpn_enabled()) | |
d62a17ae | 7418 | return 0; |
13d60d35 | 7419 | |
d62a17ae | 7420 | zif = ifp->info; |
7421 | assert(zif); | |
7422 | vxl = &zif->l2info.vxl; | |
7423 | vni = vxl->vni; | |
13d60d35 | 7424 | |
643215ce | 7425 | zl3vni = zl3vni_lookup(vni); |
7426 | if (zl3vni) { | |
13d60d35 | 7427 | |
b7cfce93 | 7428 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
7429 | zlog_debug("Intf %s(%u) L3-VNI %u is UP", ifp->name, |
7430 | ifp->ifindex, vni); | |
13d60d35 | 7431 | |
b7cfce93 | 7432 | /* we need to associate with SVI, if any, we can associate with |
523cafc4 | 7433 | * svi-if only after association with vxlan-intf is complete |
7434 | */ | |
b7cfce93 MK |
7435 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); |
7436 | ||
7437 | if (is_l3vni_oper_up(zl3vni)) | |
7438 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
7439 | } else { | |
7440 | /* Handle L2-VNI add */ | |
b7cfce93 MK |
7441 | struct interface *vlan_if = NULL; |
7442 | ||
7443 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 LB |
7444 | zlog_debug("Intf %s(%u) L2-VNI %u is UP", ifp->name, |
7445 | ifp->ifindex, vni); | |
b7cfce93 MK |
7446 | |
7447 | /* Locate hash entry; it is expected to exist. */ | |
7448 | zvni = zvni_lookup(vni); | |
7449 | if (!zvni) { | |
9df414fe | 7450 | zlog_debug( |
b7cfce93 MK |
7451 | "Failed to locate VNI hash at UP, IF %s(%u) VNI %u", |
7452 | ifp->name, ifp->ifindex, vni); | |
7453 | return -1; | |
7454 | } | |
7455 | ||
7456 | assert(zvni->vxlan_if == ifp); | |
7457 | vlan_if = zvni_map_to_svi(vxl->access_vlan, | |
7458 | zif->brslave_info.br_if); | |
7459 | if (vlan_if) { | |
7460 | zvni->vrf_id = vlan_if->vrf_id; | |
7461 | zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); | |
7462 | if (zl3vni) | |
7463 | listnode_add_sort(zl3vni->l2vnis, zvni); | |
7464 | } | |
7465 | ||
7466 | /* If part of a bridge, inform BGP about this VNI. */ | |
7467 | /* Also, read and populate local MACs and neighbors. */ | |
7468 | if (zif->brslave_info.br_if) { | |
7469 | zvni_send_add_to_client(zvni); | |
7470 | zvni_read_mac_neigh(zvni, ifp); | |
7471 | } | |
d62a17ae | 7472 | } |
13d60d35 | 7473 | |
d62a17ae | 7474 | return 0; |
13d60d35 | 7475 | } |
7476 | ||
7477 | /* | |
7478 | * Handle VxLAN interface delete. Locate and remove entry in hash table | |
7479 | * and update BGP, if required. | |
7480 | */ | |
d62a17ae | 7481 | int zebra_vxlan_if_del(struct interface *ifp) |
13d60d35 | 7482 | { |
d62a17ae | 7483 | vni_t vni; |
b7cfce93 MK |
7484 | struct zebra_if *zif = NULL; |
7485 | struct zebra_l2info_vxlan *vxl = NULL; | |
643215ce | 7486 | zebra_vni_t *zvni = NULL; |
7487 | zebra_l3vni_t *zl3vni = NULL; | |
13d60d35 | 7488 | |
2853fed6 | 7489 | /* Check if EVPN is enabled. */ |
7490 | if (!is_evpn_enabled()) | |
d62a17ae | 7491 | return 0; |
13d60d35 | 7492 | |
d62a17ae | 7493 | zif = ifp->info; |
7494 | assert(zif); | |
7495 | vxl = &zif->l2info.vxl; | |
7496 | vni = vxl->vni; | |
13d60d35 | 7497 | |
643215ce | 7498 | zl3vni = zl3vni_lookup(vni); |
7499 | if (zl3vni) { | |
b7cfce93 MK |
7500 | |
7501 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 LB |
7502 | zlog_debug("Del L3-VNI %u intf %s(%u)", vni, ifp->name, |
7503 | ifp->ifindex); | |
13d60d35 | 7504 | |
b7cfce93 MK |
7505 | /* process oper-down for l3-vni */ |
7506 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
2232a77c | 7507 | |
b7cfce93 | 7508 | /* remove the association with vxlan_if */ |
b67a60d2 | 7509 | memset(&zl3vni->local_vtep_ip, 0, sizeof(struct in_addr)); |
b7cfce93 MK |
7510 | zl3vni->vxlan_if = NULL; |
7511 | } else { | |
13d60d35 | 7512 | |
b7cfce93 | 7513 | /* process if-del for l2-vni*/ |
b7cfce93 | 7514 | if (IS_ZEBRA_DEBUG_VXLAN) |
996c9314 LB |
7515 | zlog_debug("Del L2-VNI %u intf %s(%u)", vni, ifp->name, |
7516 | ifp->ifindex); | |
b7cfce93 MK |
7517 | |
7518 | /* Locate hash entry; it is expected to exist. */ | |
7519 | zvni = zvni_lookup(vni); | |
7520 | if (!zvni) { | |
9df414fe | 7521 | zlog_debug( |
b7cfce93 MK |
7522 | "Failed to locate VNI hash at del, IF %s(%u) VNI %u", |
7523 | ifp->name, ifp->ifindex, vni); | |
7524 | return 0; | |
7525 | } | |
7526 | ||
7527 | /* remove from l3-vni list */ | |
7528 | zl3vni = zl3vni_from_vrf(zvni->vrf_id); | |
7529 | if (zl3vni) | |
7530 | listnode_delete(zl3vni->l2vnis, zvni); | |
7531 | ||
7532 | /* Delete VNI from BGP. */ | |
7533 | zvni_send_del_to_client(zvni->vni); | |
7534 | ||
7535 | /* Free up all neighbors and MAC, if any. */ | |
7536 | zvni_neigh_del_all(zvni, 0, 0, DEL_ALL_NEIGH); | |
7537 | zvni_mac_del_all(zvni, 0, 0, DEL_ALL_MAC); | |
7538 | ||
7539 | /* Free up all remote VTEPs, if any. */ | |
7540 | zvni_vtep_del_all(zvni, 0); | |
7541 | ||
7542 | /* Delete the hash entry. */ | |
7543 | if (zvni_del(zvni)) { | |
e914ccbe | 7544 | flog_err(EC_ZEBRA_VNI_DEL_FAILED, |
1c50c1c0 QY |
7545 | "Failed to del VNI hash %p, IF %s(%u) VNI %u", |
7546 | zvni, ifp->name, ifp->ifindex, zvni->vni); | |
b7cfce93 MK |
7547 | return -1; |
7548 | } | |
d62a17ae | 7549 | } |
d62a17ae | 7550 | return 0; |
13d60d35 | 7551 | } |
7552 | ||
7553 | /* | |
7554 | * Handle VxLAN interface update - change to tunnel IP, master or VLAN. | |
7555 | */ | |
d7c0a89a | 7556 | int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags) |
d62a17ae | 7557 | { |
d62a17ae | 7558 | vni_t vni; |
b7cfce93 MK |
7559 | struct zebra_if *zif = NULL; |
7560 | struct zebra_l2info_vxlan *vxl = NULL; | |
643215ce | 7561 | zebra_vni_t *zvni = NULL; |
7562 | zebra_l3vni_t *zl3vni = NULL; | |
d62a17ae | 7563 | |
2853fed6 | 7564 | /* Check if EVPN is enabled. */ |
7565 | if (!is_evpn_enabled()) | |
d62a17ae | 7566 | return 0; |
7567 | ||
7568 | zif = ifp->info; | |
7569 | assert(zif); | |
7570 | vxl = &zif->l2info.vxl; | |
7571 | vni = vxl->vni; | |
7572 | ||
643215ce | 7573 | zl3vni = zl3vni_lookup(vni); |
7574 | if (zl3vni) { | |
af026ae4 | 7575 | |
b7cfce93 MK |
7576 | if (IS_ZEBRA_DEBUG_VXLAN) |
7577 | zlog_debug( | |
7578 | "Update L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x", | |
996c9314 LB |
7579 | vni, ifp->name, ifp->ifindex, vxl->access_vlan, |
7580 | inet_ntoa(vxl->vtep_ip), | |
b7cfce93 MK |
7581 | zif->brslave_info.bridge_ifindex, chgflags); |
7582 | ||
7583 | /* Removed from bridge? Cleanup and return */ | |
7584 | if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) | |
7585 | && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { | |
7586 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
7587 | return 0; | |
7588 | } | |
7589 | ||
7590 | /* access-vlan change - process oper down, associate with new | |
523cafc4 | 7591 | * svi_if and then process oper up again |
7592 | */ | |
b7cfce93 MK |
7593 | if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { |
7594 | if (if_is_operative(ifp)) { | |
7595 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
7596 | zl3vni->svi_if = NULL; | |
7597 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); | |
bca63dc8 | 7598 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
b7cfce93 MK |
7599 | if (is_l3vni_oper_up(zl3vni)) |
7600 | zebra_vxlan_process_l3vni_oper_up( | |
996c9314 | 7601 | zl3vni); |
b7cfce93 MK |
7602 | } |
7603 | } | |
d62a17ae | 7604 | |
12eeac84 MK |
7605 | /* |
7606 | * local-ip change - process oper down, associate with new | |
7607 | * local-ip and then process oper up again | |
7608 | */ | |
7609 | if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { | |
7610 | if (if_is_operative(ifp)) { | |
7611 | zebra_vxlan_process_l3vni_oper_down(zl3vni); | |
7612 | zl3vni->local_vtep_ip = vxl->vtep_ip; | |
7613 | if (is_l3vni_oper_up(zl3vni)) | |
7614 | zebra_vxlan_process_l3vni_oper_up( | |
996c9314 | 7615 | zl3vni); |
12eeac84 MK |
7616 | } |
7617 | } | |
7618 | ||
bca63dc8 MK |
7619 | /* Update local tunnel IP. */ |
7620 | zl3vni->local_vtep_ip = vxl->vtep_ip; | |
7621 | ||
12eeac84 MK |
7622 | /* if we have a valid new master, process l3-vni oper up */ |
7623 | if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { | |
7624 | if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) | |
b7cfce93 MK |
7625 | zebra_vxlan_process_l3vni_oper_up(zl3vni); |
7626 | } | |
7627 | } else { | |
d62a17ae | 7628 | |
b7cfce93 MK |
7629 | /* Update VNI hash. */ |
7630 | zvni = zvni_lookup(vni); | |
7631 | if (!zvni) { | |
9df414fe | 7632 | zlog_debug( |
b7cfce93 MK |
7633 | "Failed to find L2-VNI hash on update, IF %s(%u) VNI %u", |
7634 | ifp->name, ifp->ifindex, vni); | |
7635 | return -1; | |
7636 | } | |
d62a17ae | 7637 | |
b7cfce93 MK |
7638 | if (IS_ZEBRA_DEBUG_VXLAN) |
7639 | zlog_debug( | |
7640 | "Update L2-VNI %u intf %s(%u) VLAN %u local IP %s master %u chg 0x%x", | |
996c9314 LB |
7641 | vni, ifp->name, ifp->ifindex, vxl->access_vlan, |
7642 | inet_ntoa(vxl->vtep_ip), | |
b7cfce93 MK |
7643 | zif->brslave_info.bridge_ifindex, chgflags); |
7644 | ||
7645 | /* Removed from bridge? Cleanup and return */ | |
7646 | if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) | |
7647 | && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { | |
7648 | /* Delete from client, remove all remote VTEPs */ | |
7649 | /* Also, free up all MACs and neighbors. */ | |
7650 | zvni_send_del_to_client(zvni->vni); | |
7651 | zvni_neigh_del_all(zvni, 1, 0, DEL_ALL_NEIGH); | |
7652 | zvni_mac_del_all(zvni, 1, 0, DEL_ALL_MAC); | |
7653 | zvni_vtep_del_all(zvni, 1); | |
7654 | return 0; | |
7655 | } | |
d62a17ae | 7656 | |
b7cfce93 MK |
7657 | /* Handle other changes. */ |
7658 | if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { | |
7659 | /* Remove all existing local neigh and MACs for this VNI | |
7660 | * (including from BGP) | |
7661 | */ | |
7662 | zvni_neigh_del_all(zvni, 0, 1, DEL_LOCAL_MAC); | |
7663 | zvni_mac_del_all(zvni, 0, 1, DEL_LOCAL_MAC); | |
7664 | } | |
d62a17ae | 7665 | |
b7cfce93 MK |
7666 | zvni->local_vtep_ip = vxl->vtep_ip; |
7667 | zvni->vxlan_if = ifp; | |
d62a17ae | 7668 | |
b7cfce93 MK |
7669 | /* Take further actions needed. |
7670 | * Note that if we are here, there is a change of interest. | |
7671 | */ | |
7672 | /* If down or not mapped to a bridge, we're done. */ | |
7673 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
7674 | return 0; | |
d62a17ae | 7675 | |
b7cfce93 MK |
7676 | /* Inform BGP, if there is a change of interest. */ |
7677 | if (chgflags | |
7678 | & (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE)) | |
7679 | zvni_send_add_to_client(zvni); | |
7680 | ||
7681 | /* If there is a valid new master or a VLAN mapping change, | |
7682 | * read and populate local MACs and neighbors. | |
7683 | * Also, reinstall any remote MACs and neighbors | |
7684 | * for this VNI (based on new VLAN). | |
7685 | */ | |
7686 | if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) | |
7687 | zvni_read_mac_neigh(zvni, ifp); | |
7688 | else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { | |
7689 | struct mac_walk_ctx m_wctx; | |
7690 | struct neigh_walk_ctx n_wctx; | |
7691 | ||
7692 | zvni_read_mac_neigh(zvni, ifp); | |
7693 | ||
7694 | memset(&m_wctx, 0, sizeof(struct mac_walk_ctx)); | |
7695 | m_wctx.zvni = zvni; | |
996c9314 | 7696 | hash_iterate(zvni->mac_table, zvni_install_mac_hash, |
b7cfce93 MK |
7697 | &m_wctx); |
7698 | ||
7699 | memset(&n_wctx, 0, sizeof(struct neigh_walk_ctx)); | |
7700 | n_wctx.zvni = zvni; | |
7701 | hash_iterate(zvni->neigh_table, zvni_install_neigh_hash, | |
7702 | &n_wctx); | |
7703 | } | |
d62a17ae | 7704 | } |
7705 | ||
7706 | return 0; | |
13d60d35 | 7707 | } |
7708 | ||
7709 | /* | |
7710 | * Handle VxLAN interface add. | |
7711 | */ | |
d62a17ae | 7712 | int zebra_vxlan_if_add(struct interface *ifp) |
13d60d35 | 7713 | { |
d62a17ae | 7714 | vni_t vni; |
b7cfce93 MK |
7715 | struct zebra_if *zif = NULL; |
7716 | struct zebra_l2info_vxlan *vxl = NULL; | |
643215ce | 7717 | zebra_vni_t *zvni = NULL; |
7718 | zebra_l3vni_t *zl3vni = NULL; | |
13d60d35 | 7719 | |
2853fed6 | 7720 | /* Check if EVPN is enabled. */ |
7721 | if (!is_evpn_enabled()) | |
d62a17ae | 7722 | return 0; |
13d60d35 | 7723 | |
d62a17ae | 7724 | zif = ifp->info; |
7725 | assert(zif); | |
7726 | vxl = &zif->l2info.vxl; | |
7727 | vni = vxl->vni; | |
13d60d35 | 7728 | |
643215ce | 7729 | zl3vni = zl3vni_lookup(vni); |
7730 | if (zl3vni) { | |
13d60d35 | 7731 | |
b7cfce93 | 7732 | /* process if-add for l3-vni*/ |
b7cfce93 MK |
7733 | if (IS_ZEBRA_DEBUG_VXLAN) |
7734 | zlog_debug( | |
7735 | "Add L3-VNI %u intf %s(%u) VLAN %u local IP %s master %u", | |
996c9314 LB |
7736 | vni, ifp->name, ifp->ifindex, vxl->access_vlan, |
7737 | inet_ntoa(vxl->vtep_ip), | |
b7cfce93 MK |
7738 | zif->brslave_info.bridge_ifindex); |
7739 | ||
b7cfce93 | 7740 | /* associate with vxlan_if */ |
b67a60d2 | 7741 | zl3vni->local_vtep_ip = vxl->vtep_ip; |
b7cfce93 MK |
7742 | zl3vni->vxlan_if = ifp; |
7743 | ||
7744 | /* Associate with SVI, if any. We can associate with svi-if only | |
7745 | * after association with vxlan_if is complete */ | |
7746 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); | |
7747 | ||
7748 | if (is_l3vni_oper_up(zl3vni)) | |
7749 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
7750 | } else { | |
7751 | ||
7752 | /* process if-add for l2-vni */ | |
b7cfce93 MK |
7753 | struct interface *vlan_if = NULL; |
7754 | ||
7755 | /* Create or update VNI hash. */ | |
7756 | zvni = zvni_lookup(vni); | |
7757 | if (!zvni) { | |
7758 | zvni = zvni_add(vni); | |
7759 | if (!zvni) { | |
af4c2728 | 7760 | flog_err( |
e914ccbe | 7761 | EC_ZEBRA_VNI_ADD_FAILED, |
b7cfce93 MK |
7762 | "Failed to add VNI hash, IF %s(%u) VNI %u", |
7763 | ifp->name, ifp->ifindex, vni); | |
7764 | return -1; | |
7765 | } | |
7766 | } | |
7767 | ||
7768 | zvni->local_vtep_ip = vxl->vtep_ip; | |
7769 | zvni->vxlan_if = ifp; | |
7770 | vlan_if = zvni_map_to_svi(vxl->access_vlan, | |
7771 | zif->brslave_info.br_if); | |
7772 | if (vlan_if) { | |
7773 | zvni->vrf_id = vlan_if->vrf_id; | |
7774 | zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); | |
7775 | if (zl3vni) | |
7776 | listnode_add_sort(zl3vni->l2vnis, zvni); | |
7777 | } | |
7778 | ||
7779 | if (IS_ZEBRA_DEBUG_VXLAN) | |
7780 | zlog_debug( | |
7781 | "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %s master %u", | |
7782 | vni, | |
996c9314 LB |
7783 | vlan_if ? vrf_id_to_name(vlan_if->vrf_id) |
7784 | : "Default", | |
7785 | ifp->name, ifp->ifindex, vxl->access_vlan, | |
7786 | inet_ntoa(vxl->vtep_ip), | |
b7cfce93 MK |
7787 | zif->brslave_info.bridge_ifindex); |
7788 | ||
7789 | /* If down or not mapped to a bridge, we're done. */ | |
7790 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
7791 | return 0; | |
7792 | ||
7793 | /* Inform BGP */ | |
7794 | zvni_send_add_to_client(zvni); | |
7795 | ||
7796 | /* Read and populate local MACs and neighbors */ | |
7797 | zvni_read_mac_neigh(zvni, ifp); | |
7798 | } | |
7799 | ||
7800 | return 0; | |
7801 | } | |
7802 | ||
996c9314 LB |
7803 | int zebra_vxlan_process_vrf_vni_cmd(struct zebra_vrf *zvrf, vni_t vni, |
7804 | char *err, int err_str_sz, int filter, | |
7805 | int add) | |
b7cfce93 MK |
7806 | { |
7807 | zebra_l3vni_t *zl3vni = NULL; | |
7808 | struct zebra_vrf *zvrf_default = NULL; | |
7809 | ||
7810 | zvrf_default = zebra_vrf_lookup_by_id(VRF_DEFAULT); | |
7811 | if (!zvrf_default) | |
7812 | return -1; | |
7813 | ||
7814 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 | 7815 | zlog_debug("vrf %s vni %u %s", zvrf_name(zvrf), vni, |
b7cfce93 MK |
7816 | add ? "ADD" : "DEL"); |
7817 | ||
7818 | if (add) { | |
7819 | ||
7820 | zebra_vxlan_handle_vni_transition(zvrf, vni, add); | |
7821 | ||
7822 | /* check if the vni is already present under zvrf */ | |
7823 | if (zvrf->l3vni) { | |
3f02fbab | 7824 | snprintf(err, err_str_sz, |
b7cfce93 MK |
7825 | "VNI is already configured under the vrf"); |
7826 | return -1; | |
7827 | } | |
7828 | ||
7829 | /* check if this VNI is already present in the system */ | |
7830 | zl3vni = zl3vni_lookup(vni); | |
7831 | if (zl3vni) { | |
3f02fbab | 7832 | snprintf(err, err_str_sz, |
b7cfce93 MK |
7833 | "VNI is already configured as L3-VNI"); |
7834 | return -1; | |
7835 | } | |
7836 | ||
7837 | /* add the L3-VNI to the global table */ | |
7838 | zl3vni = zl3vni_add(vni, zvrf_id(zvrf)); | |
7839 | if (!zl3vni) { | |
996c9314 | 7840 | snprintf(err, err_str_sz, "Could not add L3-VNI"); |
b7cfce93 MK |
7841 | return -1; |
7842 | } | |
7843 | ||
7844 | /* associate the vrf with vni */ | |
7845 | zvrf->l3vni = vni; | |
7846 | ||
c48d9f5f MK |
7847 | /* set the filter in l3vni to denote if we are using l3vni only |
7848 | * for prefix routes | |
7849 | */ | |
7850 | if (filter) | |
7851 | SET_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY); | |
7852 | ||
b7cfce93 | 7853 | /* associate with vxlan-intf; |
523cafc4 | 7854 | * we need to associate with the vxlan-intf first |
7855 | */ | |
b7cfce93 MK |
7856 | zl3vni->vxlan_if = zl3vni_map_to_vxlan_if(zl3vni); |
7857 | ||
7858 | /* associate with corresponding SVI interface, we can associate | |
7859 | * with svi-if only after vxlan interface association is | |
523cafc4 | 7860 | * complete |
7861 | */ | |
b7cfce93 MK |
7862 | zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni); |
7863 | ||
7864 | /* formulate l2vni list */ | |
996c9314 LB |
7865 | hash_iterate(zvrf_default->vni_table, zvni_add_to_l3vni_list, |
7866 | zl3vni); | |
b7cfce93 MK |
7867 | |
7868 | if (is_l3vni_oper_up(zl3vni)) | |
7869 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
7870 | ||
7871 | } else { | |
7872 | zl3vni = zl3vni_lookup(vni); | |
7873 | if (!zl3vni) { | |
3f02fbab | 7874 | snprintf(err, err_str_sz, "VNI doesn't exist"); |
d62a17ae | 7875 | return -1; |
7876 | } | |
b7cfce93 | 7877 | |
cf299714 MK |
7878 | if (filter && !CHECK_FLAG(zl3vni->filter, PREFIX_ROUTES_ONLY)) { |
7879 | snprintf(err, ERR_STR_SZ, | |
7880 | "prefix-routes-only is not set for the vni"); | |
7881 | return -1; | |
7882 | } | |
7883 | ||
b7cfce93 MK |
7884 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
7885 | ||
5e06422c | 7886 | /* delete and uninstall all rmacs */ |
996c9314 | 7887 | hash_iterate(zl3vni->rmac_table, zl3vni_del_rmac_hash_entry, |
5e06422c MK |
7888 | zl3vni); |
7889 | ||
7890 | /* delete and uninstall all next-hops */ | |
996c9314 | 7891 | hash_iterate(zl3vni->nh_table, zl3vni_del_nh_hash_entry, |
5e06422c MK |
7892 | zl3vni); |
7893 | ||
b7cfce93 MK |
7894 | zvrf->l3vni = 0; |
7895 | zl3vni_del(zl3vni); | |
7896 | ||
7897 | zebra_vxlan_handle_vni_transition(zvrf, vni, add); | |
d62a17ae | 7898 | } |
b7cfce93 MK |
7899 | return 0; |
7900 | } | |
13d60d35 | 7901 | |
84915b0a | 7902 | int zebra_vxlan_vrf_enable(struct zebra_vrf *zvrf) |
7903 | { | |
7904 | zebra_l3vni_t *zl3vni = NULL; | |
7905 | ||
7906 | if (zvrf->l3vni) | |
7907 | zl3vni = zl3vni_lookup(zvrf->l3vni); | |
7908 | if (!zl3vni) | |
7909 | return 0; | |
7910 | ||
7911 | zl3vni->vrf_id = zvrf_id(zvrf); | |
7912 | if (is_l3vni_oper_up(zl3vni)) | |
7913 | zebra_vxlan_process_l3vni_oper_up(zl3vni); | |
7914 | return 0; | |
7915 | } | |
7916 | ||
7917 | int zebra_vxlan_vrf_disable(struct zebra_vrf *zvrf) | |
b7cfce93 MK |
7918 | { |
7919 | zebra_l3vni_t *zl3vni = NULL; | |
13d60d35 | 7920 | |
84915b0a | 7921 | if (zvrf->l3vni) |
7922 | zl3vni = zl3vni_lookup(zvrf->l3vni); | |
b7cfce93 | 7923 | if (!zl3vni) |
d62a17ae | 7924 | return 0; |
13d60d35 | 7925 | |
84915b0a | 7926 | zl3vni->vrf_id = VRF_UNKNOWN; |
b7cfce93 | 7927 | zebra_vxlan_process_l3vni_oper_down(zl3vni); |
84915b0a | 7928 | return 0; |
7929 | } | |
7930 | ||
7931 | int zebra_vxlan_vrf_delete(struct zebra_vrf *zvrf) | |
7932 | { | |
7933 | zebra_l3vni_t *zl3vni = NULL; | |
7934 | vni_t vni; | |
7935 | ||
7936 | if (zvrf->l3vni) | |
7937 | zl3vni = zl3vni_lookup(zvrf->l3vni); | |
7938 | if (!zl3vni) | |
7939 | return 0; | |
7940 | ||
7941 | vni = zl3vni->vni; | |
b7cfce93 | 7942 | zl3vni_del(zl3vni); |
84915b0a | 7943 | zebra_vxlan_handle_vni_transition(zvrf, vni, 0); |
2232a77c | 7944 | |
d62a17ae | 7945 | return 0; |
13d60d35 | 7946 | } |
7947 | ||
fbac9605 DS |
7948 | /* |
7949 | * Handle message from client to specify the flooding mechanism for | |
7950 | * BUM packets. The default is to do head-end (ingress) replication | |
7951 | * and the other supported option is to disable it. This applies to | |
7952 | * all BUM traffic and disabling it applies to both the transmit and | |
7953 | * receive direction. | |
7954 | */ | |
7955 | void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS) | |
7956 | { | |
7957 | struct stream *s; | |
7958 | enum vxlan_flood_control flood_ctrl; | |
7959 | ||
7960 | if (zvrf_id(zvrf) != VRF_DEFAULT) { | |
7961 | zlog_err("EVPN flood control for non-default VRF %u", | |
7962 | zvrf_id(zvrf)); | |
7963 | return; | |
7964 | } | |
7965 | ||
7966 | s = msg; | |
7967 | STREAM_GETC(s, flood_ctrl); | |
7968 | ||
7969 | if (IS_ZEBRA_DEBUG_VXLAN) | |
7970 | zlog_debug("EVPN flood control %u, currently %u", | |
7971 | flood_ctrl, zvrf->vxlan_flood_ctrl); | |
7972 | ||
7973 | if (zvrf->vxlan_flood_ctrl == flood_ctrl) | |
7974 | return; | |
7975 | ||
7976 | zvrf->vxlan_flood_ctrl = flood_ctrl; | |
7977 | ||
7978 | /* Install or uninstall flood entries corresponding to | |
7979 | * remote VTEPs. | |
7980 | */ | |
7981 | hash_iterate(zvrf->vni_table, zvni_handle_flooding_remote_vteps, | |
7982 | zvrf); | |
7983 | ||
7984 | stream_failure: | |
7985 | return; | |
7986 | } | |
7987 | ||
31310b25 MK |
7988 | /* |
7989 | * Handle message from client to enable/disable advertisement of g/w macip | |
7990 | * routes | |
7991 | */ | |
89f4e507 | 7992 | void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS) |
31310b25 MK |
7993 | { |
7994 | struct stream *s; | |
7995 | int advertise; | |
7996 | vni_t vni = 0; | |
7997 | zebra_vni_t *zvni = NULL; | |
7998 | struct interface *ifp = NULL; | |
7999 | struct zebra_if *zif = NULL; | |
8000 | struct zebra_l2info_vxlan zl2_info; | |
8001 | struct interface *vlan_if = NULL; | |
8002 | ||
8003 | if (zvrf_id(zvrf) != VRF_DEFAULT) { | |
9df414fe QY |
8004 | zlog_debug("EVPN GW-MACIP Adv for non-default VRF %u", |
8005 | zvrf_id(zvrf)); | |
8068a649 | 8006 | return; |
31310b25 MK |
8007 | } |
8008 | ||
1002497a | 8009 | s = msg; |
2017b3ea | 8010 | STREAM_GETC(s, advertise); |
31310b25 MK |
8011 | vni = stream_get3(s); |
8012 | ||
8013 | zvni = zvni_lookup(vni); | |
8014 | if (!zvni) | |
8068a649 | 8015 | return; |
31310b25 MK |
8016 | |
8017 | if (zvni->advertise_subnet == advertise) | |
8068a649 | 8018 | return; |
31310b25 MK |
8019 | |
8020 | if (IS_ZEBRA_DEBUG_VXLAN) | |
996c9314 LB |
8021 | zlog_debug("EVPN subnet Adv %s on VNI %d , currently %s", |
8022 | advertise ? "enabled" : "disabled", vni, | |
8023 | zvni->advertise_subnet ? "enabled" : "disabled"); | |
31310b25 MK |
8024 | |
8025 | ||
8026 | zvni->advertise_subnet = advertise; | |
8027 | ||
8028 | ifp = zvni->vxlan_if; | |
8029 | if (!ifp) | |
8068a649 | 8030 | return; |
31310b25 MK |
8031 | |
8032 | zif = ifp->info; | |
8033 | ||
8034 | /* If down or not mapped to a bridge, we're done. */ | |
8035 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) | |
8068a649 | 8036 | return; |
31310b25 MK |
8037 | |
8038 | zl2_info = zif->l2info.vxl; | |
8039 | ||
996c9314 LB |
8040 | vlan_if = |
8041 | zvni_map_to_svi(zl2_info.access_vlan, zif->brslave_info.br_if); | |
31310b25 | 8042 | if (!vlan_if) |
8068a649 | 8043 | return; |
31310b25 MK |
8044 | |
8045 | if (zvni->advertise_subnet) | |
8046 | zvni_advertise_subnet(zvni, vlan_if, 1); | |
8047 | else | |
8048 | zvni_advertise_subnet(zvni, vlan_if, 0); | |
2017b3ea DS |
8049 | |
8050 | stream_failure: | |
8051 | return; | |
31310b25 MK |
8052 | } |
8053 | ||
1a98c087 MK |
8054 | /* |
8055 | * Handle message from client to enable/disable advertisement of g/w macip | |
8056 | * routes | |
8057 | */ | |
89f4e507 | 8058 | void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS) |
1a98c087 MK |
8059 | { |
8060 | struct stream *s; | |
8061 | int advertise; | |
8062 | vni_t vni = 0; | |
8063 | zebra_vni_t *zvni = NULL; | |
b5ebdc9b | 8064 | struct interface *ifp = NULL; |
1a98c087 | 8065 | |
2853fed6 | 8066 | if (zvrf_id(zvrf) != VRF_DEFAULT) { |
9df414fe QY |
8067 | zlog_debug("EVPN GW-MACIP Adv for non-default VRF %u", |
8068 | zvrf_id(zvrf)); | |
8068a649 | 8069 | return; |
2853fed6 | 8070 | } |
8071 | ||
1002497a | 8072 | s = msg; |
ec93aa12 | 8073 | STREAM_GETC(s, advertise); |
cc6d5476 | 8074 | STREAM_GETL(s, vni); |
1a98c087 MK |
8075 | |
8076 | if (!vni) { | |
8077 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2853fed6 | 8078 | zlog_debug("EVPN gateway macip Adv %s, currently %s", |
1a98c087 | 8079 | advertise ? "enabled" : "disabled", |
2853fed6 | 8080 | advertise_gw_macip_enabled(NULL) |
1a98c087 MK |
8081 | ? "enabled" |
8082 | : "disabled"); | |
8083 | ||
8084 | if (zvrf->advertise_gw_macip == advertise) | |
8068a649 | 8085 | return; |
1a98c087 MK |
8086 | |
8087 | zvrf->advertise_gw_macip = advertise; | |
8088 | ||
2853fed6 | 8089 | if (advertise_gw_macip_enabled(zvni)) |
1a98c087 | 8090 | hash_iterate(zvrf->vni_table, |
2853fed6 | 8091 | zvni_gw_macip_add_for_vni_hash, NULL); |
1a98c087 MK |
8092 | else |
8093 | hash_iterate(zvrf->vni_table, | |
2853fed6 | 8094 | zvni_gw_macip_del_for_vni_hash, NULL); |
1a98c087 MK |
8095 | |
8096 | } else { | |
8097 | struct zebra_if *zif = NULL; | |
8098 | struct zebra_l2info_vxlan zl2_info; | |
8099 | struct interface *vlan_if = NULL; | |
8100 | struct interface *vrr_if = NULL; | |
8101 | ||
01a6143b MK |
8102 | zvni = zvni_lookup(vni); |
8103 | if (!zvni) | |
124ead27 | 8104 | return; |
01a6143b | 8105 | |
1a98c087 MK |
8106 | if (IS_ZEBRA_DEBUG_VXLAN) |
8107 | zlog_debug( | |
2853fed6 | 8108 | "EVPN gateway macip Adv %s on VNI %d , currently %s", |
1a98c087 | 8109 | advertise ? "enabled" : "disabled", vni, |
996c9314 LB |
8110 | advertise_gw_macip_enabled(zvni) ? "enabled" |
8111 | : "disabled"); | |
1a98c087 | 8112 | |
1a98c087 | 8113 | if (zvni->advertise_gw_macip == advertise) |
8068a649 | 8114 | return; |
1a98c087 MK |
8115 | |
8116 | zvni->advertise_gw_macip = advertise; | |
8117 | ||
b5ebdc9b | 8118 | ifp = zvni->vxlan_if; |
8119 | if (!ifp) | |
8068a649 | 8120 | return; |
b5ebdc9b | 8121 | |
8122 | zif = ifp->info; | |
8123 | ||
8124 | /* If down or not mapped to a bridge, we're done. */ | |
b682f6de | 8125 | if (!if_is_operative(ifp) || !zif->brslave_info.br_if) |
8068a649 | 8126 | return; |
b5ebdc9b | 8127 | |
1a98c087 MK |
8128 | zl2_info = zif->l2info.vxl; |
8129 | ||
2853fed6 | 8130 | vlan_if = zvni_map_to_svi(zl2_info.access_vlan, |
1a98c087 MK |
8131 | zif->brslave_info.br_if); |
8132 | if (!vlan_if) | |
8068a649 | 8133 | return; |
1a98c087 | 8134 | |
2853fed6 | 8135 | if (advertise_gw_macip_enabled(zvni)) { |
1a98c087 MK |
8136 | /* Add primary SVI MAC-IP */ |
8137 | zvni_add_macip_for_intf(vlan_if, zvni); | |
8138 | ||
8139 | /* Add VRR MAC-IP - if any*/ | |
8140 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
8141 | if (vrr_if) | |
8142 | zvni_add_macip_for_intf(vrr_if, zvni); | |
8143 | } else { | |
8144 | /* Del primary MAC-IP */ | |
8145 | zvni_del_macip_for_intf(vlan_if, zvni); | |
8146 | ||
8147 | /* Del VRR MAC-IP - if any*/ | |
8148 | vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); | |
8149 | if (vrr_if) | |
8150 | zvni_del_macip_for_intf(vrr_if, zvni); | |
8151 | } | |
8152 | } | |
8153 | ||
ec93aa12 | 8154 | stream_failure: |
8068a649 | 8155 | return; |
1a98c087 MK |
8156 | } |
8157 | ||
8158 | ||
13d60d35 | 8159 | /* |
8160 | * Handle message from client to learn (or stop learning) about VNIs and MACs. | |
8161 | * When enabled, the VNI hash table will be built and MAC FDB table read; | |
8162 | * when disabled, the entries should be deleted and remote VTEPs and MACs | |
8163 | * uninstalled from the kernel. | |
fbac9605 DS |
8164 | * This also informs the setting for BUM handling at the time this change |
8165 | * occurs; it is relevant only when specifying "learn". | |
13d60d35 | 8166 | */ |
89f4e507 | 8167 | void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS) |
13d60d35 | 8168 | { |
655b04d1 MK |
8169 | struct stream *s = NULL; |
8170 | int advertise = 0; | |
fbac9605 | 8171 | enum vxlan_flood_control flood_ctrl; |
13d60d35 | 8172 | |
2853fed6 | 8173 | if (zvrf_id(zvrf) != VRF_DEFAULT) { |
9df414fe QY |
8174 | zlog_debug("EVPN VNI Adv for non-default VRF %u", |
8175 | zvrf_id(zvrf)); | |
8068a649 | 8176 | return; |
2853fed6 | 8177 | } |
8178 | ||
1002497a | 8179 | s = msg; |
ec93aa12 | 8180 | STREAM_GETC(s, advertise); |
fbac9605 | 8181 | STREAM_GETC(s, flood_ctrl); |
13d60d35 | 8182 | |
d62a17ae | 8183 | if (IS_ZEBRA_DEBUG_VXLAN) |
fbac9605 | 8184 | zlog_debug("EVPN VNI Adv %s, currently %s, flood control %u", |
d62a17ae | 8185 | advertise ? "enabled" : "disabled", |
fbac9605 DS |
8186 | is_evpn_enabled() ? "enabled" : "disabled", |
8187 | flood_ctrl); | |
13d60d35 | 8188 | |
d62a17ae | 8189 | if (zvrf->advertise_all_vni == advertise) |
8068a649 | 8190 | return; |
13d60d35 | 8191 | |
d62a17ae | 8192 | zvrf->advertise_all_vni = advertise; |
2853fed6 | 8193 | if (is_evpn_enabled()) { |
fbac9605 DS |
8194 | /* Note BUM handling */ |
8195 | zvrf->vxlan_flood_ctrl = flood_ctrl; | |
8196 | ||
d62a17ae | 8197 | /* Build VNI hash table and inform BGP. */ |
2853fed6 | 8198 | zvni_build_hash_table(); |
2232a77c | 8199 | |
1a98c087 MK |
8200 | /* Add all SVI (L3 GW) MACs to BGP*/ |
8201 | hash_iterate(zvrf->vni_table, zvni_gw_macip_add_for_vni_hash, | |
2853fed6 | 8202 | NULL); |
1a98c087 | 8203 | |
d62a17ae | 8204 | /* Read the MAC FDB */ |
8205 | macfdb_read(zvrf->zns); | |
2232a77c | 8206 | |
d62a17ae | 8207 | /* Read neighbors */ |
8208 | neigh_read(zvrf->zns); | |
8209 | } else { | |
8210 | /* Cleanup VTEPs for all VNIs - uninstall from | |
8211 | * kernel and free entries. | |
8212 | */ | |
8213 | hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf); | |
655b04d1 MK |
8214 | |
8215 | /* cleanup all l3vnis */ | |
89272910 | 8216 | hash_iterate(zrouter.l3vni_table, zl3vni_cleanup_all, NULL); |
d62a17ae | 8217 | } |
13d60d35 | 8218 | |
ec93aa12 | 8219 | stream_failure: |
8068a649 | 8220 | return; |
13d60d35 | 8221 | } |
8222 | ||
8223 | /* | |
8224 | * Allocate VNI hash table for this VRF and do other initialization. | |
8225 | * NOTE: Currently supported only for default VRF. | |
8226 | */ | |
d62a17ae | 8227 | void zebra_vxlan_init_tables(struct zebra_vrf *zvrf) |
13d60d35 | 8228 | { |
d62a17ae | 8229 | if (!zvrf) |
8230 | return; | |
8231 | zvrf->vni_table = hash_create(vni_hash_keymake, vni_hash_cmp, | |
8232 | "Zebra VRF VNI Table"); | |
13d60d35 | 8233 | } |
8234 | ||
84915b0a | 8235 | /* Cleanup VNI info, but don't free the table. */ |
8236 | void zebra_vxlan_cleanup_tables(struct zebra_vrf *zvrf) | |
8237 | { | |
8238 | if (!zvrf) | |
8239 | return; | |
8240 | hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf); | |
8241 | } | |
8242 | ||
13d60d35 | 8243 | /* Close all VNI handling */ |
d62a17ae | 8244 | void zebra_vxlan_close_tables(struct zebra_vrf *zvrf) |
13d60d35 | 8245 | { |
2853fed6 | 8246 | if (!zvrf) |
8247 | return; | |
d62a17ae | 8248 | hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf); |
9b67b514 | 8249 | hash_free(zvrf->vni_table); |
13d60d35 | 8250 | } |
b7cfce93 MK |
8251 | |
8252 | /* init the l3vni table */ | |
8253 | void zebra_vxlan_ns_init(struct zebra_ns *zns) | |
8254 | { | |
89272910 DS |
8255 | zrouter.l3vni_table = hash_create(l3vni_hash_keymake, l3vni_hash_cmp, |
8256 | "Zebra VRF L3 VNI table"); | |
b7cfce93 MK |
8257 | } |
8258 | ||
8259 | /* free l3vni table */ | |
8260 | void zebra_vxlan_ns_disable(struct zebra_ns *zns) | |
8261 | { | |
89272910 | 8262 | hash_free(zrouter.l3vni_table); |
b7cfce93 | 8263 | } |
d3135ba3 | 8264 | |
8265 | /* get the l3vni svi ifindex */ | |
8266 | ifindex_t get_l3vni_svi_ifindex(vrf_id_t vrf_id) | |
8267 | { | |
8268 | zebra_l3vni_t *zl3vni = NULL; | |
8269 | ||
8270 | zl3vni = zl3vni_from_vrf(vrf_id); | |
8271 | if (!zl3vni || !is_l3vni_oper_up(zl3vni)) | |
8272 | return 0; | |
8273 | ||
8274 | return zl3vni->svi_if->ifindex; | |
8275 | } | |
c80a972c CS |
8276 | |
8277 | static int zebra_vxlan_dad_ip_auto_recovery_exp(struct thread *t) | |
8278 | { | |
8279 | struct zebra_vrf *zvrf = NULL; | |
8280 | zebra_neigh_t *nbr = NULL; | |
8281 | zebra_vni_t *zvni = NULL; | |
8282 | char buf1[INET6_ADDRSTRLEN]; | |
8283 | char buf2[ETHER_ADDR_STRLEN]; | |
8284 | ||
8285 | nbr = THREAD_ARG(t); | |
8286 | ||
8287 | /* since this is asynchronous we need sanity checks*/ | |
8288 | zvrf = vrf_info_lookup(nbr->zvni->vrf_id); | |
8289 | if (!zvrf) | |
8290 | goto exit; | |
8291 | ||
8292 | zvni = zvni_lookup(nbr->zvni->vni); | |
8293 | if (!zvni) | |
8294 | goto exit; | |
8295 | ||
8296 | nbr = zvni_neigh_lookup(zvni, &nbr->ip); | |
8297 | if (!nbr) | |
8298 | goto exit; | |
8299 | ||
8300 | if (IS_ZEBRA_DEBUG_VXLAN) | |
8301 | zlog_debug("%s: duplicate addr MAC %s IP %s flags 0x%x learn count %u vni %u auto recovery expired", | |
8302 | __PRETTY_FUNCTION__, | |
8303 | prefix_mac2str(&nbr->emac, buf1, sizeof(buf1)), | |
8304 | ipaddr2str(&nbr->ip, buf2, sizeof(buf2)), | |
8305 | nbr->flags, | |
8306 | nbr->dad_count, zvni->vni); | |
8307 | ||
8308 | UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
8309 | nbr->dad_count = 0; | |
8310 | nbr->detect_start_time.tv_sec = 0; | |
8311 | nbr->detect_start_time.tv_usec = 0; | |
8312 | nbr->dad_dup_detect_time = 0; | |
8313 | nbr->dad_ip_auto_recovery_timer = NULL; | |
8314 | ||
8315 | /* Send to BGP */ | |
8316 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) { | |
8317 | zvni_neigh_send_add_to_client(zvni->vni, &nbr->ip, &nbr->emac, | |
8318 | nbr->flags, nbr->loc_seq); | |
8319 | } else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) { | |
8320 | zvni_neigh_install(zvni, nbr); | |
8321 | } | |
8322 | ||
8323 | exit: | |
8324 | return 0; | |
8325 | } | |
8326 | ||
8327 | static int zebra_vxlan_dad_mac_auto_recovery_exp(struct thread *t) | |
8328 | { | |
8329 | struct zebra_vrf *zvrf = NULL; | |
8330 | zebra_mac_t *mac = NULL; | |
8331 | zebra_vni_t *zvni = NULL; | |
8332 | struct listnode *node = NULL; | |
8333 | zebra_neigh_t *nbr = NULL; | |
8334 | char buf[ETHER_ADDR_STRLEN]; | |
8335 | ||
8336 | mac = THREAD_ARG(t); | |
8337 | ||
8338 | /* since this is asynchronous we need sanity checks*/ | |
8339 | zvrf = vrf_info_lookup(mac->zvni->vrf_id); | |
8340 | if (!zvrf) | |
8341 | goto exit; | |
8342 | ||
8343 | zvni = zvni_lookup(mac->zvni->vni); | |
8344 | if (!zvni) | |
8345 | goto exit; | |
8346 | ||
8347 | mac = zvni_mac_lookup(zvni, &mac->macaddr); | |
8348 | if (!mac) | |
8349 | goto exit; | |
8350 | ||
8351 | if (IS_ZEBRA_DEBUG_VXLAN) | |
8352 | zlog_debug("%s: duplicate addr mac %s flags 0x%x learn count %u host count %u auto recovery expired", | |
8353 | __PRETTY_FUNCTION__, | |
8354 | prefix_mac2str(&mac->macaddr, buf, sizeof(buf)), | |
8355 | mac->flags, | |
8356 | mac->dad_count, | |
8357 | listcount(mac->neigh_list)); | |
8358 | ||
8359 | /* Remove all IPs as duplicate associcated with this MAC */ | |
8360 | for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) { | |
8361 | if (nbr->dad_count) { | |
8362 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) | |
8363 | ZEBRA_NEIGH_SET_INACTIVE(nbr); | |
8364 | else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) | |
8365 | zvni_neigh_install(zvni, nbr); | |
8366 | } | |
8367 | ||
8368 | UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
8369 | nbr->dad_count = 0; | |
8370 | nbr->detect_start_time.tv_sec = 0; | |
8371 | nbr->dad_dup_detect_time = 0; | |
8372 | } | |
8373 | ||
8374 | UNSET_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE); | |
8375 | mac->dad_count = 0; | |
8376 | mac->detect_start_time.tv_sec = 0; | |
8377 | mac->detect_start_time.tv_usec = 0; | |
8378 | mac->dad_dup_detect_time = 0; | |
8379 | mac->dad_mac_auto_recovery_timer = NULL; | |
8380 | ||
8381 | if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) { | |
8382 | /* Inform to BGP */ | |
8383 | if (zvni_mac_send_add_to_client(zvni->vni, &mac->macaddr, | |
8384 | mac->flags, mac->loc_seq)) | |
8385 | return -1; | |
8386 | ||
8387 | /* Process all neighbors associated with this MAC. */ | |
8388 | zvni_process_neigh_on_local_mac_change(zvni, mac, 0); | |
8389 | ||
8390 | } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { | |
8391 | zvni_process_neigh_on_remote_mac_add(zvni, mac); | |
8392 | ||
8393 | /* Install the entry. */ | |
8394 | zvni_mac_install(zvni, mac); | |
8395 | } | |
8396 | ||
8397 | exit: | |
8398 | return 0; | |
8399 | } |