]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
fb018d25 DS |
2 | /* BGP Nexthop tracking |
3 | * Copyright (C) 2013 Cumulus Networks, Inc. | |
fb018d25 DS |
4 | */ |
5 | ||
6 | #include <zebra.h> | |
7 | ||
8 | #include "command.h" | |
24a58196 | 9 | #include "frrevent.h" |
fb018d25 DS |
10 | #include "prefix.h" |
11 | #include "zclient.h" | |
12 | #include "stream.h" | |
13 | #include "network.h" | |
14 | #include "log.h" | |
15 | #include "memory.h" | |
16 | #include "nexthop.h" | |
7076bb2f | 17 | #include "vrf.h" |
039f3a34 | 18 | #include "filter.h" |
8bcb09a1 | 19 | #include "nexthop_group.h" |
fb018d25 DS |
20 | |
21 | #include "bgpd/bgpd.h" | |
22 | #include "bgpd/bgp_table.h" | |
23 | #include "bgpd/bgp_route.h" | |
24 | #include "bgpd/bgp_attr.h" | |
25 | #include "bgpd/bgp_nexthop.h" | |
26 | #include "bgpd/bgp_debug.h" | |
14454c9f | 27 | #include "bgpd/bgp_errors.h" |
fb018d25 | 28 | #include "bgpd/bgp_nht.h" |
ffd0c037 | 29 | #include "bgpd/bgp_fsm.h" |
afbb1c59 | 30 | #include "bgpd/bgp_zebra.h" |
0378bcaa | 31 | #include "bgpd/bgp_flowspec_util.h" |
7c312383 | 32 | #include "bgpd/bgp_evpn.h" |
9e15d76a | 33 | #include "bgpd/bgp_rd.h" |
577be36a | 34 | #include "bgpd/bgp_mplsvpn.h" |
fb018d25 DS |
35 | |
36 | extern struct zclient *zclient; | |
fb018d25 | 37 | |
23f60ffd DA |
38 | static void register_zebra_rnh(struct bgp_nexthop_cache *bnc); |
39 | static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc); | |
40381db7 | 40 | static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p); |
e6685141 | 41 | static void bgp_nht_ifp_initial(struct event *thread); |
fb018d25 | 42 | |
d62a17ae | 43 | static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc) |
d4d9d757 | 44 | { |
d62a17ae | 45 | return (bgp_zebra_num_connects() == 0 |
c3b95419 EDP |
46 | || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) |
47 | && bnc->nexthop_num > 0)); | |
d4d9d757 LB |
48 | } |
49 | ||
4cd690ae PG |
50 | static int bgp_isvalid_nexthop_for_ebgp(struct bgp_nexthop_cache *bnc, |
51 | struct bgp_path_info *path) | |
52 | { | |
53 | struct interface *ifp = NULL; | |
54 | struct nexthop *nexthop; | |
55 | struct bgp_interface *iifp; | |
56 | struct peer *peer; | |
57 | ||
58 | if (!path->extra || !path->extra->peer_orig) | |
59 | return false; | |
60 | ||
61 | peer = path->extra->peer_orig; | |
62 | ||
63 | /* only connected ebgp peers are valid */ | |
64 | if (peer->sort != BGP_PEER_EBGP || peer->ttl != BGP_DEFAULT_TTL || | |
65 | CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) || | |
66 | CHECK_FLAG(peer->bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) | |
67 | return false; | |
68 | ||
69 | for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) { | |
70 | if (nexthop->type == NEXTHOP_TYPE_IFINDEX || | |
71 | nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX || | |
72 | nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { | |
73 | ifp = if_lookup_by_index( | |
74 | bnc->ifindex ? bnc->ifindex : nexthop->ifindex, | |
75 | bnc->bgp->vrf_id); | |
76 | } | |
77 | if (!ifp) | |
78 | continue; | |
79 | iifp = ifp->info; | |
80 | if (CHECK_FLAG(iifp->flags, BGP_INTERFACE_MPLS_BGP_FORWARDING)) | |
81 | return true; | |
82 | } | |
83 | return false; | |
84 | } | |
85 | ||
1bb550b6 PG |
86 | static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc, |
87 | struct bgp_path_info *path) | |
88 | { | |
89 | struct interface *ifp = NULL; | |
90 | struct nexthop *nexthop; | |
91 | ||
92 | for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) { | |
93 | if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) { | |
94 | ifp = if_lookup_by_index( | |
95 | bnc->ifindex ? bnc->ifindex : nexthop->ifindex, | |
96 | bnc->bgp->vrf_id); | |
97 | if (ifp && (ifp->ll_type == ZEBRA_LLT_IPGRE || | |
98 | ifp->ll_type == ZEBRA_LLT_IP6GRE)) | |
99 | break; | |
100 | } | |
101 | } | |
102 | if (!ifp) | |
103 | return false; | |
104 | ||
105 | if (CHECK_FLAG(path->attr->rmap_change_flags, | |
106 | BATTR_RMAP_L3VPN_ACCEPT_GRE)) | |
107 | return true; | |
108 | ||
109 | return false; | |
110 | } | |
111 | ||
112 | static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc, | |
113 | struct bgp_path_info *path) | |
960035b2 | 114 | { |
7f8c7d91 | 115 | /* |
1bb550b6 | 116 | * - In the case of MPLS-VPN, the label is learned from LDP or other |
7f8c7d91 HS |
117 | * protocols, and nexthop tracking is enabled for the label. |
118 | * The value is recorded as BGP_NEXTHOP_LABELED_VALID. | |
1bb550b6 | 119 | * - In the case of SRv6-VPN, we need to track the reachability to the |
7f8c7d91 HS |
120 | * SID (in other words, IPv6 address). As in MPLS, we need to record |
121 | * the value as BGP_NEXTHOP_SID_VALID. However, this function is | |
122 | * currently not implemented, and this function assumes that all | |
123 | * Transit routes for SRv6-VPN are valid. | |
1bb550b6 | 124 | * - Otherwise check for mpls-gre acceptance |
7f8c7d91 | 125 | */ |
1bb550b6 PG |
126 | return (bgp_zebra_num_connects() == 0 || |
127 | (bnc && (bnc->nexthop_num > 0 && | |
46dbf9d0 DA |
128 | (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) || |
129 | CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) || | |
1bb550b6 | 130 | bnc->bgp->srv6_enabled || |
4cd690ae | 131 | bgp_isvalid_nexthop_for_ebgp(bnc, path) || |
1bb550b6 | 132 | bgp_isvalid_nexthop_for_mplsovergre(bnc, path))))); |
960035b2 PZ |
133 | } |
134 | ||
d62a17ae | 135 | static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) |
fb018d25 | 136 | { |
d5c4bac9 | 137 | if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) { |
036f482f DA |
138 | if (BGP_DEBUG(nht, NHT)) |
139 | zlog_debug("%s: freeing bnc %pFX(%d)(%u)(%s)", __func__, | |
140 | &bnc->prefix, bnc->ifindex, bnc->srte_color, | |
35aae5c9 | 141 | bnc->bgp->name_pretty); |
e37e1e27 PR |
142 | /* only unregister if this is the last nh for this prefix*/ |
143 | if (!bnc_existing_for_prefix(bnc)) | |
23f60ffd | 144 | unregister_zebra_rnh(bnc); |
d62a17ae | 145 | bnc_free(bnc); |
fb018d25 | 146 | } |
fb018d25 DS |
147 | } |
148 | ||
4b7e6066 | 149 | void bgp_unlink_nexthop(struct bgp_path_info *path) |
f9164b1d | 150 | { |
d62a17ae | 151 | struct bgp_nexthop_cache *bnc = path->nexthop; |
152 | ||
577be36a PG |
153 | bgp_mplsvpn_path_nh_label_unlink(path); |
154 | ||
d62a17ae | 155 | if (!bnc) |
156 | return; | |
f9164b1d | 157 | |
7f040da1 | 158 | path_nh_map(path, NULL, false); |
f9164b1d | 159 | |
d62a17ae | 160 | bgp_unlink_nexthop_check(bnc); |
f9164b1d PJ |
161 | } |
162 | ||
996319e6 DS |
163 | void bgp_replace_nexthop_by_peer(struct peer *from, struct peer *to) |
164 | { | |
165 | struct prefix pp; | |
166 | struct prefix pt; | |
167 | struct bgp_nexthop_cache *bncp, *bnct; | |
168 | afi_t afi; | |
35aae5c9 | 169 | ifindex_t ifindex = 0; |
996319e6 DS |
170 | |
171 | if (!sockunion2hostprefix(&from->su, &pp)) | |
172 | return; | |
173 | ||
35aae5c9 DS |
174 | /* |
175 | * Gather the ifindex for if up/down events to be | |
176 | * tagged into this fun | |
177 | */ | |
178 | if (from->conf_if && IN6_IS_ADDR_LINKLOCAL(&from->su.sin6.sin6_addr)) | |
179 | ifindex = from->su.sin6.sin6_scope_id; | |
180 | ||
996319e6 | 181 | afi = family2afi(pp.family); |
35aae5c9 | 182 | bncp = bnc_find(&from->bgp->nexthop_cache_table[afi], &pp, 0, ifindex); |
996319e6 DS |
183 | |
184 | if (!sockunion2hostprefix(&to->su, &pt)) | |
185 | return; | |
186 | ||
35aae5c9 DS |
187 | /* |
188 | * Gather the ifindex for if up/down events to be | |
189 | * tagged into this fun | |
190 | */ | |
191 | ifindex = 0; | |
192 | if (to->conf_if && IN6_IS_ADDR_LINKLOCAL(&to->su.sin6.sin6_addr)) | |
193 | ifindex = to->su.sin6.sin6_scope_id; | |
194 | bnct = bnc_find(&to->bgp->nexthop_cache_table[afi], &pt, 0, ifindex); | |
996319e6 DS |
195 | |
196 | if (bnct != bncp) | |
197 | return; | |
198 | ||
199 | if (bnct) | |
200 | bnct->nht_info = to; | |
201 | } | |
202 | ||
51f3216b PJD |
203 | /* |
204 | * Returns the bnc whose bnc->nht_info matches the LL peer by | |
205 | * looping through the IPv6 nexthop table | |
206 | */ | |
207 | static struct bgp_nexthop_cache * | |
208 | bgp_find_ipv6_nexthop_matching_peer(struct peer *peer) | |
209 | { | |
210 | struct bgp_nexthop_cache *bnc; | |
211 | ||
212 | frr_each (bgp_nexthop_cache, &peer->bgp->nexthop_cache_table[AFI_IP6], | |
213 | bnc) { | |
214 | if (bnc->nht_info == peer) { | |
215 | if (BGP_DEBUG(nht, NHT)) { | |
216 | zlog_debug( | |
217 | "Found bnc: %pFX(%u)(%u)(%p) for peer: %s(%s) %p", | |
218 | &bnc->prefix, bnc->ifindex, | |
219 | bnc->srte_color, bnc, peer->host, | |
220 | peer->bgp->name_pretty, peer); | |
221 | } | |
222 | return bnc; | |
223 | } | |
224 | } | |
225 | ||
226 | if (BGP_DEBUG(nht, NHT)) | |
227 | zlog_debug( | |
228 | "Could not find bnc for peer %s(%s) %p in v6 nexthop table", | |
229 | peer->host, peer->bgp->name_pretty, peer); | |
230 | ||
231 | return NULL; | |
232 | } | |
233 | ||
d62a17ae | 234 | void bgp_unlink_nexthop_by_peer(struct peer *peer) |
f9164b1d | 235 | { |
d62a17ae | 236 | struct prefix p; |
d62a17ae | 237 | struct bgp_nexthop_cache *bnc; |
238 | afi_t afi = family2afi(peer->su.sa.sa_family); | |
35aae5c9 | 239 | ifindex_t ifindex = 0; |
d62a17ae | 240 | |
51f3216b PJD |
241 | if (!sockunion2hostprefix(&peer->su, &p)) { |
242 | /* | |
243 | * In scenarios where unnumbered BGP session is brought | |
244 | * down by shutting down the interface before unconfiguring | |
245 | * the BGP neighbor, neighbor information in peer->su.sa | |
246 | * will be cleared when the interface is shutdown. So | |
247 | * during the deletion of unnumbered bgp peer, above check | |
248 | * will return true. Therefore, in this case,BGP needs to | |
249 | * find the bnc whose bnc->nht_info matches the | |
250 | * peer being deleted and free it. | |
251 | */ | |
252 | bnc = bgp_find_ipv6_nexthop_matching_peer(peer); | |
253 | } else { | |
254 | /* | |
255 | * Gather the ifindex for if up/down events to be | |
256 | * tagged into this fun | |
257 | */ | |
258 | if (afi == AFI_IP6 && | |
259 | IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) | |
260 | ifindex = peer->su.sin6.sin6_scope_id; | |
261 | bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0, | |
262 | ifindex); | |
263 | } | |
264 | ||
14315f2d | 265 | if (!bnc) |
d62a17ae | 266 | return; |
267 | ||
d62a17ae | 268 | /* cleanup the peer reference */ |
269 | bnc->nht_info = NULL; | |
270 | ||
271 | bgp_unlink_nexthop_check(bnc); | |
f9164b1d PJ |
272 | } |
273 | ||
960035b2 PZ |
274 | /* |
275 | * A route and its nexthop might belong to different VRFs. Therefore, | |
276 | * we need both the bgp_route and bgp_nexthop pointers. | |
277 | */ | |
278 | int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, | |
4053e952 | 279 | afi_t afi, safi_t safi, struct bgp_path_info *pi, |
654a5978 PG |
280 | struct peer *peer, int connected, |
281 | const struct prefix *orig_prefix) | |
fb018d25 | 282 | { |
f663c581 | 283 | struct bgp_nexthop_cache_head *tree = NULL; |
d62a17ae | 284 | struct bgp_nexthop_cache *bnc; |
ac2f64d3 | 285 | struct bgp_path_info *bpi_ultimate; |
d62a17ae | 286 | struct prefix p; |
545aeef1 | 287 | uint32_t srte_color = 0; |
d62a17ae | 288 | int is_bgp_static_route = 0; |
8761cd6d | 289 | ifindex_t ifindex = 0; |
d62a17ae | 290 | |
40381db7 DS |
291 | if (pi) { |
292 | is_bgp_static_route = ((pi->type == ZEBRA_ROUTE_BGP) | |
293 | && (pi->sub_type == BGP_ROUTE_STATIC)) | |
d62a17ae | 294 | ? 1 |
295 | : 0; | |
296 | ||
297 | /* Since Extended Next-hop Encoding (RFC5549) support, we want | |
298 | to derive | |
299 | address-family from the next-hop. */ | |
300 | if (!is_bgp_static_route) | |
7226bc40 TA |
301 | afi = BGP_ATTR_MP_NEXTHOP_LEN_IP6(pi->attr) ? AFI_IP6 |
302 | : AFI_IP; | |
d62a17ae | 303 | |
92d6f769 K |
304 | /* Validation for the ipv4 mapped ipv6 nexthop. */ |
305 | if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) { | |
306 | afi = AFI_IP; | |
307 | } | |
308 | ||
2951a7a4 | 309 | /* This will return true if the global IPv6 NH is a link local |
d62a17ae | 310 | * addr */ |
40381db7 | 311 | if (make_prefix(afi, pi, &p) < 0) |
d62a17ae | 312 | return 1; |
545aeef1 | 313 | |
654a5978 PG |
314 | if (!is_bgp_static_route && orig_prefix |
315 | && prefix_same(&p, orig_prefix)) { | |
316 | if (BGP_DEBUG(nht, NHT)) { | |
317 | zlog_debug( | |
318 | "%s(%pFX): prefix loops through itself", | |
319 | __func__, &p); | |
320 | } | |
321 | return 0; | |
322 | } | |
323 | ||
545aeef1 | 324 | srte_color = pi->attr->srte_color; |
d62a17ae | 325 | } else if (peer) { |
8761cd6d DS |
326 | /* |
327 | * Gather the ifindex for if up/down events to be | |
328 | * tagged into this fun | |
329 | */ | |
e9ad26e5 | 330 | if (afi == AFI_IP6 && peer->conf_if && |
35aae5c9 | 331 | IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) { |
8761cd6d | 332 | ifindex = peer->su.sin6.sin6_scope_id; |
35aae5c9 DS |
333 | if (ifindex == 0) { |
334 | if (BGP_DEBUG(nht, NHT)) { | |
335 | zlog_debug( | |
336 | "%s: Unable to locate ifindex, waiting till we have one", | |
337 | peer->conf_if); | |
338 | } | |
339 | return 0; | |
340 | } | |
341 | } | |
8761cd6d | 342 | |
d62a17ae | 343 | if (!sockunion2hostprefix(&peer->su, &p)) { |
344 | if (BGP_DEBUG(nht, NHT)) { | |
345 | zlog_debug( | |
346 | "%s: Attempting to register with unknown AFI %d (not %d or %d)", | |
15569c58 | 347 | __func__, afi, AFI_IP, AFI_IP6); |
d62a17ae | 348 | } |
349 | return 0; | |
350 | } | |
351 | } else | |
352 | return 0; | |
353 | ||
354 | if (is_bgp_static_route) | |
f663c581 | 355 | tree = &bgp_nexthop->import_check_table[afi]; |
d62a17ae | 356 | else |
f663c581 | 357 | tree = &bgp_nexthop->nexthop_cache_table[afi]; |
d62a17ae | 358 | |
35aae5c9 | 359 | bnc = bnc_find(tree, &p, srte_color, ifindex); |
14315f2d | 360 | if (!bnc) { |
35aae5c9 | 361 | bnc = bnc_new(tree, &p, srte_color, ifindex); |
960035b2 | 362 | bnc->bgp = bgp_nexthop; |
036f482f DA |
363 | if (BGP_DEBUG(nht, NHT)) |
364 | zlog_debug("Allocated bnc %pFX(%d)(%u)(%s) peer %p", | |
365 | &bnc->prefix, bnc->ifindex, bnc->srte_color, | |
35aae5c9 | 366 | bnc->bgp->name_pretty, peer); |
4115b296 | 367 | } else { |
036f482f | 368 | if (BGP_DEBUG(nht, NHT)) |
4115b296 | 369 | zlog_debug( |
036f482f DA |
370 | "Found existing bnc %pFX(%d)(%s) flags 0x%x ifindex %d #paths %d peer %p", |
371 | &bnc->prefix, bnc->ifindex, | |
372 | bnc->bgp->name_pretty, bnc->flags, bnc->ifindex, | |
373 | bnc->path_count, bnc->nht_info); | |
fc9a856f | 374 | } |
d62a17ae | 375 | |
021b6596 AD |
376 | if (pi && is_route_parent_evpn(pi)) |
377 | bnc->is_evpn_gwip_nexthop = true; | |
378 | ||
2bb8b49c | 379 | if (is_bgp_static_route) { |
d62a17ae | 380 | SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); |
381 | ||
382 | /* If we're toggling the type, re-register */ | |
892fedb6 | 383 | if ((CHECK_FLAG(bgp_route->flags, BGP_FLAG_IMPORT_CHECK)) |
d62a17ae | 384 | && !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) { |
385 | SET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); | |
386 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
387 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
892fedb6 DA |
388 | } else if ((!CHECK_FLAG(bgp_route->flags, |
389 | BGP_FLAG_IMPORT_CHECK)) | |
d62a17ae | 390 | && CHECK_FLAG(bnc->flags, |
391 | BGP_STATIC_ROUTE_EXACT_MATCH)) { | |
392 | UNSET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); | |
393 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
394 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
395 | } | |
078430f6 | 396 | } |
d62a17ae | 397 | /* When nexthop is already known, but now requires 'connected' |
398 | * resolution, | |
399 | * re-register it. The reverse scenario where the nexthop currently | |
400 | * requires | |
401 | * 'connected' resolution does not need a re-register (i.e., we treat | |
402 | * 'connected-required' as an override) except in the scenario where | |
403 | * this | |
404 | * is actually a case of tracking a peer for connectivity (e.g., after | |
405 | * disable connected-check). | |
406 | * NOTE: We don't track the number of paths separately for 'connected- | |
407 | * required' vs 'connected-not-required' as this change is not a common | |
408 | * scenario. | |
409 | */ | |
410 | else if (connected && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) { | |
411 | SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); | |
412 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
413 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
2bb8b49c DS |
414 | } else if (peer && !connected |
415 | && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) { | |
d62a17ae | 416 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); |
417 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
418 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
078430f6 | 419 | } |
4115b296 | 420 | if (peer && (bnc->ifindex != ifindex)) { |
421 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
422 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
423 | bnc->ifindex = ifindex; | |
424 | } | |
960035b2 | 425 | if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) { |
1ee0a2df DS |
426 | SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); |
427 | SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
b54892e0 | 428 | } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED) |
f663c581 | 429 | && !is_default_host_route(&bnc->prefix)) |
23f60ffd | 430 | register_zebra_rnh(bnc); |
1eb6c3ea | 431 | |
40381db7 | 432 | if (pi && pi->nexthop != bnc) { |
d62a17ae | 433 | /* Unlink from existing nexthop cache, if any. This will also |
434 | * free | |
435 | * the nexthop cache entry, if appropriate. | |
436 | */ | |
40381db7 | 437 | bgp_unlink_nexthop(pi); |
d62a17ae | 438 | |
7f040da1 DS |
439 | /* updates NHT pi list reference */ |
440 | path_nh_map(pi, bnc, true); | |
d62a17ae | 441 | |
ac2f64d3 | 442 | bpi_ultimate = bgp_get_imported_bpi_ultimate(pi); |
d62a17ae | 443 | if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) |
ac2f64d3 LS |
444 | (bgp_path_info_extra_get(bpi_ultimate))->igpmetric = |
445 | bnc->metric; | |
446 | else if (bpi_ultimate->extra) | |
447 | bpi_ultimate->extra->igpmetric = 0; | |
996319e6 DS |
448 | } else if (peer) { |
449 | /* | |
4667220e | 450 | * Let's not accidentally save the peer data for a peer |
996319e6 DS |
451 | * we are going to throw away in a second or so. |
452 | * When we come back around we'll fix up this | |
453 | * data properly in replace_nexthop_by_peer | |
454 | */ | |
455 | if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) | |
456 | bnc->nht_info = (void *)peer; /* NHT peer reference */ | |
457 | } | |
d62a17ae | 458 | |
459 | /* | |
460 | * We are cheating here. Views have no associated underlying | |
461 | * ability to detect nexthops. So when we have a view | |
462 | * just tell everyone the nexthop is valid | |
463 | */ | |
960035b2 | 464 | if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) |
d62a17ae | 465 | return 1; |
1bb550b6 PG |
466 | else if (safi == SAFI_UNICAST && pi && |
467 | pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra && | |
468 | pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop) | |
469 | return bgp_isvalid_nexthop_for_mpls(bnc, pi); | |
470 | else | |
d62a17ae | 471 | return (bgp_isvalid_nexthop(bnc)); |
fb018d25 DS |
472 | } |
473 | ||
d62a17ae | 474 | void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer) |
9a233a02 | 475 | { |
d62a17ae | 476 | struct bgp_nexthop_cache *bnc; |
477 | struct prefix p; | |
35aae5c9 | 478 | ifindex_t ifindex = 0; |
d62a17ae | 479 | |
480 | if (!peer) | |
481 | return; | |
482 | ||
51f3216b PJD |
483 | /* |
484 | * In case the below check evaluates true and if | |
485 | * the bnc has not been freed at this point, then | |
486 | * we might have to do something similar to what's | |
487 | * done in bgp_unlink_nexthop_by_peer(). Since | |
488 | * bgp_unlink_nexthop_by_peer() loops through the | |
489 | * nodes of V6 nexthop cache to find the bnc, it is | |
490 | * currently not being called here. | |
491 | */ | |
d62a17ae | 492 | if (!sockunion2hostprefix(&peer->su, &p)) |
493 | return; | |
35aae5c9 DS |
494 | /* |
495 | * Gather the ifindex for if up/down events to be | |
496 | * tagged into this fun | |
497 | */ | |
498 | if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) | |
499 | ifindex = peer->su.sin6.sin6_scope_id; | |
f663c581 | 500 | bnc = bnc_find(&peer->bgp->nexthop_cache_table[family2afi(p.family)], |
35aae5c9 | 501 | &p, 0, ifindex); |
14315f2d DS |
502 | if (!bnc) { |
503 | if (BGP_DEBUG(nht, NHT)) | |
8c1a4c10 | 504 | zlog_debug( |
f663c581 | 505 | "Cannot find connected NHT node for peer %s(%s)", |
8c1a4c10 | 506 | peer->host, peer->bgp->name_pretty); |
14315f2d DS |
507 | return; |
508 | } | |
d62a17ae | 509 | |
510 | if (bnc->nht_info != peer) { | |
511 | if (BGP_DEBUG(nht, NHT)) | |
512 | zlog_debug( | |
8c1a4c10 DS |
513 | "Connected NHT %p node for peer %s(%s) points to %p", |
514 | bnc, peer->host, bnc->bgp->name_pretty, | |
515 | bnc->nht_info); | |
d62a17ae | 516 | return; |
517 | } | |
518 | ||
519 | bnc->nht_info = NULL; | |
520 | ||
521 | if (LIST_EMPTY(&(bnc->paths))) { | |
522 | if (BGP_DEBUG(nht, NHT)) | |
8c1a4c10 DS |
523 | zlog_debug( |
524 | "Freeing connected NHT node %p for peer %s(%s)", | |
525 | bnc, peer->host, bnc->bgp->name_pretty); | |
23f60ffd | 526 | unregister_zebra_rnh(bnc); |
d62a17ae | 527 | bnc_free(bnc); |
528 | } | |
9a233a02 DS |
529 | } |
530 | ||
545aeef1 | 531 | static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, |
9f002fa5 DS |
532 | struct zapi_route *nhr, |
533 | bool import_check) | |
fb018d25 | 534 | { |
d62a17ae | 535 | struct nexthop *nexthop; |
536 | struct nexthop *oldnh; | |
537 | struct nexthop *nhlist_head = NULL; | |
538 | struct nexthop *nhlist_tail = NULL; | |
d62a17ae | 539 | int i; |
021b6596 | 540 | bool evpn_resolved = false; |
14315f2d | 541 | |
083ec940 | 542 | bnc->last_update = monotime(NULL); |
d62a17ae | 543 | bnc->change_flags = 0; |
d62a17ae | 544 | |
545 | /* debug print the input */ | |
987a720a DS |
546 | if (BGP_DEBUG(nht, NHT)) { |
547 | char bnc_buf[BNC_FLAG_DUMP_SIZE]; | |
548 | ||
d62a17ae | 549 | zlog_debug( |
35aae5c9 | 550 | "%s(%u): Rcvd NH update %pFX(%u)%u) - metric %d/%d #nhops %d/%d flags %s", |
2dbe669b | 551 | bnc->bgp->name_pretty, bnc->bgp->vrf_id, &nhr->prefix, |
35aae5c9 | 552 | bnc->ifindex, bnc->srte_color, nhr->metric, bnc->metric, |
987a720a DS |
553 | nhr->nexthop_num, bnc->nexthop_num, |
554 | bgp_nexthop_dump_bnc_flags(bnc, bnc_buf, | |
555 | sizeof(bnc_buf))); | |
556 | } | |
d62a17ae | 557 | |
545aeef1 | 558 | if (nhr->metric != bnc->metric) |
d62a17ae | 559 | bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED; |
560 | ||
545aeef1 | 561 | if (nhr->nexthop_num != bnc->nexthop_num) |
d62a17ae | 562 | bnc->change_flags |= BGP_NEXTHOP_CHANGED; |
563 | ||
9f002fa5 DS |
564 | if (import_check && (nhr->type == ZEBRA_ROUTE_BGP || |
565 | !prefix_same(&bnc->prefix, &nhr->prefix))) { | |
566 | SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); | |
567 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
568 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID); | |
569 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE); | |
570 | ||
571 | bnc_nexthop_free(bnc); | |
572 | bnc->nexthop = NULL; | |
573 | ||
574 | if (BGP_DEBUG(nht, NHT)) | |
575 | zlog_debug( | |
576 | "%s: Import Check does not resolve to the same prefix for %pFX received %pFX or matching route is BGP", | |
577 | __func__, &bnc->prefix, &nhr->prefix); | |
578 | } else if (nhr->nexthop_num) { | |
6137a77d DS |
579 | struct peer *peer = bnc->nht_info; |
580 | ||
d62a17ae | 581 | /* notify bgp fsm if nbr ip goes from invalid->valid */ |
582 | if (!bnc->nexthop_num) | |
583 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
584 | ||
021b6596 AD |
585 | if (!bnc->is_evpn_gwip_nexthop) |
586 | bnc->flags |= BGP_NEXTHOP_VALID; | |
545aeef1 RW |
587 | bnc->metric = nhr->metric; |
588 | bnc->nexthop_num = nhr->nexthop_num; | |
4a749e2c | 589 | |
960035b2 PZ |
590 | bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */ |
591 | ||
545aeef1 | 592 | for (i = 0; i < nhr->nexthop_num; i++) { |
960035b2 PZ |
593 | int num_labels = 0; |
594 | ||
545aeef1 | 595 | nexthop = nexthop_from_zapi_nexthop(&nhr->nexthops[i]); |
d62a17ae | 596 | |
6137a77d DS |
597 | /* |
598 | * Turn on RA for the v6 nexthops | |
599 | * we receive from bgp. This is to allow us | |
600 | * to work with v4 routing over v6 nexthops | |
601 | */ | |
687a2b5d DS |
602 | if (peer && !peer->ifp |
603 | && CHECK_FLAG(peer->flags, | |
604 | PEER_FLAG_CAPABILITY_ENHE) | |
545aeef1 | 605 | && nhr->prefix.family == AF_INET6 |
65f803e8 | 606 | && nexthop->type != NEXTHOP_TYPE_BLACKHOLE) { |
6137a77d DS |
607 | struct interface *ifp; |
608 | ||
609 | ifp = if_lookup_by_index(nexthop->ifindex, | |
610 | nexthop->vrf_id); | |
8c9769e0 DS |
611 | if (ifp) |
612 | zclient_send_interface_radv_req( | |
613 | zclient, nexthop->vrf_id, ifp, | |
614 | true, | |
615 | BGP_UNNUM_DEFAULT_RA_INTERVAL); | |
6137a77d | 616 | } |
960035b2 PZ |
617 | /* There is at least one label-switched path */ |
618 | if (nexthop->nh_label && | |
619 | nexthop->nh_label->num_labels) { | |
620 | ||
621 | bnc->flags |= BGP_NEXTHOP_LABELED_VALID; | |
622 | num_labels = nexthop->nh_label->num_labels; | |
623 | } | |
624 | ||
d62a17ae | 625 | if (BGP_DEBUG(nht, NHT)) { |
626 | char buf[NEXTHOP_STRLEN]; | |
627 | zlog_debug( | |
960035b2 PZ |
628 | " nhop via %s (%d labels)", |
629 | nexthop2str(nexthop, buf, sizeof(buf)), | |
630 | num_labels); | |
d62a17ae | 631 | } |
632 | ||
633 | if (nhlist_tail) { | |
634 | nhlist_tail->next = nexthop; | |
635 | nhlist_tail = nexthop; | |
636 | } else { | |
637 | nhlist_tail = nexthop; | |
638 | nhlist_head = nexthop; | |
639 | } | |
640 | ||
641 | /* No need to evaluate the nexthop if we have already | |
642 | * determined | |
643 | * that there has been a change. | |
644 | */ | |
645 | if (bnc->change_flags & BGP_NEXTHOP_CHANGED) | |
646 | continue; | |
647 | ||
648 | for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next) | |
78fba41b | 649 | if (nexthop_same(oldnh, nexthop)) |
d62a17ae | 650 | break; |
651 | ||
652 | if (!oldnh) | |
653 | bnc->change_flags |= BGP_NEXTHOP_CHANGED; | |
654 | } | |
655 | bnc_nexthop_free(bnc); | |
656 | bnc->nexthop = nhlist_head; | |
021b6596 AD |
657 | |
658 | /* | |
659 | * Gateway IP nexthop is L3 reachable. Mark it as | |
660 | * BGP_NEXTHOP_VALID only if it is recursively resolved with a | |
661 | * remote EVPN RT-2. | |
662 | * Else, mark it as BGP_NEXTHOP_EVPN_INCOMPLETE. | |
663 | * When its mapping with EVPN RT-2 is established, unset | |
664 | * BGP_NEXTHOP_EVPN_INCOMPLETE and set BGP_NEXTHOP_VALID. | |
665 | */ | |
666 | if (bnc->is_evpn_gwip_nexthop) { | |
667 | evpn_resolved = bgp_evpn_is_gateway_ip_resolved(bnc); | |
668 | ||
511211bf | 669 | if (BGP_DEBUG(nht, NHT)) |
021b6596 | 670 | zlog_debug( |
511211bf DA |
671 | "EVPN gateway IP %pFX recursive MAC/IP lookup %s", |
672 | &bnc->prefix, | |
021b6596 AD |
673 | (evpn_resolved ? "successful" |
674 | : "failed")); | |
021b6596 AD |
675 | |
676 | if (evpn_resolved) { | |
677 | bnc->flags |= BGP_NEXTHOP_VALID; | |
678 | bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; | |
679 | bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED; | |
680 | } else { | |
681 | bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE; | |
682 | bnc->flags &= ~BGP_NEXTHOP_VALID; | |
683 | } | |
684 | } | |
d62a17ae | 685 | } else { |
021b6596 | 686 | bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; |
d62a17ae | 687 | bnc->flags &= ~BGP_NEXTHOP_VALID; |
c3b95419 | 688 | bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; |
545aeef1 | 689 | bnc->nexthop_num = nhr->nexthop_num; |
d62a17ae | 690 | |
691 | /* notify bgp fsm if nbr ip goes from valid->invalid */ | |
692 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
693 | ||
694 | bnc_nexthop_free(bnc); | |
695 | bnc->nexthop = NULL; | |
696 | } | |
697 | ||
698 | evaluate_paths(bnc); | |
fb018d25 DS |
699 | } |
700 | ||
8761cd6d DS |
701 | static void bgp_nht_ifp_table_handle(struct bgp *bgp, |
702 | struct bgp_nexthop_cache_head *table, | |
703 | struct interface *ifp, bool up) | |
704 | { | |
705 | struct bgp_nexthop_cache *bnc; | |
706 | ||
707 | frr_each (bgp_nexthop_cache, table, bnc) { | |
708 | if (bnc->ifindex != ifp->ifindex) | |
709 | continue; | |
710 | ||
083ec940 | 711 | bnc->last_update = monotime(NULL); |
8761cd6d DS |
712 | bnc->change_flags = 0; |
713 | ||
474cfe4a DS |
714 | /* |
715 | * For interface based routes ( ala the v6 LL routes | |
716 | * that this was written for ) the metric received | |
717 | * for the connected route is 0 not 1. | |
718 | */ | |
719 | bnc->metric = 0; | |
8761cd6d DS |
720 | if (up) { |
721 | SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
722 | SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); | |
8761cd6d DS |
723 | bnc->nexthop_num = 1; |
724 | } else { | |
725 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
726 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
727 | SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); | |
728 | bnc->nexthop_num = 0; | |
8761cd6d DS |
729 | } |
730 | ||
731 | evaluate_paths(bnc); | |
732 | } | |
733 | } | |
734 | static void bgp_nht_ifp_handle(struct interface *ifp, bool up) | |
735 | { | |
736 | struct bgp *bgp; | |
737 | ||
096f7609 | 738 | bgp = ifp->vrf->info; |
8761cd6d DS |
739 | if (!bgp) |
740 | return; | |
741 | ||
7f2e9cce DS |
742 | bgp_nht_ifp_table_handle(bgp, &bgp->nexthop_cache_table[AFI_IP], ifp, |
743 | up); | |
744 | bgp_nht_ifp_table_handle(bgp, &bgp->import_check_table[AFI_IP], ifp, | |
745 | up); | |
8761cd6d DS |
746 | bgp_nht_ifp_table_handle(bgp, &bgp->nexthop_cache_table[AFI_IP6], ifp, |
747 | up); | |
748 | bgp_nht_ifp_table_handle(bgp, &bgp->import_check_table[AFI_IP6], ifp, | |
749 | up); | |
750 | } | |
751 | ||
752 | void bgp_nht_ifp_up(struct interface *ifp) | |
753 | { | |
754 | bgp_nht_ifp_handle(ifp, true); | |
755 | } | |
756 | ||
757 | void bgp_nht_ifp_down(struct interface *ifp) | |
758 | { | |
759 | bgp_nht_ifp_handle(ifp, false); | |
760 | } | |
761 | ||
e6685141 | 762 | static void bgp_nht_ifp_initial(struct event *thread) |
8761cd6d | 763 | { |
e16d030c DS |
764 | ifindex_t ifindex = EVENT_VAL(thread); |
765 | struct bgp *bgp = EVENT_ARG(thread); | |
0b52b75a | 766 | struct interface *ifp = if_lookup_by_index(ifindex, bgp->vrf_id); |
8761cd6d DS |
767 | |
768 | if (!ifp) | |
cc9f21da | 769 | return; |
8761cd6d | 770 | |
4115b296 | 771 | if (BGP_DEBUG(nht, NHT)) |
772 | zlog_debug( | |
773 | "Handle NHT initial update for Intf %s(%d) status %s", | |
774 | ifp->name, ifp->ifindex, if_is_up(ifp) ? "up" : "down"); | |
775 | ||
8761cd6d DS |
776 | if (if_is_up(ifp)) |
777 | bgp_nht_ifp_up(ifp); | |
778 | else | |
779 | bgp_nht_ifp_down(ifp); | |
8761cd6d DS |
780 | } |
781 | ||
782 | /* | |
783 | * So the bnc code has the ability to handle interface up/down | |
784 | * events to properly handle v6 LL peering. | |
785 | * What is happening here: | |
786 | * The event system for peering expects the nht code to | |
787 | * report on the tracking events after we move to active | |
788 | * So let's give the system a chance to report on that event | |
789 | * in a manner that is expected. | |
790 | */ | |
791 | void bgp_nht_interface_events(struct peer *peer) | |
792 | { | |
793 | struct bgp *bgp = peer->bgp; | |
794 | struct bgp_nexthop_cache_head *table; | |
795 | struct bgp_nexthop_cache *bnc; | |
796 | struct prefix p; | |
35aae5c9 | 797 | ifindex_t ifindex = 0; |
8761cd6d DS |
798 | |
799 | if (!IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) | |
800 | return; | |
801 | ||
802 | if (!sockunion2hostprefix(&peer->su, &p)) | |
803 | return; | |
35aae5c9 DS |
804 | /* |
805 | * Gather the ifindex for if up/down events to be | |
806 | * tagged into this fun | |
807 | */ | |
808 | if (peer->conf_if && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) | |
809 | ifindex = peer->su.sin6.sin6_scope_id; | |
8761cd6d DS |
810 | |
811 | table = &bgp->nexthop_cache_table[AFI_IP6]; | |
35aae5c9 | 812 | bnc = bnc_find(table, &p, 0, ifindex); |
8761cd6d DS |
813 | if (!bnc) |
814 | return; | |
815 | ||
816 | if (bnc->ifindex) | |
907a2395 DS |
817 | event_add_event(bm->master, bgp_nht_ifp_initial, bnc->bgp, |
818 | bnc->ifindex, NULL); | |
8761cd6d DS |
819 | } |
820 | ||
545aeef1 RW |
821 | void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) |
822 | { | |
823 | struct bgp_nexthop_cache_head *tree = NULL; | |
b8210849 | 824 | struct bgp_nexthop_cache *bnc_nhc, *bnc_import; |
545aeef1 | 825 | struct bgp *bgp; |
06e4e901 | 826 | struct prefix match; |
545aeef1 RW |
827 | struct zapi_route nhr; |
828 | afi_t afi; | |
829 | ||
830 | bgp = bgp_lookup_by_vrf_id(vrf_id); | |
831 | if (!bgp) { | |
832 | flog_err( | |
833 | EC_BGP_NH_UPD, | |
834 | "parse nexthop update: instance not found for vrf_id %u", | |
835 | vrf_id); | |
836 | return; | |
837 | } | |
838 | ||
06e4e901 | 839 | if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) { |
cc42c4f0 DS |
840 | zlog_err("%s[%s]: Failure to decode nexthop update", __func__, |
841 | bgp->name_pretty); | |
545aeef1 RW |
842 | return; |
843 | } | |
844 | ||
06e4e901 | 845 | afi = family2afi(match.family); |
b8210849 | 846 | tree = &bgp->nexthop_cache_table[afi]; |
545aeef1 | 847 | |
35aae5c9 | 848 | bnc_nhc = bnc_find(tree, &match, nhr.srte_color, 0); |
2bb8b49c DS |
849 | if (!bnc_nhc) { |
850 | if (BGP_DEBUG(nht, NHT)) | |
851 | zlog_debug( | |
852 | "parse nexthop update(%pFX(%u)(%s)): bnc info not found for nexthop cache", | |
853 | &nhr.prefix, nhr.srte_color, bgp->name_pretty); | |
854 | } else | |
9f002fa5 | 855 | bgp_process_nexthop_update(bnc_nhc, &nhr, false); |
b8210849 DS |
856 | |
857 | tree = &bgp->import_check_table[afi]; | |
858 | ||
35aae5c9 | 859 | bnc_import = bnc_find(tree, &match, nhr.srte_color, 0); |
2bb8b49c DS |
860 | if (!bnc_import) { |
861 | if (BGP_DEBUG(nht, NHT)) | |
862 | zlog_debug( | |
863 | "parse nexthop update(%pFX(%u)(%s)): bnc info not found for import check", | |
864 | &nhr.prefix, nhr.srte_color, bgp->name_pretty); | |
865 | } else | |
d00a5f6b | 866 | bgp_process_nexthop_update(bnc_import, &nhr, true); |
1e24860b | 867 | |
545aeef1 RW |
868 | /* |
869 | * HACK: if any BGP route is dependant on an SR-policy that doesn't | |
870 | * exist, zebra will never send NH updates relative to that policy. In | |
871 | * that case, whenever we receive an update about a colorless NH, update | |
872 | * the corresponding colorful NHs that share the same endpoint but that | |
873 | * are inactive. This ugly hack should work around the problem at the | |
874 | * cost of a performance pernalty. Long term, what should be done is to | |
875 | * make zebra's RNH subsystem aware of SR-TE colors (like bgpd is), | |
876 | * which should provide a better infrastructure to solve this issue in | |
877 | * a more efficient and elegant way. | |
878 | */ | |
b8210849 | 879 | if (nhr.srte_color == 0 && bnc_nhc) { |
545aeef1 RW |
880 | struct bgp_nexthop_cache *bnc_iter; |
881 | ||
882 | frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], | |
883 | bnc_iter) { | |
d00a5f6b DS |
884 | if (!prefix_same(&bnc_nhc->prefix, &bnc_iter->prefix) || |
885 | bnc_iter->srte_color == 0 || | |
886 | CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID)) | |
545aeef1 RW |
887 | continue; |
888 | ||
9f002fa5 | 889 | bgp_process_nexthop_update(bnc_iter, &nhr, false); |
545aeef1 RW |
890 | } |
891 | } | |
892 | } | |
893 | ||
ee7ca6c0 | 894 | /* |
895 | * Cleanup nexthop registration and status information for BGP nexthops | |
896 | * pertaining to this VRF. This is invoked upon VRF deletion. | |
897 | */ | |
898 | void bgp_cleanup_nexthops(struct bgp *bgp) | |
899 | { | |
f663c581 RW |
900 | for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) { |
901 | struct bgp_nexthop_cache *bnc; | |
ee7ca6c0 | 902 | |
f663c581 RW |
903 | frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], |
904 | bnc) { | |
ee7ca6c0 | 905 | /* Clear relevant flags. */ |
906 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
907 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
908 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
021b6596 | 909 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE); |
ee7ca6c0 | 910 | } |
911 | } | |
912 | } | |
913 | ||
fb018d25 DS |
914 | /** |
915 | * make_prefix - make a prefix structure from the path (essentially | |
916 | * path's node. | |
917 | */ | |
40381db7 | 918 | static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) |
fb018d25 | 919 | { |
078430f6 | 920 | |
40381db7 DS |
921 | int is_bgp_static = ((pi->type == ZEBRA_ROUTE_BGP) |
922 | && (pi->sub_type == BGP_ROUTE_STATIC)) | |
d62a17ae | 923 | ? 1 |
924 | : 0; | |
9bcb3eef DS |
925 | struct bgp_dest *net = pi->net; |
926 | const struct prefix *p_orig = bgp_dest_get_prefix(net); | |
92d6f769 | 927 | struct in_addr ipv4; |
0378bcaa PG |
928 | |
929 | if (p_orig->family == AF_FLOWSPEC) { | |
930 | if (!pi->peer) | |
931 | return -1; | |
932 | return bgp_flowspec_get_first_nh(pi->peer->bgp, | |
1840384b | 933 | pi, p, afi); |
0378bcaa | 934 | } |
d62a17ae | 935 | memset(p, 0, sizeof(struct prefix)); |
936 | switch (afi) { | |
937 | case AFI_IP: | |
938 | p->family = AF_INET; | |
939 | if (is_bgp_static) { | |
b54892e0 DS |
940 | p->u.prefix4 = p_orig->u.prefix4; |
941 | p->prefixlen = p_orig->prefixlen; | |
d62a17ae | 942 | } else { |
92d6f769 K |
943 | if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) { |
944 | ipv4_mapped_ipv6_to_ipv4( | |
945 | &pi->attr->mp_nexthop_global, &ipv4); | |
946 | p->u.prefix4 = ipv4; | |
947 | p->prefixlen = IPV4_MAX_BITLEN; | |
948 | } else { | |
7226bc40 TA |
949 | if (p_orig->family == AF_EVPN) |
950 | p->u.prefix4 = | |
951 | pi->attr->mp_nexthop_global_in; | |
952 | else | |
953 | p->u.prefix4 = pi->attr->nexthop; | |
92d6f769 K |
954 | p->prefixlen = IPV4_MAX_BITLEN; |
955 | } | |
d62a17ae | 956 | } |
957 | break; | |
958 | case AFI_IP6: | |
d62a17ae | 959 | p->family = AF_INET6; |
960 | ||
961 | if (is_bgp_static) { | |
b54892e0 DS |
962 | p->u.prefix6 = p_orig->u.prefix6; |
963 | p->prefixlen = p_orig->prefixlen; | |
d62a17ae | 964 | } else { |
606fdbb1 DA |
965 | /* If we receive MP_REACH nexthop with ::(LL) |
966 | * or LL(LL), use LL address as nexthop cache. | |
967 | */ | |
968 | if (pi->attr->mp_nexthop_len | |
969 | == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL | |
970 | && (IN6_IS_ADDR_UNSPECIFIED( | |
971 | &pi->attr->mp_nexthop_global) | |
972 | || IN6_IS_ADDR_LINKLOCAL( | |
973 | &pi->attr->mp_nexthop_global))) | |
974 | p->u.prefix6 = pi->attr->mp_nexthop_local; | |
17ef5a93 PG |
975 | /* If we receive MR_REACH with (GA)::(LL) |
976 | * then check for route-map to choose GA or LL | |
977 | */ | |
978 | else if (pi->attr->mp_nexthop_len | |
979 | == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { | |
2bb8b49c | 980 | if (pi->attr->mp_nexthop_prefer_global) |
17ef5a93 PG |
981 | p->u.prefix6 = |
982 | pi->attr->mp_nexthop_global; | |
983 | else | |
984 | p->u.prefix6 = | |
985 | pi->attr->mp_nexthop_local; | |
986 | } else | |
606fdbb1 | 987 | p->u.prefix6 = pi->attr->mp_nexthop_global; |
d62a17ae | 988 | p->prefixlen = IPV6_MAX_BITLEN; |
989 | } | |
990 | break; | |
991 | default: | |
992 | if (BGP_DEBUG(nht, NHT)) { | |
993 | zlog_debug( | |
994 | "%s: Attempting to make prefix with unknown AFI %d (not %d or %d)", | |
15569c58 | 995 | __func__, afi, AFI_IP, AFI_IP6); |
d62a17ae | 996 | } |
997 | break; | |
65740e1b | 998 | } |
d62a17ae | 999 | return 0; |
fb018d25 DS |
1000 | } |
1001 | ||
1002 | /** | |
078430f6 | 1003 | * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister |
fb018d25 DS |
1004 | * command to Zebra. |
1005 | * ARGUMENTS: | |
1006 | * struct bgp_nexthop_cache *bnc -- the nexthop structure. | |
078430f6 | 1007 | * int command -- command to send to zebra |
fb018d25 DS |
1008 | * RETURNS: |
1009 | * void. | |
1010 | */ | |
d62a17ae | 1011 | static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) |
fb018d25 | 1012 | { |
3c192540 | 1013 | bool exact_match = false; |
ed6cec97 | 1014 | bool resolve_via_default = false; |
d62a17ae | 1015 | int ret; |
1016 | ||
3c192540 | 1017 | if (!zclient) |
d62a17ae | 1018 | return; |
1019 | ||
1020 | /* Don't try to register if Zebra doesn't know of this instance. */ | |
bb4ef1ae DS |
1021 | if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bnc->bgp)) { |
1022 | if (BGP_DEBUG(zebra, ZEBRA)) | |
15569c58 DA |
1023 | zlog_debug( |
1024 | "%s: No zebra instance to talk to, not installing NHT entry", | |
1025 | __func__); | |
d62a17ae | 1026 | return; |
bb4ef1ae | 1027 | } |
d62a17ae | 1028 | |
1ee0a2df DS |
1029 | if (!bgp_zebra_num_connects()) { |
1030 | if (BGP_DEBUG(zebra, ZEBRA)) | |
15569c58 DA |
1031 | zlog_debug( |
1032 | "%s: We have not connected yet, cannot send nexthops", | |
1033 | __func__); | |
1ee0a2df | 1034 | } |
ed6cec97 DS |
1035 | if (command == ZEBRA_NEXTHOP_REGISTER) { |
1036 | if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) | |
1037 | exact_match = true; | |
1038 | if (CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) | |
1039 | resolve_via_default = true; | |
1040 | } | |
d62a17ae | 1041 | |
f663c581 RW |
1042 | if (BGP_DEBUG(zebra, ZEBRA)) |
1043 | zlog_debug("%s: sending cmd %s for %pFX (vrf %s)", __func__, | |
1044 | zserv_command_string(command), &bnc->prefix, | |
1045 | bnc->bgp->name_pretty); | |
960035b2 | 1046 | |
eb3c9d97 DL |
1047 | ret = zclient_send_rnh(zclient, command, &bnc->prefix, SAFI_UNICAST, |
1048 | exact_match, resolve_via_default, | |
1049 | bnc->bgp->vrf_id); | |
a6522038 | 1050 | if (ret == ZCLIENT_SEND_FAILURE) { |
e50f7cfd | 1051 | flog_warn(EC_BGP_ZEBRA_SEND, |
f162a5b9 | 1052 | "sendmsg_nexthop: zclient_send_message() failed"); |
a6522038 | 1053 | return; |
1054 | } | |
d62a17ae | 1055 | |
3d174ce0 | 1056 | if (command == ZEBRA_NEXTHOP_REGISTER) |
d62a17ae | 1057 | SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); |
3d174ce0 | 1058 | else if (command == ZEBRA_NEXTHOP_UNREGISTER) |
d62a17ae | 1059 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); |
1060 | return; | |
fb018d25 DS |
1061 | } |
1062 | ||
1063 | /** | |
078430f6 DS |
1064 | * register_zebra_rnh - register a NH/route with Zebra for notification |
1065 | * when the route or the route to the nexthop changes. | |
fb018d25 | 1066 | * ARGUMENTS: |
078430f6 | 1067 | * struct bgp_nexthop_cache *bnc |
fb018d25 DS |
1068 | * RETURNS: |
1069 | * void. | |
1070 | */ | |
23f60ffd | 1071 | static void register_zebra_rnh(struct bgp_nexthop_cache *bnc) |
fb018d25 | 1072 | { |
d62a17ae | 1073 | /* Check if we have already registered */ |
1074 | if (bnc->flags & BGP_NEXTHOP_REGISTERED) | |
1075 | return; | |
8761cd6d DS |
1076 | |
1077 | if (bnc->ifindex) { | |
1078 | SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
1079 | return; | |
1080 | } | |
1081 | ||
3d174ce0 | 1082 | sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER); |
fb018d25 DS |
1083 | } |
1084 | ||
1085 | /** | |
078430f6 | 1086 | * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra. |
fb018d25 | 1087 | * ARGUMENTS: |
078430f6 | 1088 | * struct bgp_nexthop_cache *bnc |
fb018d25 DS |
1089 | * RETURNS: |
1090 | * void. | |
1091 | */ | |
23f60ffd | 1092 | static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc) |
fb018d25 | 1093 | { |
d62a17ae | 1094 | /* Check if we have already registered */ |
1095 | if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) | |
1096 | return; | |
1097 | ||
8761cd6d DS |
1098 | if (bnc->ifindex) { |
1099 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
1100 | return; | |
1101 | } | |
1102 | ||
3d174ce0 | 1103 | sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER); |
fb018d25 DS |
1104 | } |
1105 | ||
1106 | /** | |
1107 | * evaluate_paths - Evaluate the paths/nets associated with a nexthop. | |
1108 | * ARGUMENTS: | |
1109 | * struct bgp_nexthop_cache *bnc -- the nexthop structure. | |
1110 | * RETURNS: | |
1111 | * void. | |
1112 | */ | |
021b6596 | 1113 | void evaluate_paths(struct bgp_nexthop_cache *bnc) |
fb018d25 | 1114 | { |
9bcb3eef | 1115 | struct bgp_dest *dest; |
4b7e6066 | 1116 | struct bgp_path_info *path; |
ac2f64d3 | 1117 | struct bgp_path_info *bpi_ultimate; |
d62a17ae | 1118 | int afi; |
1119 | struct peer *peer = (struct peer *)bnc->nht_info; | |
1120 | struct bgp_table *table; | |
1121 | safi_t safi; | |
960035b2 | 1122 | struct bgp *bgp_path; |
b54892e0 | 1123 | const struct prefix *p; |
d62a17ae | 1124 | |
1125 | if (BGP_DEBUG(nht, NHT)) { | |
987a720a | 1126 | char bnc_buf[BNC_FLAG_DUMP_SIZE]; |
df2a41a9 | 1127 | char chg_buf[BNC_FLAG_DUMP_SIZE]; |
987a720a | 1128 | |
d62a17ae | 1129 | zlog_debug( |
036f482f DA |
1130 | "NH update for %pFX(%d)(%u)(%s) - flags %s chgflags %s- evaluate paths", |
1131 | &bnc->prefix, bnc->ifindex, bnc->srte_color, | |
35aae5c9 | 1132 | bnc->bgp->name_pretty, |
df2a41a9 DS |
1133 | bgp_nexthop_dump_bnc_flags(bnc, bnc_buf, |
1134 | sizeof(bnc_buf)), | |
1135 | bgp_nexthop_dump_bnc_change_flags(bnc, chg_buf, | |
1136 | sizeof(bnc_buf))); | |
fb018d25 DS |
1137 | } |
1138 | ||
a2addae8 | 1139 | LIST_FOREACH (path, &(bnc->paths), nh_thread) { |
882d7b81 PG |
1140 | if (path->type == ZEBRA_ROUTE_BGP && |
1141 | (path->sub_type == BGP_ROUTE_NORMAL || | |
1142 | path->sub_type == BGP_ROUTE_STATIC || | |
1143 | path->sub_type == BGP_ROUTE_IMPORTED)) | |
1144 | /* evaluate the path */ | |
1145 | ; | |
1146 | else if (path->sub_type == BGP_ROUTE_REDISTRIBUTE) { | |
1147 | /* evaluate the path for redistributed routes | |
1148 | * except those from VNC | |
1149 | */ | |
1150 | if ((path->type == ZEBRA_ROUTE_VNC) || | |
1151 | (path->type == ZEBRA_ROUTE_VNC_DIRECT)) | |
1152 | continue; | |
1153 | } else | |
1154 | /* don't evaluate the path */ | |
d62a17ae | 1155 | continue; |
1156 | ||
9bcb3eef DS |
1157 | dest = path->net; |
1158 | assert(dest && bgp_dest_table(dest)); | |
1159 | p = bgp_dest_get_prefix(dest); | |
b54892e0 | 1160 | afi = family2afi(p->family); |
9bcb3eef | 1161 | table = bgp_dest_table(dest); |
d62a17ae | 1162 | safi = table->safi; |
1163 | ||
960035b2 PZ |
1164 | /* |
1165 | * handle routes from other VRFs (they can have a | |
1166 | * nexthop in THIS VRF). bgp_path is the bgp instance | |
1167 | * that owns the route referencing this nexthop. | |
1168 | */ | |
1169 | bgp_path = table->bgp; | |
1170 | ||
1171 | /* | |
1172 | * Path becomes valid/invalid depending on whether the nexthop | |
d62a17ae | 1173 | * reachable/unreachable. |
960035b2 PZ |
1174 | * |
1175 | * In case of unicast routes that were imported from vpn | |
1176 | * and that have labels, they are valid only if there are | |
1177 | * nexthops with labels | |
a2299aba AD |
1178 | * |
1179 | * If the nexthop is EVPN gateway-IP, | |
1180 | * do not check for a valid label. | |
d62a17ae | 1181 | */ |
960035b2 | 1182 | |
34ea39b6 | 1183 | bool bnc_is_valid_nexthop = false; |
1184 | bool path_valid = false; | |
960035b2 | 1185 | |
021b6596 AD |
1186 | if (safi == SAFI_UNICAST && path->sub_type == BGP_ROUTE_IMPORTED |
1187 | && path->extra && path->extra->num_labels | |
1188 | && (path->attr->evpn_overlay.type | |
1189 | != OVERLAY_INDEX_GATEWAY_IP)) { | |
960035b2 | 1190 | bnc_is_valid_nexthop = |
1bb550b6 PG |
1191 | bgp_isvalid_nexthop_for_mpls(bnc, path) ? true |
1192 | : false; | |
960035b2 | 1193 | } else { |
e7cbe5e5 NT |
1194 | if (bgp_update_martian_nexthop( |
1195 | bnc->bgp, afi, safi, path->type, | |
9bcb3eef | 1196 | path->sub_type, path->attr, dest)) { |
e7cbe5e5 NT |
1197 | if (BGP_DEBUG(nht, NHT)) |
1198 | zlog_debug( | |
56ca3b5b | 1199 | "%s: prefix %pBD (vrf %s), ignoring path due to martian or self-next-hop", |
9bcb3eef | 1200 | __func__, dest, bgp_path->name); |
e7cbe5e5 NT |
1201 | } else |
1202 | bnc_is_valid_nexthop = | |
34ea39b6 | 1203 | bgp_isvalid_nexthop(bnc) ? true : false; |
960035b2 PZ |
1204 | } |
1205 | ||
9e15d76a | 1206 | if (BGP_DEBUG(nht, NHT)) { |
4a8cd6ad PG |
1207 | |
1208 | if (dest->pdest) { | |
1209 | char rd_buf[RD_ADDRSTRLEN]; | |
1210 | ||
1211 | prefix_rd2str( | |
c4f64ea9 DA |
1212 | (struct prefix_rd *)bgp_dest_get_prefix( |
1213 | dest->pdest), | |
4a8cd6ad PG |
1214 | rd_buf, sizeof(rd_buf), |
1215 | bgp_get_asnotation(bnc->bgp)); | |
1216 | zlog_debug( | |
1217 | "... eval path %d/%d %pBD RD %s %s flags 0x%x", | |
1218 | afi, safi, dest, rd_buf, | |
9e15d76a | 1219 | bgp_path->name_pretty, path->flags); |
4a8cd6ad | 1220 | } else |
9e15d76a | 1221 | zlog_debug( |
56ca3b5b | 1222 | "... eval path %d/%d %pBD %s flags 0x%x", |
9bcb3eef | 1223 | afi, safi, dest, bgp_path->name_pretty, |
9e15d76a | 1224 | path->flags); |
1225 | } | |
d62a17ae | 1226 | |
0139efe0 | 1227 | /* Skip paths marked for removal or as history. */ |
1228 | if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED) | |
1229 | || CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) | |
1230 | continue; | |
1231 | ||
d62a17ae | 1232 | /* Copy the metric to the path. Will be used for bestpath |
1233 | * computation */ | |
ac2f64d3 | 1234 | bpi_ultimate = bgp_get_imported_bpi_ultimate(path); |
d62a17ae | 1235 | if (bgp_isvalid_nexthop(bnc) && bnc->metric) |
ac2f64d3 | 1236 | (bgp_path_info_extra_get(bpi_ultimate))->igpmetric = |
18ee8310 | 1237 | bnc->metric; |
ac2f64d3 LS |
1238 | else if (bpi_ultimate->extra) |
1239 | bpi_ultimate->extra->igpmetric = 0; | |
d62a17ae | 1240 | |
1241 | if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED) | |
545aeef1 RW |
1242 | || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED) |
1243 | || path->attr->srte_color != 0) | |
1defdda8 | 1244 | SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED); |
d62a17ae | 1245 | |
d4980edf | 1246 | path_valid = CHECK_FLAG(path->flags, BGP_PATH_VALID); |
577be36a PG |
1247 | if (path->type == ZEBRA_ROUTE_BGP && |
1248 | path->sub_type == BGP_ROUTE_STATIC && | |
1249 | !CHECK_FLAG(bgp_path->flags, BGP_FLAG_IMPORT_CHECK)) | |
1250 | /* static routes with 'no bgp network import-check' are | |
1251 | * always valid. if nht is called with static routes, | |
1252 | * the vpn exportation needs to be triggered | |
1253 | */ | |
1254 | vpn_leak_from_vrf_update(bgp_get_default(), bgp_path, | |
1255 | path); | |
882d7b81 PG |
1256 | else if (path->sub_type == BGP_ROUTE_REDISTRIBUTE && |
1257 | safi == SAFI_UNICAST && | |
1258 | (bgp_path->inst_type == BGP_INSTANCE_TYPE_VRF || | |
1259 | bgp_path->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) | |
1260 | /* redistribute routes are always valid | |
1261 | * if nht is called with redistribute routes, the vpn | |
1262 | * exportation needs to be triggered | |
1263 | */ | |
1264 | vpn_leak_from_vrf_update(bgp_get_default(), bgp_path, | |
1265 | path); | |
577be36a | 1266 | else if (path_valid != bnc_is_valid_nexthop) { |
34ea39b6 | 1267 | if (path_valid) { |
1268 | /* No longer valid, clear flag; also for EVPN | |
1269 | * routes, unimport from VRFs if needed. | |
1270 | */ | |
1271 | bgp_aggregate_decrement(bgp_path, p, path, afi, | |
1272 | safi); | |
9bcb3eef | 1273 | bgp_path_info_unset_flag(dest, path, |
34ea39b6 | 1274 | BGP_PATH_VALID); |
1275 | if (safi == SAFI_EVPN && | |
9bcb3eef | 1276 | bgp_evpn_is_prefix_nht_supported(bgp_dest_get_prefix(dest))) |
34ea39b6 | 1277 | bgp_evpn_unimport_route(bgp_path, |
9bcb3eef | 1278 | afi, safi, bgp_dest_get_prefix(dest), path); |
577be36a PG |
1279 | if (safi == SAFI_UNICAST && |
1280 | (bgp_path->inst_type != | |
1281 | BGP_INSTANCE_TYPE_VIEW)) | |
1282 | vpn_leak_from_vrf_withdraw( | |
1283 | bgp_get_default(), bgp_path, | |
1284 | path); | |
34ea39b6 | 1285 | } else { |
1286 | /* Path becomes valid, set flag; also for EVPN | |
1287 | * routes, import from VRFs if needed. | |
1288 | */ | |
9bcb3eef | 1289 | bgp_path_info_set_flag(dest, path, |
34ea39b6 | 1290 | BGP_PATH_VALID); |
1291 | bgp_aggregate_increment(bgp_path, p, path, afi, | |
1292 | safi); | |
1293 | if (safi == SAFI_EVPN && | |
9bcb3eef | 1294 | bgp_evpn_is_prefix_nht_supported(bgp_dest_get_prefix(dest))) |
34ea39b6 | 1295 | bgp_evpn_import_route(bgp_path, |
9bcb3eef | 1296 | afi, safi, bgp_dest_get_prefix(dest), path); |
577be36a PG |
1297 | if (safi == SAFI_UNICAST && |
1298 | (bgp_path->inst_type != | |
1299 | BGP_INSTANCE_TYPE_VIEW)) | |
1300 | vpn_leak_from_vrf_update( | |
1301 | bgp_get_default(), bgp_path, | |
1302 | path); | |
34ea39b6 | 1303 | } |
7c312383 AD |
1304 | } |
1305 | ||
9bcb3eef | 1306 | bgp_process(bgp_path, dest, afi, safi); |
d62a17ae | 1307 | } |
fc9a856f | 1308 | |
1e91f1d1 DS |
1309 | if (peer) { |
1310 | int valid_nexthops = bgp_isvalid_nexthop(bnc); | |
1311 | ||
824065c4 DS |
1312 | if (valid_nexthops) { |
1313 | /* | |
1314 | * Peering cannot occur across a blackhole nexthop | |
1315 | */ | |
e817f2cc | 1316 | if (bnc->nexthop_num == 1 && bnc->nexthop |
824065c4 DS |
1317 | && bnc->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { |
1318 | peer->last_reset = PEER_DOWN_WAITING_NHT; | |
1319 | valid_nexthops = 0; | |
1320 | } else | |
1321 | peer->last_reset = PEER_DOWN_WAITING_OPEN; | |
1322 | } else | |
1e91f1d1 DS |
1323 | peer->last_reset = PEER_DOWN_WAITING_NHT; |
1324 | ||
1325 | if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) { | |
1326 | if (BGP_DEBUG(nht, NHT)) | |
15569c58 | 1327 | zlog_debug( |
8761cd6d | 1328 | "%s: Updating peer (%s(%s)) status with NHT nexthops %d", |
15569c58 | 1329 | __func__, peer->host, |
8761cd6d DS |
1330 | peer->bgp->name_pretty, |
1331 | !!valid_nexthops); | |
f8dcd38d | 1332 | bgp_fsm_nht_update(peer, !!valid_nexthops); |
1e91f1d1 DS |
1333 | SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); |
1334 | } | |
d62a17ae | 1335 | } |
fc9a856f | 1336 | |
d62a17ae | 1337 | RESET_FLAG(bnc->change_flags); |
fb018d25 DS |
1338 | } |
1339 | ||
1340 | /** | |
1341 | * path_nh_map - make or break path-to-nexthop association. | |
1342 | * ARGUMENTS: | |
1343 | * path - pointer to the path structure | |
1344 | * bnc - pointer to the nexthop structure | |
1345 | * make - if set, make the association. if unset, just break the existing | |
1346 | * association. | |
1347 | */ | |
7f040da1 DS |
1348 | void path_nh_map(struct bgp_path_info *path, struct bgp_nexthop_cache *bnc, |
1349 | bool make) | |
fb018d25 | 1350 | { |
d62a17ae | 1351 | if (path->nexthop) { |
1352 | LIST_REMOVE(path, nh_thread); | |
1353 | path->nexthop->path_count--; | |
1354 | path->nexthop = NULL; | |
1355 | } | |
1356 | if (make) { | |
1357 | LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread); | |
1358 | path->nexthop = bnc; | |
1359 | path->nexthop->path_count++; | |
1360 | } | |
fb018d25 | 1361 | } |
1ee0a2df DS |
1362 | |
1363 | /* | |
1364 | * This function is called to register nexthops to zebra | |
1365 | * as that we may have tried to install the nexthops | |
1366 | * before we actually have a zebra connection | |
1367 | */ | |
1368 | void bgp_nht_register_nexthops(struct bgp *bgp) | |
1369 | { | |
f663c581 RW |
1370 | for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) { |
1371 | struct bgp_nexthop_cache *bnc; | |
1ee0a2df | 1372 | |
f663c581 RW |
1373 | frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], |
1374 | bnc) { | |
23f60ffd | 1375 | register_zebra_rnh(bnc); |
1ee0a2df DS |
1376 | } |
1377 | } | |
1378 | } | |
1ea03b90 | 1379 | |
b3a3290e | 1380 | void bgp_nht_reg_enhe_cap_intfs(struct peer *peer) |
1ea03b90 DS |
1381 | { |
1382 | struct bgp *bgp; | |
1ea03b90 DS |
1383 | struct bgp_nexthop_cache *bnc; |
1384 | struct nexthop *nhop; | |
1385 | struct interface *ifp; | |
1386 | struct prefix p; | |
35aae5c9 | 1387 | ifindex_t ifindex = 0; |
1ea03b90 DS |
1388 | |
1389 | if (peer->ifp) | |
1390 | return; | |
1391 | ||
1392 | bgp = peer->bgp; | |
1ea03b90 | 1393 | if (!sockunion2hostprefix(&peer->su, &p)) { |
b3a3290e DS |
1394 | zlog_warn("%s: Unable to convert sockunion to prefix for %s", |
1395 | __func__, peer->host); | |
1ea03b90 DS |
1396 | return; |
1397 | } | |
1398 | ||
1399 | if (p.family != AF_INET6) | |
1400 | return; | |
35aae5c9 DS |
1401 | /* |
1402 | * Gather the ifindex for if up/down events to be | |
1403 | * tagged into this fun | |
1404 | */ | |
1405 | if (peer->conf_if && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) | |
1406 | ifindex = peer->su.sin6.sin6_scope_id; | |
1ea03b90 | 1407 | |
35aae5c9 | 1408 | bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0, ifindex); |
1ea03b90 DS |
1409 | if (!bnc) |
1410 | return; | |
1411 | ||
1412 | if (peer != bnc->nht_info) | |
1413 | return; | |
1414 | ||
1415 | for (nhop = bnc->nexthop; nhop; nhop = nhop->next) { | |
8c9769e0 DS |
1416 | ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id); |
1417 | ||
1418 | if (!ifp) | |
1419 | continue; | |
1420 | ||
1ea03b90 DS |
1421 | zclient_send_interface_radv_req(zclient, |
1422 | nhop->vrf_id, | |
1423 | ifp, true, | |
1424 | BGP_UNNUM_DEFAULT_RA_INTERVAL); | |
1425 | } | |
1426 | } | |
b3a3290e DS |
1427 | |
1428 | void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer) | |
1429 | { | |
1430 | struct bgp *bgp; | |
b3a3290e DS |
1431 | struct bgp_nexthop_cache *bnc; |
1432 | struct nexthop *nhop; | |
1433 | struct interface *ifp; | |
1434 | struct prefix p; | |
35aae5c9 | 1435 | ifindex_t ifindex = 0; |
b3a3290e DS |
1436 | |
1437 | if (peer->ifp) | |
1438 | return; | |
1439 | ||
1440 | bgp = peer->bgp; | |
1441 | ||
b3a3290e DS |
1442 | if (!sockunion2hostprefix(&peer->su, &p)) { |
1443 | zlog_warn("%s: Unable to convert sockunion to prefix for %s", | |
1444 | __func__, peer->host); | |
1445 | return; | |
1446 | } | |
1447 | ||
1448 | if (p.family != AF_INET6) | |
1449 | return; | |
35aae5c9 DS |
1450 | /* |
1451 | * Gather the ifindex for if up/down events to be | |
1452 | * tagged into this fun | |
1453 | */ | |
1454 | if (peer->conf_if && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) | |
1455 | ifindex = peer->su.sin6.sin6_scope_id; | |
b3a3290e | 1456 | |
35aae5c9 | 1457 | bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0, ifindex); |
b3a3290e DS |
1458 | if (!bnc) |
1459 | return; | |
1460 | ||
1461 | if (peer != bnc->nht_info) | |
1462 | return; | |
1463 | ||
1464 | for (nhop = bnc->nexthop; nhop; nhop = nhop->next) { | |
1465 | ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id); | |
1466 | ||
68cecc3b DS |
1467 | if (!ifp) |
1468 | continue; | |
1469 | ||
b3a3290e DS |
1470 | zclient_send_interface_radv_req(zclient, nhop->vrf_id, ifp, 0, |
1471 | 0); | |
1472 | } | |
1473 | } | |
c589d847 AK |
1474 | |
1475 | /**************************************************************************** | |
1476 | * L3 NHGs are used for fast failover of nexthops in the dplane. These are | |
1477 | * the APIs for allocating L3 NHG ids. Management of the L3 NHG itself is | |
1478 | * left to the application using it. | |
1479 | * PS: Currently EVPN host routes is the only app using L3 NHG for fast | |
1480 | * failover of remote ES links. | |
1481 | ***************************************************************************/ | |
1482 | static bitfield_t bgp_nh_id_bitmap; | |
8bcb09a1 | 1483 | static uint32_t bgp_l3nhg_start; |
c589d847 | 1484 | |
8bcb09a1 AK |
1485 | /* XXX - currently we do nothing on the callbacks */ |
1486 | static void bgp_l3nhg_add_cb(const char *name) | |
1487 | { | |
1488 | } | |
f3c6dd49 DS |
1489 | |
1490 | static void bgp_l3nhg_modify_cb(const struct nexthop_group_cmd *nhgc) | |
1491 | { | |
1492 | } | |
1493 | ||
8bcb09a1 AK |
1494 | static void bgp_l3nhg_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, |
1495 | const struct nexthop *nhop) | |
1496 | { | |
1497 | } | |
f3c6dd49 | 1498 | |
8bcb09a1 AK |
1499 | static void bgp_l3nhg_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, |
1500 | const struct nexthop *nhop) | |
1501 | { | |
1502 | } | |
f3c6dd49 | 1503 | |
8bcb09a1 | 1504 | static void bgp_l3nhg_del_cb(const char *name) |
c589d847 | 1505 | { |
c589d847 AK |
1506 | } |
1507 | ||
8bcb09a1 | 1508 | static void bgp_l3nhg_zebra_init(void) |
c589d847 | 1509 | { |
8bcb09a1 AK |
1510 | static bool bgp_l3nhg_zebra_inited; |
1511 | if (bgp_l3nhg_zebra_inited) | |
c589d847 AK |
1512 | return; |
1513 | ||
8bcb09a1 AK |
1514 | bgp_l3nhg_zebra_inited = true; |
1515 | bgp_l3nhg_start = zclient_get_nhg_start(ZEBRA_ROUTE_BGP); | |
f3c6dd49 DS |
1516 | nexthop_group_init(bgp_l3nhg_add_cb, bgp_l3nhg_modify_cb, |
1517 | bgp_l3nhg_add_nexthop_cb, bgp_l3nhg_del_nexthop_cb, | |
1518 | bgp_l3nhg_del_cb); | |
c589d847 AK |
1519 | } |
1520 | ||
8bcb09a1 | 1521 | |
c589d847 AK |
1522 | void bgp_l3nhg_init(void) |
1523 | { | |
8bcb09a1 AK |
1524 | uint32_t id_max; |
1525 | ||
7a8ce9d5 | 1526 | id_max = MIN(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024); |
8bcb09a1 | 1527 | bf_init(bgp_nh_id_bitmap, id_max); |
c589d847 | 1528 | bf_assign_zero_index(bgp_nh_id_bitmap); |
8bcb09a1 AK |
1529 | |
1530 | if (BGP_DEBUG(nht, NHT) || BGP_DEBUG(evpn_mh, EVPN_MH_ES)) | |
1531 | zlog_debug("bgp l3_nhg range %u - %u", bgp_l3nhg_start + 1, | |
1532 | bgp_l3nhg_start + id_max); | |
c589d847 AK |
1533 | } |
1534 | ||
1535 | void bgp_l3nhg_finish(void) | |
1536 | { | |
1537 | bf_free(bgp_nh_id_bitmap); | |
1538 | } | |
8bcb09a1 AK |
1539 | |
1540 | uint32_t bgp_l3nhg_id_alloc(void) | |
1541 | { | |
1542 | uint32_t nhg_id = 0; | |
1543 | ||
1544 | bgp_l3nhg_zebra_init(); | |
1545 | bf_assign_index(bgp_nh_id_bitmap, nhg_id); | |
1546 | if (nhg_id) | |
1547 | nhg_id += bgp_l3nhg_start; | |
1548 | ||
1549 | return nhg_id; | |
1550 | } | |
1551 | ||
1552 | void bgp_l3nhg_id_free(uint32_t nhg_id) | |
1553 | { | |
1554 | if (!nhg_id || (nhg_id <= bgp_l3nhg_start)) | |
1555 | return; | |
1556 | ||
1557 | nhg_id -= bgp_l3nhg_start; | |
1558 | ||
1559 | bf_release_index(bgp_nh_id_bitmap, nhg_id); | |
1560 | } |