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