blob: 21e1411b8928bc96ac655d51969a6ec787820d4d [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"
42
43extern struct zclient *zclient;
44extern struct bgp_table *bgp_nexthop_cache_table[AFI_MAX];
45
46static void register_nexthop(struct bgp_nexthop_cache *bnc);
47static void unregister_nexthop (struct bgp_nexthop_cache *bnc);
48static void evaluate_paths(struct bgp_nexthop_cache *bnc);
49static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p);
50static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc,
51 int keep);
52
53int
54bgp_find_nexthop (struct bgp_info *path, int *changed, int *metricchanged)
55{
56 struct bgp_nexthop_cache *bnc = path->nexthop;
57
58 if (!bnc)
59 return 0;
60
61 if (changed)
62 *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
63
64 if (metricchanged)
65 *metricchanged = CHECK_FLAG(bnc->change_flags,
66 BGP_NEXTHOP_METRIC_CHANGED);
67
68 return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
69}
70
71void
72bgp_unlink_nexthop (struct bgp_info *path)
73{
74 struct bgp_nexthop_cache *bnc = path->nexthop;
75
76 if (!bnc)
77 return;
78
79 path_nh_map(path, NULL, 0);
80
81 if (LIST_EMPTY(&(bnc->paths)))
82 {
83 if (BGP_DEBUG(nht, NHT))
84 {
85 char buf[INET6_ADDRSTRLEN];
86 zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
87 bnc_str(bnc, buf, INET6_ADDRSTRLEN));
88 }
89 unregister_nexthop(bnc);
90 bnc->node->info = NULL;
91 bgp_unlock_node(bnc->node);
92 bnc_free(bnc);
93 }
94}
95
96int
97bgp_find_or_add_nexthop (afi_t afi, struct bgp_info *ri, int *changed,
98 int *metricchanged)
99{
100 struct bgp_node *rn;
101 struct bgp_nexthop_cache *bnc;
102 struct prefix p;
103
104 if (make_prefix(afi, ri, &p) < 0)
105 return 1;
106 rn = bgp_node_get (bgp_nexthop_cache_table[afi], &p);
107
108 if (!rn->info)
109 {
110 bnc = bnc_new();
111 rn->info = bnc;
112 bnc->node = rn;
113 bgp_lock_node(rn);
114 register_nexthop(bnc);
115 }
116 bnc = rn->info;
117 bgp_unlock_node (rn);
118 path_nh_map(ri, bnc, 1);
119
120 if (changed)
121 *changed = CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
122
123 if (metricchanged)
124 *metricchanged = CHECK_FLAG(bnc->change_flags,
125 BGP_NEXTHOP_METRIC_CHANGED);
126
127 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
128 (bgp_info_extra_get(ri))->igpmetric = bnc->metric;
129 else if (ri->extra)
130 ri->extra->igpmetric = 0;
131
132 return (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID));
133}
134
135void
136bgp_parse_nexthop_update (void)
137{
138 struct stream *s;
139 struct bgp_node *rn;
140 struct bgp_nexthop_cache *bnc;
141 struct nexthop *nexthop;
142 struct nexthop *oldnh;
143 struct nexthop *nhlist_head = NULL;
144 struct nexthop *nhlist_tail = NULL;
145 uint32_t metric;
146 u_char nexthop_num;
147 struct prefix p;
148 int i;
149
150 s = zclient->ibuf;
151
152 memset(&p, 0, sizeof(struct prefix));
153 p.family = stream_getw(s);
154 p.prefixlen = stream_getc(s);
155 switch (p.family)
156 {
157 case AF_INET:
158 p.u.prefix4.s_addr = stream_get_ipv4 (s);
159 break;
160 case AF_INET6:
161 stream_get(&p.u.prefix6, s, 16);
162 break;
163 default:
164 break;
165 }
166
167 rn = bgp_node_lookup(bgp_nexthop_cache_table[family2afi(p.family)], &p);
168 if (!rn || !rn->info)
169 {
170 if (BGP_DEBUG(nht, NHT))
171 {
172 char buf[INET6_ADDRSTRLEN];
173 prefix2str(&p, buf, INET6_ADDRSTRLEN);
174 zlog_debug("parse nexthop update(%s): rn not found", buf);
175 }
176 if (rn)
177 bgp_unlock_node (rn);
178 return;
179 }
180
181 bnc = rn->info;
182 bgp_unlock_node (rn);
183 bnc->last_update = bgp_clock();
184 bnc->change_flags = 0;
185 metric = stream_getl (s);
186 nexthop_num = stream_getc (s);
187
188 /* debug print the input */
189 if (BGP_DEBUG(nht, NHT))
190 {
191 char buf[INET6_ADDRSTRLEN];
192 prefix2str(&p, buf, INET6_ADDRSTRLEN);
193 zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf,
194 metric, nexthop_num);
195 }
196
197 if (metric != bnc->metric)
198 bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED;
199
200 if(nexthop_num != bnc->nexthop_num)
201 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
202
203 if (nexthop_num)
204 {
205 bnc->flags |= BGP_NEXTHOP_VALID;
206 bnc->metric = metric;
207 bnc->nexthop_num = nexthop_num;
208
209 for (i = 0; i < nexthop_num; i++)
210 {
211 nexthop = nexthop_new();
212 nexthop->type = stream_getc (s);
213 switch (nexthop->type)
214 {
215 case ZEBRA_NEXTHOP_IPV4:
216 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
217 break;
218 case ZEBRA_NEXTHOP_IFINDEX:
219 case ZEBRA_NEXTHOP_IFNAME:
220 nexthop->ifindex = stream_getl (s);
221 break;
222 case ZEBRA_NEXTHOP_IPV4_IFINDEX:
223 case ZEBRA_NEXTHOP_IPV4_IFNAME:
224 nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s);
225 nexthop->ifindex = stream_getl (s);
226 break;
227#ifdef HAVE_IPV6
228 case ZEBRA_NEXTHOP_IPV6:
229 stream_get (&nexthop->gate.ipv6, s, 16);
230 break;
231 case ZEBRA_NEXTHOP_IPV6_IFINDEX:
232 case ZEBRA_NEXTHOP_IPV6_IFNAME:
233 stream_get (&nexthop->gate.ipv6, s, 16);
234 nexthop->ifindex = stream_getl (s);
235 break;
236#endif
237 default:
238 /* do nothing */
239 break;
240 }
241
242 if (nhlist_tail)
243 {
244 nhlist_tail->next = nexthop;
245 nhlist_tail = nexthop;
246 }
247 else
248 {
249 nhlist_tail = nexthop;
250 nhlist_head = nexthop;
251 }
252
253 /* No need to evaluate the nexthop if we have already determined
254 * that there has been a change.
255 */
256 if (bnc->change_flags & BGP_NEXTHOP_CHANGED)
257 continue;
258
259 for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next)
260 if (nexthop_same_no_recurse(oldnh, nexthop))
261 break;
262
263 if (!oldnh)
264 bnc->change_flags |= BGP_NEXTHOP_CHANGED;
265 }
266 bnc_nexthop_free(bnc);
267 bnc->nexthop = nhlist_head;
268 }
269 else
270 {
271 bnc->flags &= ~BGP_NEXTHOP_VALID;
272 bnc_nexthop_free(bnc);
273 bnc->nexthop = NULL;
274 }
275
276 evaluate_paths(bnc);
277}
278
279/**
280 * make_prefix - make a prefix structure from the path (essentially
281 * path's node.
282 */
283static int
284make_prefix (int afi, struct bgp_info *ri, struct prefix *p)
285{
286 memset (p, 0, sizeof (struct prefix));
287 switch (afi)
288 {
289 case AFI_IP:
290 p->family = AF_INET;
291 p->prefixlen = IPV4_MAX_BITLEN;
292 p->u.prefix4 = ri->attr->nexthop;
293 break;
294#ifdef HAVE_IPV6
295 case AFI_IP6:
296 if (ri->attr->extra->mp_nexthop_len != 16
297 || IN6_IS_ADDR_LINKLOCAL (&ri->attr->extra->mp_nexthop_global))
298 return -1;
299
300 p->family = AF_INET6;
301 p->prefixlen = IPV6_MAX_BITLEN;
302 p->u.prefix6 = ri->attr->extra->mp_nexthop_global;
303 break;
304#endif
305 default:
306 break;
307 }
308 return 0;
309}
310
311/**
312 * sendmsg_nexthop -- Format and send a nexthop register/Unregister
313 * command to Zebra.
314 * ARGUMENTS:
315 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
316 * int command -- either ZEBRA_NEXTHOP_REGISTER or ZEBRA_NEXTHOP_UNREGISTER
317 * RETURNS:
318 * void.
319 */
320static void
321sendmsg_nexthop (struct bgp_nexthop_cache *bnc, int command)
322{
323 struct stream *s;
324 struct prefix *p;
325 int ret;
326
327 /* Check socket. */
328 if (!zclient || zclient->sock < 0)
329 return;
330
331 p = &(bnc->node->p);
332 s = zclient->obuf;
333 stream_reset (s);
334 zclient_create_header (s, command, VRF_DEFAULT);
335 stream_putw(s, PREFIX_FAMILY(p));
336 stream_putc(s, p->prefixlen);
337 switch (PREFIX_FAMILY(p))
338 {
339 case AF_INET:
340 stream_put_in_addr (s, &p->u.prefix4);
341 break;
342#ifdef HAVE_IPV6
343 case AF_INET6:
344 stream_put(s, &(p->u.prefix6), 16);
345 break;
346#endif
347 default:
348 break;
349 }
350 stream_putw_at (s, 0, stream_get_endp (s));
351
352 ret = zclient_send_message(zclient);
353 /* TBD: handle the failure */
354 if (ret < 0)
355 zlog_warn("sendmsg_nexthop: zclient_send_message() failed");
356 return;
357}
358
359/**
360 * register_nexthop - register a nexthop with Zebra for notification
361 * when the route to the nexthop changes.
362 * ARGUMENTS:
363 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
364 * RETURNS:
365 * void.
366 */
367static void
368register_nexthop (struct bgp_nexthop_cache *bnc)
369{
370 /* Check if we have already registered */
371 if (bnc->flags & BGP_NEXTHOP_REGISTERED)
372 return;
373 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_REGISTER);
374 SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
375}
376
377/**
378 * unregister_nexthop -- Unregister the nexthop from Zebra.
379 * ARGUMENTS:
380 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
381 * RETURNS:
382 * void.
383 */
384static void
385unregister_nexthop (struct bgp_nexthop_cache *bnc)
386{
387 /* Check if we have already registered */
388 if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
389 return;
390
391 sendmsg_nexthop(bnc, ZEBRA_NEXTHOP_UNREGISTER);
392 UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
393}
394
395/**
396 * evaluate_paths - Evaluate the paths/nets associated with a nexthop.
397 * ARGUMENTS:
398 * struct bgp_nexthop_cache *bnc -- the nexthop structure.
399 * RETURNS:
400 * void.
401 */
402static void
403evaluate_paths (struct bgp_nexthop_cache *bnc)
404{
405 struct bgp_node *rn;
406 struct bgp_info *path;
407 struct bgp *bgp = bgp_get_default();
408 int afi;
409
410 LIST_FOREACH(path, &(bnc->paths), nh_thread)
411 {
412 if (!(path->type == ZEBRA_ROUTE_BGP &&
413 path->sub_type == BGP_ROUTE_NORMAL))
414 continue;
415
416 rn = path->net;
417 afi = family2afi(rn->p.family);
418
419 /* Path becomes valid/invalid depending on whether the nexthop
420 * reachable/unreachable.
421 */
422 if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) !=
423 (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) ? 1 : 0))
424 {
425 if (CHECK_FLAG (path->flags, BGP_INFO_VALID))
426 {
427 bgp_aggregate_decrement (bgp, &rn->p, path,
428 afi, SAFI_UNICAST);
429 bgp_info_unset_flag (rn, path, BGP_INFO_VALID);
430 }
431 else
432 {
433 bgp_info_set_flag (rn, path, BGP_INFO_VALID);
434 bgp_aggregate_increment (bgp, &rn->p, path,
435 afi, SAFI_UNICAST);
436 }
437 }
438
439 /* Copy the metric to the path. Will be used for bestpath computation */
440 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric)
441 (bgp_info_extra_get(path))->igpmetric = bnc->metric;
442 else if (path->extra)
443 path->extra->igpmetric = 0;
444
445 if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_METRIC_CHANGED) ||
446 CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CHANGED))
447 SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED);
448
449 bgp_process(bgp, rn, afi, SAFI_UNICAST);
450 }
451 RESET_FLAG(bnc->change_flags);
452}
453
454/**
455 * path_nh_map - make or break path-to-nexthop association.
456 * ARGUMENTS:
457 * path - pointer to the path structure
458 * bnc - pointer to the nexthop structure
459 * make - if set, make the association. if unset, just break the existing
460 * association.
461 */
462static void
463path_nh_map (struct bgp_info *path, struct bgp_nexthop_cache *bnc, int make)
464{
465 if (path->nexthop)
466 {
467 LIST_REMOVE(path, nh_thread);
468 path->nexthop->path_count--;
469 path->nexthop = NULL;
470 }
471 if (make)
472 {
473 LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread);
474 path->nexthop = bnc;
475 path->nexthop->path_count++;
476 }
477}