1 /* BGP Nexthop tracking
2 * Copyright (C) 2013 Cumulus Networks, Inc.
4 * This file is part of GNU Zebra.
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
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.
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
35 #include "bgpd/bgpd.h"
36 #include "bgpd/bgp_table.h"
37 #include "bgpd/bgp_route.h"
38 #include "bgpd/bgp_attr.h"
39 #include "bgpd/bgp_nexthop.h"
40 #include "bgpd/bgp_debug.h"
41 #include "bgpd/bgp_nht.h"
42 #include "bgpd/bgp_fsm.h"
43 #include "bgpd/bgp_zebra.h"
45 extern struct zclient
*zclient
;
47 static void register_zebra_rnh(struct bgp_nexthop_cache
*bnc
,
48 int is_bgp_static_route
);
49 static void unregister_zebra_rnh(struct bgp_nexthop_cache
*bnc
,
50 int is_bgp_static_route
);
51 static void evaluate_paths(struct bgp_nexthop_cache
*bnc
);
52 static int make_prefix(int afi
, struct bgp_info
*ri
, struct prefix
*p
);
53 static void path_nh_map(struct bgp_info
*path
, struct bgp_nexthop_cache
*bnc
,
57 bgp_isvalid_nexthop (struct bgp_nexthop_cache
*bnc
)
59 return (bgp_zebra_num_connects() == 0 ||
60 (bnc
&& CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
)));
64 bgp_find_nexthop (struct bgp_info
*path
, int connected
)
66 struct bgp_nexthop_cache
*bnc
= path
->nexthop
;
72 * We are cheating here. Views have no associated underlying
73 * ability to detect nexthops. So when we have a view
74 * just tell everyone the nexthop is valid
76 if (path
->peer
&& path
->peer
->bgp
->inst_type
== BGP_INSTANCE_TYPE_VIEW
)
79 if (connected
&& !(CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
)))
82 return (bgp_isvalid_nexthop(bnc
));
86 bgp_unlink_nexthop_check (struct bgp_nexthop_cache
*bnc
)
88 if (LIST_EMPTY(&(bnc
->paths
)) && !bnc
->nht_info
)
90 if (BGP_DEBUG(nht
, NHT
))
92 char buf
[PREFIX2STR_BUFFER
];
93 zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
94 bnc_str(bnc
, buf
, PREFIX2STR_BUFFER
));
96 unregister_zebra_rnh(bnc
, CHECK_FLAG(bnc
->flags
, BGP_STATIC_ROUTE
));
97 bnc
->node
->info
= NULL
;
98 bgp_unlock_node(bnc
->node
);
105 bgp_unlink_nexthop (struct bgp_info
*path
)
107 struct bgp_nexthop_cache
*bnc
= path
->nexthop
;
112 path_nh_map(path
, NULL
, 0);
114 bgp_unlink_nexthop_check (bnc
);
118 bgp_unlink_nexthop_by_peer (struct peer
*peer
)
122 struct bgp_nexthop_cache
*bnc
;
123 afi_t afi
= family2afi(peer
->su
.sa
.sa_family
);
125 if (! sockunion2hostprefix (&peer
->su
, &p
))
128 rn
= bgp_node_get (peer
->bgp
->nexthop_cache_table
[afi
], &p
);
135 /* cleanup the peer reference */
136 bnc
->nht_info
= NULL
;
138 bgp_unlink_nexthop_check (bnc
);
142 bgp_find_or_add_nexthop (struct bgp
*bgp
, afi_t afi
, struct bgp_info
*ri
,
143 struct peer
*peer
, int connected
)
146 struct bgp_nexthop_cache
*bnc
;
148 int is_bgp_static_route
= 0;
152 is_bgp_static_route
= ((ri
->type
== ZEBRA_ROUTE_BGP
) &&
153 (ri
->sub_type
== BGP_ROUTE_STATIC
)) ? 1 : 0;
155 /* Since Extended Next-hop Encoding (RFC5549) support, we want to derive
156 address-family from the next-hop. */
157 if (!is_bgp_static_route
)
158 afi
= BGP_ATTR_NEXTHOP_AFI_IP6(ri
->attr
) ? AFI_IP6
: AFI_IP
;
160 /* This will return TRUE if the global IPv6 NH is a link local addr */
161 if (make_prefix(afi
, ri
, &p
) < 0)
166 /* Don't register link local NH */
167 if (afi
== AFI_IP6
&& IN6_IS_ADDR_LINKLOCAL (&peer
->su
.sin6
.sin6_addr
))
170 if (! sockunion2hostprefix (&peer
->su
, &p
))
172 if (BGP_DEBUG(nht
, NHT
))
174 zlog_debug("%s: Attempting to register with unknown AFI %d (not %d or %d)",
175 __FUNCTION__
, afi
, AFI_IP
, AFI_IP6
);
183 if (is_bgp_static_route
)
184 rn
= bgp_node_get (bgp
->import_check_table
[afi
], &p
);
186 rn
= bgp_node_get (bgp
->nexthop_cache_table
[afi
], &p
);
195 if (BGP_DEBUG(nht
, NHT
))
197 char buf
[PREFIX2STR_BUFFER
];
199 zlog_debug("Allocated bnc %s peer %p",
200 bnc_str(bnc
, buf
, PREFIX2STR_BUFFER
), peer
);
205 bgp_unlock_node (rn
);
206 if (is_bgp_static_route
)
208 SET_FLAG(bnc
->flags
, BGP_STATIC_ROUTE
);
210 /* If we're toggling the type, re-register */
211 if ((bgp_flag_check(bgp
, BGP_FLAG_IMPORT_CHECK
)) &&
212 !CHECK_FLAG(bnc
->flags
, BGP_STATIC_ROUTE_EXACT_MATCH
))
214 SET_FLAG(bnc
->flags
, BGP_STATIC_ROUTE_EXACT_MATCH
);
215 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
216 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
);
218 else if ((!bgp_flag_check(bgp
, BGP_FLAG_IMPORT_CHECK
)) &&
219 CHECK_FLAG(bnc
->flags
, BGP_STATIC_ROUTE_EXACT_MATCH
))
221 UNSET_FLAG(bnc
->flags
, BGP_STATIC_ROUTE_EXACT_MATCH
);
222 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
223 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
);
226 /* When nexthop is already known, but now requires 'connected' resolution,
227 * re-register it. The reverse scenario where the nexthop currently requires
228 * 'connected' resolution does not need a re-register (i.e., we treat
229 * 'connected-required' as an override) except in the scenario where this
230 * is actually a case of tracking a peer for connectivity (e.g., after
231 * disable connected-check).
232 * NOTE: We don't track the number of paths separately for 'connected-
233 * required' vs 'connected-not-required' as this change is not a common
236 else if (connected
&& ! CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
))
238 SET_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
);
239 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
240 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
);
242 else if (peer
&& !connected
&& CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
))
244 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
);
245 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
246 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
);
248 if (bgp
->inst_type
== BGP_INSTANCE_TYPE_VIEW
)
250 bnc
->flags
|= BGP_NEXTHOP_REGISTERED
;
251 bnc
->flags
|= BGP_NEXTHOP_VALID
;
253 else if (!CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
))
254 register_zebra_rnh(bnc
, is_bgp_static_route
);
255 if (ri
&& ri
->nexthop
!= bnc
)
257 /* Unlink from existing nexthop cache, if any. This will also free
258 * the nexthop cache entry, if appropriate.
260 bgp_unlink_nexthop (ri
);
262 path_nh_map(ri
, bnc
, 1); /* updates NHT ri list reference */
264 if (CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
) && bnc
->metric
)
265 (bgp_info_extra_get(ri
))->igpmetric
= bnc
->metric
;
267 ri
->extra
->igpmetric
= 0;
270 bnc
->nht_info
= (void *)peer
; /* NHT peer reference */
273 * We are cheating here. Views have no associated underlying
274 * ability to detect nexthops. So when we have a view
275 * just tell everyone the nexthop is valid
277 if (bgp
->inst_type
== BGP_INSTANCE_TYPE_VIEW
)
280 return (bgp_isvalid_nexthop(bnc
));
284 bgp_delete_connected_nexthop (afi_t afi
, struct peer
*peer
)
287 struct bgp_nexthop_cache
*bnc
;
293 /* We don't register link local address for NHT */
294 if (afi
== AFI_IP6
&& IN6_IS_ADDR_LINKLOCAL (&peer
->su
.sin6
.sin6_addr
))
297 if (! sockunion2hostprefix (&peer
->su
, &p
))
300 rn
= bgp_node_lookup(peer
->bgp
->nexthop_cache_table
[family2afi(p
.family
)], &p
);
301 if (!rn
|| !rn
->info
)
303 if (BGP_DEBUG(nht
, NHT
))
304 zlog_debug("Cannot find connected NHT node for peer %s", peer
->host
);
306 bgp_unlock_node (rn
);
313 if (bnc
->nht_info
!= peer
)
315 if (BGP_DEBUG(nht
, NHT
))
316 zlog_debug("Connected NHT %p node for peer %s points to %p",
317 bnc
, peer
->host
, bnc
->nht_info
);
321 bnc
->nht_info
= NULL
;
323 if (LIST_EMPTY(&(bnc
->paths
)))
325 if (BGP_DEBUG(nht
, NHT
))
326 zlog_debug("Freeing connected NHT node %p for peer %s",
328 unregister_zebra_rnh(bnc
, 0);
329 bnc
->node
->info
= NULL
;
330 bgp_unlock_node(bnc
->node
);
336 bgp_parse_nexthop_update (int command
, vrf_id_t vrf_id
)
339 struct bgp_node
*rn
= NULL
;
340 struct bgp_nexthop_cache
*bnc
;
341 struct nexthop
*nexthop
;
342 struct nexthop
*oldnh
;
343 struct nexthop
*nhlist_head
= NULL
;
344 struct nexthop
*nhlist_tail
= NULL
;
351 bgp
= bgp_lookup_by_vrf_id (vrf_id
);
354 zlog_err("parse nexthop update: instance not found for vrf_id %d", vrf_id
);
360 memset(&p
, 0, sizeof(struct prefix
));
361 p
.family
= stream_getw(s
);
362 p
.prefixlen
= stream_getc(s
);
366 p
.u
.prefix4
.s_addr
= stream_get_ipv4 (s
);
369 stream_get(&p
.u
.prefix6
, s
, 16);
375 if (command
== ZEBRA_NEXTHOP_UPDATE
)
376 rn
= bgp_node_lookup(bgp
->nexthop_cache_table
[family2afi(p
.family
)], &p
);
377 else if (command
== ZEBRA_IMPORT_CHECK_UPDATE
)
378 rn
= bgp_node_lookup(bgp
->import_check_table
[family2afi(p
.family
)], &p
);
380 if (!rn
|| !rn
->info
)
382 if (BGP_DEBUG(nht
, NHT
))
384 char buf
[PREFIX2STR_BUFFER
];
385 prefix2str(&p
, buf
, sizeof(buf
));
386 zlog_debug("parse nexthop update(%s): rn not found", buf
);
389 bgp_unlock_node (rn
);
394 bgp_unlock_node (rn
);
395 bnc
->last_update
= bgp_clock();
396 bnc
->change_flags
= 0;
397 stream_getc (s
); // Distance but not currently used
398 metric
= stream_getl (s
);
399 nexthop_num
= stream_getc (s
);
401 /* debug print the input */
402 if (BGP_DEBUG(nht
, NHT
))
404 char buf
[PREFIX2STR_BUFFER
];
405 prefix2str(&p
, buf
, sizeof (buf
));
406 zlog_debug("%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
407 vrf_id
, buf
, metric
, bnc
->metric
, nexthop_num
, bnc
->nexthop_num
,
411 if (metric
!= bnc
->metric
)
412 bnc
->change_flags
|= BGP_NEXTHOP_METRIC_CHANGED
;
414 if(nexthop_num
!= bnc
->nexthop_num
)
415 bnc
->change_flags
|= BGP_NEXTHOP_CHANGED
;
419 /* notify bgp fsm if nbr ip goes from invalid->valid */
420 if (!bnc
->nexthop_num
)
421 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_PEER_NOTIFIED
);
423 bnc
->flags
|= BGP_NEXTHOP_VALID
;
424 bnc
->metric
= metric
;
425 bnc
->nexthop_num
= nexthop_num
;
427 for (i
= 0; i
< nexthop_num
; i
++)
429 nexthop
= nexthop_new();
430 nexthop
->type
= stream_getc (s
);
431 switch (nexthop
->type
)
433 case NEXTHOP_TYPE_IPV4
:
434 nexthop
->gate
.ipv4
.s_addr
= stream_get_ipv4 (s
);
435 nexthop
->ifindex
= stream_getl (s
);
437 case NEXTHOP_TYPE_IFINDEX
:
438 nexthop
->ifindex
= stream_getl (s
);
440 case NEXTHOP_TYPE_IPV4_IFINDEX
:
441 nexthop
->gate
.ipv4
.s_addr
= stream_get_ipv4 (s
);
442 nexthop
->ifindex
= stream_getl (s
);
444 case NEXTHOP_TYPE_IPV6
:
445 stream_get (&nexthop
->gate
.ipv6
, s
, 16);
446 nexthop
->ifindex
= stream_getl (s
);
448 case NEXTHOP_TYPE_IPV6_IFINDEX
:
449 stream_get (&nexthop
->gate
.ipv6
, s
, 16);
450 nexthop
->ifindex
= stream_getl (s
);
457 if (BGP_DEBUG(nht
, NHT
))
459 char buf
[NEXTHOP_STRLEN
];
460 zlog_debug(" nhop via %s",
461 nexthop2str (nexthop
, buf
, sizeof (buf
)));
466 nhlist_tail
->next
= nexthop
;
467 nhlist_tail
= nexthop
;
471 nhlist_tail
= nexthop
;
472 nhlist_head
= nexthop
;
475 /* No need to evaluate the nexthop if we have already determined
476 * that there has been a change.
478 if (bnc
->change_flags
& BGP_NEXTHOP_CHANGED
)
481 for (oldnh
= bnc
->nexthop
; oldnh
; oldnh
= oldnh
->next
)
482 if (nexthop_same_no_recurse(oldnh
, nexthop
))
486 bnc
->change_flags
|= BGP_NEXTHOP_CHANGED
;
488 bnc_nexthop_free(bnc
);
489 bnc
->nexthop
= nhlist_head
;
493 bnc
->flags
&= ~BGP_NEXTHOP_VALID
;
494 bnc
->nexthop_num
= nexthop_num
;
496 /* notify bgp fsm if nbr ip goes from valid->invalid */
497 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_PEER_NOTIFIED
);
499 bnc_nexthop_free(bnc
);
507 * make_prefix - make a prefix structure from the path (essentially
511 make_prefix (int afi
, struct bgp_info
*ri
, struct prefix
*p
)
514 int is_bgp_static
= ((ri
->type
== ZEBRA_ROUTE_BGP
) &&
515 (ri
->sub_type
== BGP_ROUTE_STATIC
)) ? 1 : 0;
517 memset (p
, 0, sizeof (struct prefix
));
524 p
->u
.prefix4
= ri
->net
->p
.u
.prefix4
;
525 p
->prefixlen
= ri
->net
->p
.prefixlen
;
529 p
->u
.prefix4
= ri
->attr
->nexthop
;
530 p
->prefixlen
= IPV4_MAX_BITLEN
;
534 /* We don't register link local NH */
535 if (ri
->attr
->extra
->mp_nexthop_len
!= BGP_ATTR_NHLEN_IPV6_GLOBAL
536 || IN6_IS_ADDR_LINKLOCAL (&ri
->attr
->extra
->mp_nexthop_global
))
539 p
->family
= AF_INET6
;
543 p
->u
.prefix6
= ri
->net
->p
.u
.prefix6
;
544 p
->prefixlen
= ri
->net
->p
.prefixlen
;
548 p
->u
.prefix6
= ri
->attr
->extra
->mp_nexthop_global
;
549 p
->prefixlen
= IPV6_MAX_BITLEN
;
553 if (BGP_DEBUG(nht
, NHT
))
555 zlog_debug("%s: Attempting to make prefix with unknown AFI %d (not %d or %d)",
556 __FUNCTION__
, afi
, AFI_IP
, AFI_IP6
);
564 * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
567 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
568 * int command -- command to send to zebra
573 sendmsg_zebra_rnh (struct bgp_nexthop_cache
*bnc
, int command
)
580 if (!zclient
|| zclient
->sock
< 0)
583 /* Don't try to register if Zebra doesn't know of this instance. */
584 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bnc
->bgp
))
590 zclient_create_header (s
, command
, bnc
->bgp
->vrf_id
);
591 if (CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
) ||
592 CHECK_FLAG(bnc
->flags
, BGP_STATIC_ROUTE_EXACT_MATCH
))
597 stream_putw(s
, PREFIX_FAMILY(p
));
598 stream_putc(s
, p
->prefixlen
);
599 switch (PREFIX_FAMILY(p
))
602 stream_put_in_addr (s
, &p
->u
.prefix4
);
605 stream_put(s
, &(p
->u
.prefix6
), 16);
610 stream_putw_at (s
, 0, stream_get_endp (s
));
612 ret
= zclient_send_message(zclient
);
613 /* TBD: handle the failure */
615 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
617 if ((command
== ZEBRA_NEXTHOP_REGISTER
) ||
618 (command
== ZEBRA_IMPORT_ROUTE_REGISTER
))
619 SET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
620 else if ((command
== ZEBRA_NEXTHOP_UNREGISTER
) ||
621 (command
== ZEBRA_IMPORT_ROUTE_UNREGISTER
))
622 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
627 * register_zebra_rnh - register a NH/route with Zebra for notification
628 * when the route or the route to the nexthop changes.
630 * struct bgp_nexthop_cache *bnc
635 register_zebra_rnh (struct bgp_nexthop_cache
*bnc
, int is_bgp_import_route
)
637 /* Check if we have already registered */
638 if (bnc
->flags
& BGP_NEXTHOP_REGISTERED
)
640 if (is_bgp_import_route
)
641 sendmsg_zebra_rnh(bnc
, ZEBRA_IMPORT_ROUTE_REGISTER
);
643 sendmsg_zebra_rnh(bnc
, ZEBRA_NEXTHOP_REGISTER
);
647 * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra.
649 * struct bgp_nexthop_cache *bnc
654 unregister_zebra_rnh (struct bgp_nexthop_cache
*bnc
, int is_bgp_import_route
)
656 /* Check if we have already registered */
657 if (!CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
))
660 if (is_bgp_import_route
)
661 sendmsg_zebra_rnh(bnc
, ZEBRA_IMPORT_ROUTE_UNREGISTER
);
663 sendmsg_zebra_rnh(bnc
, ZEBRA_NEXTHOP_UNREGISTER
);
667 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
669 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
674 evaluate_paths (struct bgp_nexthop_cache
*bnc
)
677 struct bgp_info
*path
;
678 struct bgp
*bgp
= bnc
->bgp
;
680 struct peer
*peer
= (struct peer
*)bnc
->nht_info
;
681 struct bgp_table
*table
;
684 if (BGP_DEBUG(nht
, NHT
))
686 char buf
[PREFIX2STR_BUFFER
];
687 bnc_str(bnc
, buf
, PREFIX2STR_BUFFER
);
688 zlog_debug("NH update for %s - flags 0x%x chgflags 0x%x - evaluate paths",
689 buf
, bnc
->flags
, bnc
->change_flags
);
692 LIST_FOREACH(path
, &(bnc
->paths
), nh_thread
)
694 if (!(path
->type
== ZEBRA_ROUTE_BGP
&&
695 ((path
->sub_type
== BGP_ROUTE_NORMAL
) ||
696 (path
->sub_type
== BGP_ROUTE_STATIC
))))
700 assert (rn
&& bgp_node_table (rn
));
701 afi
= family2afi(rn
->p
.family
);
702 table
= bgp_node_table (rn
);
705 /* Path becomes valid/invalid depending on whether the nexthop
706 * reachable/unreachable.
708 if ((CHECK_FLAG(path
->flags
, BGP_INFO_VALID
) ? 1 : 0) !=
709 (bgp_isvalid_nexthop(bnc
) ? 1 : 0))
711 if (CHECK_FLAG (path
->flags
, BGP_INFO_VALID
))
713 bgp_aggregate_decrement (bgp
, &rn
->p
, path
, afi
, safi
);
714 bgp_info_unset_flag (rn
, path
, BGP_INFO_VALID
);
718 bgp_info_set_flag (rn
, path
, BGP_INFO_VALID
);
719 bgp_aggregate_increment (bgp
, &rn
->p
, path
, afi
, safi
);
723 /* Copy the metric to the path. Will be used for bestpath computation */
724 if (bgp_isvalid_nexthop(bnc
) && bnc
->metric
)
725 (bgp_info_extra_get(path
))->igpmetric
= bnc
->metric
;
726 else if (path
->extra
)
727 path
->extra
->igpmetric
= 0;
729 if (CHECK_FLAG(bnc
->change_flags
, BGP_NEXTHOP_METRIC_CHANGED
) ||
730 CHECK_FLAG(bnc
->change_flags
, BGP_NEXTHOP_CHANGED
))
731 SET_FLAG(path
->flags
, BGP_INFO_IGP_CHANGED
);
733 bgp_process(bgp
, rn
, afi
, safi
);
736 if (peer
&& !CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_PEER_NOTIFIED
))
738 if (BGP_DEBUG(nht
, NHT
))
739 zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__
, peer
->host
);
740 bgp_fsm_nht_update(peer
, bgp_isvalid_nexthop(bnc
));
741 SET_FLAG(bnc
->flags
, BGP_NEXTHOP_PEER_NOTIFIED
);
744 RESET_FLAG(bnc
->change_flags
);
748 * path_nh_map - make or break path-to-nexthop association.
750 * path - pointer to the path structure
751 * bnc - pointer to the nexthop structure
752 * make - if set, make the association. if unset, just break the existing
756 path_nh_map (struct bgp_info
*path
, struct bgp_nexthop_cache
*bnc
, int make
)
760 LIST_REMOVE(path
, nh_thread
);
761 path
->nexthop
->path_count
--;
762 path
->nexthop
= NULL
;
766 LIST_INSERT_HEAD(&(bnc
->paths
), path
, nh_thread
);
768 path
->nexthop
->path_count
++;