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