blob: 5762d3f2c0c533721905f68c1a26847c8f8f315d [file] [log] [blame]
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -05001/* Zebra next hop tracking code
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 "prefix.h"
25#include "table.h"
26#include "memory.h"
27#include "str.h"
28#include "command.h"
29#include "if.h"
30#include "log.h"
31#include "sockunion.h"
32#include "linklist.h"
33#include "thread.h"
34#include "workqueue.h"
35#include "prefix.h"
36#include "routemap.h"
37#include "stream.h"
38#include "nexthop.h"
39
40#include "zebra/rib.h"
41#include "zebra/rt.h"
42#include "zebra/zserv.h"
43#include "zebra/redistribute.h"
44#include "zebra/debug.h"
45#include "zebra/zebra_rnh.h"
46
47#define lookup_rnh_table(v, f) \
48({ \
49 struct zebra_vrf *zvrf; \
50 struct route_table *t = NULL; \
51 zvrf = zebra_vrf_lookup(v); \
52 if (zvrf) \
53 t = zvrf->rnh_table[family2afi(f)]; \
54 t; \
55})
56
57static void free_state(struct rib *rib);
58static void copy_state(struct rnh *rnh, struct rib *rib);
59static int compare_state(struct rib *r1, struct rib *r2);
60static int send_client(struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id);
61static void print_rnh(struct route_node *rn, struct vty *vty);
62
63char *
64rnh_str (struct rnh *rnh, char *buf, int size)
65{
66 prefix2str(&(rnh->node->p), buf, size);
67 return buf;
68}
69
70struct rnh *
71zebra_add_rnh (struct prefix *p, vrf_id_t vrfid)
72{
73 struct route_table *table;
74 struct route_node *rn;
75 struct rnh *rnh = NULL;
76
77 if (IS_ZEBRA_DEBUG_NHT)
78 {
79 char buf[INET6_ADDRSTRLEN];
80 prefix2str(p, buf, INET6_ADDRSTRLEN);
81 zlog_debug("add rnh %s in vrf %d", buf, vrfid);
82 }
83 table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
84 if (!table)
85 {
86 zlog_debug("add_rnh: rnh table not found\n");
87 return NULL;
88 }
89
90 /* Make it sure prefixlen is applied to the prefix. */
91 apply_mask (p);
92
93 /* Lookup (or add) route node.*/
94 rn = route_node_get (table, p);
95
96 if (!rn->info)
97 {
98 rnh = XCALLOC(MTYPE_RNH, sizeof(struct rnh));
99 rnh->client_list = list_new();
100 route_lock_node (rn);
101 rn->info = rnh;
102 rnh->node = rn;
103 }
104
105 route_unlock_node (rn);
106 return (rn->info);
107}
108
109struct rnh *
110zebra_lookup_rnh (struct prefix *p, vrf_id_t vrfid)
111{
112 struct route_table *table;
113 struct route_node *rn;
114
115 table = lookup_rnh_table(vrfid, PREFIX_FAMILY(p));
116 if (!table)
117 return NULL;
118
119 /* Make it sure prefixlen is applied to the prefix. */
120 apply_mask (p);
121
122 /* Lookup route node.*/
123 rn = route_node_lookup (table, p);
124 if (!rn)
125 return NULL;
126
127 route_unlock_node (rn);
128 return (rn->info);
129}
130
131void
132zebra_delete_rnh (struct rnh *rnh)
133{
134 struct route_node *rn;
135
136 if (!rnh || !(rn = rnh->node))
137 return;
138
139 if (IS_ZEBRA_DEBUG_NHT)
140 {
141 char buf[INET6_ADDRSTRLEN];
142 zlog_debug("delete rnh %s", rnh_str(rnh, buf, INET6_ADDRSTRLEN));
143 }
144
145 list_free(rnh->client_list);
146 free_state(rnh->state);
147 XFREE(MTYPE_RNH, rn->info);
148 rn->info = NULL;
149 route_unlock_node (rn);
150 return;
151}
152
153void
154zebra_add_rnh_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id)
155{
156 if (IS_ZEBRA_DEBUG_NHT)
157 {
158 char buf[INET6_ADDRSTRLEN];
159 zlog_debug("client %s registers rnh %s",
160 zebra_route_string(client->proto),
161 rnh_str(rnh, buf, INET6_ADDRSTRLEN));
162 }
163 if (!listnode_lookup(rnh->client_list, client))
164 {
165 listnode_add(rnh->client_list, client);
166 send_client(rnh, client, vrf_id);
167 }
168}
169
170void
171zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client)
172{
173 if (IS_ZEBRA_DEBUG_NHT)
174 {
175 char buf[INET6_ADDRSTRLEN];
176 zlog_debug("client %s unregisters rnh %s",
177 zebra_route_string(client->proto),
178 rnh_str(rnh, buf, INET6_ADDRSTRLEN));
179 }
180 listnode_delete(rnh->client_list, client);
181 if (list_isempty(rnh->client_list))
182 zebra_delete_rnh(rnh);
183}
184
185int
186zebra_evaluate_rnh_table (vrf_id_t vrfid, int family)
187{
188 struct route_table *ptable;
189 struct route_table *ntable;
190 struct route_node *prn;
191 struct route_node *nrn;
192 struct rnh *rnh;
193 struct zserv *client;
194 struct listnode *node;
195 struct rib *rib;
196
197 ntable = lookup_rnh_table(vrfid, family);
198 if (!ntable)
199 {
200 zlog_debug("evaluate_rnh_table: rnh table not found\n");
201 return -1;
202 }
203
204 ptable = zebra_vrf_table(family2afi(family), SAFI_UNICAST, vrfid);
205 if (!ptable)
206 {
207 zlog_debug("evaluate_rnh_table: prefix table not found\n");
208 return -1;
209 }
210
211 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
212 {
213 if (!nrn->info)
214 continue;
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700215
216 rnh = nrn->info;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500217 prn = route_node_match(ptable, &nrn->p);
218 if (!prn)
219 rib = NULL;
220 else
221 {
222 RNODE_FOREACH_RIB(prn, rib)
223 {
224 if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
225 continue;
Timo Teräs631fcd22016-10-19 16:02:31 +0300226 if (CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700227 {
228 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
229 {
230 if (rib->type == ZEBRA_ROUTE_CONNECT)
231 break;
232 }
233 else
234 break;
235 }
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500236 }
237 }
238
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500239 if (compare_state(rib, rnh->state))
240 {
241 if (IS_ZEBRA_DEBUG_NHT)
242 {
243 char bufn[INET6_ADDRSTRLEN];
244 char bufp[INET6_ADDRSTRLEN];
245 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
246 if (prn)
247 prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
248 else
249 strcpy(bufp, "null");
250 zlog_debug("rnh %s resolved through route %s - sending "
251 "nexthop %s event to clients", bufn, bufp,
252 rib ? "reachable" : "unreachable");
253 }
254 copy_state(rnh, rib);
255 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
256 send_client(rnh, client, vrfid);
257 }
258 }
259 return 1;
260}
261
262int
263zebra_dispatch_rnh_table (vrf_id_t vrfid, int family, struct zserv *client)
264{
265 struct route_table *ntable;
266 struct route_node *nrn;
267 struct rnh *rnh;
268
269 ntable = lookup_rnh_table(vrfid, family);
270 if (!ntable)
271 {
272 zlog_debug("dispatch_rnh_table: rnh table not found\n");
273 return -1;
274 }
275
276 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
277 {
278 if (!nrn->info)
279 continue;
280
281 rnh = nrn->info;
282 if (IS_ZEBRA_DEBUG_NHT)
283 {
284 char bufn[INET6_ADDRSTRLEN];
285 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
286 zlog_debug("rnh %s - sending nexthop %s event to client %s", bufn,
287 rnh->state ? "reachable" : "unreachable",
288 zebra_route_string(client->proto));
289 }
290 send_client(rnh, client, vrfid);
291 }
292 return 1;
293}
294
295void
296zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty)
297{
298 struct route_table *table;
299 struct route_node *rn;
300
301 table = lookup_rnh_table(vrfid, af);
302 if (!table)
303 {
304 zlog_debug("print_rnhs: rnh table not found\n");
305 return;
306 }
307
308 for (rn = route_top(table); rn; rn = route_next(rn))
309 if (rn->info)
310 print_rnh(rn, vty);
311}
312
313int
314zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client)
315{
316 struct route_table *ntable;
317 struct route_node *nrn;
318 struct rnh *rnh;
319
320 ntable = lookup_rnh_table(vrfid, family);
321 if (!ntable)
322 {
323 zlog_debug("cleanup_rnh_client: rnh table not found\n");
324 return -1;
325 }
326
327 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
328 {
329 if (!nrn->info)
330 continue;
331
332 rnh = nrn->info;
333 if (IS_ZEBRA_DEBUG_NHT)
334 {
335 char bufn[INET6_ADDRSTRLEN];
336 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
337 zlog_debug("rnh %s - cleaning state for client %s", bufn,
338 zebra_route_string(client->proto));
339 }
340 zebra_remove_rnh_client(rnh, client);
341 }
342 return 1;
343}
344
345/**
346 * free_state - free up the rib structure associated with the rnh.
347 */
348static void
349free_state (struct rib *rib)
350{
351 struct nexthop *nexthop, *next;
352
353 if (!rib)
354 return;
355
356 /* free RIB and nexthops */
357 for (nexthop = rib->nexthop; nexthop; nexthop = next)
358 {
359 next = nexthop->next;
360 nexthop_free (nexthop);
361 }
362 XFREE (MTYPE_RIB, rib);
363}
364
365/**
366 * copy_nexthop - copy a nexthop to the rib structure.
367 */
368static void
369rib_copy_nexthop (struct rib *state, struct nexthop *nh)
370{
371 struct nexthop *nexthop;
372
373 nexthop = nexthop_new();
374 nexthop->flags = nh->flags;
375 nexthop->type = nh->type;
376 nexthop->ifindex = nh->ifindex;
377 if (nh->ifname)
378 nexthop->ifname = XSTRDUP(0, nh->ifname);
379 memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
380 memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
381
382 rib_nexthop_add(state, nexthop);
383}
384
385static void
386copy_state (struct rnh *rnh, struct rib *rib)
387{
388 struct rib *state;
389 struct nexthop *nh;
390
391 if (rnh->state)
392 {
393 free_state(rnh->state);
394 rnh->state = NULL;
395 }
396
397 if (!rib)
398 return;
399
400 state = XCALLOC (MTYPE_RIB, sizeof (struct rib));
401 state->type = rib->type;
402 state->metric = rib->metric;
403
404 for (nh = rib->nexthop; nh; nh = nh->next)
405 rib_copy_nexthop(state, nh);
406 rnh->state = state;
407}
408
409static int
410compare_state (struct rib *r1, struct rib *r2)
411{
412 struct nexthop *nh1;
413 struct nexthop *nh2;
414 u_char found_nh = 0;
415
416 if (!r1 && !r2)
417 return 0;
418
419 if ((!r1 && r2) || (r1 && !r2))
420 return 1;
421
422 if (r1->metric != r2->metric)
423 return 1;
424
425 if (r1->nexthop_num != r2->nexthop_num)
426 return 1;
427
428 /* We need to verify that the nexthops for r1 match the nexthops for r2.
429 * Since it is possible for a rib entry to have the same nexthop multiple
430 * times (Example: [a,a]) we need to keep track of which r2 nexthops we have
431 * already used as a match against a r1 nexthop. We track this
432 * via NEXTHOP_FLAG_MATCHED. Clear this flag for all r2 nexthops when you
433 * are finished.
434 *
435 * TRUE: r1 [a,b], r2 [a,b]
436 * TRUE: r1 [a,b], r2 [b,a]
437 * FALSE: r1 [a,b], r2 [a,c]
438 * FALSE: r1 [a,a], r2 [a,b]
439 */
440 for (nh1 = r1->nexthop; nh1; nh1 = nh1->next)
441 {
442 found_nh = 0;
443 for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
444 {
445 if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
446 continue;
447
448 if (nexthop_same_no_recurse(nh1, nh2))
449 {
450 SET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
451 found_nh = 1;
452 break;
453 }
454 }
455
456 if (!found_nh)
457 {
458 for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
459 if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
460 UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
461 return 1;
462 }
463 }
464
465 for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
466 if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
467 UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
468
469 return 0;
470}
471
472static int
473send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id)
474{
475 struct stream *s;
476 struct rib *rib;
477 unsigned long nump;
478 u_char num;
479 struct nexthop *nexthop;
480 struct route_node *rn;
481
482 rn = rnh->node;
483 rib = rnh->state;
484
485 /* Get output stream. */
486 s = client->obuf;
487 stream_reset (s);
488
489 zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE, vrf_id);
490
491 stream_putw(s, rn->p.family);
492 stream_put_prefix (s, &rn->p);
493
494 if (rib)
495 {
496 stream_putl (s, rib->metric);
497 num = 0;
498 nump = stream_get_endp(s);
499 stream_putc (s, 0);
500 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
Timo Teräsb41bb622016-10-19 16:02:32 +0300501 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) &&
502 ! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) &&
Daniel Waltonfc2cee22015-05-19 18:03:44 -0700503 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500504 {
505 stream_putc (s, nexthop->type);
506 switch (nexthop->type)
507 {
508 case ZEBRA_NEXTHOP_IPV4:
509 stream_put_in_addr (s, &nexthop->gate.ipv4);
510 break;
511 case ZEBRA_NEXTHOP_IFINDEX:
512 case ZEBRA_NEXTHOP_IFNAME:
513 stream_putl (s, nexthop->ifindex);
514 break;
515 case ZEBRA_NEXTHOP_IPV4_IFINDEX:
516 case ZEBRA_NEXTHOP_IPV4_IFNAME:
517 stream_put_in_addr (s, &nexthop->gate.ipv4);
518 stream_putl (s, nexthop->ifindex);
519 break;
520#ifdef HAVE_IPV6
521 case ZEBRA_NEXTHOP_IPV6:
522 stream_put (s, &nexthop->gate.ipv6, 16);
523 break;
524 case ZEBRA_NEXTHOP_IPV6_IFINDEX:
525 case ZEBRA_NEXTHOP_IPV6_IFNAME:
526 stream_put (s, &nexthop->gate.ipv6, 16);
527 stream_putl (s, nexthop->ifindex);
528 break;
529#endif /* HAVE_IPV6 */
530 default:
531 /* do nothing */
532 break;
533 }
534 num++;
535 }
536 stream_putc_at (s, nump, num);
537 }
538 else
539 {
540 stream_putl (s, 0);
541 stream_putc (s, 0);
542 }
543 stream_putw_at (s, 0, stream_get_endp (s));
Dinesh Dutt9ae85522015-05-19 17:47:22 -0700544
545 client->nh_last_upd_time = quagga_time(NULL);
546 client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500547 return zebra_server_send_message(client);
548}
549
550static void
551print_nh (struct nexthop *nexthop, struct vty *vty)
552{
553 char buf[BUFSIZ];
554
555 switch (nexthop->type)
556 {
557 case NEXTHOP_TYPE_IPV4:
558 case NEXTHOP_TYPE_IPV4_IFINDEX:
559 vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
560 if (nexthop->ifindex)
561 vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
562 break;
563 case NEXTHOP_TYPE_IPV6:
564 case NEXTHOP_TYPE_IPV6_IFINDEX:
565 case NEXTHOP_TYPE_IPV6_IFNAME:
566 vty_out (vty, " %s",
567 inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
568 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
569 vty_out (vty, ", %s", nexthop->ifname);
570 else if (nexthop->ifindex)
571 vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
572 break;
573 case NEXTHOP_TYPE_IFINDEX:
574 vty_out (vty, " is directly connected, %s",
575 ifindex2ifname (nexthop->ifindex));
576 break;
577 case NEXTHOP_TYPE_IFNAME:
578 vty_out (vty, " is directly connected, %s", nexthop->ifname);
579 break;
580 case NEXTHOP_TYPE_BLACKHOLE:
581 vty_out (vty, " is directly connected, Null0");
582 break;
583 default:
584 break;
585 }
586 vty_out(vty, "%s", VTY_NEWLINE);
587}
588
589static void
590print_rnh (struct route_node *rn, struct vty *vty)
591{
592 struct rnh *rnh;
593 struct nexthop *nexthop;
594 struct listnode *node;
595 struct zserv *client;
596 char buf[BUFSIZ];
597
598 rnh = rn->info;
599 vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
600 VTY_NEWLINE);
601 if (rnh->state)
602 {
603 vty_out(vty, " resolved via %s%s",
604 zebra_route_string(rnh->state->type), VTY_NEWLINE);
605 for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next)
606 print_nh(nexthop, vty);
607 }
608 else
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700609 vty_out(vty, " unresolved%s%s",
610 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
611 VTY_NEWLINE);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500612
613 vty_out(vty, " Client list:");
614 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
615 vty_out(vty, " %s(fd %d)", zebra_route_string(client->proto),
616 client->sock);
617 vty_out(vty, "%s", VTY_NEWLINE);
618}