]>
Commit | Line | Data |
---|---|---|
6336e12b | 1 | /* |
7cbae20a | 2 | * Zebra EVPN Neighbor code |
6336e12b PR |
3 | * Copyright (C) 2016, 2017 Cumulus Networks, Inc. |
4 | * | |
5 | * This file is part of FRR. | |
6 | * | |
7 | * FRR is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2, or (at your option) any | |
10 | * later version. | |
11 | * | |
12 | * FRR is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with FRR; see the file COPYING. If not, write to the Free | |
19 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
20 | * 02111-1307, USA. | |
21 | */ | |
22 | ||
23 | #include <zebra.h> | |
24 | ||
25 | #include "hash.h" | |
7cbae20a | 26 | #include "interface.h" |
6336e12b | 27 | #include "jhash.h" |
6336e12b PR |
28 | #include "memory.h" |
29 | #include "prefix.h" | |
6336e12b | 30 | #include "vlan.h" |
7cbae20a | 31 | #include "json.h" |
6336e12b | 32 | |
7cbae20a | 33 | #include "zebra/zserv.h" |
6336e12b | 34 | #include "zebra/debug.h" |
7cbae20a | 35 | #include "zebra/zebra_router.h" |
6336e12b | 36 | #include "zebra/rt.h" |
7cbae20a | 37 | #include "zebra/zebra_errors.h" |
6336e12b | 38 | #include "zebra/zebra_vrf.h" |
6336e12b | 39 | #include "zebra/zebra_evpn.h" |
6336e12b | 40 | #include "zebra/zebra_evpn_mh.h" |
7cbae20a PR |
41 | #include "zebra/zebra_evpn_neigh.h" |
42 | #include "zebra/zebra_evpn_mac.h" | |
43 | ||
44 | DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "EVI Neighbor"); | |
6336e12b | 45 | |
7cbae20a PR |
46 | /* |
47 | * Make hash key for neighbors. | |
48 | */ | |
49 | static unsigned int neigh_hash_keymake(const void *p) | |
6336e12b | 50 | { |
72de4110 | 51 | const struct zebra_neigh *n = p; |
7cbae20a | 52 | const struct ipaddr *ip = &n->ip; |
6336e12b | 53 | |
7cbae20a PR |
54 | if (IS_IPADDR_V4(ip)) |
55 | return jhash_1word(ip->ipaddr_v4.s_addr, 0); | |
6336e12b | 56 | |
7cbae20a PR |
57 | return jhash2(ip->ipaddr_v6.s6_addr32, |
58 | array_size(ip->ipaddr_v6.s6_addr32), 0); | |
59 | } | |
6336e12b | 60 | |
7cbae20a PR |
61 | /* |
62 | * Compare two neighbor hash structures. | |
63 | */ | |
64 | static bool neigh_cmp(const void *p1, const void *p2) | |
65 | { | |
72de4110 DS |
66 | const struct zebra_neigh *n1 = p1; |
67 | const struct zebra_neigh *n2 = p2; | |
6336e12b | 68 | |
7cbae20a PR |
69 | if (n1 == NULL && n2 == NULL) |
70 | return true; | |
6336e12b | 71 | |
7cbae20a PR |
72 | if (n1 == NULL || n2 == NULL) |
73 | return false; | |
6336e12b | 74 | |
7cbae20a | 75 | return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0); |
6336e12b | 76 | } |
6336e12b | 77 | |
7cbae20a | 78 | int neigh_list_cmp(void *p1, void *p2) |
6336e12b | 79 | { |
72de4110 DS |
80 | const struct zebra_neigh *n1 = p1; |
81 | const struct zebra_neigh *n2 = p2; | |
6336e12b | 82 | |
7cbae20a PR |
83 | return memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)); |
84 | } | |
6336e12b | 85 | |
7cbae20a PR |
86 | struct hash *zebra_neigh_db_create(const char *desc) |
87 | { | |
da55bcbc | 88 | return hash_create_size(8, neigh_hash_keymake, neigh_cmp, desc); |
6336e12b PR |
89 | } |
90 | ||
f6371c34 | 91 | uint32_t num_dup_detected_neighs(struct zebra_evpn *zevpn) |
6336e12b PR |
92 | { |
93 | unsigned int i; | |
94 | uint32_t num_neighs = 0; | |
95 | struct hash *hash; | |
96 | struct hash_bucket *hb; | |
72de4110 | 97 | struct zebra_neigh *nbr; |
6336e12b PR |
98 | |
99 | hash = zevpn->neigh_table; | |
100 | if (!hash) | |
101 | return num_neighs; | |
102 | for (i = 0; i < hash->size; i++) { | |
103 | for (hb = hash->index[i]; hb; hb = hb->next) { | |
72de4110 | 104 | nbr = (struct zebra_neigh *)hb->data; |
6336e12b PR |
105 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) |
106 | num_neighs++; | |
107 | } | |
108 | } | |
109 | ||
110 | return num_neighs; | |
111 | } | |
112 | ||
7cbae20a PR |
113 | /* |
114 | * Helper function to determine maximum width of neighbor IP address for | |
115 | * display - just because we're dealing with IPv6 addresses that can | |
116 | * widely vary. | |
117 | */ | |
118 | void zebra_evpn_find_neigh_addr_width(struct hash_bucket *bucket, void *ctxt) | |
6336e12b | 119 | { |
72de4110 | 120 | struct zebra_neigh *n; |
7cbae20a PR |
121 | char buf[INET6_ADDRSTRLEN]; |
122 | struct neigh_walk_ctx *wctx = ctxt; | |
123 | int width; | |
6336e12b | 124 | |
72de4110 | 125 | n = (struct zebra_neigh *)bucket->data; |
6336e12b | 126 | |
7cbae20a PR |
127 | ipaddr2str(&n->ip, buf, sizeof(buf)); |
128 | width = strlen(buf); | |
129 | if (width > wctx->addr_width) | |
130 | wctx->addr_width = width; | |
131 | } | |
6336e12b | 132 | |
7cbae20a PR |
133 | /* |
134 | * Count of remote neighbors referencing this MAC. | |
135 | */ | |
3198b2b3 | 136 | int remote_neigh_count(struct zebra_mac *zmac) |
7cbae20a | 137 | { |
72de4110 | 138 | struct zebra_neigh *n = NULL; |
7cbae20a PR |
139 | struct listnode *node = NULL; |
140 | int count = 0; | |
141 | ||
142 | for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { | |
143 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) | |
144 | count++; | |
145 | } | |
146 | ||
147 | return count; | |
6336e12b PR |
148 | } |
149 | ||
7cbae20a PR |
150 | /* |
151 | * Install remote neighbor into the kernel. | |
152 | */ | |
72de4110 DS |
153 | int zebra_evpn_rem_neigh_install(struct zebra_evpn *zevpn, |
154 | struct zebra_neigh *n, bool was_static) | |
6336e12b | 155 | { |
7cbae20a PR |
156 | struct interface *vlan_if; |
157 | int flags; | |
158 | int ret = 0; | |
6336e12b | 159 | |
7cbae20a PR |
160 | if (!(n->flags & ZEBRA_NEIGH_REMOTE)) |
161 | return 0; | |
6336e12b | 162 | |
7cbae20a PR |
163 | vlan_if = zevpn_map_to_svi(zevpn); |
164 | if (!vlan_if) | |
165 | return -1; | |
6336e12b | 166 | |
7cbae20a PR |
167 | flags = DPLANE_NTF_EXT_LEARNED; |
168 | if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG) | |
169 | flags |= DPLANE_NTF_ROUTER; | |
170 | ZEBRA_NEIGH_SET_ACTIVE(n); | |
171 | ||
172 | dplane_rem_neigh_add(vlan_if, &n->ip, &n->emac, flags, was_static); | |
173 | ||
174 | return ret; | |
6336e12b PR |
175 | } |
176 | ||
7cbae20a PR |
177 | /* |
178 | * Install neighbor hash entry - called upon access VLAN change. | |
6336e12b | 179 | */ |
7cbae20a | 180 | void zebra_evpn_install_neigh_hash(struct hash_bucket *bucket, void *ctxt) |
6336e12b | 181 | { |
72de4110 | 182 | struct zebra_neigh *n; |
7cbae20a | 183 | struct neigh_walk_ctx *wctx = ctxt; |
6336e12b | 184 | |
72de4110 | 185 | n = (struct zebra_neigh *)bucket->data; |
6336e12b | 186 | |
7cbae20a PR |
187 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) |
188 | zebra_evpn_rem_neigh_install(wctx->zevpn, n, | |
189 | false /*was_static*/); | |
6336e12b PR |
190 | } |
191 | ||
7cbae20a PR |
192 | /* |
193 | * Callback to allocate neighbor hash entry. | |
194 | */ | |
195 | static void *zebra_evpn_neigh_alloc(void *p) | |
6336e12b | 196 | { |
72de4110 DS |
197 | const struct zebra_neigh *tmp_n = p; |
198 | struct zebra_neigh *n; | |
6336e12b | 199 | |
72de4110 | 200 | n = XCALLOC(MTYPE_NEIGH, sizeof(struct zebra_neigh)); |
7cbae20a | 201 | *n = *tmp_n; |
6336e12b | 202 | |
7cbae20a PR |
203 | return ((void *)n); |
204 | } | |
205 | ||
72de4110 | 206 | static void zebra_evpn_local_neigh_ref_mac(struct zebra_neigh *n, |
1a3bd37f | 207 | const struct ethaddr *macaddr, |
3198b2b3 | 208 | struct zebra_mac *mac, |
7cbae20a PR |
209 | bool send_mac_update) |
210 | { | |
7cbae20a PR |
211 | bool old_static; |
212 | bool new_static; | |
213 | ||
214 | memcpy(&n->emac, macaddr, ETH_ALEN); | |
215 | n->mac = mac; | |
216 | ||
217 | /* Link to new MAC */ | |
218 | if (!mac) | |
6336e12b PR |
219 | return; |
220 | ||
7cbae20a PR |
221 | listnode_add_sort(mac->neigh_list, n); |
222 | if (n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) { | |
223 | old_static = zebra_evpn_mac_is_static(mac); | |
224 | ++mac->sync_neigh_cnt; | |
225 | new_static = zebra_evpn_mac_is_static(mac); | |
226 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) | |
6336e12b | 227 | zlog_debug( |
ef7b8be4 DL |
228 | "sync-neigh ref mac vni %u ip %pIA mac %pEA ref %d", |
229 | n->zevpn->vni, &n->ip, &n->emac, | |
7cbae20a PR |
230 | mac->sync_neigh_cnt); |
231 | if ((old_static != new_static) && send_mac_update) | |
232 | /* program the local mac in the kernel */ | |
233 | zebra_evpn_sync_mac_dp_install( | |
234 | mac, false /*set_inactive*/, | |
235 | false /*force_clear_static*/, __func__); | |
236 | } | |
237 | } | |
6336e12b | 238 | |
7cbae20a | 239 | /* sync-path that is active on an ES peer */ |
72de4110 | 240 | static void zebra_evpn_sync_neigh_dp_install(struct zebra_neigh *n, |
33064a62 PR |
241 | bool set_inactive, |
242 | bool force_clear_static, | |
243 | const char *caller) | |
7cbae20a | 244 | { |
7cbae20a PR |
245 | struct zebra_ns *zns; |
246 | struct interface *ifp; | |
247 | bool set_static; | |
248 | bool set_router; | |
6336e12b | 249 | |
7cbae20a PR |
250 | zns = zebra_ns_lookup(NS_DEFAULT); |
251 | ifp = if_lookup_by_index_per_ns(zns, n->ifindex); | |
252 | if (!ifp) { | |
253 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) | |
254 | zlog_debug( | |
ef7b8be4 DL |
255 | "%s: dp-install sync-neigh vni %u ip %pIA mac %pEA if %d f 0x%x skipped", |
256 | caller, n->zevpn->vni, &n->ip, &n->emac, | |
7cbae20a | 257 | n->ifindex, n->flags); |
6336e12b PR |
258 | return; |
259 | } | |
260 | ||
7cbae20a PR |
261 | if (force_clear_static) |
262 | set_static = false; | |
263 | else | |
264 | set_static = zebra_evpn_neigh_is_static(n); | |
6336e12b | 265 | |
7cbae20a | 266 | set_router = !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); |
6336e12b | 267 | |
7cbae20a PR |
268 | /* XXX - this will change post integration with the new kernel */ |
269 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) | |
270 | set_inactive = true; | |
6336e12b | 271 | |
7cbae20a | 272 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) |
6336e12b | 273 | zlog_debug( |
ef7b8be4 DL |
274 | "%s: dp-install sync-neigh vni %u ip %pIA mac %pEA if %s(%d) f 0x%x%s%s%s", |
275 | caller, n->zevpn->vni, &n->ip, &n->emac, | |
7cbae20a PR |
276 | ifp->name, n->ifindex, n->flags, |
277 | set_router ? " router" : "", | |
278 | set_static ? " static" : "", | |
279 | set_inactive ? " inactive" : ""); | |
280 | dplane_local_neigh_add(ifp, &n->ip, &n->emac, set_router, set_static, | |
281 | set_inactive); | |
6336e12b PR |
282 | } |
283 | ||
284 | /* | |
7cbae20a | 285 | * Inform BGP about local neighbor addition. |
6336e12b | 286 | */ |
1a3bd37f MS |
287 | int zebra_evpn_neigh_send_add_to_client(vni_t vni, const struct ipaddr *ip, |
288 | const struct ethaddr *macaddr, | |
3198b2b3 DS |
289 | struct zebra_mac *zmac, |
290 | uint32_t neigh_flags, uint32_t seq) | |
6336e12b | 291 | { |
7cbae20a | 292 | uint8_t flags = 0; |
6336e12b | 293 | |
7cbae20a PR |
294 | if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) { |
295 | /* host reachability has not been verified locally */ | |
6336e12b | 296 | |
7cbae20a PR |
297 | /* if no ES peer is claiming reachability we can't advertise |
298 | * the entry | |
299 | */ | |
300 | if (!CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) | |
301 | return 0; | |
6336e12b | 302 | |
7cbae20a PR |
303 | /* ES peers are claiming reachability; we will |
304 | * advertise the entry but with a proxy flag | |
305 | */ | |
306 | SET_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT); | |
6336e12b PR |
307 | } |
308 | ||
7cbae20a PR |
309 | if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW)) |
310 | SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); | |
311 | /* Set router flag (R-bit) based on local neigh entry add */ | |
312 | if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ROUTER_FLAG)) | |
313 | SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); | |
314 | if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_SVI_IP)) | |
315 | SET_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP); | |
6336e12b | 316 | |
00a7710c AK |
317 | return zebra_evpn_macip_send_msg_to_client(vni, macaddr, ip, flags, seq, |
318 | ZEBRA_NEIGH_ACTIVE, zmac->es, | |
319 | ZEBRA_MACIP_ADD); | |
6336e12b PR |
320 | } |
321 | ||
322 | /* | |
7cbae20a | 323 | * Inform BGP about local neighbor deletion. |
6336e12b | 324 | */ |
7cbae20a PR |
325 | int zebra_evpn_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip, |
326 | struct ethaddr *macaddr, uint32_t flags, | |
327 | int state, bool force) | |
6336e12b | 328 | { |
7cbae20a PR |
329 | if (!force) { |
330 | if (CHECK_FLAG(flags, ZEBRA_NEIGH_LOCAL_INACTIVE) | |
331 | && !CHECK_FLAG(flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) | |
332 | /* the neigh was not advertised - nothing to delete */ | |
333 | return 0; | |
6336e12b PR |
334 | } |
335 | ||
7cbae20a PR |
336 | return zebra_evpn_macip_send_msg_to_client( |
337 | vni, macaddr, ip, flags, 0, state, NULL, ZEBRA_MACIP_DEL); | |
6336e12b PR |
338 | } |
339 | ||
72de4110 | 340 | static void zebra_evpn_neigh_send_add_del_to_client(struct zebra_neigh *n, |
33064a62 PR |
341 | bool old_bgp_ready, |
342 | bool new_bgp_ready) | |
6336e12b | 343 | { |
7cbae20a PR |
344 | if (new_bgp_ready) |
345 | zebra_evpn_neigh_send_add_to_client(n->zevpn->vni, &n->ip, | |
346 | &n->emac, n->mac, n->flags, | |
347 | n->loc_seq); | |
348 | else if (old_bgp_ready) | |
349 | zebra_evpn_neigh_send_del_to_client(n->zevpn->vni, &n->ip, | |
350 | &n->emac, n->flags, | |
351 | n->state, true /*force*/); | |
6336e12b PR |
352 | } |
353 | ||
7cbae20a PR |
354 | /* if the static flag associated with the neigh changes we need |
355 | * to update the sync-neigh references against the MAC | |
356 | * and inform the dataplane about the static flag changes. | |
6336e12b | 357 | */ |
72de4110 | 358 | void zebra_evpn_sync_neigh_static_chg(struct zebra_neigh *n, bool old_n_static, |
7cbae20a PR |
359 | bool new_n_static, bool defer_n_dp, |
360 | bool defer_mac_dp, const char *caller) | |
6336e12b | 361 | { |
3198b2b3 | 362 | struct zebra_mac *mac = n->mac; |
7cbae20a PR |
363 | bool old_mac_static; |
364 | bool new_mac_static; | |
6336e12b | 365 | |
7cbae20a PR |
366 | if (old_n_static == new_n_static) |
367 | return; | |
6336e12b | 368 | |
7cbae20a PR |
369 | /* update the neigh sync references in the dataplane. if |
370 | * the neigh is in the middle of updates the caller can | |
371 | * request for a defer | |
372 | */ | |
373 | if (!defer_n_dp) | |
374 | zebra_evpn_sync_neigh_dp_install(n, false /* set_inactive */, | |
375 | false /* force_clear_static */, | |
376 | __func__); | |
6336e12b | 377 | |
7cbae20a PR |
378 | if (!mac) |
379 | return; | |
6336e12b | 380 | |
7cbae20a PR |
381 | /* update the mac sync ref cnt */ |
382 | old_mac_static = zebra_evpn_mac_is_static(mac); | |
383 | if (new_n_static) { | |
384 | ++mac->sync_neigh_cnt; | |
385 | } else if (old_n_static) { | |
386 | if (mac->sync_neigh_cnt) | |
387 | --mac->sync_neigh_cnt; | |
6336e12b | 388 | } |
7cbae20a | 389 | new_mac_static = zebra_evpn_mac_is_static(mac); |
6336e12b | 390 | |
7cbae20a PR |
391 | /* update the mac sync references in the dataplane */ |
392 | if ((old_mac_static != new_mac_static) && !defer_mac_dp) | |
393 | zebra_evpn_sync_mac_dp_install(mac, false /* set_inactive */, | |
394 | false /* force_clear_static */, | |
395 | __func__); | |
6336e12b | 396 | |
7cbae20a PR |
397 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) |
398 | zlog_debug( | |
ef7b8be4 DL |
399 | "sync-neigh ref-chg vni %u ip %pIA mac %pEA f 0x%x %d%s%s%s%s by %s", |
400 | n->zevpn->vni, &n->ip, &n->emac, n->flags, | |
401 | mac->sync_neigh_cnt, | |
7cbae20a PR |
402 | old_n_static ? " old_n_static" : "", |
403 | new_n_static ? " new_n_static" : "", | |
404 | old_mac_static ? " old_mac_static" : "", | |
405 | new_mac_static ? " new_mac_static" : "", caller); | |
6336e12b PR |
406 | } |
407 | ||
7cbae20a PR |
408 | /* Neigh hold timer is used to age out peer-active flag. |
409 | * | |
410 | * During this wait time we expect the dataplane component or an | |
411 | * external neighmgr daemon to probe existing hosts to independently | |
412 | * establish their presence on the ES. | |
6336e12b | 413 | */ |
7cbae20a | 414 | static int zebra_evpn_neigh_hold_exp_cb(struct thread *t) |
6336e12b | 415 | { |
72de4110 | 416 | struct zebra_neigh *n; |
7cbae20a PR |
417 | bool old_bgp_ready; |
418 | bool new_bgp_ready; | |
419 | bool old_n_static; | |
420 | bool new_n_static; | |
7cbae20a PR |
421 | |
422 | n = THREAD_ARG(t); | |
423 | /* the purpose of the hold timer is to age out the peer-active | |
424 | * flag | |
425 | */ | |
426 | if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) | |
427 | return 0; | |
6336e12b | 428 | |
7cbae20a PR |
429 | old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); |
430 | old_n_static = zebra_evpn_neigh_is_static(n); | |
431 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE); | |
432 | new_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); | |
433 | new_n_static = zebra_evpn_neigh_is_static(n); | |
6336e12b | 434 | |
7cbae20a | 435 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) |
ef7b8be4 DL |
436 | zlog_debug("sync-neigh vni %u ip %pIA mac %pEA 0x%x hold expired", |
437 | n->zevpn->vni, &n->ip, &n->emac, n->flags); | |
6336e12b | 438 | |
7cbae20a PR |
439 | /* re-program the local neigh in the dataplane if the neigh is no |
440 | * longer static | |
441 | */ | |
442 | if (old_n_static != new_n_static) | |
443 | zebra_evpn_sync_neigh_static_chg( | |
444 | n, old_n_static, new_n_static, false /*defer_n_dp*/, | |
445 | false /*defer_mac_dp*/, __func__); | |
6336e12b | 446 | |
7cbae20a PR |
447 | /* inform bgp if needed */ |
448 | if (old_bgp_ready != new_bgp_ready) | |
449 | zebra_evpn_neigh_send_add_del_to_client(n, old_bgp_ready, | |
450 | new_bgp_ready); | |
6336e12b | 451 | |
6336e12b PR |
452 | return 0; |
453 | } | |
454 | ||
72de4110 | 455 | static inline void zebra_evpn_neigh_start_hold_timer(struct zebra_neigh *n) |
6336e12b | 456 | { |
7cbae20a PR |
457 | if (n->hold_timer) |
458 | return; | |
6336e12b | 459 | |
7cbae20a | 460 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) |
ef7b8be4 DL |
461 | zlog_debug("sync-neigh vni %u ip %pIA mac %pEA 0x%x hold start", |
462 | n->zevpn->vni, &n->ip, &n->emac, n->flags); | |
7cbae20a PR |
463 | thread_add_timer(zrouter.master, zebra_evpn_neigh_hold_exp_cb, n, |
464 | zmh_info->neigh_hold_time, &n->hold_timer); | |
465 | } | |
6336e12b | 466 | |
72de4110 | 467 | static void zebra_evpn_local_neigh_deref_mac(struct zebra_neigh *n, |
7cbae20a PR |
468 | bool send_mac_update) |
469 | { | |
3198b2b3 | 470 | struct zebra_mac *mac = n->mac; |
f6371c34 | 471 | struct zebra_evpn *zevpn = n->zevpn; |
7cbae20a PR |
472 | bool old_static; |
473 | bool new_static; | |
6336e12b | 474 | |
7cbae20a PR |
475 | n->mac = NULL; |
476 | if (!mac) | |
477 | return; | |
6336e12b | 478 | |
7cbae20a PR |
479 | if ((n->flags & ZEBRA_NEIGH_ALL_PEER_FLAGS) && mac->sync_neigh_cnt) { |
480 | old_static = zebra_evpn_mac_is_static(mac); | |
481 | --mac->sync_neigh_cnt; | |
482 | new_static = zebra_evpn_mac_is_static(mac); | |
483 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) | |
6336e12b | 484 | zlog_debug( |
ef7b8be4 DL |
485 | "sync-neigh deref mac vni %u ip %pIA mac %pEA ref %d", |
486 | n->zevpn->vni, &n->ip, &n->emac, | |
7cbae20a PR |
487 | mac->sync_neigh_cnt); |
488 | if ((old_static != new_static) && send_mac_update) | |
489 | /* program the local mac in the kernel */ | |
490 | zebra_evpn_sync_mac_dp_install( | |
491 | mac, false /* set_inactive */, | |
492 | false /* force_clear_static */, __func__); | |
6336e12b PR |
493 | } |
494 | ||
7cbae20a PR |
495 | listnode_delete(mac->neigh_list, n); |
496 | zebra_evpn_deref_ip2mac(zevpn, mac); | |
6336e12b PR |
497 | } |
498 | ||
72de4110 DS |
499 | bool zebra_evpn_neigh_is_bgp_seq_ok(struct zebra_evpn *zevpn, |
500 | struct zebra_neigh *n, | |
1a3bd37f | 501 | const struct ethaddr *macaddr, uint32_t seq, |
16de1338 | 502 | bool sync) |
6336e12b | 503 | { |
7cbae20a | 504 | uint32_t tmp_seq; |
16de1338 | 505 | const char *n_type; |
6336e12b | 506 | |
16de1338 | 507 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { |
7cbae20a | 508 | tmp_seq = n->loc_seq; |
16de1338 AK |
509 | n_type = "local"; |
510 | } else { | |
7cbae20a | 511 | tmp_seq = n->rem_seq; |
16de1338 AK |
512 | n_type = "remote"; |
513 | } | |
6336e12b | 514 | |
7cbae20a PR |
515 | if (seq < tmp_seq) { |
516 | /* if the neigh was never advertised to bgp we must accept | |
517 | * whatever sequence number bgp sends | |
518 | * XXX - check with Vivek | |
519 | */ | |
520 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) | |
521 | && !zebra_evpn_neigh_is_ready_for_bgp(n)) { | |
16de1338 AK |
522 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH |
523 | || IS_ZEBRA_DEBUG_VXLAN) | |
7cbae20a | 524 | zlog_debug( |
ef7b8be4 | 525 | "%s-macip accept vni %u %s mac %pEA IP %pIA lower seq %u f 0x%x", |
16de1338 | 526 | sync ? "sync" : "remote", zevpn->vni, |
ef7b8be4 | 527 | n_type, macaddr, &n->ip, |
7cbae20a PR |
528 | tmp_seq, n->flags); |
529 | return true; | |
530 | } | |
6336e12b | 531 | |
16de1338 | 532 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH || IS_ZEBRA_DEBUG_VXLAN) |
7cbae20a | 533 | zlog_debug( |
ef7b8be4 | 534 | "%s-macip ignore vni %u %s mac %pEA IP %pIA as existing has higher seq %u f 0x%x", |
16de1338 | 535 | sync ? "sync" : "remote", zevpn->vni, n_type, |
ef7b8be4 | 536 | macaddr, &n->ip, tmp_seq, n->flags); |
7cbae20a | 537 | return false; |
6336e12b | 538 | } |
7cbae20a PR |
539 | |
540 | return true; | |
6336e12b PR |
541 | } |
542 | ||
543 | /* | |
7cbae20a | 544 | * Add neighbor entry. |
6336e12b | 545 | */ |
72de4110 DS |
546 | static struct zebra_neigh *zebra_evpn_neigh_add(struct zebra_evpn *zevpn, |
547 | const struct ipaddr *ip, | |
548 | const struct ethaddr *mac, | |
549 | struct zebra_mac *zmac, | |
550 | uint32_t n_flags) | |
6336e12b | 551 | { |
72de4110 DS |
552 | struct zebra_neigh tmp_n; |
553 | struct zebra_neigh *n = NULL; | |
6336e12b | 554 | |
72de4110 | 555 | memset(&tmp_n, 0, sizeof(struct zebra_neigh)); |
7cbae20a PR |
556 | memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr)); |
557 | n = hash_get(zevpn->neigh_table, &tmp_n, zebra_evpn_neigh_alloc); | |
558 | assert(n); | |
6336e12b | 559 | |
7cbae20a PR |
560 | n->state = ZEBRA_NEIGH_INACTIVE; |
561 | n->zevpn = zevpn; | |
562 | n->dad_ip_auto_recovery_timer = NULL; | |
563 | n->flags = n_flags; | |
a05111ba | 564 | n->uptime = monotime(NULL); |
6336e12b | 565 | |
7cbae20a PR |
566 | if (!zmac) |
567 | zmac = zebra_evpn_mac_lookup(zevpn, mac); | |
568 | zebra_evpn_local_neigh_ref_mac(n, mac, zmac, | |
569 | false /* send_mac_update */); | |
6336e12b | 570 | |
7cbae20a | 571 | return n; |
6336e12b PR |
572 | } |
573 | ||
574 | /* | |
7cbae20a | 575 | * Delete neighbor entry. |
6336e12b | 576 | */ |
72de4110 | 577 | int zebra_evpn_neigh_del(struct zebra_evpn *zevpn, struct zebra_neigh *n) |
6336e12b | 578 | { |
72de4110 | 579 | struct zebra_neigh *tmp_n; |
6336e12b | 580 | |
7cbae20a PR |
581 | if (n->mac) |
582 | listnode_delete(n->mac->neigh_list, n); | |
6336e12b | 583 | |
7cbae20a PR |
584 | /* Cancel auto recovery */ |
585 | THREAD_OFF(n->dad_ip_auto_recovery_timer); | |
6336e12b | 586 | |
2b9e207e AK |
587 | /* Cancel proxy hold timer */ |
588 | zebra_evpn_neigh_stop_hold_timer(n); | |
589 | ||
7cbae20a PR |
590 | /* Free the VNI hash entry and allocated memory. */ |
591 | tmp_n = hash_release(zevpn->neigh_table, n); | |
592 | XFREE(MTYPE_NEIGH, tmp_n); | |
6336e12b PR |
593 | |
594 | return 0; | |
595 | } | |
596 | ||
72de4110 | 597 | void zebra_evpn_sync_neigh_del(struct zebra_neigh *n) |
6336e12b | 598 | { |
7cbae20a PR |
599 | bool old_n_static; |
600 | bool new_n_static; | |
6336e12b | 601 | |
7cbae20a | 602 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) |
ef7b8be4 DL |
603 | zlog_debug("sync-neigh del vni %u ip %pIA mac %pEA f 0x%x", |
604 | n->zevpn->vni, &n->ip, &n->emac, n->flags); | |
6336e12b | 605 | |
7cbae20a PR |
606 | old_n_static = zebra_evpn_neigh_is_static(n); |
607 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY); | |
608 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) | |
609 | zebra_evpn_neigh_start_hold_timer(n); | |
610 | new_n_static = zebra_evpn_neigh_is_static(n); | |
6336e12b | 611 | |
7cbae20a PR |
612 | if (old_n_static != new_n_static) |
613 | zebra_evpn_sync_neigh_static_chg( | |
614 | n, old_n_static, new_n_static, false /*defer-dp*/, | |
615 | false /*defer_mac_dp*/, __func__); | |
616 | } | |
6336e12b | 617 | |
72de4110 DS |
618 | struct zebra_neigh *zebra_evpn_proc_sync_neigh_update( |
619 | struct zebra_evpn *zevpn, struct zebra_neigh *n, uint16_t ipa_len, | |
620 | const struct ipaddr *ipaddr, uint8_t flags, uint32_t seq, | |
621 | const esi_t *esi, struct sync_mac_ip_ctx *ctx) | |
7cbae20a PR |
622 | { |
623 | struct interface *ifp = NULL; | |
624 | bool is_router; | |
3198b2b3 | 625 | struct zebra_mac *mac = ctx->mac; |
7cbae20a PR |
626 | uint32_t tmp_seq; |
627 | bool old_router = false; | |
628 | bool old_bgp_ready = false; | |
629 | bool new_bgp_ready; | |
630 | bool inform_dataplane = false; | |
631 | bool inform_bgp = false; | |
632 | bool old_mac_static; | |
633 | bool new_mac_static; | |
634 | bool set_dp_inactive = false; | |
7cbae20a PR |
635 | bool created; |
636 | ifindex_t ifindex = 0; | |
6336e12b | 637 | |
7cbae20a PR |
638 | /* locate l3-svi */ |
639 | ifp = zevpn_map_to_svi(zevpn); | |
640 | if (ifp) | |
641 | ifindex = ifp->ifindex; | |
6336e12b | 642 | |
7cbae20a PR |
643 | is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); |
644 | old_mac_static = zebra_evpn_mac_is_static(mac); | |
6336e12b | 645 | |
7cbae20a PR |
646 | if (!n) { |
647 | uint32_t n_flags = 0; | |
6336e12b | 648 | |
7cbae20a PR |
649 | /* New neighbor - create */ |
650 | SET_FLAG(n_flags, ZEBRA_NEIGH_LOCAL); | |
651 | if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) | |
652 | SET_FLAG(n_flags, ZEBRA_NEIGH_ES_PEER_PROXY); | |
653 | else | |
654 | SET_FLAG(n_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE); | |
655 | SET_FLAG(n_flags, ZEBRA_NEIGH_LOCAL_INACTIVE); | |
6336e12b | 656 | |
7cbae20a PR |
657 | n = zebra_evpn_neigh_add(zevpn, ipaddr, &mac->macaddr, mac, |
658 | n_flags); | |
659 | n->ifindex = ifindex; | |
660 | ZEBRA_NEIGH_SET_ACTIVE(n); | |
6336e12b | 661 | |
7cbae20a PR |
662 | created = true; |
663 | inform_dataplane = true; | |
664 | inform_bgp = true; | |
665 | set_dp_inactive = true; | |
666 | } else { | |
667 | bool mac_change; | |
668 | uint32_t old_flags = n->flags; | |
669 | bool old_n_static; | |
670 | bool new_n_static; | |
6336e12b | 671 | |
7cbae20a PR |
672 | created = false; |
673 | old_n_static = zebra_evpn_neigh_is_static(n); | |
674 | old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); | |
675 | old_router = !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
6336e12b | 676 | |
7cbae20a PR |
677 | mac_change = !!memcmp(&n->emac, &mac->macaddr, ETH_ALEN); |
678 | ||
679 | /* deref and clear old info */ | |
680 | if (mac_change) { | |
681 | if (old_bgp_ready) { | |
682 | zebra_evpn_neigh_send_del_to_client( | |
683 | zevpn->vni, &n->ip, &n->emac, n->flags, | |
684 | n->state, false /*force*/); | |
685 | old_bgp_ready = false; | |
6336e12b | 686 | } |
bc3cd39b DS |
687 | zebra_evpn_local_neigh_deref_mac(n, |
688 | false /*send_mac_update*/); | |
6336e12b | 689 | } |
7cbae20a PR |
690 | /* clear old fwd info */ |
691 | n->rem_seq = 0; | |
692 | n->r_vtep_ip.s_addr = 0; | |
6336e12b | 693 | |
7cbae20a PR |
694 | /* setup new flags */ |
695 | n->flags = 0; | |
696 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
697 | /* retain activity flag if the neigh was | |
698 | * previously local | |
6336e12b | 699 | */ |
7cbae20a PR |
700 | if (old_flags & ZEBRA_NEIGH_LOCAL) { |
701 | n->flags |= (old_flags & ZEBRA_NEIGH_LOCAL_INACTIVE); | |
702 | } else { | |
703 | inform_dataplane = true; | |
704 | set_dp_inactive = true; | |
705 | n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE; | |
6336e12b PR |
706 | } |
707 | ||
7cbae20a PR |
708 | if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) |
709 | SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY); | |
710 | else | |
711 | SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE); | |
6336e12b | 712 | |
7cbae20a PR |
713 | if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) { |
714 | SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY); | |
715 | /* if the neigh was peer-active previously we | |
716 | * need to keep the flag and start the | |
717 | * holdtimer on it. the peer-active flag is | |
718 | * cleared on holdtimer expiry. | |
719 | */ | |
720 | if (CHECK_FLAG(old_flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) { | |
721 | SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE); | |
722 | zebra_evpn_neigh_start_hold_timer(n); | |
723 | } | |
724 | } else { | |
725 | SET_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE); | |
726 | /* stop hold timer if a peer has verified | |
727 | * reachability | |
728 | */ | |
729 | zebra_evpn_neigh_stop_hold_timer(n); | |
6336e12b | 730 | } |
7cbae20a | 731 | ZEBRA_NEIGH_SET_ACTIVE(n); |
6336e12b | 732 | |
7cbae20a | 733 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH && (old_flags != n->flags)) |
6336e12b | 734 | zlog_debug( |
ef7b8be4 DL |
735 | "sync-neigh vni %u ip %pIA mac %pEA old_f 0x%x new_f 0x%x", |
736 | n->zevpn->vni, &n->ip, &n->emac, | |
7cbae20a | 737 | old_flags, n->flags); |
6336e12b | 738 | |
7cbae20a PR |
739 | new_n_static = zebra_evpn_neigh_is_static(n); |
740 | if (mac_change) { | |
741 | set_dp_inactive = true; | |
742 | n->flags |= ZEBRA_NEIGH_LOCAL_INACTIVE; | |
743 | inform_dataplane = true; | |
744 | zebra_evpn_local_neigh_ref_mac( | |
745 | n, &mac->macaddr, mac, | |
746 | false /*send_mac_update*/); | |
747 | } else if (old_n_static != new_n_static) { | |
748 | inform_dataplane = true; | |
749 | /* if static flags have changed without a mac change | |
750 | * we need to create the correct sync-refs against | |
751 | * the existing mac | |
6336e12b | 752 | */ |
7cbae20a PR |
753 | zebra_evpn_sync_neigh_static_chg( |
754 | n, old_n_static, new_n_static, | |
755 | true /*defer_dp*/, true /*defer_mac_dp*/, | |
756 | __func__); | |
6336e12b | 757 | } |
6336e12b | 758 | |
7cbae20a PR |
759 | /* Update the forwarding info. */ |
760 | if (n->ifindex != ifindex) { | |
761 | n->ifindex = ifindex; | |
762 | inform_dataplane = true; | |
6336e12b | 763 | } |
a05111ba DS |
764 | |
765 | n->uptime = monotime(NULL); | |
6336e12b PR |
766 | } |
767 | ||
7cbae20a PR |
768 | /* update the neigh seq. we don't bother with the mac seq as |
769 | * sync_mac_update already took care of that | |
770 | */ | |
771 | tmp_seq = MAX(n->loc_seq, seq); | |
772 | if (tmp_seq != n->loc_seq) { | |
773 | n->loc_seq = tmp_seq; | |
774 | inform_bgp = true; | |
775 | } | |
6336e12b | 776 | |
7cbae20a PR |
777 | /* Mark Router flag (R-bit) */ |
778 | if (is_router) | |
779 | SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
780 | else | |
781 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
6336e12b | 782 | |
7cbae20a PR |
783 | if (old_router != is_router) |
784 | inform_dataplane = true; | |
6336e12b | 785 | |
7cbae20a PR |
786 | new_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); |
787 | if (old_bgp_ready != new_bgp_ready) | |
788 | inform_bgp = true; | |
6336e12b | 789 | |
7cbae20a PR |
790 | new_mac_static = zebra_evpn_mac_is_static(mac); |
791 | if ((old_mac_static != new_mac_static) || ctx->mac_dp_update_deferred) | |
792 | zebra_evpn_sync_mac_dp_install(mac, ctx->mac_inactive, | |
793 | false /* force_clear_static */, | |
794 | __func__); | |
6336e12b | 795 | |
7cbae20a PR |
796 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) |
797 | zlog_debug( | |
ef7b8be4 | 798 | "sync-neigh %s vni %u ip %pIA mac %pEA if %s(%d) seq %d f 0x%x%s%s", |
7cbae20a | 799 | created ? "created" : "updated", n->zevpn->vni, |
ef7b8be4 | 800 | &n->ip, &n->emac, |
7cbae20a PR |
801 | ifp ? ifp->name : "", ifindex, n->loc_seq, n->flags, |
802 | inform_bgp ? " inform_bgp" : "", | |
803 | inform_dataplane ? " inform_dp" : ""); | |
6336e12b | 804 | |
7cbae20a PR |
805 | if (inform_dataplane) |
806 | zebra_evpn_sync_neigh_dp_install(n, set_dp_inactive, | |
807 | false /* force_clear_static */, | |
808 | __func__); | |
6336e12b | 809 | |
7cbae20a PR |
810 | if (inform_bgp) |
811 | zebra_evpn_neigh_send_add_del_to_client(n, old_bgp_ready, | |
812 | new_bgp_ready); | |
6336e12b | 813 | |
7cbae20a PR |
814 | return n; |
815 | } | |
6336e12b | 816 | |
7cbae20a PR |
817 | /* |
818 | * Uninstall remote neighbor from the kernel. | |
819 | */ | |
f6371c34 | 820 | static int zebra_evpn_neigh_uninstall(struct zebra_evpn *zevpn, |
72de4110 | 821 | struct zebra_neigh *n) |
7cbae20a PR |
822 | { |
823 | struct interface *vlan_if; | |
6336e12b | 824 | |
7cbae20a PR |
825 | if (!(n->flags & ZEBRA_NEIGH_REMOTE)) |
826 | return 0; | |
6336e12b | 827 | |
7cbae20a PR |
828 | vlan_if = zevpn_map_to_svi(zevpn); |
829 | if (!vlan_if) | |
830 | return -1; | |
6336e12b | 831 | |
7cbae20a PR |
832 | ZEBRA_NEIGH_SET_INACTIVE(n); |
833 | n->loc_seq = 0; | |
6336e12b | 834 | |
7cbae20a | 835 | dplane_rem_neigh_delete(vlan_if, &n->ip); |
6336e12b PR |
836 | |
837 | return 0; | |
838 | } | |
839 | ||
7cbae20a PR |
840 | /* |
841 | * Free neighbor hash entry (callback) | |
842 | */ | |
843 | static void zebra_evpn_neigh_del_hash_entry(struct hash_bucket *bucket, | |
844 | void *arg) | |
6336e12b | 845 | { |
7cbae20a | 846 | struct neigh_walk_ctx *wctx = arg; |
72de4110 | 847 | struct zebra_neigh *n = bucket->data; |
6336e12b | 848 | |
7cbae20a PR |
849 | if (((wctx->flags & DEL_LOCAL_NEIGH) && (n->flags & ZEBRA_NEIGH_LOCAL)) |
850 | || ((wctx->flags & DEL_REMOTE_NEIGH) | |
851 | && (n->flags & ZEBRA_NEIGH_REMOTE)) | |
852 | || ((wctx->flags & DEL_REMOTE_NEIGH_FROM_VTEP) | |
853 | && (n->flags & ZEBRA_NEIGH_REMOTE) | |
854 | && IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) { | |
855 | if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL)) | |
856 | zebra_evpn_neigh_send_del_to_client( | |
857 | wctx->zevpn->vni, &n->ip, &n->emac, n->flags, | |
858 | n->state, false /*force*/); | |
6336e12b | 859 | |
7cbae20a PR |
860 | if (wctx->uninstall) { |
861 | if (zebra_evpn_neigh_is_static(n)) | |
862 | zebra_evpn_sync_neigh_dp_install( | |
863 | n, false /* set_inactive */, | |
864 | true /* force_clear_static */, | |
865 | __func__); | |
866 | if ((n->flags & ZEBRA_NEIGH_REMOTE)) | |
867 | zebra_evpn_neigh_uninstall(wctx->zevpn, n); | |
6336e12b PR |
868 | } |
869 | ||
7cbae20a PR |
870 | zebra_evpn_neigh_del(wctx->zevpn, n); |
871 | } | |
6336e12b | 872 | |
7cbae20a PR |
873 | return; |
874 | } | |
6336e12b | 875 | |
7cbae20a PR |
876 | /* |
877 | * Delete all neighbor entries for this EVPN. | |
878 | */ | |
f6371c34 | 879 | void zebra_evpn_neigh_del_all(struct zebra_evpn *zevpn, int uninstall, |
7cbae20a PR |
880 | int upd_client, uint32_t flags) |
881 | { | |
882 | struct neigh_walk_ctx wctx; | |
6336e12b | 883 | |
7cbae20a PR |
884 | if (!zevpn->neigh_table) |
885 | return; | |
6336e12b | 886 | |
7cbae20a PR |
887 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); |
888 | wctx.zevpn = zevpn; | |
889 | wctx.uninstall = uninstall; | |
890 | wctx.upd_client = upd_client; | |
891 | wctx.flags = flags; | |
6336e12b | 892 | |
7cbae20a PR |
893 | hash_iterate(zevpn->neigh_table, zebra_evpn_neigh_del_hash_entry, |
894 | &wctx); | |
895 | } | |
6336e12b | 896 | |
7cbae20a PR |
897 | /* |
898 | * Look up neighbor hash entry. | |
899 | */ | |
72de4110 DS |
900 | struct zebra_neigh *zebra_evpn_neigh_lookup(struct zebra_evpn *zevpn, |
901 | const struct ipaddr *ip) | |
7cbae20a | 902 | { |
72de4110 DS |
903 | struct zebra_neigh tmp; |
904 | struct zebra_neigh *n; | |
6336e12b | 905 | |
7cbae20a PR |
906 | memset(&tmp, 0, sizeof(tmp)); |
907 | memcpy(&tmp.ip, ip, sizeof(struct ipaddr)); | |
908 | n = hash_lookup(zevpn->neigh_table, &tmp); | |
6336e12b | 909 | |
7cbae20a PR |
910 | return n; |
911 | } | |
6336e12b | 912 | |
7cbae20a PR |
913 | /* |
914 | * Process all neighbors associated with a MAC upon the MAC being learnt | |
915 | * locally or undergoing any other change (such as sequence number). | |
916 | */ | |
f6371c34 | 917 | void zebra_evpn_process_neigh_on_local_mac_change(struct zebra_evpn *zevpn, |
3198b2b3 | 918 | struct zebra_mac *zmac, |
7cbae20a PR |
919 | bool seq_change, |
920 | bool es_change) | |
921 | { | |
72de4110 | 922 | struct zebra_neigh *n = NULL; |
7cbae20a PR |
923 | struct listnode *node = NULL; |
924 | struct zebra_vrf *zvrf = NULL; | |
6336e12b | 925 | |
7cbae20a | 926 | zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id); |
6336e12b | 927 | |
7cbae20a | 928 | if (IS_ZEBRA_DEBUG_VXLAN) |
ef7b8be4 DL |
929 | zlog_debug("Processing neighbors on local MAC %pEA %s, VNI %u", |
930 | &zmac->macaddr, seq_change ? "CHANGE" : "ADD", | |
931 | zevpn->vni); | |
6336e12b | 932 | |
7cbae20a PR |
933 | /* Walk all neighbors and mark any inactive local neighbors as |
934 | * active and/or update sequence number upon a move, and inform BGP. | |
935 | * The action for remote neighbors is TBD. | |
936 | * NOTE: We can't simply uninstall remote neighbors as the kernel may | |
937 | * accidentally end up deleting a just-learnt local neighbor. | |
938 | */ | |
939 | for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { | |
940 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
941 | if (IS_ZEBRA_NEIGH_INACTIVE(n) || seq_change | |
942 | || es_change) { | |
943 | ZEBRA_NEIGH_SET_ACTIVE(n); | |
944 | n->loc_seq = zmac->loc_seq; | |
b2ee2b71 AK |
945 | if (!(zebra_evpn_do_dup_addr_detect(zvrf) |
946 | && zvrf->dad_freeze | |
7cbae20a PR |
947 | && !!CHECK_FLAG(n->flags, |
948 | ZEBRA_NEIGH_DUPLICATE))) | |
949 | zebra_evpn_neigh_send_add_to_client( | |
950 | zevpn->vni, &n->ip, &n->emac, | |
951 | n->mac, n->flags, n->loc_seq); | |
952 | } | |
6336e12b | 953 | } |
7cbae20a PR |
954 | } |
955 | } | |
6336e12b | 956 | |
7cbae20a PR |
957 | /* |
958 | * Process all neighbors associated with a local MAC upon the MAC being | |
959 | * deleted. | |
960 | */ | |
f6371c34 | 961 | void zebra_evpn_process_neigh_on_local_mac_del(struct zebra_evpn *zevpn, |
3198b2b3 | 962 | struct zebra_mac *zmac) |
7cbae20a | 963 | { |
72de4110 | 964 | struct zebra_neigh *n = NULL; |
7cbae20a | 965 | struct listnode *node = NULL; |
6336e12b | 966 | |
7cbae20a | 967 | if (IS_ZEBRA_DEBUG_VXLAN) |
ef7b8be4 DL |
968 | zlog_debug("Processing neighbors on local MAC %pEA DEL, VNI %u", |
969 | &zmac->macaddr, zevpn->vni); | |
6336e12b | 970 | |
7cbae20a PR |
971 | /* Walk all local neighbors and mark as inactive and inform |
972 | * BGP, if needed. | |
973 | * TBD: There is currently no handling for remote neighbors. We | |
974 | * don't expect them to exist, if they do, do we install the MAC | |
975 | * as a remote MAC and the neighbor as remote? | |
976 | */ | |
977 | for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { | |
978 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
979 | if (IS_ZEBRA_NEIGH_ACTIVE(n)) { | |
980 | ZEBRA_NEIGH_SET_INACTIVE(n); | |
981 | n->loc_seq = 0; | |
982 | zebra_evpn_neigh_send_del_to_client( | |
983 | zevpn->vni, &n->ip, &n->emac, n->flags, | |
984 | ZEBRA_NEIGH_ACTIVE, false /*force*/); | |
985 | } | |
986 | } | |
6336e12b | 987 | } |
6336e12b PR |
988 | } |
989 | ||
7cbae20a PR |
990 | /* |
991 | * Process all neighbors associated with a MAC upon the MAC being remotely | |
992 | * learnt. | |
993 | */ | |
f6371c34 | 994 | void zebra_evpn_process_neigh_on_remote_mac_add(struct zebra_evpn *zevpn, |
3198b2b3 | 995 | struct zebra_mac *zmac) |
6336e12b | 996 | { |
72de4110 | 997 | struct zebra_neigh *n = NULL; |
7cbae20a | 998 | struct listnode *node = NULL; |
6336e12b | 999 | |
7cbae20a | 1000 | if (IS_ZEBRA_DEBUG_VXLAN) |
ef7b8be4 DL |
1001 | zlog_debug("Processing neighbors on remote MAC %pEA ADD, VNI %u", |
1002 | &zmac->macaddr, zevpn->vni); | |
6336e12b | 1003 | |
7cbae20a PR |
1004 | /* Walk all local neighbors and mark as inactive and inform |
1005 | * BGP, if needed. | |
1006 | */ | |
1007 | for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { | |
1008 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
1009 | if (IS_ZEBRA_NEIGH_ACTIVE(n)) { | |
1010 | ZEBRA_NEIGH_SET_INACTIVE(n); | |
1011 | n->loc_seq = 0; | |
1012 | zebra_evpn_neigh_send_del_to_client( | |
1013 | zevpn->vni, &n->ip, &n->emac, n->flags, | |
1014 | ZEBRA_NEIGH_ACTIVE, false /* force */); | |
1015 | } | |
1016 | } | |
1017 | } | |
6336e12b PR |
1018 | } |
1019 | ||
7cbae20a PR |
1020 | /* |
1021 | * Process all neighbors associated with a remote MAC upon the MAC being | |
1022 | * deleted. | |
1023 | */ | |
f6371c34 | 1024 | void zebra_evpn_process_neigh_on_remote_mac_del(struct zebra_evpn *zevpn, |
3198b2b3 | 1025 | struct zebra_mac *zmac) |
6336e12b | 1026 | { |
7cbae20a | 1027 | /* NOTE: Currently a NO-OP. */ |
6336e12b PR |
1028 | } |
1029 | ||
7cbae20a | 1030 | static inline void zebra_evpn_local_neigh_update_log( |
72de4110 DS |
1031 | const char *pfx, struct zebra_neigh *n, bool is_router, |
1032 | bool local_inactive, bool old_bgp_ready, bool new_bgp_ready, | |
1033 | bool inform_dataplane, bool inform_bgp, const char *sfx) | |
7cbae20a | 1034 | { |
7cbae20a | 1035 | if (!IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) |
6336e12b PR |
1036 | return; |
1037 | ||
ef7b8be4 DL |
1038 | zlog_debug("%s neigh vni %u ip %pIA mac %pEA f 0x%x%s%s%s%s%s%s %s", pfx, |
1039 | n->zevpn->vni, &n->ip, &n->emac, n->flags, | |
7cbae20a PR |
1040 | is_router ? " router" : "", |
1041 | local_inactive ? " local-inactive" : "", | |
1042 | old_bgp_ready ? " old_bgp_ready" : "", | |
1043 | new_bgp_ready ? " new_bgp_ready" : "", | |
1044 | inform_dataplane ? " inform_dp" : "", | |
1045 | inform_bgp ? " inform_bgp" : "", sfx); | |
1046 | } | |
1047 | ||
1048 | /* As part Duplicate Address Detection (DAD) for IP mobility | |
1049 | * MAC binding changes, ensure to inherit duplicate flag | |
1050 | * from MAC. | |
1051 | */ | |
036daaca | 1052 | static int zebra_evpn_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf, |
3198b2b3 DS |
1053 | struct zebra_mac *old_zmac, |
1054 | struct zebra_mac *new_zmac, | |
72de4110 | 1055 | struct zebra_neigh *nbr) |
7cbae20a PR |
1056 | { |
1057 | bool is_old_mac_dup = false; | |
1058 | bool is_new_mac_dup = false; | |
6336e12b | 1059 | |
b2ee2b71 | 1060 | if (!zebra_evpn_do_dup_addr_detect(zvrf)) |
7cbae20a PR |
1061 | return 0; |
1062 | /* Check old or new MAC is detected as duplicate | |
1063 | * mark this neigh as duplicate | |
1064 | */ | |
1065 | if (old_zmac) | |
1066 | is_old_mac_dup = | |
1067 | CHECK_FLAG(old_zmac->flags, ZEBRA_MAC_DUPLICATE); | |
1068 | if (new_zmac) | |
1069 | is_new_mac_dup = | |
1070 | CHECK_FLAG(new_zmac->flags, ZEBRA_MAC_DUPLICATE); | |
1071 | /* Old and/or new MAC can be in duplicate state, | |
1072 | * based on that IP/Neigh Inherits the flag. | |
1073 | * If New MAC is marked duplicate, inherit to the IP. | |
1074 | * If old MAC is duplicate but new MAC is not, clear | |
1075 | * duplicate flag for IP and reset detection params | |
1076 | * and let IP DAD retrigger. | |
6336e12b | 1077 | */ |
7cbae20a PR |
1078 | if (is_new_mac_dup && !CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) { |
1079 | SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
1080 | /* Capture Duplicate detection time */ | |
1081 | nbr->dad_dup_detect_time = monotime(NULL); | |
1082 | /* Mark neigh inactive */ | |
1083 | ZEBRA_NEIGH_SET_INACTIVE(nbr); | |
6336e12b | 1084 | |
7cbae20a PR |
1085 | return 1; |
1086 | } else if (is_old_mac_dup && !is_new_mac_dup) { | |
1087 | UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
1088 | nbr->dad_count = 0; | |
1089 | nbr->detect_start_time.tv_sec = 0; | |
1090 | nbr->detect_start_time.tv_usec = 0; | |
1091 | } | |
1092 | return 0; | |
6336e12b PR |
1093 | } |
1094 | ||
7cbae20a | 1095 | static int zebra_evpn_dad_ip_auto_recovery_exp(struct thread *t) |
6336e12b | 1096 | { |
7cbae20a | 1097 | struct zebra_vrf *zvrf = NULL; |
72de4110 | 1098 | struct zebra_neigh *nbr = NULL; |
f6371c34 | 1099 | struct zebra_evpn *zevpn = NULL; |
6336e12b | 1100 | |
7cbae20a | 1101 | nbr = THREAD_ARG(t); |
6336e12b | 1102 | |
7cbae20a PR |
1103 | /* since this is asynchronous we need sanity checks*/ |
1104 | zvrf = vrf_info_lookup(nbr->zevpn->vrf_id); | |
1105 | if (!zvrf) | |
1106 | return 0; | |
6336e12b | 1107 | |
8b5fdf2e | 1108 | zevpn = zebra_evpn_lookup(nbr->zevpn->vni); |
7cbae20a PR |
1109 | if (!zevpn) |
1110 | return 0; | |
6336e12b | 1111 | |
7cbae20a PR |
1112 | nbr = zebra_evpn_neigh_lookup(zevpn, &nbr->ip); |
1113 | if (!nbr) | |
1114 | return 0; | |
1115 | ||
1116 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1117 | zlog_debug( | |
ef7b8be4 DL |
1118 | "%s: duplicate addr MAC %pEA IP %pIA flags 0x%x learn count %u vni %u auto recovery expired", |
1119 | __func__, &nbr->emac, &nbr->ip, nbr->flags, | |
7cbae20a | 1120 | nbr->dad_count, zevpn->vni); |
6336e12b | 1121 | |
7cbae20a PR |
1122 | UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); |
1123 | nbr->dad_count = 0; | |
1124 | nbr->detect_start_time.tv_sec = 0; | |
1125 | nbr->detect_start_time.tv_usec = 0; | |
1126 | nbr->dad_dup_detect_time = 0; | |
1127 | nbr->dad_ip_auto_recovery_timer = NULL; | |
1128 | ZEBRA_NEIGH_SET_ACTIVE(nbr); | |
6336e12b | 1129 | |
7cbae20a PR |
1130 | /* Send to BGP */ |
1131 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) { | |
1132 | zebra_evpn_neigh_send_add_to_client(zevpn->vni, &nbr->ip, | |
1133 | &nbr->emac, nbr->mac, | |
1134 | nbr->flags, nbr->loc_seq); | |
1135 | } else if (!!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) { | |
1136 | zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/); | |
1137 | } | |
6336e12b | 1138 | |
7cbae20a PR |
1139 | return 0; |
1140 | } | |
6336e12b | 1141 | |
72de4110 DS |
1142 | static void zebra_evpn_dup_addr_detect_for_neigh( |
1143 | struct zebra_vrf *zvrf, struct zebra_neigh *nbr, struct in_addr vtep_ip, | |
1144 | bool do_dad, bool *is_dup_detect, bool is_local) | |
7cbae20a PR |
1145 | { |
1146 | ||
1147 | struct timeval elapsed = {0, 0}; | |
7cbae20a | 1148 | bool reset_params = false; |
6336e12b | 1149 | |
b2ee2b71 | 1150 | if (!zebra_evpn_do_dup_addr_detect(zvrf)) |
7cbae20a PR |
1151 | return; |
1152 | ||
1153 | /* IP is detected as duplicate or inherit dup | |
1154 | * state, hold on to install as remote entry | |
1155 | * only if freeze is enabled. | |
1156 | */ | |
1157 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) { | |
6336e12b PR |
1158 | if (IS_ZEBRA_DEBUG_VXLAN) |
1159 | zlog_debug( | |
ef7b8be4 DL |
1160 | "%s: duplicate addr MAC %pEA IP %pIA flags 0x%x skip installing, learn count %u recover time %u", |
1161 | __func__, &nbr->emac, &nbr->ip, | |
7cbae20a PR |
1162 | nbr->flags, nbr->dad_count, |
1163 | zvrf->dad_freeze_time); | |
6336e12b | 1164 | |
7cbae20a PR |
1165 | if (zvrf->dad_freeze) |
1166 | *is_dup_detect = true; | |
6336e12b | 1167 | |
7cbae20a PR |
1168 | /* warn-only action, neigh will be installed. |
1169 | * freeze action, it wil not be installed. | |
6336e12b | 1170 | */ |
7cbae20a PR |
1171 | return; |
1172 | } | |
6336e12b | 1173 | |
7cbae20a PR |
1174 | if (!do_dad) |
1175 | return; | |
6336e12b | 1176 | |
7cbae20a PR |
1177 | /* Check if detection time (M-secs) expired. |
1178 | * Reset learn count and detection start time. | |
1179 | * During remote mac add, count should already be 1 | |
1180 | * via local learning. | |
1181 | */ | |
1182 | monotime_since(&nbr->detect_start_time, &elapsed); | |
1183 | reset_params = (elapsed.tv_sec > zvrf->dad_time); | |
6336e12b | 1184 | |
7cbae20a PR |
1185 | if (is_local && !reset_params) { |
1186 | /* RFC-7432: A PE/VTEP that detects a MAC mobility | |
1187 | * event via LOCAL learning starts an M-second timer. | |
1188 | * | |
1189 | * NOTE: This is the START of the probe with count is | |
1190 | * 0 during LOCAL learn event. | |
1191 | */ | |
1192 | reset_params = !nbr->dad_count; | |
6336e12b PR |
1193 | } |
1194 | ||
7cbae20a PR |
1195 | if (reset_params) { |
1196 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1197 | zlog_debug( | |
ef7b8be4 DL |
1198 | "%s: duplicate addr MAC %pEA IP %pIA flags 0x%x detection time passed, reset learn count %u", |
1199 | __func__, &nbr->emac, &nbr->ip, | |
7cbae20a PR |
1200 | nbr->flags, nbr->dad_count); |
1201 | /* Reset learn count but do not start detection | |
1202 | * during REMOTE learn event. | |
1203 | */ | |
1204 | nbr->dad_count = 0; | |
1205 | /* Start dup. addr detection (DAD) start time, | |
1206 | * ONLY during LOCAL learn. | |
1207 | */ | |
1208 | if (is_local) | |
1209 | monotime(&nbr->detect_start_time); | |
6336e12b | 1210 | |
7cbae20a PR |
1211 | } else if (!is_local) { |
1212 | /* For REMOTE IP/Neigh, increment detection count | |
1213 | * ONLY while in probe window, once window passed, | |
1214 | * next local learn event should trigger DAD. | |
1215 | */ | |
1216 | nbr->dad_count++; | |
6336e12b PR |
1217 | } |
1218 | ||
7cbae20a PR |
1219 | /* For LOCAL IP/Neigh learn event, once count is reset above via either |
1220 | * initial/start detection time or passed the probe time, the count | |
1221 | * needs to be incremented. | |
1222 | */ | |
1223 | if (is_local) | |
1224 | nbr->dad_count++; | |
6336e12b | 1225 | |
7cbae20a PR |
1226 | if (nbr->dad_count >= zvrf->dad_max_moves) { |
1227 | flog_warn( | |
1228 | EC_ZEBRA_DUP_IP_DETECTED, | |
ef7b8be4 DL |
1229 | "VNI %u: MAC %pEA IP %pIA detected as duplicate during %s VTEP %pI4", |
1230 | nbr->zevpn->vni, &nbr->emac, &nbr->ip, | |
7cbae20a | 1231 | is_local ? "local update, last" : "remote update, from", |
9bcef951 | 1232 | &vtep_ip); |
6336e12b | 1233 | |
7cbae20a | 1234 | SET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); |
6336e12b | 1235 | |
7cbae20a PR |
1236 | /* Capture Duplicate detection time */ |
1237 | nbr->dad_dup_detect_time = monotime(NULL); | |
6336e12b | 1238 | |
7cbae20a PR |
1239 | /* Start auto recovery timer for this IP */ |
1240 | THREAD_OFF(nbr->dad_ip_auto_recovery_timer); | |
1241 | if (zvrf->dad_freeze && zvrf->dad_freeze_time) { | |
1242 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1243 | zlog_debug( | |
ef7b8be4 DL |
1244 | "%s: duplicate addr MAC %pEA IP %pIA flags 0x%x auto recovery time %u start", |
1245 | __func__, &nbr->emac, &nbr->ip, | |
7cbae20a | 1246 | nbr->flags, zvrf->dad_freeze_time); |
6336e12b | 1247 | |
7cbae20a PR |
1248 | thread_add_timer(zrouter.master, |
1249 | zebra_evpn_dad_ip_auto_recovery_exp, | |
1250 | nbr, zvrf->dad_freeze_time, | |
1251 | &nbr->dad_ip_auto_recovery_timer); | |
1252 | } | |
1253 | if (zvrf->dad_freeze) | |
1254 | *is_dup_detect = true; | |
1255 | } | |
6336e12b PR |
1256 | } |
1257 | ||
f6371c34 DS |
1258 | int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn, |
1259 | struct interface *ifp, | |
1a3bd37f MS |
1260 | const struct ipaddr *ip, |
1261 | const struct ethaddr *macaddr, bool is_router, | |
1262 | bool local_inactive, bool dp_static) | |
6336e12b | 1263 | { |
7cbae20a | 1264 | struct zebra_vrf *zvrf; |
72de4110 | 1265 | struct zebra_neigh *n = NULL; |
3198b2b3 | 1266 | struct zebra_mac *zmac = NULL, *old_zmac = NULL; |
7cbae20a PR |
1267 | uint32_t old_mac_seq = 0, mac_new_seq = 0; |
1268 | bool upd_mac_seq = false; | |
1269 | bool neigh_mac_change = false; | |
1270 | bool neigh_on_hold = false; | |
1271 | bool neigh_was_remote = false; | |
1272 | bool do_dad = false; | |
1273 | struct in_addr vtep_ip = {.s_addr = 0}; | |
1274 | bool inform_dataplane = false; | |
1275 | bool created = false; | |
1276 | bool new_static = false; | |
1277 | bool old_bgp_ready = false; | |
1278 | bool new_bgp_ready; | |
6336e12b | 1279 | |
7cbae20a PR |
1280 | /* Check if the MAC exists. */ |
1281 | zmac = zebra_evpn_mac_lookup(zevpn, macaddr); | |
1282 | if (!zmac) { | |
1283 | /* create a dummy MAC if the MAC is not already present */ | |
6336e12b | 1284 | if (IS_ZEBRA_DEBUG_VXLAN) |
ef7b8be4 DL |
1285 | zlog_debug("AUTO MAC %pEA created for neigh %pIA on VNI %u", |
1286 | macaddr, ip, zevpn->vni); | |
6336e12b | 1287 | |
7cbae20a PR |
1288 | zmac = zebra_evpn_mac_add(zevpn, macaddr); |
1289 | if (!zmac) { | |
ef7b8be4 | 1290 | zlog_debug("Failed to add MAC %pEA VNI %u", macaddr, |
7cbae20a PR |
1291 | zevpn->vni); |
1292 | return -1; | |
1293 | } | |
6336e12b | 1294 | |
8b07f173 | 1295 | zebra_evpn_mac_clear_fwd_info(zmac); |
7cbae20a PR |
1296 | memset(&zmac->flags, 0, sizeof(uint32_t)); |
1297 | SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO); | |
1298 | } else { | |
1299 | if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) { | |
1300 | /* | |
1301 | * We don't change the MAC to local upon a neighbor | |
1302 | * learn event, we wait for the explicit local MAC | |
1303 | * learn. However, we have to compute its sequence | |
1304 | * number in preparation for when it actually turns | |
1305 | * local. | |
1306 | */ | |
1307 | upd_mac_seq = true; | |
1308 | } | |
1309 | } | |
6336e12b | 1310 | |
7cbae20a PR |
1311 | zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id); |
1312 | if (!zvrf) { | |
1313 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1314 | zlog_debug(" Unable to find vrf for: %d", | |
1315 | zevpn->vxlan_if->vrf_id); | |
1316 | return -1; | |
1317 | } | |
6336e12b | 1318 | |
7cbae20a PR |
1319 | /* Check if the neighbor exists. */ |
1320 | n = zebra_evpn_neigh_lookup(zevpn, ip); | |
1321 | if (!n) { | |
1322 | /* New neighbor - create */ | |
1323 | n = zebra_evpn_neigh_add(zevpn, ip, macaddr, zmac, 0); | |
1324 | if (!n) { | |
1325 | flog_err( | |
1326 | EC_ZEBRA_MAC_ADD_FAILED, | |
ef7b8be4 DL |
1327 | "Failed to add neighbor %pIA MAC %pEA intf %s(%u) -> VNI %u", |
1328 | ip, macaddr, ifp->name, ifp->ifindex, | |
1329 | zevpn->vni); | |
7cbae20a PR |
1330 | return -1; |
1331 | } | |
1332 | /* Set "local" forwarding info. */ | |
1333 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
1334 | n->ifindex = ifp->ifindex; | |
1335 | created = true; | |
6336e12b | 1336 | } else { |
7cbae20a PR |
1337 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { |
1338 | bool mac_different; | |
1339 | bool cur_is_router; | |
1340 | bool old_local_inactive; | |
6336e12b | 1341 | |
7cbae20a PR |
1342 | old_local_inactive = !!CHECK_FLAG( |
1343 | n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE); | |
6336e12b | 1344 | |
7cbae20a | 1345 | old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); |
6336e12b | 1346 | |
7cbae20a PR |
1347 | /* Note any changes and see if of interest to BGP. */ |
1348 | mac_different = !!memcmp(&n->emac, macaddr, ETH_ALEN); | |
1349 | cur_is_router = | |
1350 | !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
1351 | new_static = zebra_evpn_neigh_is_static(n); | |
1352 | if (!mac_different && is_router == cur_is_router | |
1353 | && old_local_inactive == local_inactive | |
1354 | && dp_static != new_static) { | |
1355 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1356 | zlog_debug( | |
1357 | " Ignoring entry mac is the same and is_router == cur_is_router"); | |
1358 | n->ifindex = ifp->ifindex; | |
1359 | return 0; | |
1360 | } | |
6336e12b | 1361 | |
7cbae20a PR |
1362 | old_zmac = n->mac; |
1363 | if (!mac_different) { | |
1364 | /* XXX - cleanup this code duplication */ | |
1365 | bool is_neigh_freezed = false; | |
6336e12b | 1366 | |
7cbae20a PR |
1367 | /* Only the router flag has changed. */ |
1368 | if (is_router) | |
1369 | SET_FLAG(n->flags, | |
1370 | ZEBRA_NEIGH_ROUTER_FLAG); | |
1371 | else | |
1372 | UNSET_FLAG(n->flags, | |
1373 | ZEBRA_NEIGH_ROUTER_FLAG); | |
6336e12b | 1374 | |
7cbae20a PR |
1375 | if (local_inactive) |
1376 | SET_FLAG(n->flags, | |
1377 | ZEBRA_NEIGH_LOCAL_INACTIVE); | |
1378 | else | |
1379 | UNSET_FLAG(n->flags, | |
1380 | ZEBRA_NEIGH_LOCAL_INACTIVE); | |
1381 | new_bgp_ready = | |
1382 | zebra_evpn_neigh_is_ready_for_bgp(n); | |
6336e12b | 1383 | |
7c0e4dc6 AK |
1384 | if (dp_static != new_static) |
1385 | inform_dataplane = true; | |
1386 | ||
7cbae20a PR |
1387 | /* Neigh is in freeze state and freeze action |
1388 | * is enabled, do not send update to client. | |
1389 | */ | |
1390 | is_neigh_freezed = | |
b2ee2b71 | 1391 | (zebra_evpn_do_dup_addr_detect(zvrf) |
7cbae20a PR |
1392 | && zvrf->dad_freeze |
1393 | && CHECK_FLAG(n->flags, | |
1394 | ZEBRA_NEIGH_DUPLICATE)); | |
6336e12b | 1395 | |
7cbae20a PR |
1396 | zebra_evpn_local_neigh_update_log( |
1397 | "local", n, is_router, local_inactive, | |
1398 | old_bgp_ready, new_bgp_ready, false, | |
1399 | false, "flag-update"); | |
6336e12b | 1400 | |
7c0e4dc6 AK |
1401 | if (inform_dataplane) |
1402 | zebra_evpn_sync_neigh_dp_install( | |
1403 | n, false /* set_inactive */, | |
1404 | false /* force_clear_static */, | |
1405 | __func__); | |
1406 | ||
7cbae20a PR |
1407 | /* if the neigh can no longer be advertised |
1408 | * remove it from bgp | |
1409 | */ | |
1410 | if (!is_neigh_freezed) { | |
1411 | zebra_evpn_neigh_send_add_del_to_client( | |
1412 | n, old_bgp_ready, | |
1413 | new_bgp_ready); | |
1414 | } else { | |
1415 | if (IS_ZEBRA_DEBUG_VXLAN | |
1416 | && IS_ZEBRA_NEIGH_ACTIVE(n)) | |
1417 | zlog_debug( | |
1418 | " Neighbor active and frozen"); | |
1419 | } | |
1420 | return 0; | |
1421 | } | |
6336e12b | 1422 | |
7cbae20a PR |
1423 | /* The MAC has changed, need to issue a delete |
1424 | * first as this means a different MACIP route. | |
1425 | * Also, need to do some unlinking/relinking. | |
1426 | * We also need to update the MAC's sequence number | |
1427 | * in different situations. | |
1428 | */ | |
1429 | if (old_bgp_ready) { | |
1430 | zebra_evpn_neigh_send_del_to_client( | |
1431 | zevpn->vni, &n->ip, &n->emac, n->flags, | |
1432 | n->state, false /*force*/); | |
1433 | old_bgp_ready = false; | |
1434 | } | |
1435 | if (old_zmac) { | |
1436 | old_mac_seq = CHECK_FLAG(old_zmac->flags, | |
1437 | ZEBRA_MAC_REMOTE) | |
1438 | ? old_zmac->rem_seq | |
1439 | : old_zmac->loc_seq; | |
1440 | neigh_mac_change = upd_mac_seq = true; | |
1441 | zebra_evpn_local_neigh_deref_mac( | |
1442 | n, true /* send_mac_update */); | |
1443 | } | |
6336e12b | 1444 | |
7cbae20a PR |
1445 | /* if mac changes abandon peer flags and tell |
1446 | * dataplane to clear the static flag | |
1447 | */ | |
1448 | if (zebra_evpn_neigh_clear_sync_info(n)) | |
1449 | inform_dataplane = true; | |
1450 | /* Update the forwarding info. */ | |
1451 | n->ifindex = ifp->ifindex; | |
1452 | ||
1453 | /* Link to new MAC */ | |
1454 | zebra_evpn_local_neigh_ref_mac( | |
1455 | n, macaddr, zmac, true /* send_mac_update */); | |
1456 | } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
1457 | /* | |
1458 | * Neighbor has moved from remote to local. Its | |
1459 | * MAC could have also changed as part of the move. | |
1460 | */ | |
1461 | if (memcmp(n->emac.octet, macaddr->octet, ETH_ALEN) | |
1462 | != 0) { | |
1463 | old_zmac = n->mac; | |
1464 | if (old_zmac) { | |
1465 | old_mac_seq = | |
1466 | CHECK_FLAG(old_zmac->flags, | |
1467 | ZEBRA_MAC_REMOTE) | |
1468 | ? old_zmac->rem_seq | |
1469 | : old_zmac->loc_seq; | |
1470 | neigh_mac_change = upd_mac_seq = true; | |
1471 | zebra_evpn_local_neigh_deref_mac( | |
1472 | n, true /* send_update */); | |
1473 | } | |
6336e12b | 1474 | |
7cbae20a PR |
1475 | /* Link to new MAC */ |
1476 | zebra_evpn_local_neigh_ref_mac( | |
1477 | n, macaddr, zmac, true /*send_update*/); | |
1478 | } | |
1479 | /* Based on Mobility event Scenario-B from the | |
1480 | * draft, neigh's previous state was remote treat this | |
1481 | * event for DAD. | |
1482 | */ | |
1483 | neigh_was_remote = true; | |
1484 | vtep_ip = n->r_vtep_ip; | |
1485 | /* Mark appropriately */ | |
1486 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); | |
1487 | n->r_vtep_ip.s_addr = INADDR_ANY; | |
1488 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
1489 | n->ifindex = ifp->ifindex; | |
6336e12b PR |
1490 | } |
1491 | } | |
1492 | ||
7cbae20a PR |
1493 | /* If MAC was previously remote, or the neighbor had a different |
1494 | * MAC earlier, recompute the sequence number. | |
1495 | */ | |
1496 | if (upd_mac_seq) { | |
1497 | uint32_t seq1, seq2; | |
6336e12b | 1498 | |
7cbae20a PR |
1499 | seq1 = CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE) |
1500 | ? zmac->rem_seq + 1 | |
1501 | : zmac->loc_seq; | |
1502 | seq2 = neigh_mac_change ? old_mac_seq + 1 : 0; | |
1503 | mac_new_seq = zmac->loc_seq < MAX(seq1, seq2) ? MAX(seq1, seq2) | |
1504 | : zmac->loc_seq; | |
1505 | } | |
6336e12b | 1506 | |
7cbae20a PR |
1507 | if (local_inactive) |
1508 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE); | |
1509 | else | |
1510 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE); | |
1511 | ||
1512 | /* Mark Router flag (R-bit) */ | |
1513 | if (is_router) | |
1514 | SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
1515 | else | |
1516 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
1517 | ||
7c0e4dc6 AK |
1518 | /* if zebra and dataplane don't agree this is a sync entry |
1519 | * re-install in the dataplane */ | |
1520 | new_static = zebra_evpn_neigh_is_static(n); | |
1521 | if (dp_static != new_static) | |
1522 | inform_dataplane = true; | |
7cbae20a PR |
1523 | |
1524 | /* Check old and/or new MAC detected as duplicate mark | |
1525 | * the neigh as duplicate | |
1526 | */ | |
1527 | if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_zmac, zmac, n)) { | |
1528 | flog_warn( | |
1529 | EC_ZEBRA_DUP_IP_INHERIT_DETECTED, | |
ef7b8be4 DL |
1530 | "VNI %u: MAC %pEA IP %pIA detected as duplicate during local update, inherit duplicate from MAC", |
1531 | zevpn->vni, macaddr, &n->ip); | |
7cbae20a | 1532 | } |
6336e12b | 1533 | |
7cbae20a PR |
1534 | /* For IP Duplicate Address Detection (DAD) is trigger, |
1535 | * when the event is extended mobility based on scenario-B | |
1536 | * from the draft, IP/Neigh's MAC binding changed and | |
1537 | * neigh's previous state was remote. | |
1538 | */ | |
1539 | if (neigh_mac_change && neigh_was_remote) | |
1540 | do_dad = true; | |
6336e12b | 1541 | |
7cbae20a PR |
1542 | zebra_evpn_dup_addr_detect_for_neigh(zvrf, n, vtep_ip, do_dad, |
1543 | &neigh_on_hold, true); | |
6336e12b | 1544 | |
7cbae20a PR |
1545 | if (inform_dataplane) |
1546 | zebra_evpn_sync_neigh_dp_install(n, false /* set_inactive */, | |
1547 | false /* force_clear_static */, | |
1548 | __func__); | |
6336e12b | 1549 | |
7cbae20a PR |
1550 | /* Before we program this in BGP, we need to check if MAC is locally |
1551 | * learnt. If not, force neighbor to be inactive and reset its seq. | |
1552 | */ | |
1553 | if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) { | |
1554 | zebra_evpn_local_neigh_update_log( | |
1555 | "local", n, is_router, local_inactive, false, false, | |
1556 | inform_dataplane, false, "auto-mac"); | |
1557 | ZEBRA_NEIGH_SET_INACTIVE(n); | |
1558 | n->loc_seq = 0; | |
1559 | zmac->loc_seq = mac_new_seq; | |
1560 | return 0; | |
1561 | } | |
6336e12b | 1562 | |
7cbae20a PR |
1563 | zebra_evpn_local_neigh_update_log("local", n, is_router, local_inactive, |
1564 | false, false, inform_dataplane, true, | |
1565 | created ? "created" : "updated"); | |
6336e12b | 1566 | |
7cbae20a PR |
1567 | /* If the MAC's sequence number has changed, inform the MAC and all |
1568 | * neighbors associated with the MAC to BGP, else just inform this | |
1569 | * neighbor. | |
1570 | */ | |
1571 | if (upd_mac_seq && zmac->loc_seq != mac_new_seq) { | |
1572 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1573 | zlog_debug( | |
ef7b8be4 DL |
1574 | "Seq changed for MAC %pEA VNI %u - old %u new %u", |
1575 | macaddr, zevpn->vni, | |
1576 | zmac->loc_seq, mac_new_seq); | |
7cbae20a PR |
1577 | zmac->loc_seq = mac_new_seq; |
1578 | if (zebra_evpn_mac_send_add_to_client(zevpn->vni, macaddr, | |
1579 | zmac->flags, | |
1580 | zmac->loc_seq, zmac->es)) | |
1581 | return -1; | |
1582 | zebra_evpn_process_neigh_on_local_mac_change(zevpn, zmac, 1, | |
1583 | 0 /*es_change*/); | |
1584 | return 0; | |
1585 | } | |
6336e12b | 1586 | |
7cbae20a | 1587 | n->loc_seq = zmac->loc_seq; |
6336e12b | 1588 | |
7cbae20a PR |
1589 | if (!neigh_on_hold) { |
1590 | ZEBRA_NEIGH_SET_ACTIVE(n); | |
1591 | new_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); | |
1592 | zebra_evpn_neigh_send_add_del_to_client(n, old_bgp_ready, | |
1593 | new_bgp_ready); | |
1594 | } else { | |
1595 | if (IS_ZEBRA_DEBUG_VXLAN) | |
1596 | zlog_debug(" Neighbor on hold not sending"); | |
1597 | } | |
1598 | return 0; | |
1599 | } | |
6336e12b | 1600 | |
f6371c34 DS |
1601 | int zebra_evpn_remote_neigh_update(struct zebra_evpn *zevpn, |
1602 | struct interface *ifp, | |
1a3bd37f MS |
1603 | const struct ipaddr *ip, |
1604 | const struct ethaddr *macaddr, | |
7cbae20a PR |
1605 | uint16_t state) |
1606 | { | |
72de4110 | 1607 | struct zebra_neigh *n = NULL; |
3198b2b3 | 1608 | struct zebra_mac *zmac = NULL; |
6336e12b | 1609 | |
7cbae20a PR |
1610 | /* If the neighbor is unknown, there is no further action. */ |
1611 | n = zebra_evpn_neigh_lookup(zevpn, ip); | |
1612 | if (!n) | |
1613 | return 0; | |
6336e12b | 1614 | |
7cbae20a PR |
1615 | /* If a remote entry, see if it needs to be refreshed */ |
1616 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
1617 | #ifdef GNU_LINUX | |
1618 | if (state & NUD_STALE) | |
1619 | zebra_evpn_rem_neigh_install(zevpn, n, | |
1620 | false /*was_static*/); | |
1621 | #endif | |
6336e12b | 1622 | } else { |
7cbae20a PR |
1623 | /* We got a "remote" neighbor notification for an entry |
1624 | * we think is local. This can happen in a multihoming | |
1625 | * scenario - but only if the MAC is already "remote". | |
1626 | * Just mark our entry as "remote". | |
6336e12b | 1627 | */ |
7cbae20a PR |
1628 | zmac = zebra_evpn_mac_lookup(zevpn, macaddr); |
1629 | if (!zmac || !CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) { | |
1630 | zlog_debug( | |
ef7b8be4 DL |
1631 | "Ignore remote neigh %pIA (MAC %pEA) on L2-VNI %u - MAC unknown or local", |
1632 | &n->ip, macaddr, zevpn->vni); | |
7cbae20a PR |
1633 | return -1; |
1634 | } | |
6336e12b | 1635 | |
7cbae20a PR |
1636 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_LOCAL_FLAGS); |
1637 | SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); | |
1638 | ZEBRA_NEIGH_SET_ACTIVE(n); | |
1639 | n->r_vtep_ip = zmac->fwd_info.r_vtep_ip; | |
6336e12b PR |
1640 | } |
1641 | ||
7cbae20a | 1642 | return 0; |
6336e12b PR |
1643 | } |
1644 | ||
7cbae20a PR |
1645 | /* Notify Neighbor entries to the Client, skips the GW entry */ |
1646 | static void | |
1647 | zebra_evpn_send_neigh_hash_entry_to_client(struct hash_bucket *bucket, | |
1648 | void *arg) | |
6336e12b | 1649 | { |
7cbae20a | 1650 | struct mac_walk_ctx *wctx = arg; |
72de4110 | 1651 | struct zebra_neigh *zn = bucket->data; |
3198b2b3 | 1652 | struct zebra_mac *zmac = NULL; |
6336e12b | 1653 | |
7cbae20a | 1654 | if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_DEF_GW)) |
6336e12b | 1655 | return; |
6336e12b | 1656 | |
7cbae20a PR |
1657 | if (CHECK_FLAG(zn->flags, ZEBRA_NEIGH_LOCAL) |
1658 | && IS_ZEBRA_NEIGH_ACTIVE(zn)) { | |
1659 | zmac = zebra_evpn_mac_lookup(wctx->zevpn, &zn->emac); | |
1660 | if (!zmac) | |
1661 | return; | |
6336e12b | 1662 | |
7cbae20a PR |
1663 | zebra_evpn_neigh_send_add_to_client(wctx->zevpn->vni, &zn->ip, |
1664 | &zn->emac, zn->mac, | |
1665 | zn->flags, zn->loc_seq); | |
1666 | } | |
6336e12b PR |
1667 | } |
1668 | ||
7cbae20a | 1669 | /* Iterator of a specific EVPN */ |
f6371c34 | 1670 | void zebra_evpn_send_neigh_to_client(struct zebra_evpn *zevpn) |
6336e12b | 1671 | { |
7cbae20a | 1672 | struct neigh_walk_ctx wctx; |
6336e12b | 1673 | |
7cbae20a PR |
1674 | memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); |
1675 | wctx.zevpn = zevpn; | |
6336e12b | 1676 | |
7cbae20a PR |
1677 | hash_iterate(zevpn->neigh_table, |
1678 | zebra_evpn_send_neigh_hash_entry_to_client, &wctx); | |
6336e12b PR |
1679 | } |
1680 | ||
7cbae20a | 1681 | void zebra_evpn_clear_dup_neigh_hash(struct hash_bucket *bucket, void *ctxt) |
6336e12b | 1682 | { |
7cbae20a | 1683 | struct neigh_walk_ctx *wctx = ctxt; |
72de4110 | 1684 | struct zebra_neigh *nbr; |
f6371c34 | 1685 | struct zebra_evpn *zevpn; |
7cbae20a | 1686 | char buf[INET6_ADDRSTRLEN]; |
6336e12b | 1687 | |
72de4110 | 1688 | nbr = (struct zebra_neigh *)bucket->data; |
7cbae20a PR |
1689 | if (!nbr) |
1690 | return; | |
6336e12b | 1691 | |
7cbae20a | 1692 | zevpn = wctx->zevpn; |
6336e12b | 1693 | |
7cbae20a PR |
1694 | if (!CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) |
1695 | return; | |
6336e12b | 1696 | |
7cbae20a PR |
1697 | if (IS_ZEBRA_DEBUG_VXLAN) { |
1698 | ipaddr2str(&nbr->ip, buf, sizeof(buf)); | |
1699 | zlog_debug("%s: clear neigh %s dup state, flags 0x%x seq %u", | |
1700 | __func__, buf, nbr->flags, nbr->loc_seq); | |
1701 | } | |
6336e12b PR |
1702 | |
1703 | UNSET_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE); | |
1704 | nbr->dad_count = 0; | |
1705 | nbr->detect_start_time.tv_sec = 0; | |
1706 | nbr->detect_start_time.tv_usec = 0; | |
1707 | nbr->dad_dup_detect_time = 0; | |
7cbae20a | 1708 | THREAD_OFF(nbr->dad_ip_auto_recovery_timer); |
6336e12b | 1709 | |
6336e12b | 1710 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL)) { |
7cbae20a PR |
1711 | zebra_evpn_neigh_send_add_to_client(zevpn->vni, &nbr->ip, |
1712 | &nbr->emac, nbr->mac, | |
1713 | nbr->flags, nbr->loc_seq); | |
1714 | } else if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_REMOTE)) { | |
6336e12b PR |
1715 | zebra_evpn_rem_neigh_install(zevpn, nbr, false /*was_static*/); |
1716 | } | |
6336e12b PR |
1717 | } |
1718 | ||
7cbae20a PR |
1719 | /* |
1720 | * Print a specific neighbor entry. | |
1721 | */ | |
72de4110 DS |
1722 | void zebra_evpn_print_neigh(struct zebra_neigh *n, void *ctxt, |
1723 | json_object *json) | |
6336e12b | 1724 | { |
7cbae20a PR |
1725 | struct vty *vty; |
1726 | char buf1[ETHER_ADDR_STRLEN]; | |
1727 | char buf2[INET6_ADDRSTRLEN]; | |
9bcef951 | 1728 | char addr_buf[PREFIX_STRLEN]; |
7cbae20a PR |
1729 | const char *type_str; |
1730 | const char *state_str; | |
1731 | bool flags_present = false; | |
1732 | struct zebra_vrf *zvrf = NULL; | |
1733 | struct timeval detect_start_time = {0, 0}; | |
1734 | char timebuf[MONOTIME_STRLEN]; | |
1735 | char thread_buf[THREAD_TIMER_STRLEN]; | |
a05111ba DS |
1736 | time_t uptime; |
1737 | char up_str[MONOTIME_STRLEN]; | |
6336e12b | 1738 | |
7cbae20a PR |
1739 | zvrf = zebra_vrf_get_evpn(); |
1740 | if (!zvrf) | |
1741 | return; | |
6336e12b | 1742 | |
a05111ba DS |
1743 | uptime = monotime(NULL); |
1744 | uptime -= n->uptime; | |
1745 | ||
1746 | frrtime_to_interval(uptime, up_str, sizeof(up_str)); | |
1747 | ||
7cbae20a PR |
1748 | ipaddr2str(&n->ip, buf2, sizeof(buf2)); |
1749 | prefix_mac2str(&n->emac, buf1, sizeof(buf1)); | |
1750 | type_str = CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) ? "local" : "remote"; | |
1751 | state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive"; | |
1752 | vty = (struct vty *)ctxt; | |
1753 | if (json == NULL) { | |
1754 | bool sync_info = false; | |
6336e12b | 1755 | |
7cbae20a PR |
1756 | vty_out(vty, "IP: %s\n", |
1757 | ipaddr2str(&n->ip, buf2, sizeof(buf2))); | |
1758 | vty_out(vty, " Type: %s\n", type_str); | |
1759 | vty_out(vty, " State: %s\n", state_str); | |
a05111ba | 1760 | vty_out(vty, " Uptime: %s\n", up_str); |
7cbae20a PR |
1761 | vty_out(vty, " MAC: %s\n", |
1762 | prefix_mac2str(&n->emac, buf1, sizeof(buf1))); | |
1763 | vty_out(vty, " Sync-info:"); | |
1764 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) { | |
1765 | vty_out(vty, " local-inactive"); | |
1766 | sync_info = true; | |
1767 | } | |
1768 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY)) { | |
1769 | vty_out(vty, " peer-proxy"); | |
1770 | sync_info = true; | |
1771 | } | |
1772 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) { | |
1773 | vty_out(vty, " peer-active"); | |
1774 | sync_info = true; | |
1775 | } | |
1776 | if (n->hold_timer) { | |
1777 | vty_out(vty, " (ht: %s)", | |
1778 | thread_timer_to_hhmmss(thread_buf, | |
1779 | sizeof(thread_buf), | |
1780 | n->hold_timer)); | |
1781 | sync_info = true; | |
1782 | } | |
1783 | if (!sync_info) | |
1784 | vty_out(vty, " -"); | |
1785 | vty_out(vty, "\n"); | |
1786 | } else { | |
a05111ba | 1787 | json_object_string_add(json, "uptime", up_str); |
7cbae20a PR |
1788 | json_object_string_add(json, "ip", buf2); |
1789 | json_object_string_add(json, "type", type_str); | |
1790 | json_object_string_add(json, "state", state_str); | |
1791 | json_object_string_add(json, "mac", buf1); | |
1792 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) | |
1793 | json_object_boolean_true_add(json, "localInactive"); | |
1794 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_PROXY)) | |
1795 | json_object_boolean_true_add(json, "peerProxy"); | |
1796 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ES_PEER_ACTIVE)) | |
1797 | json_object_boolean_true_add(json, "peerActive"); | |
1798 | if (n->hold_timer) | |
1799 | json_object_string_add( | |
1800 | json, "peerActiveHold", | |
1801 | thread_timer_to_hhmmss(thread_buf, | |
1802 | sizeof(thread_buf), | |
1803 | n->hold_timer)); | |
6336e12b | 1804 | } |
7cbae20a PR |
1805 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { |
1806 | if (n->mac->es) { | |
1807 | if (json) | |
1808 | json_object_string_add(json, "remoteEs", | |
1809 | n->mac->es->esi_str); | |
1810 | else | |
1811 | vty_out(vty, " Remote ES: %s\n", | |
1812 | n->mac->es->esi_str); | |
1813 | } else { | |
1814 | if (json) | |
9bcef951 MS |
1815 | json_object_string_add( |
1816 | json, "remoteVtep", | |
1817 | inet_ntop(AF_INET, &n->r_vtep_ip, | |
1818 | addr_buf, sizeof(addr_buf))); | |
7cbae20a | 1819 | else |
9bcef951 MS |
1820 | vty_out(vty, " Remote VTEP: %pI4\n", |
1821 | &n->r_vtep_ip); | |
7cbae20a | 1822 | } |
6336e12b | 1823 | } |
7cbae20a PR |
1824 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) { |
1825 | if (!json) { | |
1826 | vty_out(vty, " Flags: Default-gateway"); | |
1827 | flags_present = true; | |
1828 | } else | |
1829 | json_object_boolean_true_add(json, "defaultGateway"); | |
6336e12b | 1830 | } |
7cbae20a PR |
1831 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)) { |
1832 | if (!json) { | |
1833 | vty_out(vty, | |
1834 | flags_present ? " ,Router" : " Flags: Router"); | |
1835 | flags_present = true; | |
1836 | } | |
1837 | } | |
1838 | if (json == NULL) { | |
1839 | if (flags_present) | |
1840 | vty_out(vty, "\n"); | |
1841 | vty_out(vty, " Local Seq: %u Remote Seq: %u\n", n->loc_seq, | |
1842 | n->rem_seq); | |
6336e12b | 1843 | |
7cbae20a PR |
1844 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) { |
1845 | vty_out(vty, " Duplicate, detected at %s", | |
1846 | time_to_string(n->dad_dup_detect_time, | |
1847 | timebuf)); | |
1848 | } else if (n->dad_count) { | |
1849 | monotime_since(&n->detect_start_time, | |
1850 | &detect_start_time); | |
1851 | if (detect_start_time.tv_sec <= zvrf->dad_time) { | |
1852 | time_to_string(n->detect_start_time.tv_sec, | |
1853 | timebuf); | |
1854 | vty_out(vty, | |
1855 | " Duplicate detection started at %s, detection count %u\n", | |
1856 | timebuf, n->dad_count); | |
1857 | } | |
1858 | } | |
1859 | } else { | |
1860 | json_object_int_add(json, "localSequence", n->loc_seq); | |
1861 | json_object_int_add(json, "remoteSequence", n->rem_seq); | |
1862 | json_object_int_add(json, "detectionCount", n->dad_count); | |
1863 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) | |
1864 | json_object_boolean_true_add(json, "isDuplicate"); | |
1865 | else | |
1866 | json_object_boolean_false_add(json, "isDuplicate"); | |
1867 | } | |
6336e12b PR |
1868 | } |
1869 | ||
7cbae20a | 1870 | void zebra_evpn_print_neigh_hdr(struct vty *vty, struct neigh_walk_ctx *wctx) |
6336e12b | 1871 | { |
7cbae20a PR |
1872 | vty_out(vty, "Flags: I=local-inactive, P=peer-active, X=peer-proxy\n"); |
1873 | vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %s\n", -wctx->addr_width, | |
1874 | "Neighbor", "Type", "Flags", "State", "MAC", "Remote ES/VTEP", | |
1875 | "Seq #'s"); | |
6336e12b PR |
1876 | } |
1877 | ||
72de4110 DS |
1878 | static char *zebra_evpn_print_neigh_flags(struct zebra_neigh *n, |
1879 | char *flags_buf, | |
1880 | uint32_t flags_buf_sz) | |
6336e12b | 1881 | { |
7cbae20a PR |
1882 | snprintf(flags_buf, flags_buf_sz, "%s%s%s", |
1883 | (n->flags & ZEBRA_NEIGH_ES_PEER_ACTIVE) ? | |
1884 | "P" : "", | |
1885 | (n->flags & ZEBRA_NEIGH_ES_PEER_PROXY) ? | |
1886 | "X" : "", | |
1887 | (n->flags & ZEBRA_NEIGH_LOCAL_INACTIVE) ? | |
1888 | "I" : ""); | |
6336e12b | 1889 | |
7cbae20a | 1890 | return flags_buf; |
6336e12b PR |
1891 | } |
1892 | ||
7cbae20a PR |
1893 | /* |
1894 | * Print neighbor hash entry - called for display of all neighbors. | |
1895 | */ | |
1896 | void zebra_evpn_print_neigh_hash(struct hash_bucket *bucket, void *ctxt) | |
6336e12b | 1897 | { |
7cbae20a PR |
1898 | struct vty *vty; |
1899 | json_object *json_evpn = NULL, *json_row = NULL; | |
72de4110 | 1900 | struct zebra_neigh *n; |
7cbae20a PR |
1901 | char buf1[ETHER_ADDR_STRLEN]; |
1902 | char buf2[INET6_ADDRSTRLEN]; | |
9bcef951 | 1903 | char addr_buf[PREFIX_STRLEN]; |
7cbae20a PR |
1904 | struct neigh_walk_ctx *wctx = ctxt; |
1905 | const char *state_str; | |
1906 | char flags_buf[6]; | |
6336e12b | 1907 | |
7cbae20a PR |
1908 | vty = wctx->vty; |
1909 | json_evpn = wctx->json; | |
72de4110 | 1910 | n = (struct zebra_neigh *)bucket->data; |
6336e12b | 1911 | |
7cbae20a PR |
1912 | if (json_evpn) |
1913 | json_row = json_object_new_object(); | |
6336e12b | 1914 | |
7cbae20a PR |
1915 | prefix_mac2str(&n->emac, buf1, sizeof(buf1)); |
1916 | ipaddr2str(&n->ip, buf2, sizeof(buf2)); | |
1917 | state_str = IS_ZEBRA_NEIGH_ACTIVE(n) ? "active" : "inactive"; | |
1918 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
1919 | if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) | |
1920 | return; | |
6336e12b | 1921 | |
7cbae20a PR |
1922 | if (json_evpn == NULL) { |
1923 | vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %u/%u\n", | |
1924 | -wctx->addr_width, buf2, "local", | |
1925 | zebra_evpn_print_neigh_flags(n, flags_buf, | |
1926 | sizeof(flags_buf)), state_str, buf1, | |
1927 | "", n->loc_seq, n->rem_seq); | |
1928 | } else { | |
1929 | json_object_string_add(json_row, "type", "local"); | |
1930 | json_object_string_add(json_row, "state", state_str); | |
1931 | json_object_string_add(json_row, "mac", buf1); | |
1932 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) | |
1933 | json_object_boolean_true_add(json_row, | |
1934 | "defaultGateway"); | |
1935 | json_object_int_add(json_row, "localSequence", | |
1936 | n->loc_seq); | |
1937 | json_object_int_add(json_row, "remoteSequence", | |
1938 | n->rem_seq); | |
1939 | json_object_int_add(json_row, "detectionCount", | |
1940 | n->dad_count); | |
1941 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) | |
1942 | json_object_boolean_true_add(json_row, | |
1943 | "isDuplicate"); | |
1944 | else | |
1945 | json_object_boolean_false_add(json_row, | |
1946 | "isDuplicate"); | |
1947 | } | |
1948 | wctx->count++; | |
1949 | } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
1950 | if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) | |
1951 | && !IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip)) | |
6336e12b PR |
1952 | return; |
1953 | ||
7cbae20a PR |
1954 | if (json_evpn == NULL) { |
1955 | if ((wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) | |
1956 | && (wctx->count == 0)) | |
1957 | zebra_evpn_print_neigh_hdr(vty, wctx); | |
9bcef951 MS |
1958 | |
1959 | if (n->mac->es == NULL) | |
1960 | inet_ntop(AF_INET, &n->r_vtep_ip, | |
1961 | addr_buf, sizeof(addr_buf)); | |
1962 | ||
7cbae20a PR |
1963 | vty_out(vty, "%*s %-6s %-5s %-8s %-17s %-30s %u/%u\n", |
1964 | -wctx->addr_width, buf2, "remote", | |
1965 | zebra_evpn_print_neigh_flags(n, flags_buf, | |
1966 | sizeof(flags_buf)), state_str, buf1, | |
9bcef951 | 1967 | n->mac->es ? n->mac->es->esi_str : addr_buf, |
7cbae20a PR |
1968 | n->loc_seq, n->rem_seq); |
1969 | } else { | |
1970 | json_object_string_add(json_row, "type", "remote"); | |
1971 | json_object_string_add(json_row, "state", state_str); | |
1972 | json_object_string_add(json_row, "mac", buf1); | |
1973 | if (n->mac->es) | |
1974 | json_object_string_add(json_row, "remoteEs", | |
1975 | n->mac->es->esi_str); | |
1976 | else | |
9bcef951 MS |
1977 | json_object_string_add( |
1978 | json_row, "remoteVtep", | |
1979 | inet_ntop(AF_INET, &n->r_vtep_ip, | |
1980 | addr_buf, sizeof(addr_buf))); | |
7cbae20a PR |
1981 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) |
1982 | json_object_boolean_true_add(json_row, | |
1983 | "defaultGateway"); | |
1984 | json_object_int_add(json_row, "localSequence", | |
1985 | n->loc_seq); | |
1986 | json_object_int_add(json_row, "remoteSequence", | |
1987 | n->rem_seq); | |
1988 | json_object_int_add(json_row, "detectionCount", | |
1989 | n->dad_count); | |
1990 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) | |
1991 | json_object_boolean_true_add(json_row, | |
1992 | "isDuplicate"); | |
1993 | else | |
1994 | json_object_boolean_false_add(json_row, | |
1995 | "isDuplicate"); | |
1996 | } | |
1997 | wctx->count++; | |
6336e12b | 1998 | } |
6336e12b | 1999 | |
7cbae20a PR |
2000 | if (json_evpn) |
2001 | json_object_object_add(json_evpn, buf2, json_row); | |
6336e12b PR |
2002 | } |
2003 | ||
7cbae20a PR |
2004 | /* |
2005 | * Print neighbor hash entry in detail - called for display of all neighbors. | |
2006 | */ | |
2007 | void zebra_evpn_print_neigh_hash_detail(struct hash_bucket *bucket, void *ctxt) | |
6336e12b | 2008 | { |
7cbae20a PR |
2009 | struct vty *vty; |
2010 | json_object *json_evpn = NULL, *json_row = NULL; | |
72de4110 | 2011 | struct zebra_neigh *n; |
7cbae20a PR |
2012 | char buf[INET6_ADDRSTRLEN]; |
2013 | struct neigh_walk_ctx *wctx = ctxt; | |
6336e12b | 2014 | |
7cbae20a PR |
2015 | vty = wctx->vty; |
2016 | json_evpn = wctx->json; | |
72de4110 | 2017 | n = (struct zebra_neigh *)bucket->data; |
7cbae20a PR |
2018 | if (!n) |
2019 | return; | |
6336e12b | 2020 | |
7cbae20a PR |
2021 | ipaddr2str(&n->ip, buf, sizeof(buf)); |
2022 | if (json_evpn) | |
2023 | json_row = json_object_new_object(); | |
6336e12b | 2024 | |
7cbae20a | 2025 | zebra_evpn_print_neigh(n, vty, json_row); |
6336e12b | 2026 | |
7cbae20a PR |
2027 | if (json_evpn) |
2028 | json_object_object_add(json_evpn, buf, json_row); | |
6336e12b PR |
2029 | } |
2030 | ||
7cbae20a | 2031 | void zebra_evpn_print_dad_neigh_hash(struct hash_bucket *bucket, void *ctxt) |
6336e12b | 2032 | { |
72de4110 | 2033 | struct zebra_neigh *nbr; |
6336e12b | 2034 | |
72de4110 | 2035 | nbr = (struct zebra_neigh *)bucket->data; |
7cbae20a PR |
2036 | if (!nbr) |
2037 | return; | |
6336e12b | 2038 | |
7cbae20a PR |
2039 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) |
2040 | zebra_evpn_print_neigh_hash(bucket, ctxt); | |
6336e12b PR |
2041 | } |
2042 | ||
7cbae20a PR |
2043 | void zebra_evpn_print_dad_neigh_hash_detail(struct hash_bucket *bucket, |
2044 | void *ctxt) | |
6336e12b | 2045 | { |
72de4110 | 2046 | struct zebra_neigh *nbr; |
6336e12b | 2047 | |
72de4110 | 2048 | nbr = (struct zebra_neigh *)bucket->data; |
7cbae20a PR |
2049 | if (!nbr) |
2050 | return; | |
6336e12b | 2051 | |
7cbae20a PR |
2052 | if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_DUPLICATE)) |
2053 | zebra_evpn_print_neigh_hash_detail(bucket, ctxt); | |
6336e12b | 2054 | } |
036daaca | 2055 | |
f6371c34 | 2056 | void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn, |
272e11bf | 2057 | struct zebra_vrf *zvrf, |
1a3bd37f | 2058 | const struct ipaddr *ipaddr, |
3198b2b3 DS |
2059 | struct zebra_mac *mac, |
2060 | struct in_addr vtep_ip, uint8_t flags, | |
2061 | uint32_t seq) | |
036daaca | 2062 | { |
72de4110 | 2063 | struct zebra_neigh *n; |
036daaca | 2064 | int update_neigh = 0; |
3198b2b3 | 2065 | struct zebra_mac *old_mac = NULL; |
036daaca PR |
2066 | bool old_static = false; |
2067 | bool do_dad = false; | |
2068 | bool is_dup_detect = false; | |
2069 | bool is_router; | |
2070 | ||
2bdd4461 | 2071 | assert(mac); |
036daaca PR |
2072 | is_router = !!CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); |
2073 | ||
2074 | /* Check if the remote neighbor itself is unknown or has a | |
2075 | * change. If so, create or update and then install the entry. | |
2076 | */ | |
2077 | n = zebra_evpn_neigh_lookup(zevpn, ipaddr); | |
2078 | if (!n || !CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) | |
2079 | || is_router != !!CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG) | |
2080 | || (memcmp(&n->emac, &mac->macaddr, sizeof(struct ethaddr)) != 0) | |
2081 | || !IPV4_ADDR_SAME(&n->r_vtep_ip, &vtep_ip) || seq != n->rem_seq) | |
2082 | update_neigh = 1; | |
2083 | ||
2084 | if (update_neigh) { | |
2085 | if (!n) { | |
2086 | n = zebra_evpn_neigh_add(zevpn, ipaddr, &mac->macaddr, | |
2087 | mac, 0); | |
2088 | if (!n) { | |
2089 | zlog_warn( | |
ef7b8be4 DL |
2090 | "Failed to add Neigh %pIA MAC %pEA VNI %u Remote VTEP %pI4", |
2091 | ipaddr, &mac->macaddr, zevpn->vni, | |
2092 | &vtep_ip); | |
036daaca PR |
2093 | return; |
2094 | } | |
2095 | ||
2096 | } else { | |
036daaca PR |
2097 | /* When host moves but changes its (MAC,IP) |
2098 | * binding, BGP may install a MACIP entry that | |
2099 | * corresponds to "older" location of the host | |
2100 | * in transient situations (because {IP1,M1} | |
2101 | * is a different route from {IP1,M2}). Check | |
2102 | * the sequence number and ignore this update | |
2103 | * if appropriate. | |
2104 | */ | |
16de1338 AK |
2105 | |
2106 | if (!zebra_evpn_neigh_is_bgp_seq_ok( | |
2107 | zevpn, n, &mac->macaddr, seq, false)) | |
036daaca | 2108 | return; |
036daaca PR |
2109 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { |
2110 | old_static = zebra_evpn_neigh_is_static(n); | |
2111 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) | |
2112 | zlog_debug( | |
ef7b8be4 DL |
2113 | "sync->remote neigh vni %u ip %pIA mac %pEA seq %d f0x%x", |
2114 | n->zevpn->vni, &n->ip, &n->emac, | |
036daaca | 2115 | seq, n->flags); |
036daaca | 2116 | if (IS_ZEBRA_NEIGH_ACTIVE(n)) |
fb8f609d AK |
2117 | zebra_evpn_neigh_send_del_to_client( |
2118 | zevpn->vni, &n->ip, &n->emac, | |
2119 | n->flags, n->state, | |
2120 | false /*force*/); | |
bda6be1c | 2121 | zebra_evpn_neigh_clear_sync_info(n); |
036daaca PR |
2122 | } |
2123 | if (memcmp(&n->emac, &mac->macaddr, | |
2124 | sizeof(struct ethaddr)) | |
2125 | != 0) { | |
2126 | /* update neigh list for macs */ | |
2127 | old_mac = | |
2128 | zebra_evpn_mac_lookup(zevpn, &n->emac); | |
2129 | if (old_mac) { | |
2130 | listnode_delete(old_mac->neigh_list, n); | |
2131 | n->mac = NULL; | |
2132 | zebra_evpn_deref_ip2mac(zevpn, old_mac); | |
2133 | } | |
2134 | n->mac = mac; | |
2135 | listnode_add_sort(mac->neigh_list, n); | |
2136 | memcpy(&n->emac, &mac->macaddr, ETH_ALEN); | |
2137 | ||
2138 | /* Check Neigh's curent state is local | |
2139 | * (this is the case where neigh/host has moved | |
2140 | * from L->R) and check previous detction | |
2141 | * started via local learning. | |
2142 | * | |
2143 | * RFC-7432: A PE/VTEP that detects a MAC | |
2144 | * mobilit event via local learning starts | |
2145 | * an M-second timer. | |
2146 | * VTEP-IP or seq. change along is not | |
2147 | * considered for dup. detection. | |
2148 | * | |
2149 | * Mobilty event scenario-B IP-MAC binding | |
2150 | * changed. | |
2151 | */ | |
2152 | if ((!CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) | |
2153 | && n->dad_count) | |
2154 | do_dad = true; | |
2155 | } | |
2156 | } | |
2157 | ||
2158 | /* Set "remote" forwarding info. */ | |
2159 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_ALL_LOCAL_FLAGS); | |
2160 | n->r_vtep_ip = vtep_ip; | |
2161 | SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); | |
2162 | ||
2163 | /* Set router flag (R-bit) to this Neighbor entry */ | |
2164 | if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) | |
2165 | SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
2166 | else | |
2167 | UNSET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
2168 | ||
2169 | /* Check old or new MAC detected as duplicate, | |
2170 | * inherit duplicate flag to this neigh. | |
2171 | */ | |
2172 | if (zebra_evpn_ip_inherit_dad_from_mac(zvrf, old_mac, mac, n)) { | |
2173 | flog_warn( | |
2174 | EC_ZEBRA_DUP_IP_INHERIT_DETECTED, | |
ef7b8be4 DL |
2175 | "VNI %u: MAC %pEA IP %pIA detected as duplicate during remote update, inherit duplicate from MAC", |
2176 | zevpn->vni, &mac->macaddr, &n->ip); | |
036daaca PR |
2177 | } |
2178 | ||
2179 | /* Check duplicate address detection for IP */ | |
2180 | zebra_evpn_dup_addr_detect_for_neigh( | |
2181 | zvrf, n, n->r_vtep_ip, do_dad, &is_dup_detect, false); | |
2182 | /* Install the entry. */ | |
2183 | if (!is_dup_detect) | |
2184 | zebra_evpn_rem_neigh_install(zevpn, n, old_static); | |
2185 | } | |
2186 | ||
036daaca PR |
2187 | /* Update seq number. */ |
2188 | n->rem_seq = seq; | |
2189 | } | |
224315f3 | 2190 | |
f6371c34 DS |
2191 | int zebra_evpn_neigh_gw_macip_add(struct interface *ifp, |
2192 | struct zebra_evpn *zevpn, struct ipaddr *ip, | |
3198b2b3 | 2193 | struct zebra_mac *mac) |
224315f3 | 2194 | { |
72de4110 | 2195 | struct zebra_neigh *n; |
224315f3 | 2196 | |
2bdd4461 | 2197 | assert(mac); |
224315f3 PR |
2198 | |
2199 | n = zebra_evpn_neigh_lookup(zevpn, ip); | |
2200 | if (!n) { | |
2201 | n = zebra_evpn_neigh_add(zevpn, ip, &mac->macaddr, mac, 0); | |
2202 | if (!n) { | |
2203 | flog_err( | |
2204 | EC_ZEBRA_MAC_ADD_FAILED, | |
ef7b8be4 DL |
2205 | "Failed to add neighbor %pIA MAC %pEA intf %s(%u) -> VNI %u", |
2206 | ip, &mac->macaddr, | |
224315f3 PR |
2207 | ifp->name, ifp->ifindex, zevpn->vni); |
2208 | return -1; | |
2209 | } | |
2210 | } | |
2211 | ||
2212 | /* Set "local" forwarding info. */ | |
2213 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); | |
2214 | ZEBRA_NEIGH_SET_ACTIVE(n); | |
2215 | memcpy(&n->emac, &mac->macaddr, ETH_ALEN); | |
2216 | n->ifindex = ifp->ifindex; | |
2217 | ||
2218 | /* Only advertise in BGP if the knob is enabled */ | |
2219 | if (advertise_gw_macip_enabled(zevpn)) { | |
2220 | ||
2221 | SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW); | |
2222 | SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW); | |
2223 | /* Set Router flag (R-bit) */ | |
2224 | if (ip->ipa_type == IPADDR_V6) | |
2225 | SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); | |
2226 | ||
2227 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2228 | zlog_debug( | |
ef7b8be4 | 2229 | "SVI %s(%u) L2-VNI %u, sending GW MAC %pEA IP %pIA add to BGP with flags 0x%x", |
224315f3 | 2230 | ifp->name, ifp->ifindex, zevpn->vni, |
ef7b8be4 | 2231 | &mac->macaddr, ip, n->flags); |
224315f3 PR |
2232 | |
2233 | zebra_evpn_neigh_send_add_to_client( | |
2234 | zevpn->vni, ip, &n->emac, n->mac, n->flags, n->loc_seq); | |
2235 | } else if (advertise_svi_macip_enabled(zevpn)) { | |
2236 | ||
2237 | SET_FLAG(n->flags, ZEBRA_NEIGH_SVI_IP); | |
2238 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2239 | zlog_debug( | |
ef7b8be4 | 2240 | "SVI %s(%u) L2-VNI %u, sending SVI MAC %pEA IP %pIA add to BGP with flags 0x%x", |
224315f3 | 2241 | ifp->name, ifp->ifindex, zevpn->vni, |
ef7b8be4 | 2242 | &mac->macaddr, ip, n->flags); |
224315f3 PR |
2243 | |
2244 | zebra_evpn_neigh_send_add_to_client( | |
2245 | zevpn->vni, ip, &n->emac, n->mac, n->flags, n->loc_seq); | |
2246 | } | |
2247 | ||
2248 | return 0; | |
2249 | } | |
32fe7dfd | 2250 | |
f6371c34 | 2251 | void zebra_evpn_neigh_remote_uninstall(struct zebra_evpn *zevpn, |
72de4110 DS |
2252 | struct zebra_vrf *zvrf, |
2253 | struct zebra_neigh *n, | |
3198b2b3 | 2254 | struct zebra_mac *mac, |
1a3bd37f | 2255 | const struct ipaddr *ipaddr) |
32fe7dfd | 2256 | { |
32fe7dfd PR |
2257 | if (zvrf->dad_freeze && CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE) |
2258 | && CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE) | |
2259 | && (memcmp(n->emac.octet, mac->macaddr.octet, ETH_ALEN) == 0)) { | |
2260 | struct interface *vlan_if; | |
2261 | ||
2262 | vlan_if = zevpn_map_to_svi(zevpn); | |
2263 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2264 | zlog_debug( | |
ef7b8be4 DL |
2265 | "%s: IP %pIA (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry", |
2266 | __func__, ipaddr, n->flags, | |
2267 | vlan_if ? vlan_if->name : "Unknown"); | |
32fe7dfd PR |
2268 | if (vlan_if) |
2269 | neigh_read_specific_ip(ipaddr, vlan_if); | |
2270 | } | |
2271 | ||
2272 | /* When the MAC changes for an IP, it is possible the | |
2273 | * client may update the new MAC before trying to delete the | |
2274 | * "old" neighbor (as these are two different MACIP routes). | |
2275 | * Do the delete only if the MAC matches. | |
2276 | */ | |
2277 | if (!memcmp(n->emac.octet, mac->macaddr.octet, ETH_ALEN)) { | |
2278 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { | |
2279 | zebra_evpn_sync_neigh_del(n); | |
2280 | } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
2281 | zebra_evpn_neigh_uninstall(zevpn, n); | |
2282 | zebra_evpn_neigh_del(zevpn, n); | |
2283 | zebra_evpn_deref_ip2mac(zevpn, mac); | |
2284 | } | |
2285 | } | |
2286 | } | |
33064a62 | 2287 | |
f6371c34 | 2288 | int zebra_evpn_neigh_del_ip(struct zebra_evpn *zevpn, const struct ipaddr *ip) |
33064a62 | 2289 | { |
72de4110 | 2290 | struct zebra_neigh *n; |
3198b2b3 | 2291 | struct zebra_mac *zmac; |
33064a62 PR |
2292 | bool old_bgp_ready; |
2293 | bool new_bgp_ready; | |
33064a62 PR |
2294 | struct zebra_vrf *zvrf; |
2295 | ||
2296 | /* If entry doesn't exist, nothing to do. */ | |
2297 | n = zebra_evpn_neigh_lookup(zevpn, ip); | |
2298 | if (!n) | |
2299 | return 0; | |
2300 | ||
2301 | zmac = zebra_evpn_mac_lookup(zevpn, &n->emac); | |
2302 | if (!zmac) { | |
2303 | if (IS_ZEBRA_DEBUG_VXLAN) | |
2304 | zlog_debug( | |
ef7b8be4 DL |
2305 | "Trying to del a neigh %pIA without a mac %pEA on VNI %u", |
2306 | ip, &n->emac, | |
33064a62 PR |
2307 | zevpn->vni); |
2308 | ||
2309 | return 0; | |
2310 | } | |
2311 | ||
2312 | /* If it is a remote entry, the kernel has aged this out or someone has | |
32367e7a | 2313 | * deleted it, it needs to be re-installed as FRR is the owner. |
33064a62 PR |
2314 | */ |
2315 | if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { | |
2316 | zebra_evpn_rem_neigh_install(zevpn, n, false /*was_static*/); | |
2317 | return 0; | |
2318 | } | |
2319 | ||
2320 | /* if this is a sync entry it cannot be dropped re-install it in | |
2321 | * the dataplane | |
2322 | */ | |
2323 | old_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); | |
2324 | if (zebra_evpn_neigh_is_static(n)) { | |
2325 | if (IS_ZEBRA_DEBUG_EVPN_MH_NEIGH) | |
ef7b8be4 DL |
2326 | zlog_debug("re-add sync neigh vni %u ip %pIA mac %pEA 0x%x", |
2327 | n->zevpn->vni, &n->ip, &n->emac, | |
33064a62 PR |
2328 | n->flags); |
2329 | ||
2330 | if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE)) | |
2331 | SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL_INACTIVE); | |
2332 | /* inform-bgp about change in local-activity if any */ | |
2333 | new_bgp_ready = zebra_evpn_neigh_is_ready_for_bgp(n); | |
2334 | zebra_evpn_neigh_send_add_del_to_client(n, old_bgp_ready, | |
2335 | new_bgp_ready); | |
2336 | ||
2337 | /* re-install the entry in the kernel */ | |
2338 | zebra_evpn_sync_neigh_dp_install(n, false /* set_inactive */, | |
2339 | false /* force_clear_static */, | |
2340 | __func__); | |
2341 | ||
2342 | return 0; | |
2343 | } | |
2344 | ||
2345 | zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id); | |
2346 | if (!zvrf) { | |
2347 | zlog_debug("%s: VNI %u vrf lookup failed.", __func__, | |
2348 | zevpn->vni); | |
2349 | return -1; | |
2350 | } | |
2351 | ||
2352 | /* In case of feeze action, if local neigh is in duplicate state, | |
2353 | * Mark the Neigh as inactive before sending delete request to BGPd, | |
2354 | * If BGPd has remote entry, it will re-install | |
2355 | */ | |
2356 | if (zvrf->dad_freeze && CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE)) | |
2357 | ZEBRA_NEIGH_SET_INACTIVE(n); | |
2358 | ||
2359 | /* Remove neighbor from BGP. */ | |
2360 | zebra_evpn_neigh_send_del_to_client(zevpn->vni, &n->ip, &n->emac, | |
2361 | n->flags, n->state, | |
2362 | false /* force */); | |
2363 | ||
2364 | /* Delete this neighbor entry. */ | |
2365 | zebra_evpn_neigh_del(zevpn, n); | |
2366 | ||
2367 | /* see if the AUTO mac needs to be deleted */ | |
2368 | if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO) | |
243b74ed | 2369 | && !zebra_evpn_mac_in_use(zmac)) |
33064a62 PR |
2370 | zebra_evpn_mac_del(zevpn, zmac); |
2371 | ||
2372 | return 0; | |
2373 | } |