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