]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_nht.c
bgpd: ignore nexthop validation for srv6-vpn
[mirror_frr.git] / bgpd / bgp_nht.c
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 *
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
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"
32 #include "vrf.h"
33 #include "filter.h"
34 #include "nexthop_group.h"
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"
42 #include "bgpd/bgp_errors.h"
43 #include "bgpd/bgp_nht.h"
44 #include "bgpd/bgp_fsm.h"
45 #include "bgpd/bgp_zebra.h"
46 #include "bgpd/bgp_flowspec_util.h"
47 #include "bgpd/bgp_evpn.h"
48 #include "bgpd/bgp_rd.h"
49
50 extern struct zclient *zclient;
51
52 static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
53 int is_bgp_static_route);
54 static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
55 int is_bgp_static_route);
56 static void evaluate_paths(struct bgp_nexthop_cache *bnc);
57 static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p);
58 static int bgp_nht_ifp_initial(struct thread *thread);
59
60 static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc)
61 {
62 return (bgp_zebra_num_connects() == 0
63 || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)
64 && bnc->nexthop_num > 0));
65 }
66
67 static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc)
68 {
69 /*
70 * In the case of MPLS-VPN, the label is learned from LDP or other
71 * protocols, and nexthop tracking is enabled for the label.
72 * The value is recorded as BGP_NEXTHOP_LABELED_VALID.
73 * In the case of SRv6-VPN, we need to track the reachability to the
74 * SID (in other words, IPv6 address). As in MPLS, we need to record
75 * the value as BGP_NEXTHOP_SID_VALID. However, this function is
76 * currently not implemented, and this function assumes that all
77 * Transit routes for SRv6-VPN are valid.
78 */
79 return (bgp_zebra_num_connects() == 0
80 || (bnc && bnc->nexthop_num > 0
81 && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID)
82 || bnc->bgp->srv6_enabled)));
83 }
84
85 static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
86 {
87 if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) {
88 if (BGP_DEBUG(nht, NHT)) {
89 char buf[PREFIX2STR_BUFFER];
90 zlog_debug("%s: freeing bnc %s(%u)(%s)", __func__,
91 bnc_str(bnc, buf, PREFIX2STR_BUFFER),
92 bnc->srte_color, bnc->bgp->name_pretty);
93 }
94 /* only unregister if this is the last nh for this prefix*/
95 if (!bnc_existing_for_prefix(bnc))
96 unregister_zebra_rnh(
97 bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
98 bnc_free(bnc);
99 }
100 }
101
102 void bgp_unlink_nexthop(struct bgp_path_info *path)
103 {
104 struct bgp_nexthop_cache *bnc = path->nexthop;
105
106 if (!bnc)
107 return;
108
109 path_nh_map(path, NULL, false);
110
111 bgp_unlink_nexthop_check(bnc);
112 }
113
114 void bgp_replace_nexthop_by_peer(struct peer *from, struct peer *to)
115 {
116 struct prefix pp;
117 struct prefix pt;
118 struct bgp_nexthop_cache *bncp, *bnct;
119 afi_t afi;
120
121 if (!sockunion2hostprefix(&from->su, &pp))
122 return;
123
124 afi = family2afi(pp.family);
125 bncp = bnc_find(&from->bgp->nexthop_cache_table[afi], &pp, 0);
126
127 if (!sockunion2hostprefix(&to->su, &pt))
128 return;
129
130 bnct = bnc_find(&to->bgp->nexthop_cache_table[afi], &pt, 0);
131
132 if (bnct != bncp)
133 return;
134
135 if (bnct)
136 bnct->nht_info = to;
137 }
138
139 void bgp_unlink_nexthop_by_peer(struct peer *peer)
140 {
141 struct prefix p;
142 struct bgp_nexthop_cache *bnc;
143 afi_t afi = family2afi(peer->su.sa.sa_family);
144
145 if (!sockunion2hostprefix(&peer->su, &p))
146 return;
147
148 bnc = bnc_find(&peer->bgp->nexthop_cache_table[afi], &p, 0);
149 if (!bnc)
150 return;
151
152 /* cleanup the peer reference */
153 bnc->nht_info = NULL;
154
155 bgp_unlink_nexthop_check(bnc);
156 }
157
158 /*
159 * A route and its nexthop might belong to different VRFs. Therefore,
160 * we need both the bgp_route and bgp_nexthop pointers.
161 */
162 int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
163 afi_t afi, safi_t safi, struct bgp_path_info *pi,
164 struct peer *peer, int connected)
165 {
166 struct bgp_nexthop_cache_head *tree = NULL;
167 struct bgp_nexthop_cache *bnc;
168 struct prefix p;
169 uint32_t srte_color = 0;
170 int is_bgp_static_route = 0;
171 ifindex_t ifindex = 0;
172
173 if (pi) {
174 is_bgp_static_route = ((pi->type == ZEBRA_ROUTE_BGP)
175 && (pi->sub_type == BGP_ROUTE_STATIC))
176 ? 1
177 : 0;
178
179 /* Since Extended Next-hop Encoding (RFC5549) support, we want
180 to derive
181 address-family from the next-hop. */
182 if (!is_bgp_static_route)
183 afi = BGP_ATTR_NEXTHOP_AFI_IP6(pi->attr) ? AFI_IP6
184 : AFI_IP;
185
186 /* Validation for the ipv4 mapped ipv6 nexthop. */
187 if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
188 afi = AFI_IP;
189 }
190
191 /* This will return true if the global IPv6 NH is a link local
192 * addr */
193 if (make_prefix(afi, pi, &p) < 0)
194 return 1;
195
196 srte_color = pi->attr->srte_color;
197 } else if (peer) {
198 /*
199 * Gather the ifindex for if up/down events to be
200 * tagged into this fun
201 */
202 if (afi == AFI_IP6
203 && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
204 ifindex = peer->su.sin6.sin6_scope_id;
205
206 if (!sockunion2hostprefix(&peer->su, &p)) {
207 if (BGP_DEBUG(nht, NHT)) {
208 zlog_debug(
209 "%s: Attempting to register with unknown AFI %d (not %d or %d)",
210 __func__, afi, AFI_IP, AFI_IP6);
211 }
212 return 0;
213 }
214 } else
215 return 0;
216
217 if (is_bgp_static_route)
218 tree = &bgp_nexthop->import_check_table[afi];
219 else
220 tree = &bgp_nexthop->nexthop_cache_table[afi];
221
222 bnc = bnc_find(tree, &p, srte_color);
223 if (!bnc) {
224 bnc = bnc_new(tree, &p, srte_color);
225 bnc->bgp = bgp_nexthop;
226 bnc->ifindex = ifindex;
227 if (BGP_DEBUG(nht, NHT)) {
228 char buf[PREFIX2STR_BUFFER];
229
230 zlog_debug("Allocated bnc %s(%u)(%s) peer %p",
231 bnc_str(bnc, buf, PREFIX2STR_BUFFER),
232 bnc->srte_color, bnc->bgp->name_pretty,
233 peer);
234 }
235 } else {
236 if (BGP_DEBUG(nht, NHT)) {
237 char buf[PREFIX2STR_BUFFER];
238
239 zlog_debug(
240 "Found existing bnc %s(%s) flags 0x%x ifindex %d #paths %d peer %p",
241 bnc_str(bnc, buf, PREFIX2STR_BUFFER),
242 bnc->bgp->name_pretty, bnc->flags, bnc->ifindex,
243 bnc->path_count, bnc->nht_info);
244 }
245 }
246
247 if (is_bgp_static_route) {
248 SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
249
250 /* If we're toggling the type, re-register */
251 if ((CHECK_FLAG(bgp_route->flags, BGP_FLAG_IMPORT_CHECK))
252 && !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) {
253 SET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH);
254 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
255 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
256 } else if ((!CHECK_FLAG(bgp_route->flags,
257 BGP_FLAG_IMPORT_CHECK))
258 && CHECK_FLAG(bnc->flags,
259 BGP_STATIC_ROUTE_EXACT_MATCH)) {
260 UNSET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH);
261 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
262 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
263 }
264 }
265 /* When nexthop is already known, but now requires 'connected'
266 * resolution,
267 * re-register it. The reverse scenario where the nexthop currently
268 * requires
269 * 'connected' resolution does not need a re-register (i.e., we treat
270 * 'connected-required' as an override) except in the scenario where
271 * this
272 * is actually a case of tracking a peer for connectivity (e.g., after
273 * disable connected-check).
274 * NOTE: We don't track the number of paths separately for 'connected-
275 * required' vs 'connected-not-required' as this change is not a common
276 * scenario.
277 */
278 else if (connected && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) {
279 SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
280 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
281 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
282 } else if (peer && !connected
283 && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) {
284 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
285 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
286 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
287 }
288 if (peer && (bnc->ifindex != ifindex)) {
289 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
290 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
291 bnc->ifindex = ifindex;
292 }
293 if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) {
294 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
295 SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
296 } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)
297 && !is_default_host_route(&bnc->prefix))
298 register_zebra_rnh(bnc, is_bgp_static_route);
299
300 if (pi && pi->nexthop != bnc) {
301 /* Unlink from existing nexthop cache, if any. This will also
302 * free
303 * the nexthop cache entry, if appropriate.
304 */
305 bgp_unlink_nexthop(pi);
306
307 /* updates NHT pi list reference */
308 path_nh_map(pi, bnc, true);
309
310 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
311 (bgp_path_info_extra_get(pi))->igpmetric = bnc->metric;
312 else if (pi->extra)
313 pi->extra->igpmetric = 0;
314 } else if (peer) {
315 /*
316 * Let's not accidently save the peer data for a peer
317 * we are going to throw away in a second or so.
318 * When we come back around we'll fix up this
319 * data properly in replace_nexthop_by_peer
320 */
321 if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
322 bnc->nht_info = (void *)peer; /* NHT peer reference */
323 }
324
325 /*
326 * We are cheating here. Views have no associated underlying
327 * ability to detect nexthops. So when we have a view
328 * just tell everyone the nexthop is valid
329 */
330 if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW)
331 return 1;
332 else if (safi == SAFI_UNICAST && pi
333 && pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra
334 && pi->extra->num_labels) {
335 return bgp_isvalid_labeled_nexthop(bnc);
336 } else
337 return (bgp_isvalid_nexthop(bnc));
338 }
339
340 void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
341 {
342 struct bgp_nexthop_cache *bnc;
343 struct prefix p;
344
345 if (!peer)
346 return;
347
348 if (!sockunion2hostprefix(&peer->su, &p))
349 return;
350
351 bnc = bnc_find(&peer->bgp->nexthop_cache_table[family2afi(p.family)],
352 &p, 0);
353 if (!bnc) {
354 if (BGP_DEBUG(nht, NHT))
355 zlog_debug(
356 "Cannot find connected NHT node for peer %s(%s)",
357 peer->host, peer->bgp->name_pretty);
358 return;
359 }
360
361 if (bnc->nht_info != peer) {
362 if (BGP_DEBUG(nht, NHT))
363 zlog_debug(
364 "Connected NHT %p node for peer %s(%s) points to %p",
365 bnc, peer->host, bnc->bgp->name_pretty,
366 bnc->nht_info);
367 return;
368 }
369
370 bnc->nht_info = NULL;
371
372 if (LIST_EMPTY(&(bnc->paths))) {
373 if (BGP_DEBUG(nht, NHT))
374 zlog_debug(
375 "Freeing connected NHT node %p for peer %s(%s)",
376 bnc, peer->host, bnc->bgp->name_pretty);
377 unregister_zebra_rnh(bnc, 0);
378 bnc_free(bnc);
379 }
380 }
381
382 static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
383 struct zapi_route *nhr)
384 {
385 struct nexthop *nexthop;
386 struct nexthop *oldnh;
387 struct nexthop *nhlist_head = NULL;
388 struct nexthop *nhlist_tail = NULL;
389 int i;
390
391 bnc->last_update = bgp_clock();
392 bnc->change_flags = 0;
393
394 /* debug print the input */
395 if (BGP_DEBUG(nht, NHT)) {
396 char bnc_buf[BNC_FLAG_DUMP_SIZE];
397
398 zlog_debug(
399 "%s(%u): Rcvd NH update %pFX(%u) - metric %d/%d #nhops %d/%d flags %s",
400 bnc->bgp->name_pretty, bnc->bgp->vrf_id, &nhr->prefix,
401 bnc->srte_color, nhr->metric, bnc->metric,
402 nhr->nexthop_num, bnc->nexthop_num,
403 bgp_nexthop_dump_bnc_flags(bnc, bnc_buf,
404 sizeof(bnc_buf)));
405 }
406
407 if (nhr->metric != bnc->metric)
408 bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
409
410 if (nhr->nexthop_num != bnc->nexthop_num)
411 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
412
413 if (nhr->nexthop_num) {
414 struct peer *peer = bnc->nht_info;
415
416 /* notify bgp fsm if nbr ip goes from invalid->valid */
417 if (!bnc->nexthop_num)
418 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
419
420 bnc->flags |= BGP_NEXTHOP_VALID;
421 bnc->metric = nhr->metric;
422 bnc->nexthop_num = nhr->nexthop_num;
423
424 bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */
425
426 for (i = 0; i < nhr->nexthop_num; i++) {
427 int num_labels = 0;
428
429 nexthop = nexthop_from_zapi_nexthop(&nhr->nexthops[i]);
430
431 /*
432 * Turn on RA for the v6 nexthops
433 * we receive from bgp. This is to allow us
434 * to work with v4 routing over v6 nexthops
435 */
436 if (peer && !peer->ifp
437 && CHECK_FLAG(peer->flags,
438 PEER_FLAG_CAPABILITY_ENHE)
439 && nhr->prefix.family == AF_INET6
440 && nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
441 struct interface *ifp;
442
443 ifp = if_lookup_by_index(nexthop->ifindex,
444 nexthop->vrf_id);
445 if (ifp)
446 zclient_send_interface_radv_req(
447 zclient, nexthop->vrf_id, ifp,
448 true,
449 BGP_UNNUM_DEFAULT_RA_INTERVAL);
450 }
451 /* There is at least one label-switched path */
452 if (nexthop->nh_label &&
453 nexthop->nh_label->num_labels) {
454
455 bnc->flags |= BGP_NEXTHOP_LABELED_VALID;
456 num_labels = nexthop->nh_label->num_labels;
457 }
458
459 if (BGP_DEBUG(nht, NHT)) {
460 char buf[NEXTHOP_STRLEN];
461 zlog_debug(
462 " nhop via %s (%d labels)",
463 nexthop2str(nexthop, buf, sizeof(buf)),
464 num_labels);
465 }
466
467 if (nhlist_tail) {
468 nhlist_tail->next = nexthop;
469 nhlist_tail = nexthop;
470 } else {
471 nhlist_tail = nexthop;
472 nhlist_head = nexthop;
473 }
474
475 /* No need to evaluate the nexthop if we have already
476 * determined
477 * that there has been a change.
478 */
479 if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
480 continue;
481
482 for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
483 if (nexthop_same(oldnh, nexthop))
484 break;
485
486 if (!oldnh)
487 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
488 }
489 bnc_nexthop_free(bnc);
490 bnc->nexthop = nhlist_head;
491 } else {
492 bnc->flags &= ~BGP_NEXTHOP_VALID;
493 bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID;
494 bnc->nexthop_num = nhr->nexthop_num;
495
496 /* notify bgp fsm if nbr ip goes from valid->invalid */
497 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
498
499 bnc_nexthop_free(bnc);
500 bnc->nexthop = NULL;
501 }
502
503 evaluate_paths(bnc);
504 }
505
506 static void bgp_nht_ifp_table_handle(struct bgp *bgp,
507 struct bgp_nexthop_cache_head *table,
508 struct interface *ifp, bool up)
509 {
510 struct bgp_nexthop_cache *bnc;
511
512 frr_each (bgp_nexthop_cache, table, bnc) {
513 if (bnc->ifindex != ifp->ifindex)
514 continue;
515
516 bnc->last_update = bgp_clock();
517 bnc->change_flags = 0;
518
519 /*
520 * For interface based routes ( ala the v6 LL routes
521 * that this was written for ) the metric received
522 * for the connected route is 0 not 1.
523 */
524 bnc->metric = 0;
525 if (up) {
526 SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
527 SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
528 bnc->nexthop_num = 1;
529 } else {
530 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
531 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
532 SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
533 bnc->nexthop_num = 0;
534 }
535
536 evaluate_paths(bnc);
537 }
538 }
539 static void bgp_nht_ifp_handle(struct interface *ifp, bool up)
540 {
541 struct bgp *bgp;
542
543 bgp = bgp_lookup_by_vrf_id(ifp->vrf_id);
544 if (!bgp)
545 return;
546
547 bgp_nht_ifp_table_handle(bgp, &bgp->nexthop_cache_table[AFI_IP6], ifp,
548 up);
549 bgp_nht_ifp_table_handle(bgp, &bgp->import_check_table[AFI_IP6], ifp,
550 up);
551 }
552
553 void bgp_nht_ifp_up(struct interface *ifp)
554 {
555 bgp_nht_ifp_handle(ifp, true);
556 }
557
558 void bgp_nht_ifp_down(struct interface *ifp)
559 {
560 bgp_nht_ifp_handle(ifp, false);
561 }
562
563 static int bgp_nht_ifp_initial(struct thread *thread)
564 {
565 ifindex_t ifindex = THREAD_VAL(thread);
566 struct interface *ifp = if_lookup_by_index_all_vrf(ifindex);
567
568 if (!ifp)
569 return 0;
570
571 if (BGP_DEBUG(nht, NHT))
572 zlog_debug(
573 "Handle NHT initial update for Intf %s(%d) status %s",
574 ifp->name, ifp->ifindex, if_is_up(ifp) ? "up" : "down");
575
576 if (if_is_up(ifp))
577 bgp_nht_ifp_up(ifp);
578 else
579 bgp_nht_ifp_down(ifp);
580
581 return 0;
582 }
583
584 /*
585 * So the bnc code has the ability to handle interface up/down
586 * events to properly handle v6 LL peering.
587 * What is happening here:
588 * The event system for peering expects the nht code to
589 * report on the tracking events after we move to active
590 * So let's give the system a chance to report on that event
591 * in a manner that is expected.
592 */
593 void bgp_nht_interface_events(struct peer *peer)
594 {
595 struct bgp *bgp = peer->bgp;
596 struct bgp_nexthop_cache_head *table;
597 struct bgp_nexthop_cache *bnc;
598 struct prefix p;
599
600 if (!IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
601 return;
602
603 if (!sockunion2hostprefix(&peer->su, &p))
604 return;
605
606 table = &bgp->nexthop_cache_table[AFI_IP6];
607 bnc = bnc_find(table, &p, 0);
608 if (!bnc)
609 return;
610
611 if (bnc->ifindex)
612 thread_add_event(bm->master, bgp_nht_ifp_initial, NULL,
613 bnc->ifindex, NULL);
614 }
615
616 void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
617 {
618 struct bgp_nexthop_cache_head *tree = NULL;
619 struct bgp_nexthop_cache *bnc;
620 struct bgp *bgp;
621 struct zapi_route nhr;
622 afi_t afi;
623
624 bgp = bgp_lookup_by_vrf_id(vrf_id);
625 if (!bgp) {
626 flog_err(
627 EC_BGP_NH_UPD,
628 "parse nexthop update: instance not found for vrf_id %u",
629 vrf_id);
630 return;
631 }
632
633 if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
634 zlog_err("%s[%s]: Failure to decode nexthop update", __func__,
635 bgp->name_pretty);
636 return;
637 }
638
639 afi = family2afi(nhr.prefix.family);
640 if (command == ZEBRA_NEXTHOP_UPDATE)
641 tree = &bgp->nexthop_cache_table[afi];
642 else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
643 tree = &bgp->import_check_table[afi];
644
645 bnc = bnc_find(tree, &nhr.prefix, nhr.srte_color);
646 if (!bnc) {
647 if (BGP_DEBUG(nht, NHT))
648 zlog_debug(
649 "parse nexthop update(%pFX(%u)(%s)): bnc info not found",
650 &nhr.prefix, nhr.srte_color, bgp->name_pretty);
651 return;
652 }
653
654 bgp_process_nexthop_update(bnc, &nhr);
655
656 /*
657 * HACK: if any BGP route is dependant on an SR-policy that doesn't
658 * exist, zebra will never send NH updates relative to that policy. In
659 * that case, whenever we receive an update about a colorless NH, update
660 * the corresponding colorful NHs that share the same endpoint but that
661 * are inactive. This ugly hack should work around the problem at the
662 * cost of a performance pernalty. Long term, what should be done is to
663 * make zebra's RNH subsystem aware of SR-TE colors (like bgpd is),
664 * which should provide a better infrastructure to solve this issue in
665 * a more efficient and elegant way.
666 */
667 if (nhr.srte_color == 0) {
668 struct bgp_nexthop_cache *bnc_iter;
669
670 frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
671 bnc_iter) {
672 if (!prefix_same(&bnc->prefix, &bnc_iter->prefix)
673 || bnc_iter->srte_color == 0
674 || CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID))
675 continue;
676
677 bgp_process_nexthop_update(bnc_iter, &nhr);
678 }
679 }
680 }
681
682 /*
683 * Cleanup nexthop registration and status information for BGP nexthops
684 * pertaining to this VRF. This is invoked upon VRF deletion.
685 */
686 void bgp_cleanup_nexthops(struct bgp *bgp)
687 {
688 for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
689 struct bgp_nexthop_cache *bnc;
690
691 frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
692 bnc) {
693 /* Clear relevant flags. */
694 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
695 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
696 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
697 }
698 }
699 }
700
701 /**
702 * make_prefix - make a prefix structure from the path (essentially
703 * path's node.
704 */
705 static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p)
706 {
707
708 int is_bgp_static = ((pi->type == ZEBRA_ROUTE_BGP)
709 && (pi->sub_type == BGP_ROUTE_STATIC))
710 ? 1
711 : 0;
712 struct bgp_dest *net = pi->net;
713 const struct prefix *p_orig = bgp_dest_get_prefix(net);
714 struct in_addr ipv4;
715
716 if (p_orig->family == AF_FLOWSPEC) {
717 if (!pi->peer)
718 return -1;
719 return bgp_flowspec_get_first_nh(pi->peer->bgp,
720 pi, p, afi);
721 }
722 memset(p, 0, sizeof(struct prefix));
723 switch (afi) {
724 case AFI_IP:
725 p->family = AF_INET;
726 if (is_bgp_static) {
727 p->u.prefix4 = p_orig->u.prefix4;
728 p->prefixlen = p_orig->prefixlen;
729 } else {
730 if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) {
731 ipv4_mapped_ipv6_to_ipv4(
732 &pi->attr->mp_nexthop_global, &ipv4);
733 p->u.prefix4 = ipv4;
734 p->prefixlen = IPV4_MAX_BITLEN;
735 } else {
736 p->u.prefix4 = pi->attr->nexthop;
737 p->prefixlen = IPV4_MAX_BITLEN;
738 }
739 }
740 break;
741 case AFI_IP6:
742 p->family = AF_INET6;
743
744 if (is_bgp_static) {
745 p->u.prefix6 = p_orig->u.prefix6;
746 p->prefixlen = p_orig->prefixlen;
747 } else {
748 /* If we receive MP_REACH nexthop with ::(LL)
749 * or LL(LL), use LL address as nexthop cache.
750 */
751 if (pi->attr->mp_nexthop_len
752 == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
753 && (IN6_IS_ADDR_UNSPECIFIED(
754 &pi->attr->mp_nexthop_global)
755 || IN6_IS_ADDR_LINKLOCAL(
756 &pi->attr->mp_nexthop_global)))
757 p->u.prefix6 = pi->attr->mp_nexthop_local;
758 else
759 p->u.prefix6 = pi->attr->mp_nexthop_global;
760 p->prefixlen = IPV6_MAX_BITLEN;
761 }
762 break;
763 default:
764 if (BGP_DEBUG(nht, NHT)) {
765 zlog_debug(
766 "%s: Attempting to make prefix with unknown AFI %d (not %d or %d)",
767 __func__, afi, AFI_IP, AFI_IP6);
768 }
769 break;
770 }
771 return 0;
772 }
773
774 /**
775 * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
776 * command to Zebra.
777 * ARGUMENTS:
778 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
779 * int command -- command to send to zebra
780 * RETURNS:
781 * void.
782 */
783 static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
784 {
785 bool exact_match = false;
786 int ret;
787
788 if (!zclient)
789 return;
790
791 /* Don't try to register if Zebra doesn't know of this instance. */
792 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bnc->bgp)) {
793 if (BGP_DEBUG(zebra, ZEBRA))
794 zlog_debug(
795 "%s: No zebra instance to talk to, not installing NHT entry",
796 __func__);
797 return;
798 }
799
800 if (!bgp_zebra_num_connects()) {
801 if (BGP_DEBUG(zebra, ZEBRA))
802 zlog_debug(
803 "%s: We have not connected yet, cannot send nexthops",
804 __func__);
805 }
806 if ((command == ZEBRA_NEXTHOP_REGISTER
807 || command == ZEBRA_IMPORT_ROUTE_REGISTER)
808 && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)
809 || CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)))
810 exact_match = true;
811
812 if (BGP_DEBUG(zebra, ZEBRA))
813 zlog_debug("%s: sending cmd %s for %pFX (vrf %s)", __func__,
814 zserv_command_string(command), &bnc->prefix,
815 bnc->bgp->name_pretty);
816
817 ret = zclient_send_rnh(zclient, command, &bnc->prefix, exact_match,
818 bnc->bgp->vrf_id);
819 /* TBD: handle the failure */
820 if (ret == ZCLIENT_SEND_FAILURE)
821 flog_warn(EC_BGP_ZEBRA_SEND,
822 "sendmsg_nexthop: zclient_send_message() failed");
823
824 if ((command == ZEBRA_NEXTHOP_REGISTER)
825 || (command == ZEBRA_IMPORT_ROUTE_REGISTER))
826 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
827 else if ((command == ZEBRA_NEXTHOP_UNREGISTER)
828 || (command == ZEBRA_IMPORT_ROUTE_UNREGISTER))
829 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
830 return;
831 }
832
833 /**
834 * register_zebra_rnh - register a NH/route with Zebra for notification
835 * when the route or the route to the nexthop changes.
836 * ARGUMENTS:
837 * struct bgp_nexthop_cache *bnc
838 * RETURNS:
839 * void.
840 */
841 static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
842 int is_bgp_import_route)
843 {
844 /* Check if we have already registered */
845 if (bnc->flags & BGP_NEXTHOP_REGISTERED)
846 return;
847
848 if (bnc->ifindex) {
849 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
850 return;
851 }
852
853 if (is_bgp_import_route)
854 sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER);
855 else
856 sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER);
857 }
858
859 /**
860 * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra.
861 * ARGUMENTS:
862 * struct bgp_nexthop_cache *bnc
863 * RETURNS:
864 * void.
865 */
866 static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
867 int is_bgp_import_route)
868 {
869 /* Check if we have already registered */
870 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
871 return;
872
873 if (bnc->ifindex) {
874 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
875 return;
876 }
877
878 if (is_bgp_import_route)
879 sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER);
880 else
881 sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER);
882 }
883
884 /**
885 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
886 * ARGUMENTS:
887 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
888 * RETURNS:
889 * void.
890 */
891 static void evaluate_paths(struct bgp_nexthop_cache *bnc)
892 {
893 struct bgp_dest *dest;
894 struct bgp_path_info *path;
895 int afi;
896 struct peer *peer = (struct peer *)bnc->nht_info;
897 struct bgp_table *table;
898 safi_t safi;
899 struct bgp *bgp_path;
900 const struct prefix *p;
901
902 if (BGP_DEBUG(nht, NHT)) {
903 char buf[PREFIX2STR_BUFFER];
904 char bnc_buf[BNC_FLAG_DUMP_SIZE];
905 char chg_buf[BNC_FLAG_DUMP_SIZE];
906
907 bnc_str(bnc, buf, PREFIX2STR_BUFFER);
908 zlog_debug(
909 "NH update for %s(%u)(%s) - flags %s chgflags %s- evaluate paths",
910 buf, bnc->srte_color, bnc->bgp->name_pretty,
911 bgp_nexthop_dump_bnc_flags(bnc, bnc_buf,
912 sizeof(bnc_buf)),
913 bgp_nexthop_dump_bnc_change_flags(bnc, chg_buf,
914 sizeof(bnc_buf)));
915 }
916
917 LIST_FOREACH (path, &(bnc->paths), nh_thread) {
918 if (!(path->type == ZEBRA_ROUTE_BGP
919 && ((path->sub_type == BGP_ROUTE_NORMAL)
920 || (path->sub_type == BGP_ROUTE_STATIC)
921 || (path->sub_type == BGP_ROUTE_IMPORTED))))
922 continue;
923
924 dest = path->net;
925 assert(dest && bgp_dest_table(dest));
926 p = bgp_dest_get_prefix(dest);
927 afi = family2afi(p->family);
928 table = bgp_dest_table(dest);
929 safi = table->safi;
930
931 /*
932 * handle routes from other VRFs (they can have a
933 * nexthop in THIS VRF). bgp_path is the bgp instance
934 * that owns the route referencing this nexthop.
935 */
936 bgp_path = table->bgp;
937
938 /*
939 * Path becomes valid/invalid depending on whether the nexthop
940 * reachable/unreachable.
941 *
942 * In case of unicast routes that were imported from vpn
943 * and that have labels, they are valid only if there are
944 * nexthops with labels
945 */
946
947 bool bnc_is_valid_nexthop = false;
948 bool path_valid = false;
949
950 if (safi == SAFI_UNICAST &&
951 path->sub_type == BGP_ROUTE_IMPORTED &&
952 path->extra &&
953 path->extra->num_labels) {
954
955 bnc_is_valid_nexthop =
956 bgp_isvalid_labeled_nexthop(bnc) ? true : false;
957 } else {
958 if (bgp_update_martian_nexthop(
959 bnc->bgp, afi, safi, path->type,
960 path->sub_type, path->attr, dest)) {
961 if (BGP_DEBUG(nht, NHT))
962 zlog_debug(
963 "%s: prefix %pBD (vrf %s), ignoring path due to martian or self-next-hop",
964 __func__, dest, bgp_path->name);
965 } else
966 bnc_is_valid_nexthop =
967 bgp_isvalid_nexthop(bnc) ? true : false;
968 }
969
970 if (BGP_DEBUG(nht, NHT)) {
971 char buf1[RD_ADDRSTRLEN];
972
973 if (dest->pdest) {
974 prefix_rd2str((struct prefix_rd *)bgp_dest_get_prefix(dest->pdest),
975 buf1, sizeof(buf1));
976 zlog_debug(
977 "... eval path %d/%d %pBD RD %s %s flags 0x%x",
978 afi, safi, dest, buf1,
979 bgp_path->name_pretty, path->flags);
980 } else
981 zlog_debug(
982 "... eval path %d/%d %pBD %s flags 0x%x",
983 afi, safi, dest, bgp_path->name_pretty,
984 path->flags);
985 }
986
987 /* Skip paths marked for removal or as history. */
988 if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED)
989 || CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
990 continue;
991
992 /* Copy the metric to the path. Will be used for bestpath
993 * computation */
994 if (bgp_isvalid_nexthop(bnc) && bnc->metric)
995 (bgp_path_info_extra_get(path))->igpmetric =
996 bnc->metric;
997 else if (path->extra)
998 path->extra->igpmetric = 0;
999
1000 if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED)
1001 || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)
1002 || path->attr->srte_color != 0)
1003 SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED);
1004
1005 path_valid = !!CHECK_FLAG(path->flags, BGP_PATH_VALID);
1006 if (path_valid != bnc_is_valid_nexthop) {
1007 if (path_valid) {
1008 /* No longer valid, clear flag; also for EVPN
1009 * routes, unimport from VRFs if needed.
1010 */
1011 bgp_aggregate_decrement(bgp_path, p, path, afi,
1012 safi);
1013 bgp_path_info_unset_flag(dest, path,
1014 BGP_PATH_VALID);
1015 if (safi == SAFI_EVPN &&
1016 bgp_evpn_is_prefix_nht_supported(bgp_dest_get_prefix(dest)))
1017 bgp_evpn_unimport_route(bgp_path,
1018 afi, safi, bgp_dest_get_prefix(dest), path);
1019 } else {
1020 /* Path becomes valid, set flag; also for EVPN
1021 * routes, import from VRFs if needed.
1022 */
1023 bgp_path_info_set_flag(dest, path,
1024 BGP_PATH_VALID);
1025 bgp_aggregate_increment(bgp_path, p, path, afi,
1026 safi);
1027 if (safi == SAFI_EVPN &&
1028 bgp_evpn_is_prefix_nht_supported(bgp_dest_get_prefix(dest)))
1029 bgp_evpn_import_route(bgp_path,
1030 afi, safi, bgp_dest_get_prefix(dest), path);
1031 }
1032 }
1033
1034 bgp_process(bgp_path, dest, afi, safi);
1035 }
1036
1037 if (peer) {
1038 int valid_nexthops = bgp_isvalid_nexthop(bnc);
1039
1040 if (valid_nexthops) {
1041 /*
1042 * Peering cannot occur across a blackhole nexthop
1043 */
1044 if (bnc->nexthop_num == 1 && bnc->nexthop
1045 && bnc->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
1046 peer->last_reset = PEER_DOWN_WAITING_NHT;
1047 valid_nexthops = 0;
1048 } else
1049 peer->last_reset = PEER_DOWN_WAITING_OPEN;
1050 } else
1051 peer->last_reset = PEER_DOWN_WAITING_NHT;
1052
1053 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) {
1054 if (BGP_DEBUG(nht, NHT))
1055 zlog_debug(
1056 "%s: Updating peer (%s(%s)) status with NHT nexthops %d",
1057 __func__, peer->host,
1058 peer->bgp->name_pretty,
1059 !!valid_nexthops);
1060 bgp_fsm_nht_update(peer, !!valid_nexthops);
1061 SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
1062 }
1063 }
1064
1065 RESET_FLAG(bnc->change_flags);
1066 }
1067
1068 /**
1069 * path_nh_map - make or break path-to-nexthop association.
1070 * ARGUMENTS:
1071 * path - pointer to the path structure
1072 * bnc - pointer to the nexthop structure
1073 * make - if set, make the association. if unset, just break the existing
1074 * association.
1075 */
1076 void path_nh_map(struct bgp_path_info *path, struct bgp_nexthop_cache *bnc,
1077 bool make)
1078 {
1079 if (path->nexthop) {
1080 LIST_REMOVE(path, nh_thread);
1081 path->nexthop->path_count--;
1082 path->nexthop = NULL;
1083 }
1084 if (make) {
1085 LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
1086 path->nexthop = bnc;
1087 path->nexthop->path_count++;
1088 }
1089 }
1090
1091 /*
1092 * This function is called to register nexthops to zebra
1093 * as that we may have tried to install the nexthops
1094 * before we actually have a zebra connection
1095 */
1096 void bgp_nht_register_nexthops(struct bgp *bgp)
1097 {
1098 for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
1099 struct bgp_nexthop_cache *bnc;
1100
1101 frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi],
1102 bnc) {
1103 register_zebra_rnh(bnc, 0);
1104 }
1105 }
1106 }
1107
1108 void bgp_nht_reg_enhe_cap_intfs(struct peer *peer)
1109 {
1110 struct bgp *bgp;
1111 struct bgp_nexthop_cache *bnc;
1112 struct nexthop *nhop;
1113 struct interface *ifp;
1114 struct prefix p;
1115
1116 if (peer->ifp)
1117 return;
1118
1119 bgp = peer->bgp;
1120 if (!sockunion2hostprefix(&peer->su, &p)) {
1121 zlog_warn("%s: Unable to convert sockunion to prefix for %s",
1122 __func__, peer->host);
1123 return;
1124 }
1125
1126 if (p.family != AF_INET6)
1127 return;
1128
1129 bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);
1130 if (!bnc)
1131 return;
1132
1133 if (peer != bnc->nht_info)
1134 return;
1135
1136 for (nhop = bnc->nexthop; nhop; nhop = nhop->next) {
1137 ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
1138
1139 if (!ifp)
1140 continue;
1141
1142 zclient_send_interface_radv_req(zclient,
1143 nhop->vrf_id,
1144 ifp, true,
1145 BGP_UNNUM_DEFAULT_RA_INTERVAL);
1146 }
1147 }
1148
1149 void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer)
1150 {
1151 struct bgp *bgp;
1152 struct bgp_nexthop_cache *bnc;
1153 struct nexthop *nhop;
1154 struct interface *ifp;
1155 struct prefix p;
1156
1157 if (peer->ifp)
1158 return;
1159
1160 bgp = peer->bgp;
1161
1162 if (!sockunion2hostprefix(&peer->su, &p)) {
1163 zlog_warn("%s: Unable to convert sockunion to prefix for %s",
1164 __func__, peer->host);
1165 return;
1166 }
1167
1168 if (p.family != AF_INET6)
1169 return;
1170
1171 bnc = bnc_find(&bgp->nexthop_cache_table[AFI_IP6], &p, 0);
1172 if (!bnc)
1173 return;
1174
1175 if (peer != bnc->nht_info)
1176 return;
1177
1178 for (nhop = bnc->nexthop; nhop; nhop = nhop->next) {
1179 ifp = if_lookup_by_index(nhop->ifindex, nhop->vrf_id);
1180
1181 if (!ifp)
1182 continue;
1183
1184 zclient_send_interface_radv_req(zclient, nhop->vrf_id, ifp, 0,
1185 0);
1186 }
1187 }
1188
1189 /****************************************************************************
1190 * L3 NHGs are used for fast failover of nexthops in the dplane. These are
1191 * the APIs for allocating L3 NHG ids. Management of the L3 NHG itself is
1192 * left to the application using it.
1193 * PS: Currently EVPN host routes is the only app using L3 NHG for fast
1194 * failover of remote ES links.
1195 ***************************************************************************/
1196 static bitfield_t bgp_nh_id_bitmap;
1197 static uint32_t bgp_l3nhg_start;
1198
1199 /* XXX - currently we do nothing on the callbacks */
1200 static void bgp_l3nhg_add_cb(const char *name)
1201 {
1202 }
1203 static void bgp_l3nhg_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
1204 const struct nexthop *nhop)
1205 {
1206 }
1207 static void bgp_l3nhg_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
1208 const struct nexthop *nhop)
1209 {
1210 }
1211 static void bgp_l3nhg_del_cb(const char *name)
1212 {
1213 }
1214
1215 static void bgp_l3nhg_zebra_init(void)
1216 {
1217 static bool bgp_l3nhg_zebra_inited;
1218 if (bgp_l3nhg_zebra_inited)
1219 return;
1220
1221 bgp_l3nhg_zebra_inited = true;
1222 bgp_l3nhg_start = zclient_get_nhg_start(ZEBRA_ROUTE_BGP);
1223 nexthop_group_init(bgp_l3nhg_add_cb, bgp_l3nhg_add_nexthop_cb,
1224 bgp_l3nhg_del_nexthop_cb, bgp_l3nhg_del_cb);
1225 }
1226
1227
1228 #define min(A, B) ((A) < (B) ? (A) : (B))
1229 void bgp_l3nhg_init(void)
1230 {
1231 uint32_t id_max;
1232
1233 id_max = min(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024);
1234 bf_init(bgp_nh_id_bitmap, id_max);
1235 bf_assign_zero_index(bgp_nh_id_bitmap);
1236
1237 if (BGP_DEBUG(nht, NHT) || BGP_DEBUG(evpn_mh, EVPN_MH_ES))
1238 zlog_debug("bgp l3_nhg range %u - %u", bgp_l3nhg_start + 1,
1239 bgp_l3nhg_start + id_max);
1240 }
1241
1242 void bgp_l3nhg_finish(void)
1243 {
1244 bf_free(bgp_nh_id_bitmap);
1245 }
1246
1247 uint32_t bgp_l3nhg_id_alloc(void)
1248 {
1249 uint32_t nhg_id = 0;
1250
1251 bgp_l3nhg_zebra_init();
1252 bf_assign_index(bgp_nh_id_bitmap, nhg_id);
1253 if (nhg_id)
1254 nhg_id += bgp_l3nhg_start;
1255
1256 return nhg_id;
1257 }
1258
1259 void bgp_l3nhg_id_free(uint32_t nhg_id)
1260 {
1261 if (!nhg_id || (nhg_id <= bgp_l3nhg_start))
1262 return;
1263
1264 nhg_id -= bgp_l3nhg_start;
1265
1266 bf_release_index(bgp_nh_id_bitmap, nhg_id);
1267 }