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