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