blob: 7808505e9023b5640df5310110fbe934d5206ce4 [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
Lou Bergerbb043512016-10-10 11:56:52 -0400197 return (bgp_zebra_num_connects() == 0 ||
198 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500199}
200
201void
202bgp_parse_nexthop_update (void)
203{
204 struct stream *s;
205 struct bgp_node *rn;
206 struct bgp_nexthop_cache *bnc;
207 struct nexthop *nexthop;
208 struct nexthop *oldnh;
209 struct nexthop *nhlist_head = NULL;
210 struct nexthop *nhlist_tail = NULL;
211 uint32_t metric;
212 u_char nexthop_num;
213 struct prefix p;
214 int i;
215
216 s = zclient->ibuf;
217
218 memset(&p, 0, sizeof(struct prefix));
219 p.family = stream_getw(s);
220 p.prefixlen = stream_getc(s);
221 switch (p.family)
222 {
223 case AF_INET:
224 p.u.prefix4.s_addr = stream_get_ipv4 (s);
225 break;
226 case AF_INET6:
227 stream_get(&p.u.prefix6, s, 16);
228 break;
229 default:
230 break;
231 }
232
233 rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
234 if (!rn || !rn->info)
235 {
236 if (BGP_DEBUG(nht, NHT))
237 {
238 char buf[INET6_ADDRSTRLEN];
239 prefix2str(&p, buf, INET6_ADDRSTRLEN);
240 zlog_debug("parse nexthop update(%s): rn not found", buf);
241 }
242 if (rn)
243 bgp_unlock_node (rn);
244 return;
245 }
246
247 bnc = rn->info;
248 bgp_unlock_node (rn);
249 bnc->last_update = bgp_clock();
250 bnc->change_flags = 0;
251 metric = stream_getl (s);
252 nexthop_num = stream_getc (s);
253
254 /* debug print the input */
255 if (BGP_DEBUG(nht, NHT))
256 {
257 char buf[INET6_ADDRSTRLEN];
258 prefix2str(&p, buf, INET6_ADDRSTRLEN);
259 zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf,
260 metric, nexthop_num);
261 }
262
263 if (metric != bnc->metric)
264 bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
265
266 if(nexthop_num != bnc->nexthop_num)
267 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
268
269 if (nexthop_num)
270 {
271 bnc->flags |= BGP_NEXTHOP_VALID;
272 bnc->metric = metric;
273 bnc->nexthop_num = nexthop_num;
274
275 for (i = 0; i < nexthop_num; i++)
276 {
277 nexthop = nexthop_new();
278 nexthop->type = stream_getc (s);
279 switch (nexthop->type)
280 {
281 case ZEBRA_NEXTHOP_IPV4:
282 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
283 break;
284 case ZEBRA_NEXTHOP_IFINDEX:
285 case ZEBRA_NEXTHOP_IFNAME:
286 nexthop->ifindex = stream_getl (s);
287 break;
288 case ZEBRA_NEXTHOP_IPV4_IFINDEX:
289 case ZEBRA_NEXTHOP_IPV4_IFNAME:
290 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
291 nexthop->ifindex = stream_getl (s);
292 break;
293#ifdef HAVE_IPV6
294 case ZEBRA_NEXTHOP_IPV6:
295 stream_get (&nexthop->gate.ipv6, s, 16);
296 break;
297 case ZEBRA_NEXTHOP_IPV6_IFINDEX:
298 case ZEBRA_NEXTHOP_IPV6_IFNAME:
299 stream_get (&nexthop->gate.ipv6, s, 16);
300 nexthop->ifindex = stream_getl (s);
301 break;
302#endif
303 default:
304 /* do nothing */
305 break;
306 }
307
308 if (nhlist_tail)
309 {
310 nhlist_tail->next = nexthop;
311 nhlist_tail = nexthop;
312 }
313 else
314 {
315 nhlist_tail = nexthop;
316 nhlist_head = nexthop;
317 }
318
319 /* No need to evaluate the nexthop if we have already determined
320 * that there has been a change.
321 */
322 if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
323 continue;
324
325 for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
326 if (nexthop_same_no_recurse(oldnh, nexthop))
327 break;
328
329 if (!oldnh)
330 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
331 }
332 bnc_nexthop_free(bnc);
333 bnc->nexthop = nhlist_head;
334 }
335 else
336 {
337 bnc->flags &= ~BGP_NEXTHOP_VALID;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700338 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500339 bnc_nexthop_free(bnc);
340 bnc->nexthop = NULL;
341 }
342
343 evaluate_paths(bnc);
344}
345
346/**
347 * make_prefix - make a prefix structure from the path (essentially
348 * path's node.
349 */
350static int
351make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
352{
353 memset (p, 0, sizeof (struct prefix));
354 switch (afi)
355 {
356 case AFI_IP:
357 p->family = AF_INET;
358 p->prefixlen = IPV4_MAX_BITLEN;
359 p->u.prefix4 = ri->attr->nexthop;
360 break;
361#ifdef HAVE_IPV6
362 case AFI_IP6:
363 if (ri->attr->extra->mp_nexthop_len != 16
364 || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global))
365 return -1;
366
367 p->family = AF_INET6;
368 p->prefixlen = IPV6_MAX_BITLEN;
369 p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
370 break;
371#endif
372 default:
373 break;
374 }
375 return 0;
376}
377
378/**
379 * sendmsg_nexthop -- Format and send a nexthop register/Unregister
380 * command to Zebra.
381 * ARGUMENTS:
382 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
383 * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER
384 * RETURNS:
385 * void.
386 */
387static void
388sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
389{
390 struct stream *s;
391 struct prefix *p;
392 int ret;
393
394 /* Check socket. */
395 if (!zclient || zclient->sock < 0)
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700396 {
397 zlog_debug("%s: Can't send NH register, Zebra client not established",
398 __FUNCTION__);
399 return;
400 }
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500401
402 p = &(bnc->node->p);
403 s = zclient->obuf;
404 stream_reset (s);
405 zclient_create_header (s, command, VRF_DEFAULT);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700406 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
407 stream_putc(s, 1);
408 else
409 stream_putc(s, 0);
410
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500411 stream_putw(s, PREFIX_FAMILY(p));
412 stream_putc(s, p->prefixlen);
413 switch (PREFIX_FAMILY(p))
414 {
415 case AF_INET:
416 stream_put_in_addr (s, &p->u.prefix4);
417 break;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500418 case AF_INET6:
419 stream_put(s, &(p->u.prefix6), 16);
420 break;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500421 default:
422 break;
423 }
424 stream_putw_at (s, 0, stream_get_endp (s));
425
426 ret = zclient_send_message(zclient);
427 /* TBD: handle the failure */
428 if (ret < 0)
429 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700430
431 if (command == ZEBRA_NEXTHOP_REGISTER)
432 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
433 else if (command == ZEBRA_NEXTHOP_UNREGISTER)
434 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500435 return;
436}
437
438/**
439 * register_nexthop - register a nexthop with Zebra for notification
440 * when the route to the nexthop changes.
441 * ARGUMENTS:
442 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
443 * RETURNS:
444 * void.
445 */
446static void
447register_nexthop (struct bgp_nexthop_cache *bnc)
448{
449 /* Check if we have already registered */
450 if (bnc->flags & BGP_NEXTHOP_REGISTERED)
451 return;
452 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500453}
454
455/**
456 * unregister_nexthop -- Unregister the nexthop from Zebra.
457 * ARGUMENTS:
458 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
459 * RETURNS:
460 * void.
461 */
462static void
463unregister_nexthop (struct bgp_nexthop_cache *bnc)
464{
465 /* Check if we have already registered */
466 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
467 return;
468
469 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500470}
471
472/**
473 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
474 * ARGUMENTS:
475 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
476 * RETURNS:
477 * void.
478 */
479static void
480evaluate_paths (struct bgp_nexthop_cache *bnc)
481{
482 struct bgp_node *rn;
483 struct bgp_info *path;
484 struct bgp *bgp = bgp_get_default();
485 int afi;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700486 struct peer *peer = (struct peer *)bnc->nht_info;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500487
488 LIST_FOREACH(path, &(bnc->paths), nh_thread)
489 {
490 if (!(path->type == ZEBRA_ROUTE_BGP &&
491 path->sub_type == BGP_ROUTE_NORMAL))
492 continue;
493
494 rn = path->net;
495 afi = family2afi(rn->p.family);
496
497 /* Path becomes valid/invalid depending on whether the nexthop
498 * reachable/unreachable.
499 */
500 if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) !=
501 (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0))
502 {
503 if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
504 {
505 bgp_aggregate_decrement (bgp, &rn->p, path,
506 afi, SAFI_UNICAST);
507 bgp_info_unset_flag (rn, path, BGP_INFO_VALID);
508 }
509 else
510 {
511 bgp_info_set_flag (rn, path, BGP_INFO_VALID);
512 bgp_aggregate_increment (bgp, &rn->p, path,
513 afi, SAFI_UNICAST);
514 }
515 }
516
517 /* Copy the metric to the path. Will be used for bestpath computation */
518 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
519 (bgp_info_extra_get(path))->igpmetric = bnc->metric;
520 else if (path->extra)
521 path->extra->igpmetric = 0;
522
523 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) ||
524 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED))
525 SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
526
527 bgp_process(bgp, rn, afi, SAFI_UNICAST);
528 }
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700529
530 if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED))
531 {
532 if (BGP_DEBUG(nht, NHT))
533 zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host);
Paul Jakma743dd422016-09-30 13:55:47 +0100534 BGP_EVENT_ADD (peer, NHT_Update);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700535 SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
536 }
537
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500538 RESET_FLAG(bnc->change_flags);
539}
540
541/**
542 * path_nh_map - make or break path-to-nexthop association.
543 * ARGUMENTS:
544 * path - pointer to the path structure
545 * bnc - pointer to the nexthop structure
546 * make - if set, make the association. if unset, just break the existing
547 * association.
548 */
549static void
550path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make)
551{
552 if (path->nexthop)
553 {
554 LIST_REMOVE(path, nh_thread);
555 path->nexthop->path_count--;
556 path->nexthop = NULL;
557 }
558 if (make)
559 {
560 LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
561 path->nexthop = bnc;
562 path->nexthop->path_count++;
563 }
564}