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