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