blob: 34b5fd1c191505b165473647f5f340f22c6b33c7 [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
68void
69bgp_unlink_nexthop (struct bgp_info *path)
70{
71 struct bgp_nexthop_cache *bnc = path->nexthop;
72
73 if (!bnc)
74 return;
75
76 path_nh_map(path, NULL, 0);
77
Dinesh Duttd9ab53a2015-05-19 17:47:21 -070078 if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info)
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050079 {
80 if (BGP_DEBUG(nht, NHT))
81 {
82 char buf[INET6_ADDRSTRLEN];
83 zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
84 bnc_str(bnc, buf, INET6_ADDRSTRLEN));
85 }
86 unregister_nexthop(bnc);
87 bnc->node->info = NULL;
88 bgp_unlock_node(bnc->node);
89 bnc_free(bnc);
90 }
91}
92
93int
Dinesh Duttd9ab53a2015-05-19 17:47:21 -070094bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, struct peer *peer,
95 int connected)
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -050096{
97 struct bgp_node *rn;
98 struct bgp_nexthop_cache *bnc;
99 struct prefix p;
100
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700101 if (ri)
102 {
103 if (make_prefix(afi, ri, &p) < 0)
104 return 1;
105 }
106 else if (peer)
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 }
121
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500122 rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
123
124 if (!rn->info)
125 {
126 bnc = bnc_new();
127 rn->info = bnc;
128 bnc->node = rn;
129 bgp_lock_node(rn);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700130 if (connected)
131 SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500132 }
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700133
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500134 bnc = rn->info;
135 bgp_unlock_node (rn);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500136
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700137 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
138 register_nexthop(bnc);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500139
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700140 if (ri)
141 {
142 path_nh_map(ri, bnc, 1);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500143
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700144 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
145 (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
146 else if (ri->extra)
147 ri->extra->igpmetric = 0;
148 }
149 else if (peer)
150 bnc->nht_info = (void *)peer;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500151
152 return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
153}
154
155void
156bgp_parse_nexthop_update (void)
157{
158 struct stream *s;
159 struct bgp_node *rn;
160 struct bgp_nexthop_cache *bnc;
161 struct nexthop *nexthop;
162 struct nexthop *oldnh;
163 struct nexthop *nhlist_head = NULL;
164 struct nexthop *nhlist_tail = NULL;
165 uint32_t metric;
166 u_char nexthop_num;
167 struct prefix p;
168 int i;
169
170 s = zclient->ibuf;
171
172 memset(&p, 0, sizeof(struct prefix));
173 p.family = stream_getw(s);
174 p.prefixlen = stream_getc(s);
175 switch (p.family)
176 {
177 case AF_INET:
178 p.u.prefix4.s_addr = stream_get_ipv4 (s);
179 break;
180 case AF_INET6:
181 stream_get(&p.u.prefix6, s, 16);
182 break;
183 default:
184 break;
185 }
186
187 rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
188 if (!rn || !rn->info)
189 {
190 if (BGP_DEBUG(nht, NHT))
191 {
192 char buf[INET6_ADDRSTRLEN];
193 prefix2str(&p, buf, INET6_ADDRSTRLEN);
194 zlog_debug("parse nexthop update(%s): rn not found", buf);
195 }
196 if (rn)
197 bgp_unlock_node (rn);
198 return;
199 }
200
201 bnc = rn->info;
202 bgp_unlock_node (rn);
203 bnc->last_update = bgp_clock();
204 bnc->change_flags = 0;
205 metric = stream_getl (s);
206 nexthop_num = stream_getc (s);
207
208 /* debug print the input */
209 if (BGP_DEBUG(nht, NHT))
210 {
211 char buf[INET6_ADDRSTRLEN];
212 prefix2str(&p, buf, INET6_ADDRSTRLEN);
213 zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf,
214 metric, nexthop_num);
215 }
216
217 if (metric != bnc->metric)
218 bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
219
220 if(nexthop_num != bnc->nexthop_num)
221 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
222
223 if (nexthop_num)
224 {
225 bnc->flags |= BGP_NEXTHOP_VALID;
226 bnc->metric = metric;
227 bnc->nexthop_num = nexthop_num;
228
229 for (i = 0; i < nexthop_num; i++)
230 {
231 nexthop = nexthop_new();
232 nexthop->type = stream_getc (s);
233 switch (nexthop->type)
234 {
235 case ZEBRA_NEXTHOP_IPV4:
236 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
237 break;
238 case ZEBRA_NEXTHOP_IFINDEX:
239 case ZEBRA_NEXTHOP_IFNAME:
240 nexthop->ifindex = stream_getl (s);
241 break;
242 case ZEBRA_NEXTHOP_IPV4_IFINDEX:
243 case ZEBRA_NEXTHOP_IPV4_IFNAME:
244 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
245 nexthop->ifindex = stream_getl (s);
246 break;
247#ifdef HAVE_IPV6
248 case ZEBRA_NEXTHOP_IPV6:
249 stream_get (&nexthop->gate.ipv6, s, 16);
250 break;
251 case ZEBRA_NEXTHOP_IPV6_IFINDEX:
252 case ZEBRA_NEXTHOP_IPV6_IFNAME:
253 stream_get (&nexthop->gate.ipv6, s, 16);
254 nexthop->ifindex = stream_getl (s);
255 break;
256#endif
257 default:
258 /* do nothing */
259 break;
260 }
261
262 if (nhlist_tail)
263 {
264 nhlist_tail->next = nexthop;
265 nhlist_tail = nexthop;
266 }
267 else
268 {
269 nhlist_tail = nexthop;
270 nhlist_head = nexthop;
271 }
272
273 /* No need to evaluate the nexthop if we have already determined
274 * that there has been a change.
275 */
276 if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
277 continue;
278
279 for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
280 if (nexthop_same_no_recurse(oldnh, nexthop))
281 break;
282
283 if (!oldnh)
284 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
285 }
286 bnc_nexthop_free(bnc);
287 bnc->nexthop = nhlist_head;
288 }
289 else
290 {
291 bnc->flags &= ~BGP_NEXTHOP_VALID;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700292 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500293 bnc_nexthop_free(bnc);
294 bnc->nexthop = NULL;
295 }
296
297 evaluate_paths(bnc);
298}
299
300/**
301 * make_prefix - make a prefix structure from the path (essentially
302 * path's node.
303 */
304static int
305make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
306{
307 memset (p, 0, sizeof (struct prefix));
308 switch (afi)
309 {
310 case AFI_IP:
311 p->family = AF_INET;
312 p->prefixlen = IPV4_MAX_BITLEN;
313 p->u.prefix4 = ri->attr->nexthop;
314 break;
315#ifdef HAVE_IPV6
316 case AFI_IP6:
317 if (ri->attr->extra->mp_nexthop_len != 16
318 || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global))
319 return -1;
320
321 p->family = AF_INET6;
322 p->prefixlen = IPV6_MAX_BITLEN;
323 p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
324 break;
325#endif
326 default:
327 break;
328 }
329 return 0;
330}
331
332/**
333 * sendmsg_nexthop -- Format and send a nexthop register/Unregister
334 * command to Zebra.
335 * ARGUMENTS:
336 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
337 * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER
338 * RETURNS:
339 * void.
340 */
341static void
342sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
343{
344 struct stream *s;
345 struct prefix *p;
346 int ret;
347
348 /* Check socket. */
349 if (!zclient || zclient->sock < 0)
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700350 {
351 zlog_debug("%s: Can't send NH register, Zebra client not established",
352 __FUNCTION__);
353 return;
354 }
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500355
356 p = &(bnc->node->p);
357 s = zclient->obuf;
358 stream_reset (s);
359 zclient_create_header (s, command, VRF_DEFAULT);
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700360 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
361 stream_putc(s, 1);
362 else
363 stream_putc(s, 0);
364
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500365 stream_putw(s, PREFIX_FAMILY(p));
366 stream_putc(s, p->prefixlen);
367 switch (PREFIX_FAMILY(p))
368 {
369 case AF_INET:
370 stream_put_in_addr (s, &p->u.prefix4);
371 break;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500372 case AF_INET6:
373 stream_put(s, &(p->u.prefix6), 16);
374 break;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500375 default:
376 break;
377 }
378 stream_putw_at (s, 0, stream_get_endp (s));
379
380 ret = zclient_send_message(zclient);
381 /* TBD: handle the failure */
382 if (ret < 0)
383 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700384
385 if (command == ZEBRA_NEXTHOP_REGISTER)
386 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
387 else if (command == ZEBRA_NEXTHOP_UNREGISTER)
388 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500389 return;
390}
391
392/**
393 * register_nexthop - register a nexthop with Zebra for notification
394 * when the route to the nexthop changes.
395 * ARGUMENTS:
396 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
397 * RETURNS:
398 * void.
399 */
400static void
401register_nexthop (struct bgp_nexthop_cache *bnc)
402{
403 /* Check if we have already registered */
404 if (bnc->flags & BGP_NEXTHOP_REGISTERED)
405 return;
406 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500407}
408
409/**
410 * unregister_nexthop -- Unregister the nexthop from Zebra.
411 * ARGUMENTS:
412 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
413 * RETURNS:
414 * void.
415 */
416static void
417unregister_nexthop (struct bgp_nexthop_cache *bnc)
418{
419 /* Check if we have already registered */
420 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
421 return;
422
423 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500424}
425
426/**
427 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
428 * ARGUMENTS:
429 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
430 * RETURNS:
431 * void.
432 */
433static void
434evaluate_paths (struct bgp_nexthop_cache *bnc)
435{
436 struct bgp_node *rn;
437 struct bgp_info *path;
438 struct bgp *bgp = bgp_get_default();
439 int afi;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700440 struct peer *peer = (struct peer *)bnc->nht_info;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500441
442 LIST_FOREACH(path, &(bnc->paths), nh_thread)
443 {
444 if (!(path->type == ZEBRA_ROUTE_BGP &&
445 path->sub_type == BGP_ROUTE_NORMAL))
446 continue;
447
448 rn = path->net;
449 afi = family2afi(rn->p.family);
450
451 /* Path becomes valid/invalid depending on whether the nexthop
452 * reachable/unreachable.
453 */
454 if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) !=
455 (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0))
456 {
457 if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
458 {
459 bgp_aggregate_decrement (bgp, &rn->p, path,
460 afi, SAFI_UNICAST);
461 bgp_info_unset_flag (rn, path, BGP_INFO_VALID);
462 }
463 else
464 {
465 bgp_info_set_flag (rn, path, BGP_INFO_VALID);
466 bgp_aggregate_increment (bgp, &rn->p, path,
467 afi, SAFI_UNICAST);
468 }
469 }
470
471 /* Copy the metric to the path. Will be used for bestpath computation */
472 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
473 (bgp_info_extra_get(path))->igpmetric = bnc->metric;
474 else if (path->extra)
475 path->extra->igpmetric = 0;
476
477 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) ||
478 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED))
479 SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
480
481 bgp_process(bgp, rn, afi, SAFI_UNICAST);
482 }
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700483
484 if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED))
485 {
486 if (BGP_DEBUG(nht, NHT))
487 zlog_debug("%s: Updating peer (%s) status with NHT", __FUNCTION__, peer->host);
488 bgp_fsm_nht_update(peer, CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
489 SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
490 }
491
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500492 RESET_FLAG(bnc->change_flags);
493}
494
495/**
496 * path_nh_map - make or break path-to-nexthop association.
497 * ARGUMENTS:
498 * path - pointer to the path structure
499 * bnc - pointer to the nexthop structure
500 * make - if set, make the association. if unset, just break the existing
501 * association.
502 */
503static void
504path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make)
505{
506 if (path->nexthop)
507 {
508 LIST_REMOVE(path, nh_thread);
509 path->nexthop->path_count--;
510 path->nexthop = NULL;
511 }
512 if (make)
513 {
514 LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
515 path->nexthop = bnc;
516 path->nexthop->path_count++;
517 }
518}