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
,
56 static int bgp_isvalid_nexthop(struct bgp_nexthop_cache
*bnc
)
58 return (bgp_zebra_num_connects() == 0
59 || (bnc
&& CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
)));
62 int bgp_find_nexthop(struct bgp_info
*path
, int connected
)
64 struct bgp_nexthop_cache
*bnc
= path
->nexthop
;
70 * We are cheating here. Views have no associated underlying
71 * ability to detect nexthops. So when we have a view
72 * just tell everyone the nexthop is valid
74 if (path
->peer
&& path
->peer
->bgp
->inst_type
== BGP_INSTANCE_TYPE_VIEW
)
77 if (connected
&& !(CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
)))
80 return (bgp_isvalid_nexthop(bnc
));
83 static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache
*bnc
)
85 if (LIST_EMPTY(&(bnc
->paths
)) && !bnc
->nht_info
) {
86 if (BGP_DEBUG(nht
, NHT
)) {
87 char buf
[PREFIX2STR_BUFFER
];
88 zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
89 bnc_str(bnc
, buf
, PREFIX2STR_BUFFER
));
91 unregister_zebra_rnh(bnc
,
92 CHECK_FLAG(bnc
->flags
, BGP_STATIC_ROUTE
));
93 bnc
->node
->info
= NULL
;
94 bgp_unlock_node(bnc
->node
);
100 void bgp_unlink_nexthop(struct bgp_info
*path
)
102 struct bgp_nexthop_cache
*bnc
= path
->nexthop
;
107 path_nh_map(path
, NULL
, 0);
109 bgp_unlink_nexthop_check(bnc
);
112 void bgp_unlink_nexthop_by_peer(struct peer
*peer
)
116 struct bgp_nexthop_cache
*bnc
;
117 afi_t afi
= family2afi(peer
->su
.sa
.sa_family
);
119 if (!sockunion2hostprefix(&peer
->su
, &p
))
122 rn
= bgp_node_get(peer
->bgp
->nexthop_cache_table
[afi
], &p
);
129 /* cleanup the peer reference */
130 bnc
->nht_info
= NULL
;
132 bgp_unlink_nexthop_check(bnc
);
135 int bgp_find_or_add_nexthop(struct bgp
*bgp
, afi_t afi
, struct bgp_info
*ri
,
136 struct peer
*peer
, int connected
)
139 struct bgp_nexthop_cache
*bnc
;
141 int is_bgp_static_route
= 0;
144 is_bgp_static_route
= ((ri
->type
== ZEBRA_ROUTE_BGP
)
145 && (ri
->sub_type
== BGP_ROUTE_STATIC
))
149 /* Since Extended Next-hop Encoding (RFC5549) support, we want
151 address-family from the next-hop. */
152 if (!is_bgp_static_route
)
153 afi
= BGP_ATTR_NEXTHOP_AFI_IP6(ri
->attr
) ? AFI_IP6
156 /* This will return TRUE if the global IPv6 NH is a link local
158 if (make_prefix(afi
, ri
, &p
) < 0)
161 /* Don't register link local NH */
163 && IN6_IS_ADDR_LINKLOCAL(&peer
->su
.sin6
.sin6_addr
))
166 if (!sockunion2hostprefix(&peer
->su
, &p
)) {
167 if (BGP_DEBUG(nht
, NHT
)) {
169 "%s: Attempting to register with unknown AFI %d (not %d or %d)",
170 __FUNCTION__
, afi
, AFI_IP
, AFI_IP6
);
177 if (is_bgp_static_route
)
178 rn
= bgp_node_get(bgp
->import_check_table
[afi
], &p
);
180 rn
= bgp_node_get(bgp
->nexthop_cache_table
[afi
], &p
);
188 if (BGP_DEBUG(nht
, NHT
)) {
189 char buf
[PREFIX2STR_BUFFER
];
191 zlog_debug("Allocated bnc %s peer %p",
192 bnc_str(bnc
, buf
, PREFIX2STR_BUFFER
), peer
);
198 if (is_bgp_static_route
) {
199 SET_FLAG(bnc
->flags
, BGP_STATIC_ROUTE
);
201 /* If we're toggling the type, re-register */
202 if ((bgp_flag_check(bgp
, BGP_FLAG_IMPORT_CHECK
))
203 && !CHECK_FLAG(bnc
->flags
, BGP_STATIC_ROUTE_EXACT_MATCH
)) {
204 SET_FLAG(bnc
->flags
, BGP_STATIC_ROUTE_EXACT_MATCH
);
205 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
206 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
);
207 } else if ((!bgp_flag_check(bgp
, BGP_FLAG_IMPORT_CHECK
))
208 && CHECK_FLAG(bnc
->flags
,
209 BGP_STATIC_ROUTE_EXACT_MATCH
)) {
210 UNSET_FLAG(bnc
->flags
, BGP_STATIC_ROUTE_EXACT_MATCH
);
211 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
212 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
);
215 /* When nexthop is already known, but now requires 'connected'
217 * re-register it. The reverse scenario where the nexthop currently
219 * 'connected' resolution does not need a re-register (i.e., we treat
220 * 'connected-required' as an override) except in the scenario where
222 * is actually a case of tracking a peer for connectivity (e.g., after
223 * disable connected-check).
224 * NOTE: We don't track the number of paths separately for 'connected-
225 * required' vs 'connected-not-required' as this change is not a common
228 else if (connected
&& !CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
)) {
229 SET_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
);
230 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
231 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
);
232 } else if (peer
&& !connected
233 && CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
)) {
234 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
);
235 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
236 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
);
238 if (bgp
->inst_type
== BGP_INSTANCE_TYPE_VIEW
) {
239 bnc
->flags
|= BGP_NEXTHOP_REGISTERED
;
240 bnc
->flags
|= BGP_NEXTHOP_VALID
;
241 } else if (!CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
))
242 register_zebra_rnh(bnc
, is_bgp_static_route
);
243 if (ri
&& ri
->nexthop
!= bnc
) {
244 /* Unlink from existing nexthop cache, if any. This will also
246 * the nexthop cache entry, if appropriate.
248 bgp_unlink_nexthop(ri
);
250 path_nh_map(ri
, bnc
, 1); /* updates NHT ri list reference */
252 if (CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
) && bnc
->metric
)
253 (bgp_info_extra_get(ri
))->igpmetric
= bnc
->metric
;
255 ri
->extra
->igpmetric
= 0;
257 bnc
->nht_info
= (void *)peer
; /* NHT peer reference */
260 * We are cheating here. Views have no associated underlying
261 * ability to detect nexthops. So when we have a view
262 * just tell everyone the nexthop is valid
264 if (bgp
->inst_type
== BGP_INSTANCE_TYPE_VIEW
)
267 return (bgp_isvalid_nexthop(bnc
));
270 void bgp_delete_connected_nexthop(afi_t afi
, struct peer
*peer
)
273 struct bgp_nexthop_cache
*bnc
;
279 /* We don't register link local address for NHT */
280 if (afi
== AFI_IP6
&& IN6_IS_ADDR_LINKLOCAL(&peer
->su
.sin6
.sin6_addr
))
283 if (!sockunion2hostprefix(&peer
->su
, &p
))
286 rn
= bgp_node_lookup(
287 peer
->bgp
->nexthop_cache_table
[family2afi(p
.family
)], &p
);
288 if (!rn
|| !rn
->info
) {
289 if (BGP_DEBUG(nht
, NHT
))
290 zlog_debug("Cannot find connected NHT node for peer %s",
300 if (bnc
->nht_info
!= peer
) {
301 if (BGP_DEBUG(nht
, NHT
))
303 "Connected NHT %p node for peer %s points to %p",
304 bnc
, peer
->host
, bnc
->nht_info
);
308 bnc
->nht_info
= NULL
;
310 if (LIST_EMPTY(&(bnc
->paths
))) {
311 if (BGP_DEBUG(nht
, NHT
))
312 zlog_debug("Freeing connected NHT node %p for peer %s",
314 unregister_zebra_rnh(bnc
, 0);
315 bnc
->node
->info
= NULL
;
316 bgp_unlock_node(bnc
->node
);
321 void bgp_parse_nexthop_update(int command
, vrf_id_t vrf_id
)
324 struct bgp_node
*rn
= NULL
;
325 struct bgp_nexthop_cache
*bnc
;
326 struct nexthop
*nexthop
;
327 struct nexthop
*oldnh
;
328 struct nexthop
*nhlist_head
= NULL
;
329 struct nexthop
*nhlist_tail
= NULL
;
336 bgp
= bgp_lookup_by_vrf_id(vrf_id
);
339 "parse nexthop update: instance not found for vrf_id %d",
346 memset(&p
, 0, sizeof(struct prefix
));
347 p
.family
= stream_getw(s
);
348 p
.prefixlen
= stream_getc(s
);
351 p
.u
.prefix4
.s_addr
= stream_get_ipv4(s
);
354 stream_get(&p
.u
.prefix6
, s
, 16);
360 if (command
== ZEBRA_NEXTHOP_UPDATE
)
361 rn
= bgp_node_lookup(
362 bgp
->nexthop_cache_table
[family2afi(p
.family
)], &p
);
363 else if (command
== ZEBRA_IMPORT_CHECK_UPDATE
)
364 rn
= bgp_node_lookup(
365 bgp
->import_check_table
[family2afi(p
.family
)], &p
);
367 if (!rn
|| !rn
->info
) {
368 if (BGP_DEBUG(nht
, NHT
)) {
369 char buf
[PREFIX2STR_BUFFER
];
370 prefix2str(&p
, buf
, sizeof(buf
));
371 zlog_debug("parse nexthop update(%s): rn not found",
381 bnc
->last_update
= bgp_clock();
382 bnc
->change_flags
= 0;
383 stream_getc(s
); // Distance but not currently used
384 metric
= stream_getl(s
);
385 nexthop_num
= stream_getc(s
);
387 /* debug print the input */
388 if (BGP_DEBUG(nht
, NHT
)) {
389 char buf
[PREFIX2STR_BUFFER
];
390 prefix2str(&p
, buf
, sizeof(buf
));
392 "%d: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x",
393 vrf_id
, buf
, metric
, bnc
->metric
, nexthop_num
,
394 bnc
->nexthop_num
, bnc
->flags
);
397 if (metric
!= bnc
->metric
)
398 bnc
->change_flags
|= BGP_NEXTHOP_METRIC_CHANGED
;
400 if (nexthop_num
!= bnc
->nexthop_num
)
401 bnc
->change_flags
|= BGP_NEXTHOP_CHANGED
;
404 /* notify bgp fsm if nbr ip goes from invalid->valid */
405 if (!bnc
->nexthop_num
)
406 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_PEER_NOTIFIED
);
408 bnc
->flags
|= BGP_NEXTHOP_VALID
;
409 bnc
->metric
= metric
;
410 bnc
->nexthop_num
= nexthop_num
;
412 for (i
= 0; i
< nexthop_num
; i
++) {
413 nexthop
= nexthop_new();
414 nexthop
->type
= stream_getc(s
);
415 switch (nexthop
->type
) {
416 case NEXTHOP_TYPE_IPV4
:
417 nexthop
->gate
.ipv4
.s_addr
= stream_get_ipv4(s
);
418 nexthop
->ifindex
= stream_getl(s
);
420 case NEXTHOP_TYPE_IFINDEX
:
421 nexthop
->ifindex
= stream_getl(s
);
423 case NEXTHOP_TYPE_IPV4_IFINDEX
:
424 nexthop
->gate
.ipv4
.s_addr
= stream_get_ipv4(s
);
425 nexthop
->ifindex
= stream_getl(s
);
427 case NEXTHOP_TYPE_IPV6
:
428 stream_get(&nexthop
->gate
.ipv6
, s
, 16);
429 nexthop
->ifindex
= stream_getl(s
);
431 case NEXTHOP_TYPE_IPV6_IFINDEX
:
432 stream_get(&nexthop
->gate
.ipv6
, s
, 16);
433 nexthop
->ifindex
= stream_getl(s
);
440 if (BGP_DEBUG(nht
, NHT
)) {
441 char buf
[NEXTHOP_STRLEN
];
444 nexthop2str(nexthop
, buf
, sizeof(buf
)));
448 nhlist_tail
->next
= nexthop
;
449 nhlist_tail
= nexthop
;
451 nhlist_tail
= nexthop
;
452 nhlist_head
= nexthop
;
455 /* No need to evaluate the nexthop if we have already
457 * that there has been a change.
459 if (bnc
->change_flags
& BGP_NEXTHOP_CHANGED
)
462 for (oldnh
= bnc
->nexthop
; oldnh
; oldnh
= oldnh
->next
)
463 if (nexthop_same_no_recurse(oldnh
, nexthop
))
467 bnc
->change_flags
|= BGP_NEXTHOP_CHANGED
;
469 bnc_nexthop_free(bnc
);
470 bnc
->nexthop
= nhlist_head
;
472 bnc
->flags
&= ~BGP_NEXTHOP_VALID
;
473 bnc
->nexthop_num
= nexthop_num
;
475 /* notify bgp fsm if nbr ip goes from valid->invalid */
476 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_PEER_NOTIFIED
);
478 bnc_nexthop_free(bnc
);
486 * Cleanup nexthop registration and status information for BGP nexthops
487 * pertaining to this VRF. This is invoked upon VRF deletion.
489 void bgp_cleanup_nexthops(struct bgp
*bgp
)
493 struct bgp_nexthop_cache
*bnc
;
495 for (afi
= AFI_IP
; afi
< AFI_MAX
; afi
++) {
496 if (!bgp
->nexthop_cache_table
[afi
])
499 for (rn
= bgp_table_top(bgp
->nexthop_cache_table
[afi
]); rn
;
500 rn
= bgp_route_next(rn
)) {
505 /* Clear relevant flags. */
506 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_VALID
);
507 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
508 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_PEER_NOTIFIED
);
514 * make_prefix - make a prefix structure from the path (essentially
517 static int make_prefix(int afi
, struct bgp_info
*ri
, struct prefix
*p
)
520 int is_bgp_static
= ((ri
->type
== ZEBRA_ROUTE_BGP
)
521 && (ri
->sub_type
== BGP_ROUTE_STATIC
))
525 memset(p
, 0, sizeof(struct prefix
));
530 p
->u
.prefix4
= ri
->net
->p
.u
.prefix4
;
531 p
->prefixlen
= ri
->net
->p
.prefixlen
;
533 p
->u
.prefix4
= ri
->attr
->nexthop
;
534 p
->prefixlen
= IPV4_MAX_BITLEN
;
538 /* We don't register link local NH */
539 if (ri
->attr
->mp_nexthop_len
!= BGP_ATTR_NHLEN_IPV6_GLOBAL
540 || IN6_IS_ADDR_LINKLOCAL(&ri
->attr
->mp_nexthop_global
))
543 p
->family
= AF_INET6
;
546 p
->u
.prefix6
= ri
->net
->p
.u
.prefix6
;
547 p
->prefixlen
= ri
->net
->p
.prefixlen
;
549 p
->u
.prefix6
= ri
->attr
->mp_nexthop_global
;
550 p
->prefixlen
= IPV6_MAX_BITLEN
;
554 if (BGP_DEBUG(nht
, NHT
)) {
556 "%s: Attempting to make prefix with unknown AFI %d (not %d or %d)",
557 __FUNCTION__
, afi
, AFI_IP
, AFI_IP6
);
565 * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
568 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
569 * int command -- command to send to zebra
573 static void 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 ((command
== ZEBRA_NEXTHOP_REGISTER
||
592 command
== ZEBRA_IMPORT_ROUTE_REGISTER
) &&
593 (CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_CONNECTED
)
594 || CHECK_FLAG(bnc
->flags
, BGP_STATIC_ROUTE_EXACT_MATCH
)))
599 stream_putw(s
, PREFIX_FAMILY(p
));
600 stream_putc(s
, p
->prefixlen
);
601 switch (PREFIX_FAMILY(p
)) {
603 stream_put_in_addr(s
, &p
->u
.prefix4
);
606 stream_put(s
, &(p
->u
.prefix6
), 16);
611 stream_putw_at(s
, 0, stream_get_endp(s
));
613 ret
= zclient_send_message(zclient
);
614 /* TBD: handle the failure */
616 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
618 if ((command
== ZEBRA_NEXTHOP_REGISTER
)
619 || (command
== ZEBRA_IMPORT_ROUTE_REGISTER
))
620 SET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
621 else if ((command
== ZEBRA_NEXTHOP_UNREGISTER
)
622 || (command
== ZEBRA_IMPORT_ROUTE_UNREGISTER
))
623 UNSET_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
);
628 * register_zebra_rnh - register a NH/route with Zebra for notification
629 * when the route or the route to the nexthop changes.
631 * struct bgp_nexthop_cache *bnc
635 static void register_zebra_rnh(struct bgp_nexthop_cache
*bnc
,
636 int is_bgp_import_route
)
638 /* Check if we have already registered */
639 if (bnc
->flags
& BGP_NEXTHOP_REGISTERED
)
641 if (is_bgp_import_route
)
642 sendmsg_zebra_rnh(bnc
, ZEBRA_IMPORT_ROUTE_REGISTER
);
644 sendmsg_zebra_rnh(bnc
, ZEBRA_NEXTHOP_REGISTER
);
648 * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra.
650 * struct bgp_nexthop_cache *bnc
654 static void unregister_zebra_rnh(struct bgp_nexthop_cache
*bnc
,
655 int is_bgp_import_route
)
657 /* Check if we have already registered */
658 if (!CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_REGISTERED
))
661 if (is_bgp_import_route
)
662 sendmsg_zebra_rnh(bnc
, ZEBRA_IMPORT_ROUTE_UNREGISTER
);
664 sendmsg_zebra_rnh(bnc
, ZEBRA_NEXTHOP_UNREGISTER
);
668 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
670 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
674 static void 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
)) {
685 char buf
[PREFIX2STR_BUFFER
];
686 bnc_str(bnc
, buf
, PREFIX2STR_BUFFER
);
688 "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
) {
693 if (!(path
->type
== ZEBRA_ROUTE_BGP
694 && ((path
->sub_type
== BGP_ROUTE_NORMAL
)
695 || (path
->sub_type
== BGP_ROUTE_STATIC
))))
699 assert(rn
&& bgp_node_table(rn
));
700 afi
= family2afi(rn
->p
.family
);
701 table
= bgp_node_table(rn
);
704 /* Path becomes valid/invalid depending on whether the nexthop
705 * reachable/unreachable.
707 if ((CHECK_FLAG(path
->flags
, BGP_INFO_VALID
) ? 1 : 0)
708 != (bgp_isvalid_nexthop(bnc
) ? 1 : 0)) {
709 if (CHECK_FLAG(path
->flags
, BGP_INFO_VALID
)) {
710 bgp_aggregate_decrement(bgp
, &rn
->p
, path
, afi
,
712 bgp_info_unset_flag(rn
, path
, BGP_INFO_VALID
);
714 bgp_info_set_flag(rn
, path
, BGP_INFO_VALID
);
715 bgp_aggregate_increment(bgp
, &rn
->p
, path
, afi
,
720 /* Copy the metric to the path. Will be used for bestpath
722 if (bgp_isvalid_nexthop(bnc
) && bnc
->metric
)
723 (bgp_info_extra_get(path
))->igpmetric
= bnc
->metric
;
724 else if (path
->extra
)
725 path
->extra
->igpmetric
= 0;
727 if (CHECK_FLAG(bnc
->change_flags
, BGP_NEXTHOP_METRIC_CHANGED
)
728 || CHECK_FLAG(bnc
->change_flags
, BGP_NEXTHOP_CHANGED
))
729 SET_FLAG(path
->flags
, BGP_INFO_IGP_CHANGED
);
731 bgp_process(bgp
, rn
, afi
, safi
);
734 if (peer
&& !CHECK_FLAG(bnc
->flags
, BGP_NEXTHOP_PEER_NOTIFIED
)) {
735 if (BGP_DEBUG(nht
, NHT
))
736 zlog_debug("%s: Updating peer (%s) status with NHT",
737 __FUNCTION__
, peer
->host
);
738 bgp_fsm_nht_update(peer
, bgp_isvalid_nexthop(bnc
));
739 SET_FLAG(bnc
->flags
, BGP_NEXTHOP_PEER_NOTIFIED
);
742 RESET_FLAG(bnc
->change_flags
);
746 * path_nh_map - make or break path-to-nexthop association.
748 * path - pointer to the path structure
749 * bnc - pointer to the nexthop structure
750 * make - if set, make the association. if unset, just break the existing
753 static void path_nh_map(struct bgp_info
*path
, struct bgp_nexthop_cache
*bnc
,
757 LIST_REMOVE(path
, nh_thread
);
758 path
->nexthop
->path_count
--;
759 path
->nexthop
= NULL
;
762 LIST_INSERT_HEAD(&(bnc
->paths
), path
, nh_thread
);
764 path
->nexthop
->path_count
++;