blob: 859b6d79360f9d6716dfa1decacbbc0dc325f3bf [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äsdafa05e2017-01-19 17:27:01 +0200226 if (! CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
227 continue;
228
229 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700230 {
Timo Teräsdafa05e2017-01-19 17:27:01 +0200231 if (rib->type == ZEBRA_ROUTE_CONNECT)
232 break;
233
234 if (rib->type == ZEBRA_ROUTE_NHRP)
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700235 {
Timo Teräsdafa05e2017-01-19 17:27:01 +0200236 struct nexthop *nexthop;
237 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
238 if (nexthop->type == NEXTHOP_TYPE_IFINDEX ||
239 nexthop->type == NEXTHOP_TYPE_IFNAME)
240 break;
241 if (nexthop)
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700242 break;
243 }
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700244 }
Timo Teräsdafa05e2017-01-19 17:27:01 +0200245 else
246 break;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500247 }
248 }
249
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500250 if (compare_state(rib, rnh->state))
251 {
252 if (IS_ZEBRA_DEBUG_NHT)
253 {
254 char bufn[INET6_ADDRSTRLEN];
255 char bufp[INET6_ADDRSTRLEN];
256 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
257 if (prn)
258 prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
259 else
260 strcpy(bufp, "null");
261 zlog_debug("rnh %s resolved through route %s - sending "
262 "nexthop %s event to clients", bufn, bufp,
263 rib ? "reachable" : "unreachable");
264 }
265 copy_state(rnh, rib);
266 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
267 send_client(rnh, client, vrfid);
268 }
269 }
270 return 1;
271}
272
273int
274zebra_dispatch_rnh_table (vrf_id_t vrfid, int family, struct zserv *client)
275{
276 struct route_table *ntable;
277 struct route_node *nrn;
278 struct rnh *rnh;
279
280 ntable = lookup_rnh_table(vrfid, family);
281 if (!ntable)
282 {
283 zlog_debug("dispatch_rnh_table: rnh table not found\n");
284 return -1;
285 }
286
287 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
288 {
289 if (!nrn->info)
290 continue;
291
292 rnh = nrn->info;
293 if (IS_ZEBRA_DEBUG_NHT)
294 {
295 char bufn[INET6_ADDRSTRLEN];
296 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
297 zlog_debug("rnh %s - sending nexthop %s event to client %s", bufn,
298 rnh->state ? "reachable" : "unreachable",
299 zebra_route_string(client->proto));
300 }
301 send_client(rnh, client, vrfid);
302 }
303 return 1;
304}
305
306void
307zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty)
308{
309 struct route_table *table;
310 struct route_node *rn;
311
312 table = lookup_rnh_table(vrfid, af);
313 if (!table)
314 {
315 zlog_debug("print_rnhs: rnh table not found\n");
316 return;
317 }
318
319 for (rn = route_top(table); rn; rn = route_next(rn))
320 if (rn->info)
321 print_rnh(rn, vty);
322}
323
324int
325zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client)
326{
327 struct route_table *ntable;
328 struct route_node *nrn;
329 struct rnh *rnh;
330
331 ntable = lookup_rnh_table(vrfid, family);
332 if (!ntable)
333 {
334 zlog_debug("cleanup_rnh_client: rnh table not found\n");
335 return -1;
336 }
337
338 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
339 {
340 if (!nrn->info)
341 continue;
342
343 rnh = nrn->info;
344 if (IS_ZEBRA_DEBUG_NHT)
345 {
346 char bufn[INET6_ADDRSTRLEN];
347 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
348 zlog_debug("rnh %s - cleaning state for client %s", bufn,
349 zebra_route_string(client->proto));
350 }
351 zebra_remove_rnh_client(rnh, client);
352 }
353 return 1;
354}
355
356/**
357 * free_state - free up the rib structure associated with the rnh.
358 */
359static void
360free_state (struct rib *rib)
361{
362 struct nexthop *nexthop, *next;
363
364 if (!rib)
365 return;
366
367 /* free RIB and nexthops */
368 for (nexthop = rib->nexthop; nexthop; nexthop = next)
369 {
370 next = nexthop->next;
371 nexthop_free (nexthop);
372 }
373 XFREE (MTYPE_RIB, rib);
374}
375
376/**
377 * copy_nexthop - copy a nexthop to the rib structure.
378 */
379static void
380rib_copy_nexthop (struct rib *state, struct nexthop *nh)
381{
382 struct nexthop *nexthop;
383
384 nexthop = nexthop_new();
385 nexthop->flags = nh->flags;
386 nexthop->type = nh->type;
387 nexthop->ifindex = nh->ifindex;
388 if (nh->ifname)
389 nexthop->ifname = XSTRDUP(0, nh->ifname);
390 memcpy(&(nexthop->gate), &(nh->gate), sizeof(union g_addr));
391 memcpy(&(nexthop->src), &(nh->src), sizeof(union g_addr));
392
393 rib_nexthop_add(state, nexthop);
394}
395
396static void
397copy_state (struct rnh *rnh, struct rib *rib)
398{
399 struct rib *state;
400 struct nexthop *nh;
401
402 if (rnh->state)
403 {
404 free_state(rnh->state);
405 rnh->state = NULL;
406 }
407
408 if (!rib)
409 return;
410
411 state = XCALLOC (MTYPE_RIB, sizeof (struct rib));
412 state->type = rib->type;
413 state->metric = rib->metric;
414
415 for (nh = rib->nexthop; nh; nh = nh->next)
416 rib_copy_nexthop(state, nh);
417 rnh->state = state;
418}
419
420static int
421compare_state (struct rib *r1, struct rib *r2)
422{
423 struct nexthop *nh1;
424 struct nexthop *nh2;
425 u_char found_nh = 0;
426
427 if (!r1 && !r2)
428 return 0;
429
430 if ((!r1 && r2) || (r1 && !r2))
431 return 1;
432
433 if (r1->metric != r2->metric)
434 return 1;
435
436 if (r1->nexthop_num != r2->nexthop_num)
437 return 1;
438
439 /* We need to verify that the nexthops for r1 match the nexthops for r2.
440 * Since it is possible for a rib entry to have the same nexthop multiple
441 * times (Example: [a,a]) we need to keep track of which r2 nexthops we have
442 * already used as a match against a r1 nexthop. We track this
443 * via NEXTHOP_FLAG_MATCHED. Clear this flag for all r2 nexthops when you
444 * are finished.
445 *
446 * TRUE: r1 [a,b], r2 [a,b]
447 * TRUE: r1 [a,b], r2 [b,a]
448 * FALSE: r1 [a,b], r2 [a,c]
449 * FALSE: r1 [a,a], r2 [a,b]
450 */
451 for (nh1 = r1->nexthop; nh1; nh1 = nh1->next)
452 {
453 found_nh = 0;
454 for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
455 {
456 if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
457 continue;
458
459 if (nexthop_same_no_recurse(nh1, nh2))
460 {
461 SET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
462 found_nh = 1;
463 break;
464 }
465 }
466
467 if (!found_nh)
468 {
469 for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
470 if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
471 UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
472 return 1;
473 }
474 }
475
476 for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
477 if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
478 UNSET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
479
480 return 0;
481}
482
483static int
484send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id)
485{
486 struct stream *s;
487 struct rib *rib;
488 unsigned long nump;
489 u_char num;
490 struct nexthop *nexthop;
491 struct route_node *rn;
492
493 rn = rnh->node;
494 rib = rnh->state;
495
496 /* Get output stream. */
497 s = client->obuf;
498 stream_reset (s);
499
500 zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE, vrf_id);
501
502 stream_putw(s, rn->p.family);
503 stream_put_prefix (s, &rn->p);
504
505 if (rib)
506 {
507 stream_putl (s, rib->metric);
508 num = 0;
509 nump = stream_get_endp(s);
510 stream_putc (s, 0);
511 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
Timo Teräsb41bb622016-10-19 16:02:32 +0300512 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) &&
513 ! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) &&
Daniel Waltonfc2cee22015-05-19 18:03:44 -0700514 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500515 {
516 stream_putc (s, nexthop->type);
517 switch (nexthop->type)
518 {
519 case ZEBRA_NEXTHOP_IPV4:
520 stream_put_in_addr (s, &nexthop->gate.ipv4);
521 break;
522 case ZEBRA_NEXTHOP_IFINDEX:
523 case ZEBRA_NEXTHOP_IFNAME:
524 stream_putl (s, nexthop->ifindex);
525 break;
526 case ZEBRA_NEXTHOP_IPV4_IFINDEX:
527 case ZEBRA_NEXTHOP_IPV4_IFNAME:
528 stream_put_in_addr (s, &nexthop->gate.ipv4);
529 stream_putl (s, nexthop->ifindex);
530 break;
531#ifdef HAVE_IPV6
532 case ZEBRA_NEXTHOP_IPV6:
533 stream_put (s, &nexthop->gate.ipv6, 16);
534 break;
535 case ZEBRA_NEXTHOP_IPV6_IFINDEX:
536 case ZEBRA_NEXTHOP_IPV6_IFNAME:
537 stream_put (s, &nexthop->gate.ipv6, 16);
538 stream_putl (s, nexthop->ifindex);
539 break;
540#endif /* HAVE_IPV6 */
541 default:
542 /* do nothing */
543 break;
544 }
545 num++;
546 }
547 stream_putc_at (s, nump, num);
548 }
549 else
550 {
551 stream_putl (s, 0);
552 stream_putc (s, 0);
553 }
554 stream_putw_at (s, 0, stream_get_endp (s));
Dinesh Dutt9ae85522015-05-19 17:47:22 -0700555
556 client->nh_last_upd_time = quagga_time(NULL);
557 client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500558 return zebra_server_send_message(client);
559}
560
561static void
562print_nh (struct nexthop *nexthop, struct vty *vty)
563{
564 char buf[BUFSIZ];
565
566 switch (nexthop->type)
567 {
568 case NEXTHOP_TYPE_IPV4:
569 case NEXTHOP_TYPE_IPV4_IFINDEX:
570 vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
571 if (nexthop->ifindex)
572 vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
573 break;
574 case NEXTHOP_TYPE_IPV6:
575 case NEXTHOP_TYPE_IPV6_IFINDEX:
576 case NEXTHOP_TYPE_IPV6_IFNAME:
577 vty_out (vty, " %s",
578 inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
579 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
580 vty_out (vty, ", %s", nexthop->ifname);
581 else if (nexthop->ifindex)
582 vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
583 break;
584 case NEXTHOP_TYPE_IFINDEX:
585 vty_out (vty, " is directly connected, %s",
586 ifindex2ifname (nexthop->ifindex));
587 break;
588 case NEXTHOP_TYPE_IFNAME:
589 vty_out (vty, " is directly connected, %s", nexthop->ifname);
590 break;
591 case NEXTHOP_TYPE_BLACKHOLE:
592 vty_out (vty, " is directly connected, Null0");
593 break;
594 default:
595 break;
596 }
597 vty_out(vty, "%s", VTY_NEWLINE);
598}
599
600static void
601print_rnh (struct route_node *rn, struct vty *vty)
602{
603 struct rnh *rnh;
604 struct nexthop *nexthop;
605 struct listnode *node;
606 struct zserv *client;
607 char buf[BUFSIZ];
608
609 rnh = rn->info;
610 vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
611 VTY_NEWLINE);
612 if (rnh->state)
613 {
614 vty_out(vty, " resolved via %s%s",
615 zebra_route_string(rnh->state->type), VTY_NEWLINE);
616 for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next)
617 print_nh(nexthop, vty);
618 }
619 else
Dinesh Duttd9ab53a2015-05-19 17:47:21 -0700620 vty_out(vty, " unresolved%s%s",
621 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
622 VTY_NEWLINE);
Pradosh Mohapatra60cc9592015-11-09 20:21:41 -0500623
624 vty_out(vty, " Client list:");
625 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
626 vty_out(vty, " %s(fd %d)", zebra_route_string(client->proto),
627 client->sock);
628 vty_out(vty, "%s", VTY_NEWLINE);
629}