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