]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_nht.c
*: use clang's 'ForEachMacros' format style option
[mirror_frr.git] / bgpd / bgp_nht.c
CommitLineData
fb018d25
DS
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 *
896014f4
DL
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
fb018d25
DS
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"
7076bb2f 32#include "vrf.h"
039f3a34 33#include "filter.h"
fb018d25
DS
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"
ffd0c037 42#include "bgpd/bgp_fsm.h"
afbb1c59 43#include "bgpd/bgp_zebra.h"
fb018d25
DS
44
45extern struct zclient *zclient;
fb018d25 46
078430f6 47static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
d62a17ae 48 int is_bgp_static_route);
078430f6
DS
49static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
50 int is_bgp_static_route);
fb018d25
DS
51static void evaluate_paths(struct bgp_nexthop_cache *bnc);
52static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p);
53static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc,
54 int keep);
55
d62a17ae 56static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc)
d4d9d757 57{
d62a17ae 58 return (bgp_zebra_num_connects() == 0
59 || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)));
d4d9d757
LB
60}
61
d62a17ae 62int bgp_find_nexthop(struct bgp_info *path, int connected)
fb018d25 63{
d62a17ae 64 struct bgp_nexthop_cache *bnc = path->nexthop;
fb018d25 65
d62a17ae 66 if (!bnc)
67 return 0;
fb018d25 68
d62a17ae 69 /*
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
73 */
74 if (path->peer && path->peer->bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
75 return 1;
3f3971a9 76
d62a17ae 77 if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)))
78 return 0;
fb018d25 79
d62a17ae 80 return (bgp_isvalid_nexthop(bnc));
fb018d25
DS
81}
82
d62a17ae 83static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
fb018d25 84{
d62a17ae 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));
90 }
91 unregister_zebra_rnh(bnc,
92 CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
93 bnc->node->info = NULL;
94 bgp_unlock_node(bnc->node);
95 bnc->node = NULL;
96 bnc_free(bnc);
fb018d25 97 }
fb018d25
DS
98}
99
d62a17ae 100void bgp_unlink_nexthop(struct bgp_info *path)
f9164b1d 101{
d62a17ae 102 struct bgp_nexthop_cache *bnc = path->nexthop;
103
104 if (!bnc)
105 return;
f9164b1d 106
d62a17ae 107 path_nh_map(path, NULL, 0);
f9164b1d 108
d62a17ae 109 bgp_unlink_nexthop_check(bnc);
f9164b1d
PJ
110}
111
d62a17ae 112void bgp_unlink_nexthop_by_peer(struct peer *peer)
f9164b1d 113{
d62a17ae 114 struct prefix p;
115 struct bgp_node *rn;
116 struct bgp_nexthop_cache *bnc;
117 afi_t afi = family2afi(peer->su.sa.sa_family);
118
119 if (!sockunion2hostprefix(&peer->su, &p))
120 return;
121
122 rn = bgp_node_get(peer->bgp->nexthop_cache_table[afi], &p);
123
124 if (!rn->info)
125 return;
126
127 bnc = rn->info;
128
129 /* cleanup the peer reference */
130 bnc->nht_info = NULL;
131
132 bgp_unlink_nexthop_check(bnc);
f9164b1d
PJ
133}
134
d62a17ae 135int bgp_find_or_add_nexthop(struct bgp *bgp, afi_t afi, struct bgp_info *ri,
136 struct peer *peer, int connected)
fb018d25 137{
d62a17ae 138 struct bgp_node *rn;
139 struct bgp_nexthop_cache *bnc;
140 struct prefix p;
141 int is_bgp_static_route = 0;
142
143 if (ri) {
144 is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP)
145 && (ri->sub_type == BGP_ROUTE_STATIC))
146 ? 1
147 : 0;
148
149 /* Since Extended Next-hop Encoding (RFC5549) support, we want
150 to derive
151 address-family from the next-hop. */
152 if (!is_bgp_static_route)
153 afi = BGP_ATTR_NEXTHOP_AFI_IP6(ri->attr) ? AFI_IP6
154 : AFI_IP;
155
156 /* This will return TRUE if the global IPv6 NH is a link local
157 * addr */
158 if (make_prefix(afi, ri, &p) < 0)
159 return 1;
160 } else if (peer) {
161 /* Don't register link local NH */
162 if (afi == AFI_IP6
163 && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
164 return 1;
165
166 if (!sockunion2hostprefix(&peer->su, &p)) {
167 if (BGP_DEBUG(nht, NHT)) {
168 zlog_debug(
169 "%s: Attempting to register with unknown AFI %d (not %d or %d)",
170 __FUNCTION__, afi, AFI_IP, AFI_IP6);
171 }
172 return 0;
173 }
174 } else
175 return 0;
176
177 if (is_bgp_static_route)
178 rn = bgp_node_get(bgp->import_check_table[afi], &p);
179 else
180 rn = bgp_node_get(bgp->nexthop_cache_table[afi], &p);
181
182 if (!rn->info) {
183 bnc = bnc_new();
184 rn->info = bnc;
185 bnc->node = rn;
186 bnc->bgp = bgp;
187 bgp_lock_node(rn);
188 if (BGP_DEBUG(nht, NHT)) {
189 char buf[PREFIX2STR_BUFFER];
190
191 zlog_debug("Allocated bnc %s peer %p",
192 bnc_str(bnc, buf, PREFIX2STR_BUFFER), peer);
193 }
fc9a856f 194 }
d62a17ae 195
196 bnc = rn->info;
197 bgp_unlock_node(rn);
198 if (is_bgp_static_route) {
199 SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
200
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);
213 }
078430f6 214 }
d62a17ae 215 /* When nexthop is already known, but now requires 'connected'
216 * resolution,
217 * re-register it. The reverse scenario where the nexthop currently
218 * requires
219 * 'connected' resolution does not need a re-register (i.e., we treat
220 * 'connected-required' as an override) except in the scenario where
221 * this
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
226 * scenario.
227 */
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);
078430f6 237 }
d62a17ae 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
245 * free
246 * the nexthop cache entry, if appropriate.
247 */
248 bgp_unlink_nexthop(ri);
249
250 path_nh_map(ri, bnc, 1); /* updates NHT ri list reference */
251
252 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
253 (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
254 else if (ri->extra)
255 ri->extra->igpmetric = 0;
256 } else if (peer)
257 bnc->nht_info = (void *)peer; /* NHT peer reference */
258
259 /*
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
263 */
264 if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
265 return 1;
266 else
267 return (bgp_isvalid_nexthop(bnc));
fb018d25
DS
268}
269
d62a17ae 270void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer)
9a233a02 271{
d62a17ae 272 struct bgp_node *rn;
273 struct bgp_nexthop_cache *bnc;
274 struct prefix p;
275
276 if (!peer)
277 return;
278
279 /* We don't register link local address for NHT */
280 if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
281 return;
282
283 if (!sockunion2hostprefix(&peer->su, &p))
284 return;
285
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",
291 peer->host);
292 if (rn)
293 bgp_unlock_node(rn);
294 return;
295 }
296
297 bnc = rn->info;
298 bgp_unlock_node(rn);
299
300 if (bnc->nht_info != peer) {
301 if (BGP_DEBUG(nht, NHT))
302 zlog_debug(
303 "Connected NHT %p node for peer %s points to %p",
304 bnc, peer->host, bnc->nht_info);
305 return;
306 }
307
308 bnc->nht_info = NULL;
309
310 if (LIST_EMPTY(&(bnc->paths))) {
311 if (BGP_DEBUG(nht, NHT))
312 zlog_debug("Freeing connected NHT node %p for peer %s",
313 bnc, peer->host);
314 unregister_zebra_rnh(bnc, 0);
315 bnc->node->info = NULL;
316 bgp_unlock_node(bnc->node);
317 bnc_free(bnc);
318 }
9a233a02
DS
319}
320
d62a17ae 321void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
fb018d25 322{
d62a17ae 323 struct stream *s;
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;
330 uint32_t metric;
331 u_char nexthop_num;
332 struct prefix p;
333 int i;
334 struct bgp *bgp;
335
336 bgp = bgp_lookup_by_vrf_id(vrf_id);
337 if (!bgp) {
338 zlog_err(
339 "parse nexthop update: instance not found for vrf_id %d",
340 vrf_id);
341 return;
fb018d25 342 }
d62a17ae 343
344 s = zclient->ibuf;
345
346 memset(&p, 0, sizeof(struct prefix));
347 p.family = stream_getw(s);
348 p.prefixlen = stream_getc(s);
349 switch (p.family) {
350 case AF_INET:
351 p.u.prefix4.s_addr = stream_get_ipv4(s);
352 break;
353 case AF_INET6:
354 stream_get(&p.u.prefix6, s, 16);
355 break;
356 default:
357 break;
358 }
359
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);
366
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",
372 buf);
373 }
374 if (rn)
375 bgp_unlock_node(rn);
376 return;
fb018d25 377 }
d62a17ae 378
379 bnc = rn->info;
380 bgp_unlock_node(rn);
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);
386
387 /* debug print the input */
388 if (BGP_DEBUG(nht, NHT)) {
389 char buf[PREFIX2STR_BUFFER];
390 prefix2str(&p, buf, sizeof(buf));
391 zlog_debug(
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);
395 }
396
397 if (metric != bnc->metric)
398 bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
399
400 if (nexthop_num != bnc->nexthop_num)
401 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
402
403 if (nexthop_num) {
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);
407
408 bnc->flags |= BGP_NEXTHOP_VALID;
409 bnc->metric = metric;
410 bnc->nexthop_num = nexthop_num;
411
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);
419 break;
420 case NEXTHOP_TYPE_IFINDEX:
421 nexthop->ifindex = stream_getl(s);
422 break;
423 case NEXTHOP_TYPE_IPV4_IFINDEX:
424 nexthop->gate.ipv4.s_addr = stream_get_ipv4(s);
425 nexthop->ifindex = stream_getl(s);
426 break;
427 case NEXTHOP_TYPE_IPV6:
428 stream_get(&nexthop->gate.ipv6, s, 16);
429 nexthop->ifindex = stream_getl(s);
430 break;
431 case NEXTHOP_TYPE_IPV6_IFINDEX:
432 stream_get(&nexthop->gate.ipv6, s, 16);
433 nexthop->ifindex = stream_getl(s);
434 break;
435 default:
436 /* do nothing */
437 break;
438 }
439
440 if (BGP_DEBUG(nht, NHT)) {
441 char buf[NEXTHOP_STRLEN];
442 zlog_debug(
443 " nhop via %s",
444 nexthop2str(nexthop, buf, sizeof(buf)));
445 }
446
447 if (nhlist_tail) {
448 nhlist_tail->next = nexthop;
449 nhlist_tail = nexthop;
450 } else {
451 nhlist_tail = nexthop;
452 nhlist_head = nexthop;
453 }
454
455 /* No need to evaluate the nexthop if we have already
456 * determined
457 * that there has been a change.
458 */
459 if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
460 continue;
461
462 for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
463 if (nexthop_same_no_recurse(oldnh, nexthop))
464 break;
465
466 if (!oldnh)
467 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
468 }
469 bnc_nexthop_free(bnc);
470 bnc->nexthop = nhlist_head;
471 } else {
472 bnc->flags &= ~BGP_NEXTHOP_VALID;
473 bnc->nexthop_num = nexthop_num;
474
475 /* notify bgp fsm if nbr ip goes from valid->invalid */
476 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
477
478 bnc_nexthop_free(bnc);
479 bnc->nexthop = NULL;
480 }
481
482 evaluate_paths(bnc);
fb018d25
DS
483}
484
ee7ca6c0 485/*
486 * Cleanup nexthop registration and status information for BGP nexthops
487 * pertaining to this VRF. This is invoked upon VRF deletion.
488 */
489void bgp_cleanup_nexthops(struct bgp *bgp)
490{
491 afi_t afi;
492 struct bgp_node *rn;
493 struct bgp_nexthop_cache *bnc;
494
495 for (afi = AFI_IP; afi < AFI_MAX; afi++) {
496 if (!bgp->nexthop_cache_table[afi])
497 continue;
498
499 for (rn = bgp_table_top(bgp->nexthop_cache_table[afi]); rn;
500 rn = bgp_route_next(rn)) {
57f7feb6
MK
501 bnc = rn->info;
502 if (!bnc)
ee7ca6c0 503 continue;
504
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);
509 }
510 }
511}
512
fb018d25
DS
513/**
514 * make_prefix - make a prefix structure from the path (essentially
515 * path's node.
516 */
d62a17ae 517static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p)
fb018d25 518{
078430f6 519
d62a17ae 520 int is_bgp_static = ((ri->type == ZEBRA_ROUTE_BGP)
521 && (ri->sub_type == BGP_ROUTE_STATIC))
522 ? 1
523 : 0;
524
525 memset(p, 0, sizeof(struct prefix));
526 switch (afi) {
527 case AFI_IP:
528 p->family = AF_INET;
529 if (is_bgp_static) {
530 p->u.prefix4 = ri->net->p.u.prefix4;
531 p->prefixlen = ri->net->p.prefixlen;
532 } else {
533 p->u.prefix4 = ri->attr->nexthop;
534 p->prefixlen = IPV4_MAX_BITLEN;
535 }
536 break;
537 case AFI_IP6:
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))
541 return -1;
542
543 p->family = AF_INET6;
544
545 if (is_bgp_static) {
546 p->u.prefix6 = ri->net->p.u.prefix6;
547 p->prefixlen = ri->net->p.prefixlen;
548 } else {
549 p->u.prefix6 = ri->attr->mp_nexthop_global;
550 p->prefixlen = IPV6_MAX_BITLEN;
551 }
552 break;
553 default:
554 if (BGP_DEBUG(nht, NHT)) {
555 zlog_debug(
556 "%s: Attempting to make prefix with unknown AFI %d (not %d or %d)",
557 __FUNCTION__, afi, AFI_IP, AFI_IP6);
558 }
559 break;
65740e1b 560 }
d62a17ae 561 return 0;
fb018d25
DS
562}
563
564/**
078430f6 565 * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
fb018d25
DS
566 * command to Zebra.
567 * ARGUMENTS:
568 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
078430f6 569 * int command -- command to send to zebra
fb018d25
DS
570 * RETURNS:
571 * void.
572 */
d62a17ae 573static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command)
fb018d25 574{
d62a17ae 575 struct stream *s;
576 struct prefix *p;
577 int ret;
578
579 /* Check socket. */
580 if (!zclient || zclient->sock < 0)
581 return;
582
583 /* Don't try to register if Zebra doesn't know of this instance. */
584 if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bnc->bgp))
585 return;
586
587 p = &(bnc->node->p);
588 s = zclient->obuf;
589 stream_reset(s);
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))
593 stream_putc(s, 1);
594 else
595 stream_putc(s, 0);
596
597 stream_putw(s, PREFIX_FAMILY(p));
598 stream_putc(s, p->prefixlen);
599 switch (PREFIX_FAMILY(p)) {
600 case AF_INET:
601 stream_put_in_addr(s, &p->u.prefix4);
602 break;
603 case AF_INET6:
604 stream_put(s, &(p->u.prefix6), 16);
605 break;
606 default:
607 break;
608 }
609 stream_putw_at(s, 0, stream_get_endp(s));
610
611 ret = zclient_send_message(zclient);
612 /* TBD: handle the failure */
613 if (ret < 0)
614 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
615
616 if ((command == ZEBRA_NEXTHOP_REGISTER)
617 || (command == ZEBRA_IMPORT_ROUTE_REGISTER))
618 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
619 else if ((command == ZEBRA_NEXTHOP_UNREGISTER)
620 || (command == ZEBRA_IMPORT_ROUTE_UNREGISTER))
621 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
622 return;
fb018d25
DS
623}
624
625/**
078430f6
DS
626 * register_zebra_rnh - register a NH/route with Zebra for notification
627 * when the route or the route to the nexthop changes.
fb018d25 628 * ARGUMENTS:
078430f6 629 * struct bgp_nexthop_cache *bnc
fb018d25
DS
630 * RETURNS:
631 * void.
632 */
d62a17ae 633static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
634 int is_bgp_import_route)
fb018d25 635{
d62a17ae 636 /* Check if we have already registered */
637 if (bnc->flags & BGP_NEXTHOP_REGISTERED)
638 return;
639 if (is_bgp_import_route)
640 sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER);
641 else
642 sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER);
fb018d25
DS
643}
644
645/**
078430f6 646 * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra.
fb018d25 647 * ARGUMENTS:
078430f6 648 * struct bgp_nexthop_cache *bnc
fb018d25
DS
649 * RETURNS:
650 * void.
651 */
d62a17ae 652static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
653 int is_bgp_import_route)
fb018d25 654{
d62a17ae 655 /* Check if we have already registered */
656 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
657 return;
658
659 if (is_bgp_import_route)
660 sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER);
661 else
662 sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER);
fb018d25
DS
663}
664
665/**
666 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
667 * ARGUMENTS:
668 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
669 * RETURNS:
670 * void.
671 */
d62a17ae 672static void evaluate_paths(struct bgp_nexthop_cache *bnc)
fb018d25 673{
d62a17ae 674 struct bgp_node *rn;
675 struct bgp_info *path;
676 struct bgp *bgp = bnc->bgp;
677 int afi;
678 struct peer *peer = (struct peer *)bnc->nht_info;
679 struct bgp_table *table;
680 safi_t safi;
681
682 if (BGP_DEBUG(nht, NHT)) {
683 char buf[PREFIX2STR_BUFFER];
684 bnc_str(bnc, buf, PREFIX2STR_BUFFER);
685 zlog_debug(
686 "NH update for %s - flags 0x%x chgflags 0x%x - evaluate paths",
687 buf, bnc->flags, bnc->change_flags);
fb018d25
DS
688 }
689
a2addae8 690 LIST_FOREACH (path, &(bnc->paths), nh_thread) {
d62a17ae 691 if (!(path->type == ZEBRA_ROUTE_BGP
692 && ((path->sub_type == BGP_ROUTE_NORMAL)
693 || (path->sub_type == BGP_ROUTE_STATIC))))
694 continue;
695
696 rn = path->net;
697 assert(rn && bgp_node_table(rn));
698 afi = family2afi(rn->p.family);
699 table = bgp_node_table(rn);
700 safi = table->safi;
701
702 /* Path becomes valid/invalid depending on whether the nexthop
703 * reachable/unreachable.
704 */
705 if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0)
706 != (bgp_isvalid_nexthop(bnc) ? 1 : 0)) {
707 if (CHECK_FLAG(path->flags, BGP_INFO_VALID)) {
708 bgp_aggregate_decrement(bgp, &rn->p, path, afi,
709 safi);
710 bgp_info_unset_flag(rn, path, BGP_INFO_VALID);
711 } else {
712 bgp_info_set_flag(rn, path, BGP_INFO_VALID);
713 bgp_aggregate_increment(bgp, &rn->p, path, afi,
714 safi);
715 }
716 }
717
718 /* Copy the metric to the path. Will be used for bestpath
719 * computation */
720 if (bgp_isvalid_nexthop(bnc) && bnc->metric)
721 (bgp_info_extra_get(path))->igpmetric = bnc->metric;
722 else if (path->extra)
723 path->extra->igpmetric = 0;
724
725 if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED)
726 || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
727 SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
728
729 bgp_process(bgp, rn, afi, safi);
730 }
fc9a856f 731
d62a17ae 732 if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) {
733 if (BGP_DEBUG(nht, NHT))
734 zlog_debug("%s: Updating peer (%s) status with NHT",
735 __FUNCTION__, peer->host);
736 bgp_fsm_nht_update(peer, bgp_isvalid_nexthop(bnc));
737 SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
738 }
fc9a856f 739
d62a17ae 740 RESET_FLAG(bnc->change_flags);
fb018d25
DS
741}
742
743/**
744 * path_nh_map - make or break path-to-nexthop association.
745 * ARGUMENTS:
746 * path - pointer to the path structure
747 * bnc - pointer to the nexthop structure
748 * make - if set, make the association. if unset, just break the existing
749 * association.
750 */
d62a17ae 751static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc,
752 int make)
fb018d25 753{
d62a17ae 754 if (path->nexthop) {
755 LIST_REMOVE(path, nh_thread);
756 path->nexthop->path_count--;
757 path->nexthop = NULL;
758 }
759 if (make) {
760 LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
761 path->nexthop = bnc;
762 path->nexthop->path_count++;
763 }
fb018d25 764}