]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_rnh.c
nexthop-tracking.patch
[mirror_frr.git] / zebra / zebra_rnh.c
1 /* 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 vrf *vrf; \
50 struct route_table *t = NULL; \
51 vrf = vrf_lookup(v); \
52 if (vrf) \
53 t = vrf->rnh_table[family2afi(f)]; \
54 t; \
55 })
56
57 static void free_state(struct rib *rib);
58 static void copy_state(struct rnh *rnh, struct rib *rib);
59 static int compare_state(struct rib *r1, struct rib *r2);
60 static int send_client(struct rnh *rnh, struct zserv *client);
61 static void print_rnh(struct route_node *rn, struct vty *vty);
62
63 char *
64 rnh_str (struct rnh *rnh, char *buf, int size)
65 {
66 prefix2str(&(rnh->node->p), buf, size);
67 return buf;
68 }
69
70 struct rnh *
71 zebra_add_rnh (struct prefix *p, u_int32_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
109 struct rnh *
110 zebra_lookup_rnh (struct prefix *p, u_int32_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
131 void
132 zebra_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
153 void
154 zebra_add_rnh_client (struct rnh *rnh, struct zserv *client)
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);
167 }
168 }
169
170 void
171 zebra_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
185 int
186 zebra_evaluate_rnh_table (int 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 = 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);
249 }
250 }
251 return 1;
252 }
253
254 int
255 zebra_dispatch_rnh_table (int 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);
283 }
284 return 1;
285 }
286
287 void
288 zebra_print_rnh_table (int 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
305 int
306 zebra_cleanup_rnh_client (int 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 */
340 static void
341 free_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 */
360 static void
361 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 nexthop_add(state, nexthop);
375 }
376
377 static void
378 copy_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 copy_nexthop(state, nh);
398 rnh->state = state;
399 }
400
401 static int
402 compare_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
464 static int
465 send_client (struct rnh *rnh, struct zserv *client)
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);
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));
534 return zebra_server_send_message(client);
535 }
536
537 static void
538 print_nh (struct nexthop *nexthop, struct vty *vty)
539 {
540 char buf[BUFSIZ];
541
542 switch (nexthop->type)
543 {
544 case NEXTHOP_TYPE_IPV4:
545 case NEXTHOP_TYPE_IPV4_IFINDEX:
546 vty_out (vty, " via %s", inet_ntoa (nexthop->gate.ipv4));
547 if (nexthop->ifindex)
548 vty_out (vty, ", %s", ifindex2ifname (nexthop->ifindex));
549 break;
550 case NEXTHOP_TYPE_IPV6:
551 case NEXTHOP_TYPE_IPV6_IFINDEX:
552 case NEXTHOP_TYPE_IPV6_IFNAME:
553 vty_out (vty, " %s",
554 inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
555 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME)
556 vty_out (vty, ", %s", nexthop->ifname);
557 else if (nexthop->ifindex)
558 vty_out (vty, ", via %s", ifindex2ifname (nexthop->ifindex));
559 break;
560 case NEXTHOP_TYPE_IFINDEX:
561 vty_out (vty, " is directly connected, %s",
562 ifindex2ifname (nexthop->ifindex));
563 break;
564 case NEXTHOP_TYPE_IFNAME:
565 vty_out (vty, " is directly connected, %s", nexthop->ifname);
566 break;
567 case NEXTHOP_TYPE_BLACKHOLE:
568 vty_out (vty, " is directly connected, Null0");
569 break;
570 default:
571 break;
572 }
573 vty_out(vty, "%s", VTY_NEWLINE);
574 }
575
576 static void
577 print_rnh (struct route_node *rn, struct vty *vty)
578 {
579 struct rnh *rnh;
580 struct nexthop *nexthop;
581 struct listnode *node;
582 struct zserv *client;
583 char buf[BUFSIZ];
584
585 rnh = rn->info;
586 vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
587 VTY_NEWLINE);
588 if (rnh->state)
589 {
590 vty_out(vty, " resolved via %s%s",
591 zebra_route_string(rnh->state->type), VTY_NEWLINE);
592 for (nexthop = rnh->state->nexthop; nexthop; nexthop = nexthop->next)
593 print_nh(nexthop, vty);
594 }
595 else
596 vty_out(vty, " unresolved%s", VTY_NEWLINE);
597
598 vty_out(vty, " Client list:");
599 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
600 vty_out(vty, " %s(fd %d)", zebra_route_string(client->proto),
601 client->sock);
602 vty_out(vty, "%s", VTY_NEWLINE);
603 }