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