blob: 1158ab152e07342a1ffdc4d20688e0c40c2b223e [file] [log] [blame]
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -05001/* 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
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
24#include "command.h"
25#include "thread.h"
26#include "prefix.h"
27#include "zclient.h"
28#include "stream.h"
29#include "network.h"
30#include "log.h"
31#include "memory.h"
32#include "nexthop.h"
33#include "filter.h"
34
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"
Dinesh Duttd9ab53a2015-05-19 17:47:21 -070042#include "bgpd/bgp_fsm.h"
Lou Bergere33545c2016-10-10 09:50:58 -040043#include "bgpd/bgp_zebra.h"
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050044
45extern struct zclient *zclient;
46extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
47
48static void register_nexthop(struct bgp_nexthop_cache *bnc);
49static void unregister_nexthop (struct bgp_nexthop_cache *bnc);
50static void evaluate_paths(struct bgp_nexthop_cache *bnc);
51static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p);
52static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc,
53 int keep);
54
55int
Paul Jakma3dda6b32016-09-06 16:57:40 +010056bgp_nexthop_check (struct bgp_info *path, int connected)
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050057{
58 struct bgp_nexthop_cache *bnc = path->nexthop;
59
60 if (!bnc)
61 return 0;
62
Paul Jakma3dda6b32016-09-06 16:57:40 +010063 if (BGP_DEBUG(nht, NHT))
64 {
65 char buf[INET6_ADDRSTRLEN];
66 zlog_debug("%s: NHT checking %s",
67 __FUNCTION__,
68 bnc_str (bnc, buf, INET6_ADDRSTRLEN));
69 }
70
Dinesh Duttd9ab53a2015-05-19 17:47:21 -070071 if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)))
72 return 0;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050073
Lou Berger68bfb612016-10-06 09:59:32 -040074 return (bgp_zebra_num_connects() == 0 ||
75 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050076}
77
Paul Jakma3dda6b32016-09-06 16:57:40 +010078/* Helper to get the rn for the appropriate nexthop for path or peer.
79 * returns the locked rn - caller must bump down the refcnt.
80 *
81 * may return NULL in error cases.
82 */
83static
84struct bgp_node *
85bgp_get_nexthop_rn (struct bgp_info *path, struct peer *peer)
Paul Jakma19e6c192016-09-06 17:23:48 +010086{
87 struct prefix p;
Paul Jakma3dda6b32016-09-06 16:57:40 +010088 afi_t afi;
89
90 assert (path || peer);
91
92 if (!(path || peer))
93 return NULL;
94
95 if (path)
Paul Jakma19e6c192016-09-06 17:23:48 +010096 {
Paul Jakma3dda6b32016-09-06 16:57:40 +010097 afi = family2afi (path->net->p.family);
98 if (make_prefix(afi, path, &p) < 0)
99 return NULL;
Paul Jakma19e6c192016-09-06 17:23:48 +0100100 }
101 else
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700102 {
Paul Jakma3dda6b32016-09-06 16:57:40 +0100103 afi = family2afi(peer->su.sa.sa_family);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700104 if (afi == AFI_IP)
105 {
106 p.family = AF_INET;
107 p.prefixlen = IPV4_MAX_BITLEN;
108 p.u.prefix4 = peer->su.sin.sin_addr;
109 }
110 else if (afi == AFI_IP6)
111 {
112 p.family = AF_INET6;
113 p.prefixlen = IPV6_MAX_BITLEN;
114 p.u.prefix6 = peer->su.sin6.sin6_addr;
115 }
Paul Jakma3dda6b32016-09-06 16:57:40 +0100116 else
117 return NULL;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700118 }
Paul Jakma3dda6b32016-09-06 16:57:40 +0100119
120 return bgp_node_get (bgp_nexthop_cache_table[afi], &p);
121}
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700122
Paul Jakma3dda6b32016-09-06 16:57:40 +0100123static
124struct bgp_nexthop_cache *
125bgp_find_nexthop (struct bgp_info *path, struct peer *peer)
126{
127 struct bgp_nexthop_cache *bnc = NULL;
128 struct bgp_node *rn = bgp_get_nexthop_rn (path, peer);
129
130 if (!rn)
131 return NULL;
132
133 bnc = rn->info;
134 bgp_unlock_node (rn);
135
136 return bnc;
137}
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500138
Paul Jakma3dda6b32016-09-06 16:57:40 +0100139static void
140bgp_unlink_nexthop_check (struct bgp_nexthop_cache *bnc)
141{
142 if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info)
143 {
144 if (BGP_DEBUG(nht, NHT))
145 {
146 char buf[INET6_ADDRSTRLEN];
147 zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
148 bnc_str (bnc, buf, INET6_ADDRSTRLEN));
149 }
150 unregister_nexthop(bnc);
151 bnc->node->info = NULL;
152 bgp_unlock_node (bnc->node);
153 bnc->node = NULL;
154 bnc_free (bnc);
155 }
156}
157
158void
159bgp_unlink_nexthop (struct bgp_info *path)
160{
161 struct bgp_nexthop_cache *bnc = path->nexthop;
162
163 if (!bnc)
164 return;
165
166 if (BGP_DEBUG(nht, NHT))
167 {
168 char buf[INET6_ADDRSTRLEN];
169 zlog_debug("%s: NHT unlinking %s",
170 __FUNCTION__, bnc_str (bnc, buf, INET6_ADDRSTRLEN));
171 }
172
173 path_nh_map(path, NULL, 0);
174
175 bgp_unlink_nexthop_check (bnc);
176}
177
178void
179bgp_unlink_nexthop_by_peer (struct peer *peer)
180{
181 struct bgp_nexthop_cache *bnc = bgp_find_nexthop (NULL, peer);
182
183 if (!bnc)
184 return;
185
186 if (BGP_DEBUG(nht, NHT))
187 zlog_debug("%s: NHT unlinking %s",
188 __FUNCTION__, peer->host);
189
190 bnc->nht_info = NULL;
191
192 bgp_unlink_nexthop_check (bnc);
193}
194
195int
196bgp_ensure_nexthop (struct bgp_info *ri, struct peer *peer,
197 int connected)
198{
199 struct bgp_node *rn;
200 struct bgp_nexthop_cache *bnc;
201
202 rn = bgp_get_nexthop_rn (ri, peer);
203
204 if (!rn)
205 {
206 zlog_debug("%s: NHT could not ensure, failed to get rn!",
207 __FUNCTION__);
208 return 0;
209 }
210
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500211 if (!rn->info)
212 {
213 bnc = bnc_new();
214 rn->info = bnc;
215 bnc->node = rn;
216 bgp_lock_node(rn);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700217 if (connected)
218 SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500219 }
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700220
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500221 bnc = rn->info;
222 bgp_unlock_node (rn);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500223
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700224 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
225 register_nexthop(bnc);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500226
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700227 if (ri)
228 {
Paul Jakma19e6c192016-09-06 17:23:48 +0100229 path_nh_map(ri, bnc, 1); /* updates NHT ri list reference */
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500230
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700231 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
232 (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
233 else if (ri->extra)
234 ri->extra->igpmetric = 0;
235 }
236 else if (peer)
Paul Jakma19e6c192016-09-06 17:23:48 +0100237 bnc->nht_info = (void *)peer; /* NHT peer reference */
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500238
Paul Jakma3dda6b32016-09-06 16:57:40 +0100239 if (BGP_DEBUG(nht, NHT))
240 {
241 char buf[INET6_ADDRSTRLEN];
242 zlog_debug("%s: NHT ensured %s",
243 __FUNCTION__, bnc_str (bnc, buf, INET6_ADDRSTRLEN));
244 }
245
Lou Bergerbb043512016-10-10 11:56:52 -0400246 return (bgp_zebra_num_connects() == 0 ||
247 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500248}
249
250void
251bgp_parse_nexthop_update (void)
252{
253 struct stream *s;
254 struct bgp_node *rn;
255 struct bgp_nexthop_cache *bnc;
256 struct nexthop *nexthop;
257 struct nexthop *oldnh;
258 struct nexthop *nhlist_head = NULL;
259 struct nexthop *nhlist_tail = NULL;
260 uint32_t metric;
261 u_char nexthop_num;
262 struct prefix p;
263 int i;
264
265 s = zclient->ibuf;
266
267 memset(&p, 0, sizeof(struct prefix));
268 p.family = stream_getw(s);
269 p.prefixlen = stream_getc(s);
270 switch (p.family)
271 {
272 case AF_INET:
273 p.u.prefix4.s_addr = stream_get_ipv4 (s);
274 break;
275 case AF_INET6:
276 stream_get(&p.u.prefix6, s, 16);
277 break;
278 default:
279 break;
280 }
281
282 rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
283 if (!rn || !rn->info)
284 {
285 if (BGP_DEBUG(nht, NHT))
286 {
287 char buf[INET6_ADDRSTRLEN];
288 prefix2str(&p, buf, INET6_ADDRSTRLEN);
289 zlog_debug("parse nexthop update(%s): rn not found", buf);
290 }
291 if (rn)
292 bgp_unlock_node (rn);
293 return;
294 }
295
296 bnc = rn->info;
297 bgp_unlock_node (rn);
298 bnc->last_update = bgp_clock();
299 bnc->change_flags = 0;
300 metric = stream_getl (s);
301 nexthop_num = stream_getc (s);
302
303 /* debug print the input */
304 if (BGP_DEBUG(nht, NHT))
305 {
306 char buf[INET6_ADDRSTRLEN];
307 prefix2str(&p, buf, INET6_ADDRSTRLEN);
308 zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf,
309 metric, nexthop_num);
310 }
311
312 if (metric != bnc->metric)
313 bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
314
315 if(nexthop_num != bnc->nexthop_num)
316 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
317
318 if (nexthop_num)
319 {
320 bnc->flags |= BGP_NEXTHOP_VALID;
321 bnc->metric = metric;
322 bnc->nexthop_num = nexthop_num;
323
324 for (i = 0; i < nexthop_num; i++)
325 {
326 nexthop = nexthop_new();
327 nexthop->type = stream_getc (s);
328 switch (nexthop->type)
329 {
330 case ZEBRA_NEXTHOP_IPV4:
331 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
332 break;
333 case ZEBRA_NEXTHOP_IFINDEX:
334 case ZEBRA_NEXTHOP_IFNAME:
335 nexthop->ifindex = stream_getl (s);
336 break;
337 case ZEBRA_NEXTHOP_IPV4_IFINDEX:
338 case ZEBRA_NEXTHOP_IPV4_IFNAME:
339 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
340 nexthop->ifindex = stream_getl (s);
341 break;
342#ifdef HAVE_IPV6
343 case ZEBRA_NEXTHOP_IPV6:
344 stream_get (&nexthop->gate.ipv6, s, 16);
345 break;
346 case ZEBRA_NEXTHOP_IPV6_IFINDEX:
347 case ZEBRA_NEXTHOP_IPV6_IFNAME:
348 stream_get (&nexthop->gate.ipv6, s, 16);
349 nexthop->ifindex = stream_getl (s);
350 break;
351#endif
352 default:
353 /* do nothing */
354 break;
355 }
356
357 if (nhlist_tail)
358 {
359 nhlist_tail->next = nexthop;
360 nhlist_tail = nexthop;
361 }
362 else
363 {
364 nhlist_tail = nexthop;
365 nhlist_head = nexthop;
366 }
367
368 /* No need to evaluate the nexthop if we have already determined
369 * that there has been a change.
370 */
371 if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
372 continue;
373
374 for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
375 if (nexthop_same_no_recurse(oldnh, nexthop))
376 break;
377
378 if (!oldnh)
379 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
380 }
381 bnc_nexthop_free(bnc);
382 bnc->nexthop = nhlist_head;
383 }
384 else
385 {
386 bnc->flags &= ~BGP_NEXTHOP_VALID;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700387 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500388 bnc_nexthop_free(bnc);
389 bnc->nexthop = NULL;
390 }
391
392 evaluate_paths(bnc);
393}
394
395/**
396 * make_prefix - make a prefix structure from the path (essentially
397 * path's node.
398 */
399static int
400make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
401{
402 memset (p, 0, sizeof (struct prefix));
403 switch (afi)
404 {
405 case AFI_IP:
406 p->family = AF_INET;
407 p->prefixlen = IPV4_MAX_BITLEN;
408 p->u.prefix4 = ri->attr->nexthop;
409 break;
410#ifdef HAVE_IPV6
411 case AFI_IP6:
412 if (ri->attr->extra->mp_nexthop_len != 16
413 || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global))
414 return -1;
415
416 p->family = AF_INET6;
417 p->prefixlen = IPV6_MAX_BITLEN;
418 p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
419 break;
420#endif
421 default:
422 break;
423 }
424 return 0;
425}
426
427/**
428 * sendmsg_nexthop -- Format and send a nexthop register/Unregister
429 * command to Zebra.
430 * ARGUMENTS:
431 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
432 * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER
433 * RETURNS:
434 * void.
435 */
436static void
437sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
438{
439 struct stream *s;
440 struct prefix *p;
441 int ret;
442
443 /* Check socket. */
444 if (!zclient || zclient->sock < 0)
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700445 {
446 zlog_debug("%s: Can't send NH register, Zebra client not established",
447 __FUNCTION__);
448 return;
449 }
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500450
451 p = &(bnc->node->p);
452 s = zclient->obuf;
453 stream_reset (s);
454 zclient_create_header (s, command, VRF_DEFAULT);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700455 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
456 stream_putc(s, 1);
457 else
458 stream_putc(s, 0);
459
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500460 stream_putw(s, PREFIX_FAMILY(p));
461 stream_putc(s, p->prefixlen);
462 switch (PREFIX_FAMILY(p))
463 {
464 case AF_INET:
465 stream_put_in_addr (s, &p->u.prefix4);
466 break;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500467 case AF_INET6:
468 stream_put(s, &(p->u.prefix6), 16);
469 break;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500470 default:
471 break;
472 }
473 stream_putw_at (s, 0, stream_get_endp (s));
474
475 ret = zclient_send_message(zclient);
476 /* TBD: handle the failure */
477 if (ret < 0)
478 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700479
480 if (command == ZEBRA_NEXTHOP_REGISTER)
481 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
482 else if (command == ZEBRA_NEXTHOP_UNREGISTER)
483 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500484 return;
485}
486
487/**
488 * register_nexthop - register a nexthop with Zebra for notification
489 * when the route to the nexthop changes.
490 * ARGUMENTS:
491 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
492 * RETURNS:
493 * void.
494 */
495static void
496register_nexthop (struct bgp_nexthop_cache *bnc)
497{
498 /* Check if we have already registered */
499 if (bnc->flags & BGP_NEXTHOP_REGISTERED)
500 return;
501 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500502}
503
504/**
505 * unregister_nexthop -- Unregister the nexthop from Zebra.
506 * ARGUMENTS:
507 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
508 * RETURNS:
509 * void.
510 */
511static void
512unregister_nexthop (struct bgp_nexthop_cache *bnc)
513{
514 /* Check if we have already registered */
515 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
516 return;
517
518 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500519}
520
521/**
522 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
523 * ARGUMENTS:
524 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
525 * RETURNS:
526 * void.
527 */
528static void
529evaluate_paths (struct bgp_nexthop_cache *bnc)
530{
531 struct bgp_node *rn;
532 struct bgp_info *path;
533 struct bgp *bgp = bgp_get_default();
534 int afi;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700535 struct peer *peer = (struct peer *)bnc->nht_info;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500536
537 LIST_FOREACH(path, &(bnc->paths), nh_thread)
538 {
539 if (!(path->type == ZEBRA_ROUTE_BGP &&
540 path->sub_type == BGP_ROUTE_NORMAL))
541 continue;
542
543 rn = path->net;
544 afi = family2afi(rn->p.family);
545
546 /* Path becomes valid/invalid depending on whether the nexthop
547 * reachable/unreachable.
548 */
549 if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) !=
550 (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0))
551 {
552 if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
553 {
554 bgp_aggregate_decrement (bgp, &rn->p, path,
555 afi, SAFI_UNICAST);
556 bgp_info_unset_flag (rn, path, BGP_INFO_VALID);
557 }
558 else
559 {
560 bgp_info_set_flag (rn, path, BGP_INFO_VALID);
561 bgp_aggregate_increment (bgp, &rn->p, path,
562 afi, SAFI_UNICAST);
563 }
564 }
565
566 /* Copy the metric to the path. Will be used for bestpath computation */
567 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
568 (bgp_info_extra_get(path))->igpmetric = bnc->metric;
569 else if (path->extra)
570 path->extra->igpmetric = 0;
571
572 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) ||
573 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED))
574 SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
575
576 bgp_process(bgp, rn, afi, SAFI_UNICAST);
577 }
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700578
579 if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED))
580 {
581 if (BGP_DEBUG(nht, NHT))
582 zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700583 SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
584 }
585
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500586 RESET_FLAG(bnc->change_flags);
587}
588
589/**
590 * path_nh_map - make or break path-to-nexthop association.
591 * ARGUMENTS:
592 * path - pointer to the path structure
593 * bnc - pointer to the nexthop structure
594 * make - if set, make the association. if unset, just break the existing
595 * association.
596 */
597static void
598path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make)
599{
600 if (path->nexthop)
601 {
602 LIST_REMOVE(path, nh_thread);
603 path->nexthop->path_count--;
604 path->nexthop = NULL;
605 }
606 if (make)
607 {
608 LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
609 path->nexthop = bnc;
610 path->nexthop->path_count++;
611 }
612}