blob: 0cfcaddc89a0b524a0f2555d12b419a18199973f [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"
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050043
44extern struct zclient *zclient;
45extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
46
47static void register_nexthop(struct bgp_nexthop_cache *bnc);
48static void unregister_nexthop (struct bgp_nexthop_cache *bnc);
49static void evaluate_paths(struct bgp_nexthop_cache *bnc);
50static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p);
51static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc,
52 int keep);
53
54int
Dinesh Duttd9ab53a2015-05-19 17:47:21 -070055bgp_find_nexthop (struct bgp_info *path, int connected)
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050056{
57 struct bgp_nexthop_cache *bnc = path->nexthop;
58
59 if (!bnc)
60 return 0;
61
Dinesh Duttd9ab53a2015-05-19 17:47:21 -070062 if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)))
63 return 0;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050064
Lou Berger68bfb612016-10-06 09:59:32 -040065 return (bgp_zebra_num_connects() == 0 ||
66 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050067}
68
Paul Jakma19e6c192016-09-06 17:23:48 +010069static void
70bgp_unlink_nexthop_check (struct bgp_nexthop_cache *bnc)
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050071{
Dinesh Duttd9ab53a2015-05-19 17:47:21 -070072 if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info)
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050073 {
74 if (BGP_DEBUG(nht, NHT))
75 {
76 char buf[INET6_ADDRSTRLEN];
77 zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
78 bnc_str(bnc, buf, INET6_ADDRSTRLEN));
79 }
80 unregister_nexthop(bnc);
81 bnc->node->info = NULL;
82 bgp_unlock_node(bnc->node);
Paul Jakma19e6c192016-09-06 17:23:48 +010083 bnc->node = NULL;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050084 bnc_free(bnc);
85 }
86}
87
Paul Jakma19e6c192016-09-06 17:23:48 +010088void
89bgp_unlink_nexthop (struct bgp_info *path)
90{
91 struct bgp_nexthop_cache *bnc = path->nexthop;
92
93 if (!bnc)
94 return;
95
96 path_nh_map(path, NULL, 0);
97
98 bgp_unlink_nexthop_check (bnc);
99}
100
101void
102bgp_unlink_nexthop_by_peer (struct peer *peer)
103{
104 struct prefix p;
105 struct bgp_node *rn;
106 struct bgp_nexthop_cache *bnc;
107 afi_t afi = family2afi(peer->su.sa.sa_family);
108
109 if (afi == AFI_IP)
110 {
111 p.family = AF_INET;
112 p.prefixlen = IPV4_MAX_BITLEN;
113 p.u.prefix4 = peer->su.sin.sin_addr;
114 }
115 else if (afi == AFI_IP6)
116 {
117 p.family = AF_INET6;
118 p.prefixlen = IPV6_MAX_BITLEN;
119 p.u.prefix6 = peer->su.sin6.sin6_addr;
120 }
121 else
122 return;
123
124 rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
125
126 if (!rn->info)
127 return;
128
129 bnc = rn->info;
130
131 /* cleanup the peer reference */
132 bnc->nht_info = NULL;
133
134 bgp_unlink_nexthop_check (bnc);
135}
136
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500137int
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700138bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer,
139 int connected)
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500140{
141 struct bgp_node *rn;
142 struct bgp_nexthop_cache *bnc;
143 struct prefix p;
144
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700145 if (ri)
146 {
147 if (make_prefix(afi, ri, &p) < 0)
148 return 1;
149 }
150 else if (peer)
151 {
152 if (afi == AFI_IP)
153 {
154 p.family = AF_INET;
155 p.prefixlen = IPV4_MAX_BITLEN;
156 p.u.prefix4 = peer->su.sin.sin_addr;
157 }
158 else if (afi == AFI_IP6)
159 {
160 p.family = AF_INET6;
161 p.prefixlen = IPV6_MAX_BITLEN;
162 p.u.prefix6 = peer->su.sin6.sin6_addr;
163 }
164 }
165
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500166 rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
167
168 if (!rn->info)
169 {
170 bnc = bnc_new();
171 rn->info = bnc;
172 bnc->node = rn;
173 bgp_lock_node(rn);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700174 if (connected)
175 SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500176 }
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700177
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500178 bnc = rn->info;
179 bgp_unlock_node (rn);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500180
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700181 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
182 register_nexthop(bnc);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500183
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700184 if (ri)
185 {
Paul Jakma19e6c192016-09-06 17:23:48 +0100186 path_nh_map(ri, bnc, 1); /* updates NHT ri list reference */
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500187
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700188 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
189 (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
190 else if (ri->extra)
191 ri->extra->igpmetric = 0;
192 }
193 else if (peer)
Paul Jakma19e6c192016-09-06 17:23:48 +0100194 bnc->nht_info = (void *)peer; /* NHT peer reference */
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500195
196 return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
197}
198
199void
200bgp_parse_nexthop_update (void)
201{
202 struct stream *s;
203 struct bgp_node *rn;
204 struct bgp_nexthop_cache *bnc;
205 struct nexthop *nexthop;
206 struct nexthop *oldnh;
207 struct nexthop *nhlist_head = NULL;
208 struct nexthop *nhlist_tail = NULL;
209 uint32_t metric;
210 u_char nexthop_num;
211 struct prefix p;
212 int i;
213
214 s = zclient->ibuf;
215
216 memset(&p, 0, sizeof(struct prefix));
217 p.family = stream_getw(s);
218 p.prefixlen = stream_getc(s);
219 switch (p.family)
220 {
221 case AF_INET:
222 p.u.prefix4.s_addr = stream_get_ipv4 (s);
223 break;
224 case AF_INET6:
225 stream_get(&p.u.prefix6, s, 16);
226 break;
227 default:
228 break;
229 }
230
231 rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
232 if (!rn || !rn->info)
233 {
234 if (BGP_DEBUG(nht, NHT))
235 {
236 char buf[INET6_ADDRSTRLEN];
237 prefix2str(&p, buf, INET6_ADDRSTRLEN);
238 zlog_debug("parse nexthop update(%s): rn not found", buf);
239 }
240 if (rn)
241 bgp_unlock_node (rn);
242 return;
243 }
244
245 bnc = rn->info;
246 bgp_unlock_node (rn);
247 bnc->last_update = bgp_clock();
248 bnc->change_flags = 0;
249 metric = stream_getl (s);
250 nexthop_num = stream_getc (s);
251
252 /* debug print the input */
253 if (BGP_DEBUG(nht, NHT))
254 {
255 char buf[INET6_ADDRSTRLEN];
256 prefix2str(&p, buf, INET6_ADDRSTRLEN);
257 zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf,
258 metric, nexthop_num);
259 }
260
261 if (metric != bnc->metric)
262 bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
263
264 if(nexthop_num != bnc->nexthop_num)
265 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
266
267 if (nexthop_num)
268 {
269 bnc->flags |= BGP_NEXTHOP_VALID;
270 bnc->metric = metric;
271 bnc->nexthop_num = nexthop_num;
272
273 for (i = 0; i < nexthop_num; i++)
274 {
275 nexthop = nexthop_new();
276 nexthop->type = stream_getc (s);
277 switch (nexthop->type)
278 {
279 case ZEBRA_NEXTHOP_IPV4:
280 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
281 break;
282 case ZEBRA_NEXTHOP_IFINDEX:
283 case ZEBRA_NEXTHOP_IFNAME:
284 nexthop->ifindex = stream_getl (s);
285 break;
286 case ZEBRA_NEXTHOP_IPV4_IFINDEX:
287 case ZEBRA_NEXTHOP_IPV4_IFNAME:
288 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
289 nexthop->ifindex = stream_getl (s);
290 break;
291#ifdef HAVE_IPV6
292 case ZEBRA_NEXTHOP_IPV6:
293 stream_get (&nexthop->gate.ipv6, s, 16);
294 break;
295 case ZEBRA_NEXTHOP_IPV6_IFINDEX:
296 case ZEBRA_NEXTHOP_IPV6_IFNAME:
297 stream_get (&nexthop->gate.ipv6, s, 16);
298 nexthop->ifindex = stream_getl (s);
299 break;
300#endif
301 default:
302 /* do nothing */
303 break;
304 }
305
306 if (nhlist_tail)
307 {
308 nhlist_tail->next = nexthop;
309 nhlist_tail = nexthop;
310 }
311 else
312 {
313 nhlist_tail = nexthop;
314 nhlist_head = nexthop;
315 }
316
317 /* No need to evaluate the nexthop if we have already determined
318 * that there has been a change.
319 */
320 if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
321 continue;
322
323 for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
324 if (nexthop_same_no_recurse(oldnh, nexthop))
325 break;
326
327 if (!oldnh)
328 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
329 }
330 bnc_nexthop_free(bnc);
331 bnc->nexthop = nhlist_head;
332 }
333 else
334 {
335 bnc->flags &= ~BGP_NEXTHOP_VALID;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700336 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500337 bnc_nexthop_free(bnc);
338 bnc->nexthop = NULL;
339 }
340
341 evaluate_paths(bnc);
342}
343
344/**
345 * make_prefix - make a prefix structure from the path (essentially
346 * path's node.
347 */
348static int
349make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
350{
351 memset (p, 0, sizeof (struct prefix));
352 switch (afi)
353 {
354 case AFI_IP:
355 p->family = AF_INET;
356 p->prefixlen = IPV4_MAX_BITLEN;
357 p->u.prefix4 = ri->attr->nexthop;
358 break;
359#ifdef HAVE_IPV6
360 case AFI_IP6:
361 if (ri->attr->extra->mp_nexthop_len != 16
362 || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global))
363 return -1;
364
365 p->family = AF_INET6;
366 p->prefixlen = IPV6_MAX_BITLEN;
367 p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
368 break;
369#endif
370 default:
371 break;
372 }
373 return 0;
374}
375
376/**
377 * sendmsg_nexthop -- Format and send a nexthop register/Unregister
378 * command to Zebra.
379 * ARGUMENTS:
380 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
381 * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER
382 * RETURNS:
383 * void.
384 */
385static void
386sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
387{
388 struct stream *s;
389 struct prefix *p;
390 int ret;
391
392 /* Check socket. */
393 if (!zclient || zclient->sock < 0)
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700394 {
395 zlog_debug("%s: Can't send NH register, Zebra client not established",
396 __FUNCTION__);
397 return;
398 }
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500399
400 p = &(bnc->node->p);
401 s = zclient->obuf;
402 stream_reset (s);
403 zclient_create_header (s, command, VRF_DEFAULT);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700404 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
405 stream_putc(s, 1);
406 else
407 stream_putc(s, 0);
408
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500409 stream_putw(s, PREFIX_FAMILY(p));
410 stream_putc(s, p->prefixlen);
411 switch (PREFIX_FAMILY(p))
412 {
413 case AF_INET:
414 stream_put_in_addr (s, &p->u.prefix4);
415 break;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500416 case AF_INET6:
417 stream_put(s, &(p->u.prefix6), 16);
418 break;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500419 default:
420 break;
421 }
422 stream_putw_at (s, 0, stream_get_endp (s));
423
424 ret = zclient_send_message(zclient);
425 /* TBD: handle the failure */
426 if (ret < 0)
427 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700428
429 if (command == ZEBRA_NEXTHOP_REGISTER)
430 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
431 else if (command == ZEBRA_NEXTHOP_UNREGISTER)
432 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500433 return;
434}
435
436/**
437 * register_nexthop - register a nexthop with Zebra for notification
438 * when the route to the nexthop changes.
439 * ARGUMENTS:
440 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
441 * RETURNS:
442 * void.
443 */
444static void
445register_nexthop (struct bgp_nexthop_cache *bnc)
446{
447 /* Check if we have already registered */
448 if (bnc->flags & BGP_NEXTHOP_REGISTERED)
449 return;
450 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500451}
452
453/**
454 * unregister_nexthop -- Unregister the nexthop from Zebra.
455 * ARGUMENTS:
456 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
457 * RETURNS:
458 * void.
459 */
460static void
461unregister_nexthop (struct bgp_nexthop_cache *bnc)
462{
463 /* Check if we have already registered */
464 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
465 return;
466
467 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500468}
469
470/**
471 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
472 * ARGUMENTS:
473 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
474 * RETURNS:
475 * void.
476 */
477static void
478evaluate_paths (struct bgp_nexthop_cache *bnc)
479{
480 struct bgp_node *rn;
481 struct bgp_info *path;
482 struct bgp *bgp = bgp_get_default();
483 int afi;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700484 struct peer *peer = (struct peer *)bnc->nht_info;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500485
486 LIST_FOREACH(path, &(bnc->paths), nh_thread)
487 {
488 if (!(path->type == ZEBRA_ROUTE_BGP &&
489 path->sub_type == BGP_ROUTE_NORMAL))
490 continue;
491
492 rn = path->net;
493 afi = family2afi(rn->p.family);
494
495 /* Path becomes valid/invalid depending on whether the nexthop
496 * reachable/unreachable.
497 */
498 if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) !=
499 (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0))
500 {
501 if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
502 {
503 bgp_aggregate_decrement (bgp, &rn->p, path,
504 afi, SAFI_UNICAST);
505 bgp_info_unset_flag (rn, path, BGP_INFO_VALID);
506 }
507 else
508 {
509 bgp_info_set_flag (rn, path, BGP_INFO_VALID);
510 bgp_aggregate_increment (bgp, &rn->p, path,
511 afi, SAFI_UNICAST);
512 }
513 }
514
515 /* Copy the metric to the path. Will be used for bestpath computation */
516 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
517 (bgp_info_extra_get(path))->igpmetric = bnc->metric;
518 else if (path->extra)
519 path->extra->igpmetric = 0;
520
521 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) ||
522 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED))
523 SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
524
525 bgp_process(bgp, rn, afi, SAFI_UNICAST);
526 }
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700527
528 if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED))
529 {
530 if (BGP_DEBUG(nht, NHT))
531 zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host);
Paul Jakma743dd422016-09-30 13:55:47 +0100532 BGP_EVENT_ADD (peer, NHT_Update);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700533 SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
534 }
535
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500536 RESET_FLAG(bnc->change_flags);
537}
538
539/**
540 * path_nh_map - make or break path-to-nexthop association.
541 * ARGUMENTS:
542 * path - pointer to the path structure
543 * bnc - pointer to the nexthop structure
544 * make - if set, make the association. if unset, just break the existing
545 * association.
546 */
547static void
548path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make)
549{
550 if (path->nexthop)
551 {
552 LIST_REMOVE(path, nh_thread);
553 path->nexthop->path_count--;
554 path->nexthop = NULL;
555 }
556 if (make)
557 {
558 LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
559 path->nexthop = bnc;
560 path->nexthop->path_count++;
561 }
562}