1 /* Zebra next hop tracking code
2 * Copyright (C) 2013 Cumulus Networks, Inc.
4 * This file is part of GNU Zebra.
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
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.
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
31 #include "sockunion.h"
34 #include "workqueue.h"
40 #include "zebra/rib.h"
42 #include "zebra/zserv.h"
43 #include "zebra/redistribute.h"
44 #include "zebra/debug.h"
45 #include "zebra/zebra_rnh.h"
47 #define lookup_rnh_table(v, f) \
50 struct route_table *t = NULL; \
51 vrf = vrf_lookup(v); \
53 t = vrf->rnh_table[family2afi(f)]; \
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
);
64 rnh_str (struct rnh
*rnh
, char *buf
, int size
)
66 prefix2str(&(rnh
->node
->p
), buf
, size
);
71 zebra_add_rnh (struct prefix
*p
, u_int32_t vrfid
)
73 struct route_table
*table
;
74 struct route_node
*rn
;
75 struct rnh
*rnh
= NULL
;
77 if (IS_ZEBRA_DEBUG_NHT
)
79 char buf
[INET6_ADDRSTRLEN
];
80 prefix2str(p
, buf
, INET6_ADDRSTRLEN
);
81 zlog_debug("add rnh %s in vrf %d", buf
, vrfid
);
83 table
= lookup_rnh_table(vrfid
, PREFIX_FAMILY(p
));
86 zlog_debug("add_rnh: rnh table not found\n");
90 /* Make it sure prefixlen is applied to the prefix. */
93 /* Lookup (or add) route node.*/
94 rn
= route_node_get (table
, p
);
98 rnh
= XCALLOC(MTYPE_RNH
, sizeof(struct rnh
));
99 rnh
->client_list
= list_new();
100 route_lock_node (rn
);
105 route_unlock_node (rn
);
110 zebra_lookup_rnh (struct prefix
*p
, u_int32_t vrfid
)
112 struct route_table
*table
;
113 struct route_node
*rn
;
115 table
= lookup_rnh_table(vrfid
, PREFIX_FAMILY(p
));
119 /* Make it sure prefixlen is applied to the prefix. */
122 /* Lookup route node.*/
123 rn
= route_node_lookup (table
, p
);
127 route_unlock_node (rn
);
132 zebra_delete_rnh (struct rnh
*rnh
)
134 struct route_node
*rn
;
136 if (!rnh
|| !(rn
= rnh
->node
))
139 if (IS_ZEBRA_DEBUG_NHT
)
141 char buf
[INET6_ADDRSTRLEN
];
142 zlog_debug("delete rnh %s", rnh_str(rnh
, buf
, INET6_ADDRSTRLEN
));
145 list_free(rnh
->client_list
);
146 free_state(rnh
->state
);
147 XFREE(MTYPE_RNH
, rn
->info
);
149 route_unlock_node (rn
);
154 zebra_add_rnh_client (struct rnh
*rnh
, struct zserv
*client
)
156 if (IS_ZEBRA_DEBUG_NHT
)
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
));
163 if (!listnode_lookup(rnh
->client_list
, client
))
165 listnode_add(rnh
->client_list
, client
);
166 send_client(rnh
, client
);
171 zebra_remove_rnh_client (struct rnh
*rnh
, struct zserv
*client
)
173 if (IS_ZEBRA_DEBUG_NHT
)
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
));
180 listnode_delete(rnh
->client_list
, client
);
181 if (list_isempty(rnh
->client_list
))
182 zebra_delete_rnh(rnh
);
186 zebra_evaluate_rnh_table (int vrfid
, int family
)
188 struct route_table
*ptable
;
189 struct route_table
*ntable
;
190 struct route_node
*prn
;
191 struct route_node
*nrn
;
193 struct zserv
*client
;
194 struct listnode
*node
;
197 ntable
= lookup_rnh_table(vrfid
, family
);
200 zlog_debug("evaluate_rnh_table: rnh table not found\n");
204 ptable
= vrf_table(family2afi(family
), SAFI_UNICAST
, vrfid
);
207 zlog_debug("evaluate_rnh_table: prefix table not found\n");
211 for (nrn
= route_top (ntable
); nrn
; nrn
= route_next (nrn
))
216 prn
= route_node_match(ptable
, &nrn
->p
);
221 RNODE_FOREACH_RIB(prn
, rib
)
223 if (CHECK_FLAG (rib
->status
, RIB_ENTRY_REMOVED
))
225 if (CHECK_FLAG (rib
->flags
, ZEBRA_FLAG_SELECTED
))
231 if (compare_state(rib
, rnh
->state
))
233 if (IS_ZEBRA_DEBUG_NHT
)
235 char bufn
[INET6_ADDRSTRLEN
];
236 char bufp
[INET6_ADDRSTRLEN
];
237 prefix2str(&nrn
->p
, bufn
, INET6_ADDRSTRLEN
);
239 prefix2str(&prn
->p
, bufp
, INET6_ADDRSTRLEN
);
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");
246 copy_state(rnh
, rib
);
247 for (ALL_LIST_ELEMENTS_RO(rnh
->client_list
, node
, client
))
248 send_client(rnh
, client
);
255 zebra_dispatch_rnh_table (int vrfid
, int family
, struct zserv
*client
)
257 struct route_table
*ntable
;
258 struct route_node
*nrn
;
261 ntable
= lookup_rnh_table(vrfid
, family
);
264 zlog_debug("dispatch_rnh_table: rnh table not found\n");
268 for (nrn
= route_top (ntable
); nrn
; nrn
= route_next (nrn
))
274 if (IS_ZEBRA_DEBUG_NHT
)
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
));
282 send_client(rnh
, client
);
288 zebra_print_rnh_table (int vrfid
, int af
, struct vty
*vty
)
290 struct route_table
*table
;
291 struct route_node
*rn
;
293 table
= lookup_rnh_table(vrfid
, af
);
296 zlog_debug("print_rnhs: rnh table not found\n");
300 for (rn
= route_top(table
); rn
; rn
= route_next(rn
))
306 zebra_cleanup_rnh_client (int vrfid
, int family
, struct zserv
*client
)
308 struct route_table
*ntable
;
309 struct route_node
*nrn
;
312 ntable
= lookup_rnh_table(vrfid
, family
);
315 zlog_debug("cleanup_rnh_client: rnh table not found\n");
319 for (nrn
= route_top (ntable
); nrn
; nrn
= route_next (nrn
))
325 if (IS_ZEBRA_DEBUG_NHT
)
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
));
332 zebra_remove_rnh_client(rnh
, client
);
338 * free_state - free up the rib structure associated with the rnh.
341 free_state (struct rib
*rib
)
343 struct nexthop
*nexthop
, *next
;
348 /* free RIB and nexthops */
349 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= next
)
351 next
= nexthop
->next
;
352 nexthop_free (nexthop
);
354 XFREE (MTYPE_RIB
, rib
);
358 * copy_nexthop - copy a nexthop to the rib structure.
361 copy_nexthop (struct rib
*state
, struct nexthop
*nh
)
363 struct nexthop
*nexthop
;
365 nexthop
= nexthop_new();
366 nexthop
->flags
= nh
->flags
;
367 nexthop
->type
= nh
->type
;
368 nexthop
->ifindex
= nh
->ifindex
;
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
));
374 nexthop_add(state
, nexthop
);
378 copy_state (struct rnh
*rnh
, struct rib
*rib
)
385 free_state(rnh
->state
);
392 state
= XCALLOC (MTYPE_RIB
, sizeof (struct rib
));
393 state
->type
= rib
->type
;
394 state
->metric
= rib
->metric
;
396 for (nh
= rib
->nexthop
; nh
; nh
= nh
->next
)
397 copy_nexthop(state
, nh
);
402 compare_state (struct rib
*r1
, struct rib
*r2
)
411 if ((!r1
&& r2
) || (r1
&& !r2
))
414 if (r1
->metric
!= r2
->metric
)
417 if (r1
->nexthop_num
!= r2
->nexthop_num
)
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
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]
432 for (nh1
= r1
->nexthop
; nh1
; nh1
= nh1
->next
)
435 for (nh2
= r2
->nexthop
; nh2
; nh2
= nh2
->next
)
437 if (CHECK_FLAG (nh2
->flags
, NEXTHOP_FLAG_MATCHED
))
440 if (nexthop_same_no_recurse(nh1
, nh2
))
442 SET_FLAG (nh2
->flags
, NEXTHOP_FLAG_MATCHED
);
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
);
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
);
465 send_client (struct rnh
*rnh
, struct zserv
*client
)
471 struct nexthop
*nexthop
;
472 struct route_node
*rn
;
477 /* Get output stream. */
481 zserv_create_header (s
, ZEBRA_NEXTHOP_UPDATE
);
483 stream_putw(s
, rn
->p
.family
);
484 stream_put_prefix (s
, &rn
->p
);
488 stream_putl (s
, rib
->metric
);
490 nump
= stream_get_endp(s
);
492 for (nexthop
= rib
->nexthop
; nexthop
; nexthop
= nexthop
->next
)
493 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))
495 stream_putc (s
, nexthop
->type
);
496 switch (nexthop
->type
)
498 case ZEBRA_NEXTHOP_IPV4
:
499 stream_put_in_addr (s
, &nexthop
->gate
.ipv4
);
501 case ZEBRA_NEXTHOP_IFINDEX
:
502 case ZEBRA_NEXTHOP_IFNAME
:
503 stream_putl (s
, nexthop
->ifindex
);
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
);
511 case ZEBRA_NEXTHOP_IPV6
:
512 stream_put (s
, &nexthop
->gate
.ipv6
, 16);
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
);
519 #endif /* HAVE_IPV6 */
526 stream_putc_at (s
, nump
, num
);
533 stream_putw_at (s
, 0, stream_get_endp (s
));
534 return zebra_server_send_message(client
);
538 print_nh (struct nexthop
*nexthop
, struct vty
*vty
)
542 switch (nexthop
->type
)
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
));
550 case NEXTHOP_TYPE_IPV6
:
551 case NEXTHOP_TYPE_IPV6_IFINDEX
:
552 case NEXTHOP_TYPE_IPV6_IFNAME
:
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
));
560 case NEXTHOP_TYPE_IFINDEX
:
561 vty_out (vty
, " is directly connected, %s",
562 ifindex2ifname (nexthop
->ifindex
));
564 case NEXTHOP_TYPE_IFNAME
:
565 vty_out (vty
, " is directly connected, %s", nexthop
->ifname
);
567 case NEXTHOP_TYPE_BLACKHOLE
:
568 vty_out (vty
, " is directly connected, Null0");
573 vty_out(vty
, "%s", VTY_NEWLINE
);
577 print_rnh (struct route_node
*rn
, struct vty
*vty
)
580 struct nexthop
*nexthop
;
581 struct listnode
*node
;
582 struct zserv
*client
;
586 vty_out(vty
, "%s%s", inet_ntop(rn
->p
.family
, &rn
->p
.u
.prefix
, buf
, BUFSIZ
),
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
);
596 vty_out(vty
, " unresolved%s", VTY_NEWLINE
);
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
),
602 vty_out(vty
, "%s", VTY_NEWLINE
);