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