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