]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_nht.c
Merge pull request #740 from donaldsharp/ospf_commands
[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
DS
47static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
48 int is_bgp_static_route);
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
d4d9d757
LB
56static int
57bgp_isvalid_nexthop (struct bgp_nexthop_cache *bnc)
58{
59 return (bgp_zebra_num_connects() == 0 ||
60 (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)));
61}
62
fb018d25 63int
fc9a856f 64bgp_find_nexthop (struct bgp_info *path, int connected)
fb018d25
DS
65{
66 struct bgp_nexthop_cache *bnc = path->nexthop;
67
68 if (!bnc)
69 return 0;
70
3f3971a9
DS
71 /*
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
75 */
76 if (path->peer && path->peer->bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
77 return 1;
78
fc9a856f
DS
79 if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)))
80 return 0;
fb018d25 81
d4d9d757 82 return (bgp_isvalid_nexthop(bnc));
fb018d25
DS
83}
84
f9164b1d
PJ
85static void
86bgp_unlink_nexthop_check (struct bgp_nexthop_cache *bnc)
fb018d25 87{
fc9a856f 88 if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info)
fb018d25
DS
89 {
90 if (BGP_DEBUG(nht, NHT))
91 {
4690c7d7 92 char buf[PREFIX2STR_BUFFER];
fb018d25 93 zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
4690c7d7 94 bnc_str(bnc, buf, PREFIX2STR_BUFFER));
fb018d25 95 }
078430f6 96 unregister_zebra_rnh(bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE));
fb018d25
DS
97 bnc->node->info = NULL;
98 bgp_unlock_node(bnc->node);
f9164b1d 99 bnc->node = NULL;
fb018d25
DS
100 bnc_free(bnc);
101 }
102}
103
f9164b1d
PJ
104void
105bgp_unlink_nexthop (struct bgp_info *path)
106{
107 struct bgp_nexthop_cache *bnc = path->nexthop;
108
109 if (!bnc)
110 return;
111
112 path_nh_map(path, NULL, 0);
113
114 bgp_unlink_nexthop_check (bnc);
115}
116
117void
118bgp_unlink_nexthop_by_peer (struct peer *peer)
119{
120 struct prefix p;
121 struct bgp_node *rn;
122 struct bgp_nexthop_cache *bnc;
123 afi_t afi = family2afi(peer->su.sa.sa_family);
124
235022cb 125 if (! sockunion2hostprefix (&peer->su, &p))
f9164b1d
PJ
126 return;
127
128 rn = bgp_node_get (peer->bgp->nexthop_cache_table[afi], &p);
129
130 if (!rn->info)
131 return;
132
133 bnc = rn->info;
134
135 /* cleanup the peer reference */
136 bnc->nht_info = NULL;
137
138 bgp_unlink_nexthop_check (bnc);
139}
140
fb018d25 141int
75aead62
DS
142bgp_find_or_add_nexthop (struct bgp *bgp, afi_t afi, struct bgp_info *ri,
143 struct peer *peer, int connected)
fb018d25
DS
144{
145 struct bgp_node *rn;
146 struct bgp_nexthop_cache *bnc;
147 struct prefix p;
078430f6 148 int is_bgp_static_route = 0;
fb018d25 149
fc9a856f
DS
150 if (ri)
151 {
8a92a8a0
DS
152 is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) &&
153 (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
154
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;
159
65740e1b 160 /* This will return TRUE if the global IPv6 NH is a link local addr */
fc9a856f
DS
161 if (make_prefix(afi, ri, &p) < 0)
162 return 1;
163 }
164 else if (peer)
165 {
235022cb
RW
166 /* Don't register link local NH */
167 if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&peer->su.sin6.sin6_addr))
168 return 1;
65740e1b 169
235022cb 170 if (! sockunion2hostprefix (&peer->su, &p))
65740e1b
DS
171 {
172 if (BGP_DEBUG(nht, NHT))
173 {
174 zlog_debug("%s: Attempting to register with unknown AFI %d (not %d or %d)",
175 __FUNCTION__, afi, AFI_IP, AFI_IP6);
176 }
177 return 0;
fc9a856f
DS
178 }
179 }
65740e1b
DS
180 else
181 return 0;
fc9a856f 182
078430f6 183 if (is_bgp_static_route)
6aeb9e78 184 rn = bgp_node_get (bgp->import_check_table[afi], &p);
078430f6 185 else
6aeb9e78 186 rn = bgp_node_get (bgp->nexthop_cache_table[afi], &p);
fb018d25
DS
187
188 if (!rn->info)
189 {
190 bnc = bnc_new();
191 rn->info = bnc;
192 bnc->node = rn;
75aead62 193 bnc->bgp = bgp;
fb018d25 194 bgp_lock_node(rn);
9a233a02
DS
195 if (BGP_DEBUG(nht, NHT))
196 {
4690c7d7 197 char buf[PREFIX2STR_BUFFER];
9a233a02 198
078430f6 199 zlog_debug("Allocated bnc %s peer %p",
4690c7d7 200 bnc_str(bnc, buf, PREFIX2STR_BUFFER), peer);
9a233a02 201 }
fb018d25 202 }
fc9a856f 203
fb018d25
DS
204 bnc = rn->info;
205 bgp_unlock_node (rn);
078430f6
DS
206 if (is_bgp_static_route)
207 {
208 SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
209
210 /* If we're toggling the type, re-register */
5623e905 211 if ((bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)) &&
078430f6
DS
212 !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
213 {
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);
217 }
5623e905 218 else if ((!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)) &&
078430f6
DS
219 CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
220 {
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);
224 }
225 }
25c38b24 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
234 * scenario.
235 */
078430f6
DS
236 else if (connected && ! CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
237 {
238 SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
239 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
240 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
241 }
25c38b24 242 else if (peer && !connected && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
078430f6
DS
243 {
244 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
245 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
246 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
247 }
3f3971a9
DS
248 if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
249 {
250 bnc->flags |= BGP_NEXTHOP_REGISTERED;
251 bnc->flags |= BGP_NEXTHOP_VALID;
252 }
253 else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
078430f6 254 register_zebra_rnh(bnc, is_bgp_static_route);
22a29185 255 if (ri && ri->nexthop != bnc)
fc9a856f 256 {
22a29185
DS
257 /* Unlink from existing nexthop cache, if any. This will also free
258 * the nexthop cache entry, if appropriate.
259 */
260 bgp_unlink_nexthop (ri);
261
f9164b1d 262 path_nh_map(ri, bnc, 1); /* updates NHT ri list reference */
fb018d25 263
fc9a856f
DS
264 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
265 (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
266 else if (ri->extra)
267 ri->extra->igpmetric = 0;
268 }
269 else if (peer)
f9164b1d 270 bnc->nht_info = (void *)peer; /* NHT peer reference */
fb018d25 271
3f3971a9
DS
272 /*
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
276 */
277 if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
278 return 1;
279 else
280 return (bgp_isvalid_nexthop(bnc));
fb018d25
DS
281}
282
9a233a02
DS
283void
284bgp_delete_connected_nexthop (afi_t afi, struct peer *peer)
285{
286 struct bgp_node *rn;
287 struct bgp_nexthop_cache *bnc;
288 struct prefix p;
289
65740e1b
DS
290 if (!peer)
291 return;
292
235022cb
RW
293 /* We don't register link local address for NHT */
294 if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&peer->su.sin6.sin6_addr))
295 return;
65740e1b 296
235022cb 297 if (! sockunion2hostprefix (&peer->su, &p))
65740e1b 298 return;
9a233a02 299
6aeb9e78 300 rn = bgp_node_lookup(peer->bgp->nexthop_cache_table[family2afi(p.family)], &p);
9a233a02
DS
301 if (!rn || !rn->info)
302 {
303 if (BGP_DEBUG(nht, NHT))
304 zlog_debug("Cannot find connected NHT node for peer %s", peer->host);
305 if (rn)
306 bgp_unlock_node (rn);
307 return;
308 }
309
310 bnc = rn->info;
311 bgp_unlock_node(rn);
312
313 if (bnc->nht_info != peer)
314 {
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);
318 return;
319 }
320
321 bnc->nht_info = NULL;
322
323 if (LIST_EMPTY(&(bnc->paths)))
324 {
325 if (BGP_DEBUG(nht, NHT))
326 zlog_debug("Freeing connected NHT node %p for peer %s",
327 bnc, peer->host);
078430f6 328 unregister_zebra_rnh(bnc, 0);
9a233a02
DS
329 bnc->node->info = NULL;
330 bgp_unlock_node(bnc->node);
331 bnc_free(bnc);
332 }
333}
334
fb018d25 335void
7076bb2f 336bgp_parse_nexthop_update (int command, vrf_id_t vrf_id)
fb018d25
DS
337{
338 struct stream *s;
ffd0c037 339 struct bgp_node *rn = NULL;
fb018d25
DS
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;
345 uint32_t metric;
346 u_char nexthop_num;
347 struct prefix p;
348 int i;
6aeb9e78
DS
349 struct bgp *bgp;
350
351 bgp = bgp_lookup_by_vrf_id (vrf_id);
352 if (!bgp)
353 {
354 zlog_err("parse nexthop update: instance not found for vrf_id %d", vrf_id);
355 return;
356 }
fb018d25
DS
357
358 s = zclient->ibuf;
359
360 memset(&p, 0, sizeof(struct prefix));
361 p.family = stream_getw(s);
362 p.prefixlen = stream_getc(s);
363 switch (p.family)
364 {
365 case AF_INET:
366 p.u.prefix4.s_addr = stream_get_ipv4 (s);
367 break;
368 case AF_INET6:
369 stream_get(&p.u.prefix6, s, 16);
370 break;
371 default:
372 break;
373 }
374
078430f6 375 if (command == ZEBRA_NEXTHOP_UPDATE)
6aeb9e78 376 rn = bgp_node_lookup(bgp->nexthop_cache_table[family2afi(p.family)], &p);
078430f6 377 else if (command == ZEBRA_IMPORT_CHECK_UPDATE)
6aeb9e78 378 rn = bgp_node_lookup(bgp->import_check_table[family2afi(p.family)], &p);
078430f6 379
fb018d25
DS
380 if (!rn || !rn->info)
381 {
382 if (BGP_DEBUG(nht, NHT))
383 {
4690c7d7
DS
384 char buf[PREFIX2STR_BUFFER];
385 prefix2str(&p, buf, sizeof(buf));
fb018d25
DS
386 zlog_debug("parse nexthop update(%s): rn not found", buf);
387 }
7898cb4f
DS
388 if (rn)
389 bgp_unlock_node (rn);
fb018d25
DS
390 return;
391 }
392
393 bnc = rn->info;
7898cb4f 394 bgp_unlock_node (rn);
fb018d25
DS
395 bnc->last_update = bgp_clock();
396 bnc->change_flags = 0;
d14b95ce 397 stream_getc (s); // Distance but not currently used
fb018d25
DS
398 metric = stream_getl (s);
399 nexthop_num = stream_getc (s);
400
401 /* debug print the input */
402 if (BGP_DEBUG(nht, NHT))
403 {
4690c7d7
DS
404 char buf[PREFIX2STR_BUFFER];
405 prefix2str(&p, buf, sizeof (buf));
cd1964ff
DS
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,
408 bnc->flags);
fb018d25
DS
409 }
410
411 if (metric != bnc->metric)
412 bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
413
414 if(nexthop_num != bnc->nexthop_num)
415 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
416
417 if (nexthop_num)
418 {
9ff31ad5
DS
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);
422
fb018d25
DS
423 bnc->flags |= BGP_NEXTHOP_VALID;
424 bnc->metric = metric;
425 bnc->nexthop_num = nexthop_num;
426
427 for (i = 0; i < nexthop_num; i++)
428 {
429 nexthop = nexthop_new();
430 nexthop->type = stream_getc (s);
431 switch (nexthop->type)
432 {
5b30316e 433 case NEXTHOP_TYPE_IPV4:
fb018d25 434 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
a18ed03f 435 nexthop->ifindex = stream_getl (s);
fb018d25 436 break;
5b30316e 437 case NEXTHOP_TYPE_IFINDEX:
fb018d25
DS
438 nexthop->ifindex = stream_getl (s);
439 break;
5b30316e 440 case NEXTHOP_TYPE_IPV4_IFINDEX:
fb018d25
DS
441 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
442 nexthop->ifindex = stream_getl (s);
443 break;
5b30316e 444 case NEXTHOP_TYPE_IPV6:
fb018d25 445 stream_get (&nexthop->gate.ipv6, s, 16);
8e581e39 446 nexthop->ifindex = stream_getl (s);
fb018d25 447 break;
5b30316e 448 case NEXTHOP_TYPE_IPV6_IFINDEX:
fb018d25
DS
449 stream_get (&nexthop->gate.ipv6, s, 16);
450 nexthop->ifindex = stream_getl (s);
451 break;
fb018d25
DS
452 default:
453 /* do nothing */
454 break;
455 }
456
80c2442a 457 if (BGP_DEBUG(nht, NHT))
458 {
459 char buf[NEXTHOP_STRLEN];
460 zlog_debug(" nhop via %s",
461 nexthop2str (nexthop, buf, sizeof (buf)));
462 }
463
fb018d25
DS
464 if (nhlist_tail)
465 {
466 nhlist_tail->next = nexthop;
467 nhlist_tail = nexthop;
468 }
469 else
470 {
471 nhlist_tail = nexthop;
472 nhlist_head = nexthop;
473 }
474
475 /* No need to evaluate the nexthop if we have already determined
476 * that there has been a change.
477 */
478 if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
479 continue;
480
481 for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
482 if (nexthop_same_no_recurse(oldnh, nexthop))
483 break;
484
485 if (!oldnh)
9ff31ad5 486 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
fb018d25
DS
487 }
488 bnc_nexthop_free(bnc);
489 bnc->nexthop = nhlist_head;
490 }
491 else
492 {
493 bnc->flags &= ~BGP_NEXTHOP_VALID;
9ff31ad5
DS
494 bnc->nexthop_num = nexthop_num;
495
496 /* notify bgp fsm if nbr ip goes from valid->invalid */
fc9a856f 497 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
9ff31ad5 498
fb018d25
DS
499 bnc_nexthop_free(bnc);
500 bnc->nexthop = NULL;
501 }
502
503 evaluate_paths(bnc);
504}
505
506/**
507 * make_prefix - make a prefix structure from the path (essentially
508 * path's node.
509 */
510static int
511make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
512{
078430f6
DS
513
514 int is_bgp_static = ((ri->type == ZEBRA_ROUTE_BGP) &&
515 (ri->sub_type == BGP_ROUTE_STATIC)) ? 1 : 0;
516
fb018d25
DS
517 memset (p, 0, sizeof (struct prefix));
518 switch (afi)
519 {
520 case AFI_IP:
521 p->family = AF_INET;
078430f6
DS
522 if (is_bgp_static)
523 {
524 p->u.prefix4 = ri->net->p.u.prefix4;
525 p->prefixlen = ri->net->p.prefixlen;
526 }
527 else
528 {
529 p->u.prefix4 = ri->attr->nexthop;
530 p->prefixlen = IPV4_MAX_BITLEN;
531 }
fb018d25 532 break;
fb018d25 533 case AFI_IP6:
65740e1b 534 /* We don't register link local NH */
801a9bcc 535 if (ri->attr->extra->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL
fb018d25
DS
536 || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global))
537 return -1;
538
539 p->family = AF_INET6;
078430f6
DS
540
541 if (is_bgp_static)
542 {
543 p->u.prefix6 = ri->net->p.u.prefix6;
544 p->prefixlen = ri->net->p.prefixlen;
545 }
546 else
547 {
548 p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
549 p->prefixlen = IPV6_MAX_BITLEN;
550 }
fb018d25 551 break;
fb018d25 552 default:
65740e1b
DS
553 if (BGP_DEBUG(nht, NHT))
554 {
555 zlog_debug("%s: Attempting to make prefix with unknown AFI %d (not %d or %d)",
556 __FUNCTION__, afi, AFI_IP, AFI_IP6);
557 }
fb018d25
DS
558 break;
559 }
560 return 0;
561}
562
563/**
078430f6 564 * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
fb018d25
DS
565 * command to Zebra.
566 * ARGUMENTS:
567 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
078430f6 568 * int command -- command to send to zebra
fb018d25
DS
569 * RETURNS:
570 * void.
571 */
572static void
078430f6 573sendmsg_zebra_rnh (struct bgp_nexthop_cache *bnc, int command)
fb018d25
DS
574{
575 struct stream *s;
576 struct prefix *p;
577 int ret;
578
579 /* Check socket. */
580 if (!zclient || zclient->sock < 0)
ad4cbda1 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;
fb018d25
DS
586
587 p = &(bnc->node->p);
588 s = zclient->obuf;
589 stream_reset (s);
6aeb9e78 590 zclient_create_header (s, command, bnc->bgp->vrf_id);
078430f6
DS
591 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) ||
592 CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))
fc9a856f
DS
593 stream_putc(s, 1);
594 else
595 stream_putc(s, 0);
596
fb018d25
DS
597 stream_putw(s, PREFIX_FAMILY(p));
598 stream_putc(s, p->prefixlen);
599 switch (PREFIX_FAMILY(p))
600 {
601 case AF_INET:
602 stream_put_in_addr (s, &p->u.prefix4);
603 break;
fb018d25
DS
604 case AF_INET6:
605 stream_put(s, &(p->u.prefix6), 16);
606 break;
fb018d25
DS
607 default:
608 break;
609 }
610 stream_putw_at (s, 0, stream_get_endp (s));
611
612 ret = zclient_send_message(zclient);
613 /* TBD: handle the failure */
614 if (ret < 0)
615 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
fc9a856f 616
078430f6
DS
617 if ((command == ZEBRA_NEXTHOP_REGISTER) ||
618 (command == ZEBRA_IMPORT_ROUTE_REGISTER))
fc9a856f 619 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
078430f6
DS
620 else if ((command == ZEBRA_NEXTHOP_UNREGISTER) ||
621 (command == ZEBRA_IMPORT_ROUTE_UNREGISTER))
fc9a856f 622 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
fb018d25
DS
623 return;
624}
625
626/**
078430f6
DS
627 * register_zebra_rnh - register a NH/route with Zebra for notification
628 * when the route or the route to the nexthop changes.
fb018d25 629 * ARGUMENTS:
078430f6 630 * struct bgp_nexthop_cache *bnc
fb018d25
DS
631 * RETURNS:
632 * void.
633 */
634static void
078430f6 635register_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route)
fb018d25
DS
636{
637 /* Check if we have already registered */
638 if (bnc->flags & BGP_NEXTHOP_REGISTERED)
639 return;
078430f6
DS
640 if (is_bgp_import_route)
641 sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER);
642 else
643 sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER);
fb018d25
DS
644}
645
646/**
078430f6 647 * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra.
fb018d25 648 * ARGUMENTS:
078430f6 649 * struct bgp_nexthop_cache *bnc
fb018d25
DS
650 * RETURNS:
651 * void.
652 */
653static void
078430f6 654unregister_zebra_rnh (struct bgp_nexthop_cache *bnc, int is_bgp_import_route)
fb018d25
DS
655{
656 /* Check if we have already registered */
657 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
658 return;
659
078430f6
DS
660 if (is_bgp_import_route)
661 sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER);
662 else
663 sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER);
fb018d25
DS
664}
665
666/**
667 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
668 * ARGUMENTS:
669 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
670 * RETURNS:
671 * void.
672 */
673static void
674evaluate_paths (struct bgp_nexthop_cache *bnc)
675{
676 struct bgp_node *rn;
677 struct bgp_info *path;
75aead62 678 struct bgp *bgp = bnc->bgp;
fb018d25 679 int afi;
fc9a856f 680 struct peer *peer = (struct peer *)bnc->nht_info;
cd1964ff
DS
681 struct bgp_table *table;
682 safi_t safi;
fb018d25 683
80c2442a 684 if (BGP_DEBUG(nht, NHT))
685 {
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);
690 }
691
fb018d25
DS
692 LIST_FOREACH(path, &(bnc->paths), nh_thread)
693 {
694 if (!(path->type == ZEBRA_ROUTE_BGP &&
ffd0c037
DS
695 ((path->sub_type == BGP_ROUTE_NORMAL) ||
696 (path->sub_type == BGP_ROUTE_STATIC))))
fb018d25
DS
697 continue;
698
699 rn = path->net;
cd1964ff 700 assert (rn && bgp_node_table (rn));
fb018d25 701 afi = family2afi(rn->p.family);
cd1964ff
DS
702 table = bgp_node_table (rn);
703 safi = table->safi;
fb018d25
DS
704
705 /* Path becomes valid/invalid depending on whether the nexthop
706 * reachable/unreachable.
707 */
708 if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) !=
d4d9d757 709 (bgp_isvalid_nexthop(bnc) ? 1 : 0))
fb018d25
DS
710 {
711 if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
712 {
cd1964ff 713 bgp_aggregate_decrement (bgp, &rn->p, path, afi, safi);
fb018d25
DS
714 bgp_info_unset_flag (rn, path, BGP_INFO_VALID);
715 }
716 else
717 {
718 bgp_info_set_flag (rn, path, BGP_INFO_VALID);
cd1964ff 719 bgp_aggregate_increment (bgp, &rn->p, path, afi, safi);
fb018d25
DS
720 }
721 }
722
723 /* Copy the metric to the path. Will be used for bestpath computation */
d4d9d757 724 if (bgp_isvalid_nexthop(bnc) && bnc->metric)
fb018d25
DS
725 (bgp_info_extra_get(path))->igpmetric = bnc->metric;
726 else if (path->extra)
727 path->extra->igpmetric = 0;
728
c52d6050 729 if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED) ||
730 CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
fb018d25
DS
731 SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
732
cd1964ff 733 bgp_process(bgp, rn, afi, safi);
fb018d25 734 }
fc9a856f
DS
735
736 if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED))
737 {
738 if (BGP_DEBUG(nht, NHT))
739 zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host);
d4d9d757 740 bgp_fsm_nht_update(peer, bgp_isvalid_nexthop(bnc));
fc9a856f
DS
741 SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
742 }
743
fb018d25
DS
744 RESET_FLAG(bnc->change_flags);
745}
746
747/**
748 * path_nh_map - make or break path-to-nexthop association.
749 * ARGUMENTS:
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
753 * association.
754 */
755static void
756path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make)
757{
758 if (path->nexthop)
759 {
760 LIST_REMOVE(path, nh_thread);
761 path->nexthop->path_count--;
762 path->nexthop = NULL;
763 }
764 if (make)
765 {
766 LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
767 path->nexthop = bnc;
768 path->nexthop->path_count++;
769 }
770}