]>
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" |
fb018d25 DS |
34 | |
35 | #include "bgpd/bgpd.h" | |
36 | #include "bgpd/bgp_table.h" | |
37 | #include "bgpd/bgp_route.h" | |
38 | #include "bgpd/bgp_attr.h" | |
39 | #include "bgpd/bgp_nexthop.h" | |
40 | #include "bgpd/bgp_debug.h" | |
14454c9f | 41 | #include "bgpd/bgp_errors.h" |
fb018d25 | 42 | #include "bgpd/bgp_nht.h" |
ffd0c037 | 43 | #include "bgpd/bgp_fsm.h" |
afbb1c59 | 44 | #include "bgpd/bgp_zebra.h" |
0378bcaa | 45 | #include "bgpd/bgp_flowspec_util.h" |
7c312383 | 46 | #include "bgpd/bgp_evpn.h" |
fb018d25 DS |
47 | |
48 | extern struct zclient *zclient; | |
fb018d25 | 49 | |
078430f6 | 50 | static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, |
d62a17ae | 51 | int is_bgp_static_route); |
078430f6 DS |
52 | static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc, |
53 | int is_bgp_static_route); | |
fb018d25 | 54 | static void evaluate_paths(struct bgp_nexthop_cache *bnc); |
40381db7 | 55 | static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p); |
fb018d25 | 56 | |
d62a17ae | 57 | static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc) |
d4d9d757 | 58 | { |
d62a17ae | 59 | return (bgp_zebra_num_connects() == 0 |
60 | || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID))); | |
d4d9d757 LB |
61 | } |
62 | ||
960035b2 PZ |
63 | static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc) |
64 | { | |
65 | return (bgp_zebra_num_connects() == 0 | |
66 | || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID))); | |
67 | } | |
68 | ||
d62a17ae | 69 | static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) |
fb018d25 | 70 | { |
d5c4bac9 | 71 | if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) { |
d62a17ae | 72 | if (BGP_DEBUG(nht, NHT)) { |
73 | char buf[PREFIX2STR_BUFFER]; | |
8c1a4c10 DS |
74 | zlog_debug("bgp_unlink_nexthop: freeing bnc %s(%s)", |
75 | bnc_str(bnc, buf, PREFIX2STR_BUFFER), | |
76 | bnc->bgp->name_pretty); | |
d62a17ae | 77 | } |
78 | unregister_zebra_rnh(bnc, | |
79 | CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)); | |
5b8d32bd | 80 | bgp_node_set_bgp_nexthop_info(bnc->node, NULL); |
d62a17ae | 81 | bgp_unlock_node(bnc->node); |
82 | bnc->node = NULL; | |
83 | bnc_free(bnc); | |
fb018d25 | 84 | } |
fb018d25 DS |
85 | } |
86 | ||
4b7e6066 | 87 | void bgp_unlink_nexthop(struct bgp_path_info *path) |
f9164b1d | 88 | { |
d62a17ae | 89 | struct bgp_nexthop_cache *bnc = path->nexthop; |
90 | ||
91 | if (!bnc) | |
92 | return; | |
f9164b1d | 93 | |
7f040da1 | 94 | path_nh_map(path, NULL, false); |
f9164b1d | 95 | |
d62a17ae | 96 | bgp_unlink_nexthop_check(bnc); |
f9164b1d PJ |
97 | } |
98 | ||
d62a17ae | 99 | void bgp_unlink_nexthop_by_peer(struct peer *peer) |
f9164b1d | 100 | { |
d62a17ae | 101 | struct prefix p; |
102 | struct bgp_node *rn; | |
103 | struct bgp_nexthop_cache *bnc; | |
104 | afi_t afi = family2afi(peer->su.sa.sa_family); | |
105 | ||
106 | if (!sockunion2hostprefix(&peer->su, &p)) | |
107 | return; | |
108 | ||
109 | rn = bgp_node_get(peer->bgp->nexthop_cache_table[afi], &p); | |
110 | ||
5b8d32bd | 111 | bnc = bgp_node_get_bgp_nexthop_info(rn); |
14315f2d | 112 | if (!bnc) |
d62a17ae | 113 | return; |
114 | ||
d62a17ae | 115 | /* cleanup the peer reference */ |
116 | bnc->nht_info = NULL; | |
117 | ||
118 | bgp_unlink_nexthop_check(bnc); | |
f9164b1d PJ |
119 | } |
120 | ||
960035b2 PZ |
121 | /* |
122 | * A route and its nexthop might belong to different VRFs. Therefore, | |
123 | * we need both the bgp_route and bgp_nexthop pointers. | |
124 | */ | |
125 | int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, | |
40381db7 | 126 | afi_t afi, struct bgp_path_info *pi, |
d62a17ae | 127 | struct peer *peer, int connected) |
fb018d25 | 128 | { |
d62a17ae | 129 | struct bgp_node *rn; |
130 | struct bgp_nexthop_cache *bnc; | |
131 | struct prefix p; | |
132 | int is_bgp_static_route = 0; | |
b54892e0 | 133 | const struct prefix *bnc_p; |
d62a17ae | 134 | |
40381db7 DS |
135 | if (pi) { |
136 | is_bgp_static_route = ((pi->type == ZEBRA_ROUTE_BGP) | |
137 | && (pi->sub_type == BGP_ROUTE_STATIC)) | |
d62a17ae | 138 | ? 1 |
139 | : 0; | |
140 | ||
141 | /* Since Extended Next-hop Encoding (RFC5549) support, we want | |
142 | to derive | |
143 | address-family from the next-hop. */ | |
144 | if (!is_bgp_static_route) | |
40381db7 | 145 | afi = BGP_ATTR_NEXTHOP_AFI_IP6(pi->attr) ? AFI_IP6 |
d62a17ae | 146 | : AFI_IP; |
147 | ||
2951a7a4 | 148 | /* This will return true if the global IPv6 NH is a link local |
d62a17ae | 149 | * addr */ |
40381db7 | 150 | if (make_prefix(afi, pi, &p) < 0) |
d62a17ae | 151 | return 1; |
152 | } else if (peer) { | |
d62a17ae | 153 | if (!sockunion2hostprefix(&peer->su, &p)) { |
154 | if (BGP_DEBUG(nht, NHT)) { | |
155 | zlog_debug( | |
156 | "%s: Attempting to register with unknown AFI %d (not %d or %d)", | |
15569c58 | 157 | __func__, afi, AFI_IP, AFI_IP6); |
d62a17ae | 158 | } |
159 | return 0; | |
160 | } | |
161 | } else | |
162 | return 0; | |
163 | ||
164 | if (is_bgp_static_route) | |
960035b2 | 165 | rn = bgp_node_get(bgp_nexthop->import_check_table[afi], &p); |
d62a17ae | 166 | else |
960035b2 | 167 | rn = bgp_node_get(bgp_nexthop->nexthop_cache_table[afi], &p); |
d62a17ae | 168 | |
5b8d32bd | 169 | bnc = bgp_node_get_bgp_nexthop_info(rn); |
14315f2d | 170 | if (!bnc) { |
d62a17ae | 171 | bnc = bnc_new(); |
5b8d32bd | 172 | bgp_node_set_bgp_nexthop_info(rn, bnc); |
d62a17ae | 173 | bnc->node = rn; |
960035b2 | 174 | bnc->bgp = bgp_nexthop; |
d62a17ae | 175 | bgp_lock_node(rn); |
176 | if (BGP_DEBUG(nht, NHT)) { | |
177 | char buf[PREFIX2STR_BUFFER]; | |
178 | ||
8c1a4c10 DS |
179 | zlog_debug("Allocated bnc %s(%s) peer %p", |
180 | bnc_str(bnc, buf, PREFIX2STR_BUFFER), | |
181 | bnc->bgp->name_pretty, peer); | |
d62a17ae | 182 | } |
fc9a856f | 183 | } |
d62a17ae | 184 | |
b54892e0 DS |
185 | bnc_p = bgp_node_get_prefix(bnc->node); |
186 | ||
d62a17ae | 187 | bgp_unlock_node(rn); |
188 | if (is_bgp_static_route) { | |
189 | SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); | |
190 | ||
191 | /* If we're toggling the type, re-register */ | |
892fedb6 | 192 | if ((CHECK_FLAG(bgp_route->flags, BGP_FLAG_IMPORT_CHECK)) |
d62a17ae | 193 | && !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) { |
194 | SET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); | |
195 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
196 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
892fedb6 DA |
197 | } else if ((!CHECK_FLAG(bgp_route->flags, |
198 | BGP_FLAG_IMPORT_CHECK)) | |
d62a17ae | 199 | && CHECK_FLAG(bnc->flags, |
200 | BGP_STATIC_ROUTE_EXACT_MATCH)) { | |
201 | UNSET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); | |
202 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
203 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
204 | } | |
078430f6 | 205 | } |
d62a17ae | 206 | /* When nexthop is already known, but now requires 'connected' |
207 | * resolution, | |
208 | * re-register it. The reverse scenario where the nexthop currently | |
209 | * requires | |
210 | * 'connected' resolution does not need a re-register (i.e., we treat | |
211 | * 'connected-required' as an override) except in the scenario where | |
212 | * this | |
213 | * is actually a case of tracking a peer for connectivity (e.g., after | |
214 | * disable connected-check). | |
215 | * NOTE: We don't track the number of paths separately for 'connected- | |
216 | * required' vs 'connected-not-required' as this change is not a common | |
217 | * scenario. | |
218 | */ | |
219 | else if (connected && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) { | |
220 | SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); | |
221 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
222 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
223 | } else if (peer && !connected | |
224 | && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) { | |
225 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); | |
226 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
227 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
078430f6 | 228 | } |
960035b2 | 229 | if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) { |
1ee0a2df DS |
230 | SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); |
231 | SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
b54892e0 DS |
232 | } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED) |
233 | && !is_default_host_route(bnc_p)) | |
d62a17ae | 234 | register_zebra_rnh(bnc, is_bgp_static_route); |
1eb6c3ea | 235 | |
40381db7 | 236 | if (pi && pi->nexthop != bnc) { |
d62a17ae | 237 | /* Unlink from existing nexthop cache, if any. This will also |
238 | * free | |
239 | * the nexthop cache entry, if appropriate. | |
240 | */ | |
40381db7 | 241 | bgp_unlink_nexthop(pi); |
d62a17ae | 242 | |
7f040da1 DS |
243 | /* updates NHT pi list reference */ |
244 | path_nh_map(pi, bnc, true); | |
d62a17ae | 245 | |
246 | if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) | |
40381db7 DS |
247 | (bgp_path_info_extra_get(pi))->igpmetric = bnc->metric; |
248 | else if (pi->extra) | |
249 | pi->extra->igpmetric = 0; | |
d62a17ae | 250 | } else if (peer) |
251 | bnc->nht_info = (void *)peer; /* NHT peer reference */ | |
252 | ||
253 | /* | |
254 | * We are cheating here. Views have no associated underlying | |
255 | * ability to detect nexthops. So when we have a view | |
256 | * just tell everyone the nexthop is valid | |
257 | */ | |
960035b2 | 258 | if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) |
d62a17ae | 259 | return 1; |
260 | else | |
261 | return (bgp_isvalid_nexthop(bnc)); | |
fb018d25 DS |
262 | } |
263 | ||
d62a17ae | 264 | void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer) |
9a233a02 | 265 | { |
d62a17ae | 266 | struct bgp_node *rn; |
267 | struct bgp_nexthop_cache *bnc; | |
268 | struct prefix p; | |
269 | ||
270 | if (!peer) | |
271 | return; | |
272 | ||
d62a17ae | 273 | if (!sockunion2hostprefix(&peer->su, &p)) |
274 | return; | |
275 | ||
276 | rn = bgp_node_lookup( | |
277 | peer->bgp->nexthop_cache_table[family2afi(p.family)], &p); | |
14315f2d | 278 | if (!rn) { |
d62a17ae | 279 | if (BGP_DEBUG(nht, NHT)) |
8c1a4c10 DS |
280 | zlog_debug( |
281 | "Cannot find connected NHT node for peer %s(%s)", | |
282 | peer->host, peer->bgp->name_pretty); | |
d62a17ae | 283 | return; |
284 | } | |
285 | ||
5b8d32bd | 286 | bnc = bgp_node_get_bgp_nexthop_info(rn); |
14315f2d DS |
287 | if (!bnc) { |
288 | if (BGP_DEBUG(nht, NHT)) | |
8c1a4c10 DS |
289 | zlog_debug( |
290 | "Cannot find connected NHT node for peer %s(%s) on route_node as expected", | |
291 | peer->host, peer->bgp->name_pretty); | |
14315f2d DS |
292 | bgp_unlock_node(rn); |
293 | return; | |
294 | } | |
d62a17ae | 295 | bgp_unlock_node(rn); |
296 | ||
297 | if (bnc->nht_info != peer) { | |
298 | if (BGP_DEBUG(nht, NHT)) | |
299 | zlog_debug( | |
8c1a4c10 DS |
300 | "Connected NHT %p node for peer %s(%s) points to %p", |
301 | bnc, peer->host, bnc->bgp->name_pretty, | |
302 | bnc->nht_info); | |
d62a17ae | 303 | return; |
304 | } | |
305 | ||
306 | bnc->nht_info = NULL; | |
307 | ||
308 | if (LIST_EMPTY(&(bnc->paths))) { | |
309 | if (BGP_DEBUG(nht, NHT)) | |
8c1a4c10 DS |
310 | zlog_debug( |
311 | "Freeing connected NHT node %p for peer %s(%s)", | |
312 | bnc, peer->host, bnc->bgp->name_pretty); | |
d62a17ae | 313 | unregister_zebra_rnh(bnc, 0); |
5b8d32bd | 314 | bgp_node_set_bgp_nexthop_info(bnc->node, NULL); |
d62a17ae | 315 | bgp_unlock_node(bnc->node); |
316 | bnc_free(bnc); | |
317 | } | |
9a233a02 DS |
318 | } |
319 | ||
d62a17ae | 320 | void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) |
fb018d25 | 321 | { |
d62a17ae | 322 | struct bgp_node *rn = NULL; |
323 | struct bgp_nexthop_cache *bnc; | |
324 | struct nexthop *nexthop; | |
325 | struct nexthop *oldnh; | |
326 | struct nexthop *nhlist_head = NULL; | |
327 | struct nexthop *nhlist_tail = NULL; | |
d62a17ae | 328 | int i; |
329 | struct bgp *bgp; | |
4a749e2c | 330 | struct zapi_route nhr; |
d62a17ae | 331 | |
332 | bgp = bgp_lookup_by_vrf_id(vrf_id); | |
333 | if (!bgp) { | |
af4c2728 | 334 | flog_err( |
e50f7cfd | 335 | EC_BGP_NH_UPD, |
a8bf7d9c | 336 | "parse nexthop update: instance not found for vrf_id %u", |
d62a17ae | 337 | vrf_id); |
338 | return; | |
fb018d25 | 339 | } |
d62a17ae | 340 | |
7d30a959 DS |
341 | if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { |
342 | if (BGP_DEBUG(nht, NHT)) | |
8c1a4c10 | 343 | zlog_debug("%s[%s]: Failure to decode nexthop update", |
15569c58 | 344 | __func__, bgp->name_pretty); |
7d30a959 DS |
345 | return; |
346 | } | |
d62a17ae | 347 | |
348 | if (command == ZEBRA_NEXTHOP_UPDATE) | |
349 | rn = bgp_node_lookup( | |
4a749e2c DS |
350 | bgp->nexthop_cache_table[family2afi(nhr.prefix.family)], |
351 | &nhr.prefix); | |
d62a17ae | 352 | else if (command == ZEBRA_IMPORT_CHECK_UPDATE) |
353 | rn = bgp_node_lookup( | |
4a749e2c DS |
354 | bgp->import_check_table[family2afi(nhr.prefix.family)], |
355 | &nhr.prefix); | |
d62a17ae | 356 | |
14315f2d | 357 | if (!rn) { |
d62a17ae | 358 | if (BGP_DEBUG(nht, NHT)) { |
359 | char buf[PREFIX2STR_BUFFER]; | |
4a749e2c | 360 | prefix2str(&nhr.prefix, buf, sizeof(buf)); |
8c1a4c10 DS |
361 | zlog_debug("parse nexthop update(%s(%s)): rn not found", |
362 | buf, bgp->name_pretty); | |
d62a17ae | 363 | } |
d62a17ae | 364 | return; |
fb018d25 | 365 | } |
d62a17ae | 366 | |
5b8d32bd | 367 | bnc = bgp_node_get_bgp_nexthop_info(rn); |
14315f2d DS |
368 | if (!bnc) { |
369 | if (BGP_DEBUG(nht, NHT)) { | |
370 | char buf[PREFIX2STR_BUFFER]; | |
371 | ||
372 | prefix2str(&nhr.prefix, buf, sizeof(buf)); | |
8c1a4c10 DS |
373 | zlog_debug( |
374 | "parse nexthop update(%s(%s)): bnc node info not found", | |
375 | buf, bgp->name_pretty); | |
14315f2d DS |
376 | } |
377 | bgp_unlock_node(rn); | |
378 | return; | |
379 | } | |
380 | ||
d62a17ae | 381 | bgp_unlock_node(rn); |
382 | bnc->last_update = bgp_clock(); | |
383 | bnc->change_flags = 0; | |
d62a17ae | 384 | |
385 | /* debug print the input */ | |
386 | if (BGP_DEBUG(nht, NHT)) { | |
387 | char buf[PREFIX2STR_BUFFER]; | |
4a749e2c | 388 | prefix2str(&nhr.prefix, buf, sizeof(buf)); |
d62a17ae | 389 | zlog_debug( |
8c1a4c10 DS |
390 | "%s(%u): Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x", |
391 | bnc->bgp->name_pretty, vrf_id, buf, nhr.metric, | |
392 | bnc->metric, nhr.nexthop_num, bnc->nexthop_num, | |
393 | bnc->flags); | |
d62a17ae | 394 | } |
395 | ||
4a749e2c | 396 | if (nhr.metric != bnc->metric) |
d62a17ae | 397 | bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED; |
398 | ||
4a749e2c | 399 | if (nhr.nexthop_num != bnc->nexthop_num) |
d62a17ae | 400 | bnc->change_flags |= BGP_NEXTHOP_CHANGED; |
401 | ||
4a749e2c | 402 | if (nhr.nexthop_num) { |
6137a77d DS |
403 | struct peer *peer = bnc->nht_info; |
404 | ||
d62a17ae | 405 | /* notify bgp fsm if nbr ip goes from invalid->valid */ |
406 | if (!bnc->nexthop_num) | |
407 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
408 | ||
409 | bnc->flags |= BGP_NEXTHOP_VALID; | |
4a749e2c DS |
410 | bnc->metric = nhr.metric; |
411 | bnc->nexthop_num = nhr.nexthop_num; | |
412 | ||
960035b2 PZ |
413 | bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */ |
414 | ||
4a749e2c | 415 | for (i = 0; i < nhr.nexthop_num; i++) { |
960035b2 PZ |
416 | int num_labels = 0; |
417 | ||
4a749e2c | 418 | nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]); |
d62a17ae | 419 | |
6137a77d DS |
420 | /* |
421 | * Turn on RA for the v6 nexthops | |
422 | * we receive from bgp. This is to allow us | |
423 | * to work with v4 routing over v6 nexthops | |
424 | */ | |
687a2b5d DS |
425 | if (peer && !peer->ifp |
426 | && CHECK_FLAG(peer->flags, | |
427 | PEER_FLAG_CAPABILITY_ENHE) | |
65f803e8 CS |
428 | && nhr.prefix.family == AF_INET6 |
429 | && nexthop->type != NEXTHOP_TYPE_BLACKHOLE) { | |
6137a77d DS |
430 | struct interface *ifp; |
431 | ||
432 | ifp = if_lookup_by_index(nexthop->ifindex, | |
433 | nexthop->vrf_id); | |
8c9769e0 DS |
434 | if (ifp) |
435 | zclient_send_interface_radv_req( | |
436 | zclient, nexthop->vrf_id, ifp, | |
437 | true, | |
438 | BGP_UNNUM_DEFAULT_RA_INTERVAL); | |
6137a77d | 439 | } |
960035b2 PZ |
440 | /* There is at least one label-switched path */ |
441 | if (nexthop->nh_label && | |
442 | nexthop->nh_label->num_labels) { | |
443 | ||
444 | bnc->flags |= BGP_NEXTHOP_LABELED_VALID; | |
445 | num_labels = nexthop->nh_label->num_labels; | |
446 | } | |
447 | ||
d62a17ae | 448 | if (BGP_DEBUG(nht, NHT)) { |
449 | char buf[NEXTHOP_STRLEN]; | |
450 | zlog_debug( | |
960035b2 PZ |
451 | " nhop via %s (%d labels)", |
452 | nexthop2str(nexthop, buf, sizeof(buf)), | |
453 | num_labels); | |
d62a17ae | 454 | } |
455 | ||
456 | if (nhlist_tail) { | |
457 | nhlist_tail->next = nexthop; | |
458 | nhlist_tail = nexthop; | |
459 | } else { | |
460 | nhlist_tail = nexthop; | |
461 | nhlist_head = nexthop; | |
462 | } | |
463 | ||
464 | /* No need to evaluate the nexthop if we have already | |
465 | * determined | |
466 | * that there has been a change. | |
467 | */ | |
468 | if (bnc->change_flags & BGP_NEXTHOP_CHANGED) | |
469 | continue; | |
470 | ||
471 | for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next) | |
78fba41b | 472 | if (nexthop_same(oldnh, nexthop)) |
d62a17ae | 473 | break; |
474 | ||
475 | if (!oldnh) | |
476 | bnc->change_flags |= BGP_NEXTHOP_CHANGED; | |
477 | } | |
478 | bnc_nexthop_free(bnc); | |
479 | bnc->nexthop = nhlist_head; | |
480 | } else { | |
481 | bnc->flags &= ~BGP_NEXTHOP_VALID; | |
4a749e2c | 482 | bnc->nexthop_num = nhr.nexthop_num; |
d62a17ae | 483 | |
484 | /* notify bgp fsm if nbr ip goes from valid->invalid */ | |
485 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
486 | ||
487 | bnc_nexthop_free(bnc); | |
488 | bnc->nexthop = NULL; | |
489 | } | |
490 | ||
491 | evaluate_paths(bnc); | |
fb018d25 DS |
492 | } |
493 | ||
ee7ca6c0 | 494 | /* |
495 | * Cleanup nexthop registration and status information for BGP nexthops | |
496 | * pertaining to this VRF. This is invoked upon VRF deletion. | |
497 | */ | |
498 | void bgp_cleanup_nexthops(struct bgp *bgp) | |
499 | { | |
500 | afi_t afi; | |
501 | struct bgp_node *rn; | |
502 | struct bgp_nexthop_cache *bnc; | |
503 | ||
504 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { | |
505 | if (!bgp->nexthop_cache_table[afi]) | |
506 | continue; | |
507 | ||
508 | for (rn = bgp_table_top(bgp->nexthop_cache_table[afi]); rn; | |
509 | rn = bgp_route_next(rn)) { | |
5b8d32bd | 510 | bnc = bgp_node_get_bgp_nexthop_info(rn); |
57f7feb6 | 511 | if (!bnc) |
ee7ca6c0 | 512 | continue; |
513 | ||
514 | /* Clear relevant flags. */ | |
515 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
516 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
517 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
518 | } | |
519 | } | |
520 | } | |
521 | ||
fb018d25 DS |
522 | /** |
523 | * make_prefix - make a prefix structure from the path (essentially | |
524 | * path's node. | |
525 | */ | |
40381db7 | 526 | static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) |
fb018d25 | 527 | { |
078430f6 | 528 | |
40381db7 DS |
529 | int is_bgp_static = ((pi->type == ZEBRA_ROUTE_BGP) |
530 | && (pi->sub_type == BGP_ROUTE_STATIC)) | |
d62a17ae | 531 | ? 1 |
532 | : 0; | |
0378bcaa | 533 | struct bgp_node *net = pi->net; |
b54892e0 | 534 | const struct prefix *p_orig = bgp_node_get_prefix(net); |
0378bcaa PG |
535 | |
536 | if (p_orig->family == AF_FLOWSPEC) { | |
537 | if (!pi->peer) | |
538 | return -1; | |
539 | return bgp_flowspec_get_first_nh(pi->peer->bgp, | |
540 | pi, p); | |
541 | } | |
d62a17ae | 542 | memset(p, 0, sizeof(struct prefix)); |
543 | switch (afi) { | |
544 | case AFI_IP: | |
545 | p->family = AF_INET; | |
546 | if (is_bgp_static) { | |
b54892e0 DS |
547 | p->u.prefix4 = p_orig->u.prefix4; |
548 | p->prefixlen = p_orig->prefixlen; | |
d62a17ae | 549 | } else { |
40381db7 | 550 | p->u.prefix4 = pi->attr->nexthop; |
d62a17ae | 551 | p->prefixlen = IPV4_MAX_BITLEN; |
552 | } | |
553 | break; | |
554 | case AFI_IP6: | |
d62a17ae | 555 | p->family = AF_INET6; |
556 | ||
557 | if (is_bgp_static) { | |
b54892e0 DS |
558 | p->u.prefix6 = p_orig->u.prefix6; |
559 | p->prefixlen = p_orig->prefixlen; | |
d62a17ae | 560 | } else { |
40381db7 | 561 | p->u.prefix6 = pi->attr->mp_nexthop_global; |
d62a17ae | 562 | p->prefixlen = IPV6_MAX_BITLEN; |
563 | } | |
564 | break; | |
565 | default: | |
566 | if (BGP_DEBUG(nht, NHT)) { | |
567 | zlog_debug( | |
568 | "%s: Attempting to make prefix with unknown AFI %d (not %d or %d)", | |
15569c58 | 569 | __func__, afi, AFI_IP, AFI_IP6); |
d62a17ae | 570 | } |
571 | break; | |
65740e1b | 572 | } |
d62a17ae | 573 | return 0; |
fb018d25 DS |
574 | } |
575 | ||
576 | /** | |
078430f6 | 577 | * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister |
fb018d25 DS |
578 | * command to Zebra. |
579 | * ARGUMENTS: | |
580 | * struct bgp_nexthop_cache *bnc -- the nexthop structure. | |
078430f6 | 581 | * int command -- command to send to zebra |
fb018d25 DS |
582 | * RETURNS: |
583 | * void. | |
584 | */ | |
d62a17ae | 585 | static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) |
fb018d25 | 586 | { |
b54892e0 | 587 | const struct prefix *p; |
3c192540 | 588 | bool exact_match = false; |
d62a17ae | 589 | int ret; |
590 | ||
3c192540 | 591 | if (!zclient) |
d62a17ae | 592 | return; |
593 | ||
594 | /* Don't try to register if Zebra doesn't know of this instance. */ | |
bb4ef1ae DS |
595 | if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bnc->bgp)) { |
596 | if (BGP_DEBUG(zebra, ZEBRA)) | |
15569c58 DA |
597 | zlog_debug( |
598 | "%s: No zebra instance to talk to, not installing NHT entry", | |
599 | __func__); | |
d62a17ae | 600 | return; |
bb4ef1ae | 601 | } |
d62a17ae | 602 | |
1ee0a2df DS |
603 | if (!bgp_zebra_num_connects()) { |
604 | if (BGP_DEBUG(zebra, ZEBRA)) | |
15569c58 DA |
605 | zlog_debug( |
606 | "%s: We have not connected yet, cannot send nexthops", | |
607 | __func__); | |
1ee0a2df | 608 | } |
b54892e0 | 609 | p = bgp_node_get_prefix(bnc->node); |
996c9314 LB |
610 | if ((command == ZEBRA_NEXTHOP_REGISTER |
611 | || command == ZEBRA_IMPORT_ROUTE_REGISTER) | |
612 | && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) | |
613 | || CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))) | |
3c192540 | 614 | exact_match = true; |
d62a17ae | 615 | |
960035b2 PZ |
616 | if (BGP_DEBUG(zebra, ZEBRA)) { |
617 | char buf[PREFIX2STR_BUFFER]; | |
618 | ||
619 | prefix2str(p, buf, PREFIX2STR_BUFFER); | |
620 | zlog_debug("%s: sending cmd %s for %s (vrf %s)", | |
621 | __func__, zserv_command_string(command), buf, | |
8c1a4c10 | 622 | bnc->bgp->name_pretty); |
960035b2 PZ |
623 | } |
624 | ||
996c9314 LB |
625 | ret = zclient_send_rnh(zclient, command, p, exact_match, |
626 | bnc->bgp->vrf_id); | |
d62a17ae | 627 | /* TBD: handle the failure */ |
628 | if (ret < 0) | |
e50f7cfd | 629 | flog_warn(EC_BGP_ZEBRA_SEND, |
f162a5b9 | 630 | "sendmsg_nexthop: zclient_send_message() failed"); |
d62a17ae | 631 | |
632 | if ((command == ZEBRA_NEXTHOP_REGISTER) | |
633 | || (command == ZEBRA_IMPORT_ROUTE_REGISTER)) | |
634 | SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
635 | else if ((command == ZEBRA_NEXTHOP_UNREGISTER) | |
636 | || (command == ZEBRA_IMPORT_ROUTE_UNREGISTER)) | |
637 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
638 | return; | |
fb018d25 DS |
639 | } |
640 | ||
641 | /** | |
078430f6 DS |
642 | * register_zebra_rnh - register a NH/route with Zebra for notification |
643 | * when the route or the route to the nexthop changes. | |
fb018d25 | 644 | * ARGUMENTS: |
078430f6 | 645 | * struct bgp_nexthop_cache *bnc |
fb018d25 DS |
646 | * RETURNS: |
647 | * void. | |
648 | */ | |
d62a17ae | 649 | static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, |
650 | int is_bgp_import_route) | |
fb018d25 | 651 | { |
d62a17ae | 652 | /* Check if we have already registered */ |
653 | if (bnc->flags & BGP_NEXTHOP_REGISTERED) | |
654 | return; | |
655 | if (is_bgp_import_route) | |
656 | sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER); | |
657 | else | |
658 | sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER); | |
fb018d25 DS |
659 | } |
660 | ||
661 | /** | |
078430f6 | 662 | * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra. |
fb018d25 | 663 | * ARGUMENTS: |
078430f6 | 664 | * struct bgp_nexthop_cache *bnc |
fb018d25 DS |
665 | * RETURNS: |
666 | * void. | |
667 | */ | |
d62a17ae | 668 | static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc, |
669 | int is_bgp_import_route) | |
fb018d25 | 670 | { |
d62a17ae | 671 | /* Check if we have already registered */ |
672 | if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) | |
673 | return; | |
674 | ||
675 | if (is_bgp_import_route) | |
676 | sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER); | |
677 | else | |
678 | sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER); | |
fb018d25 DS |
679 | } |
680 | ||
681 | /** | |
682 | * evaluate_paths - Evaluate the paths/nets associated with a nexthop. | |
683 | * ARGUMENTS: | |
684 | * struct bgp_nexthop_cache *bnc -- the nexthop structure. | |
685 | * RETURNS: | |
686 | * void. | |
687 | */ | |
d62a17ae | 688 | static void evaluate_paths(struct bgp_nexthop_cache *bnc) |
fb018d25 | 689 | { |
d62a17ae | 690 | struct bgp_node *rn; |
4b7e6066 | 691 | struct bgp_path_info *path; |
d62a17ae | 692 | int afi; |
693 | struct peer *peer = (struct peer *)bnc->nht_info; | |
694 | struct bgp_table *table; | |
695 | safi_t safi; | |
960035b2 | 696 | struct bgp *bgp_path; |
b54892e0 | 697 | const struct prefix *p; |
d62a17ae | 698 | |
699 | if (BGP_DEBUG(nht, NHT)) { | |
700 | char buf[PREFIX2STR_BUFFER]; | |
701 | bnc_str(bnc, buf, PREFIX2STR_BUFFER); | |
702 | zlog_debug( | |
8c1a4c10 DS |
703 | "NH update for %s(%s) - flags 0x%x chgflags 0x%x - evaluate paths", |
704 | buf, bnc->bgp->name_pretty, bnc->flags, | |
705 | bnc->change_flags); | |
fb018d25 DS |
706 | } |
707 | ||
a2addae8 | 708 | LIST_FOREACH (path, &(bnc->paths), nh_thread) { |
d62a17ae | 709 | if (!(path->type == ZEBRA_ROUTE_BGP |
710 | && ((path->sub_type == BGP_ROUTE_NORMAL) | |
960035b2 PZ |
711 | || (path->sub_type == BGP_ROUTE_STATIC) |
712 | || (path->sub_type == BGP_ROUTE_IMPORTED)))) | |
d62a17ae | 713 | continue; |
714 | ||
715 | rn = path->net; | |
716 | assert(rn && bgp_node_table(rn)); | |
b54892e0 DS |
717 | p = bgp_node_get_prefix(rn); |
718 | afi = family2afi(p->family); | |
d62a17ae | 719 | table = bgp_node_table(rn); |
720 | safi = table->safi; | |
721 | ||
960035b2 PZ |
722 | /* |
723 | * handle routes from other VRFs (they can have a | |
724 | * nexthop in THIS VRF). bgp_path is the bgp instance | |
725 | * that owns the route referencing this nexthop. | |
726 | */ | |
727 | bgp_path = table->bgp; | |
728 | ||
729 | /* | |
730 | * Path becomes valid/invalid depending on whether the nexthop | |
d62a17ae | 731 | * reachable/unreachable. |
960035b2 PZ |
732 | * |
733 | * In case of unicast routes that were imported from vpn | |
734 | * and that have labels, they are valid only if there are | |
735 | * nexthops with labels | |
d62a17ae | 736 | */ |
960035b2 PZ |
737 | |
738 | int bnc_is_valid_nexthop = 0; | |
739 | ||
740 | if (safi == SAFI_UNICAST && | |
741 | path->sub_type == BGP_ROUTE_IMPORTED && | |
742 | path->extra && | |
743 | path->extra->num_labels) { | |
744 | ||
745 | bnc_is_valid_nexthop = | |
746 | bgp_isvalid_labeled_nexthop(bnc) ? 1 : 0; | |
747 | } else { | |
e7cbe5e5 NT |
748 | if (bgp_update_martian_nexthop( |
749 | bnc->bgp, afi, safi, path->type, | |
750 | path->sub_type, path->attr, rn)) { | |
751 | if (BGP_DEBUG(nht, NHT)) | |
752 | zlog_debug( | |
753 | "%s: prefix %pRN (vrf %s), ignoring path due to martian or self-next-hop", | |
754 | __func__, rn, bgp_path->name); | |
755 | } else | |
756 | bnc_is_valid_nexthop = | |
757 | bgp_isvalid_nexthop(bnc) ? 1 : 0; | |
960035b2 PZ |
758 | } |
759 | ||
b54892e0 DS |
760 | if (BGP_DEBUG(nht, NHT)) |
761 | zlog_debug("%s: prefix %pRN (vrf %s) %svalid", __func__, | |
762 | rn, bgp_path->name, | |
763 | (bnc_is_valid_nexthop ? "" : "not ")); | |
960035b2 | 764 | |
1defdda8 | 765 | if ((CHECK_FLAG(path->flags, BGP_PATH_VALID) ? 1 : 0) |
960035b2 | 766 | != bnc_is_valid_nexthop) { |
1defdda8 | 767 | if (CHECK_FLAG(path->flags, BGP_PATH_VALID)) { |
b54892e0 DS |
768 | bgp_aggregate_decrement(bgp_path, p, path, afi, |
769 | safi); | |
18ee8310 DS |
770 | bgp_path_info_unset_flag(rn, path, |
771 | BGP_PATH_VALID); | |
d62a17ae | 772 | } else { |
18ee8310 DS |
773 | bgp_path_info_set_flag(rn, path, |
774 | BGP_PATH_VALID); | |
b54892e0 DS |
775 | bgp_aggregate_increment(bgp_path, p, path, afi, |
776 | safi); | |
d62a17ae | 777 | } |
778 | } | |
779 | ||
780 | /* Copy the metric to the path. Will be used for bestpath | |
781 | * computation */ | |
782 | if (bgp_isvalid_nexthop(bnc) && bnc->metric) | |
18ee8310 DS |
783 | (bgp_path_info_extra_get(path))->igpmetric = |
784 | bnc->metric; | |
d62a17ae | 785 | else if (path->extra) |
786 | path->extra->igpmetric = 0; | |
787 | ||
788 | if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED) | |
789 | || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) | |
1defdda8 | 790 | SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED); |
d62a17ae | 791 | |
b54892e0 | 792 | if (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p)) { |
7c312383 | 793 | if (CHECK_FLAG(path->flags, BGP_PATH_VALID)) |
b54892e0 DS |
794 | bgp_evpn_import_route(bgp_path, afi, safi, p, |
795 | path); | |
7c312383 | 796 | else |
b54892e0 DS |
797 | bgp_evpn_unimport_route(bgp_path, afi, safi, p, |
798 | path); | |
7c312383 AD |
799 | } |
800 | ||
960035b2 | 801 | bgp_process(bgp_path, rn, afi, safi); |
d62a17ae | 802 | } |
fc9a856f | 803 | |
1e91f1d1 DS |
804 | if (peer) { |
805 | int valid_nexthops = bgp_isvalid_nexthop(bnc); | |
806 | ||
807 | if (valid_nexthops) | |
808 | peer->last_reset = PEER_DOWN_WAITING_OPEN; | |
809 | else | |
810 | peer->last_reset = PEER_DOWN_WAITING_NHT; | |
811 | ||
812 | if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) { | |
813 | if (BGP_DEBUG(nht, NHT)) | |
15569c58 DA |
814 | zlog_debug( |
815 | "%s: Updating peer (%s(%s)) status with NHT", | |
816 | __func__, peer->host, | |
817 | peer->bgp->name_pretty); | |
1e91f1d1 DS |
818 | bgp_fsm_event_update(peer, valid_nexthops); |
819 | SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
820 | } | |
d62a17ae | 821 | } |
fc9a856f | 822 | |
d62a17ae | 823 | RESET_FLAG(bnc->change_flags); |
fb018d25 DS |
824 | } |
825 | ||
826 | /** | |
827 | * path_nh_map - make or break path-to-nexthop association. | |
828 | * ARGUMENTS: | |
829 | * path - pointer to the path structure | |
830 | * bnc - pointer to the nexthop structure | |
831 | * make - if set, make the association. if unset, just break the existing | |
832 | * association. | |
833 | */ | |
7f040da1 DS |
834 | void path_nh_map(struct bgp_path_info *path, struct bgp_nexthop_cache *bnc, |
835 | bool make) | |
fb018d25 | 836 | { |
d62a17ae | 837 | if (path->nexthop) { |
838 | LIST_REMOVE(path, nh_thread); | |
839 | path->nexthop->path_count--; | |
840 | path->nexthop = NULL; | |
841 | } | |
842 | if (make) { | |
843 | LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread); | |
844 | path->nexthop = bnc; | |
845 | path->nexthop->path_count++; | |
846 | } | |
fb018d25 | 847 | } |
1ee0a2df DS |
848 | |
849 | /* | |
850 | * This function is called to register nexthops to zebra | |
851 | * as that we may have tried to install the nexthops | |
852 | * before we actually have a zebra connection | |
853 | */ | |
854 | void bgp_nht_register_nexthops(struct bgp *bgp) | |
855 | { | |
856 | struct bgp_node *rn; | |
857 | struct bgp_nexthop_cache *bnc; | |
858 | afi_t afi; | |
859 | ||
860 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { | |
861 | if (!bgp->nexthop_cache_table[afi]) | |
862 | continue; | |
863 | ||
864 | for (rn = bgp_table_top(bgp->nexthop_cache_table[afi]); rn; | |
865 | rn = bgp_route_next(rn)) { | |
5b8d32bd | 866 | bnc = bgp_node_get_bgp_nexthop_info(rn); |
1ee0a2df DS |
867 | |
868 | if (!bnc) | |
869 | continue; | |
870 | ||
871 | register_zebra_rnh(bnc, 0); | |
872 | } | |
873 | } | |
874 | } | |
1ea03b90 DS |
875 | |
876 | void bgp_nht_register_enhe_capability_interfaces(struct peer *peer) | |
877 | { | |
878 | struct bgp *bgp; | |
879 | struct bgp_node *rn; | |
880 | struct bgp_nexthop_cache *bnc; | |
881 | struct nexthop *nhop; | |
882 | struct interface *ifp; | |
883 | struct prefix p; | |
884 | ||
885 | if (peer->ifp) | |
886 | return; | |
887 | ||
888 | bgp = peer->bgp; | |
889 | ||
890 | if (!bgp->nexthop_cache_table[AFI_IP6]) | |
891 | return; | |
892 | ||
893 | if (!sockunion2hostprefix(&peer->su, &p)) { | |
894 | if (BGP_DEBUG(nht, NHT)) | |
895 | zlog_debug("%s: Unable to convert prefix to sockunion", | |
15569c58 | 896 | __func__); |
1ea03b90 DS |
897 | return; |
898 | } | |
899 | ||
900 | if (p.family != AF_INET6) | |
901 | return; | |
902 | rn = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p); | |
32fbbd9c A |
903 | if (!rn) |
904 | return; | |
1ea03b90 | 905 | |
5b8d32bd | 906 | bnc = bgp_node_get_bgp_nexthop_info(rn); |
1ea03b90 DS |
907 | if (!bnc) |
908 | return; | |
909 | ||
910 | if (peer != bnc->nht_info) | |
911 | return; | |
912 | ||
913 | for (nhop = bnc->nexthop; nhop; nhop = nhop->next) { | |
8c9769e0 DS |
914 | ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id); |
915 | ||
916 | if (!ifp) | |
917 | continue; | |
918 | ||
1ea03b90 DS |
919 | zclient_send_interface_radv_req(zclient, |
920 | nhop->vrf_id, | |
921 | ifp, true, | |
922 | BGP_UNNUM_DEFAULT_RA_INTERVAL); | |
923 | } | |
924 | } |