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) \
49 struct zebra_vrf *zvrf; \
50 struct route_table *t = NULL; \
51 zvrf = zebra_vrf_lookup(v); \
53 t = zvrf->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, vrf_id_t vrf_id);
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, vrf_id_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, vrf_id_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, vrf_id_t vrf_id)
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, vrf_id);
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 (vrf_id_t 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 = zebra_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))
217 prn = route_node_match(ptable, &nrn->p);
222 RNODE_FOREACH_RIB(prn, rib)
224 if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
226 if (! CHECK_FLAG (rib->status, RIB_ENTRY_SELECTED_FIB))
229 if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
231 if (rib->type == ZEBRA_ROUTE_CONNECT)
234 if (rib->type == ZEBRA_ROUTE_NHRP)
236 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)
250 if (compare_state(rib, rnh->state))
252 if (IS_ZEBRA_DEBUG_NHT)
254 char bufn[INET6_ADDRSTRLEN];
255 char bufp[INET6_ADDRSTRLEN];
256 prefix2str(&nrn->p, bufn, INET6_ADDRSTRLEN);
258 prefix2str(&prn->p, bufp, INET6_ADDRSTRLEN);
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");
265 copy_state(rnh, rib);
266 for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
267 send_client(rnh, client, vrfid);
274 zebra_dispatch_rnh_table (vrf_id_t vrfid, int family, struct zserv *client)
276 struct route_table *ntable;
277 struct route_node *nrn;
280 ntable = lookup_rnh_table(vrfid, family);
283 zlog_debug("dispatch_rnh_table: rnh table not found\n");
287 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
293 if (IS_ZEBRA_DEBUG_NHT)
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));
301 send_client(rnh, client, vrfid);
307 zebra_print_rnh_table (vrf_id_t vrfid, int af, struct vty *vty)
309 struct route_table *table;
310 struct route_node *rn;
312 table = lookup_rnh_table(vrfid, af);
315 zlog_debug("print_rnhs: rnh table not found\n");
319 for (rn = route_top(table); rn; rn = route_next(rn))
325 zebra_cleanup_rnh_client (vrf_id_t vrfid, int family, struct zserv *client)
327 struct route_table *ntable;
328 struct route_node *nrn;
331 ntable = lookup_rnh_table(vrfid, family);
334 zlog_debug("cleanup_rnh_client: rnh table not found\n");
338 for (nrn = route_top (ntable); nrn; nrn = route_next (nrn))
344 if (IS_ZEBRA_DEBUG_NHT)
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));
351 zebra_remove_rnh_client(rnh, client);
357 * free_state - free up the rib structure associated with the rnh.
360 free_state (struct rib *rib)
362 struct nexthop *nexthop, *next;
367 /* free RIB and nexthops */
368 for (nexthop = rib->nexthop; nexthop; nexthop = next)
370 next = nexthop->next;
371 nexthop_free (nexthop);
373 XFREE (MTYPE_RIB, rib);
377 * copy_nexthop - copy a nexthop to the rib structure.
380 rib_copy_nexthop (struct rib *state, struct nexthop *nh)
382 struct nexthop *nexthop;
384 nexthop = nexthop_new();
385 nexthop->flags = nh->flags;
386 nexthop->type = nh->type;
387 nexthop->ifindex = nh->ifindex;
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));
393 rib_nexthop_add(state, nexthop);
397 copy_state (struct rnh *rnh, struct rib *rib)
404 free_state(rnh->state);
411 state = XCALLOC (MTYPE_RIB, sizeof (struct rib));
412 state->type = rib->type;
413 state->metric = rib->metric;
415 for (nh = rib->nexthop; nh; nh = nh->next)
416 rib_copy_nexthop(state, nh);
421 compare_state (struct rib *r1, struct rib *r2)
430 if ((!r1 && r2) || (r1 && !r2))
433 if (r1->metric != r2->metric)
436 if (r1->nexthop_num != r2->nexthop_num)
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
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]
451 for (nh1 = r1->nexthop; nh1; nh1 = nh1->next)
454 for (nh2 = r2->nexthop; nh2; nh2 = nh2->next)
456 if (CHECK_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED))
459 if (nexthop_same_no_recurse(nh1, nh2))
461 SET_FLAG (nh2->flags, NEXTHOP_FLAG_MATCHED);
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);
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);
484 send_client (struct rnh *rnh, struct zserv *client, vrf_id_t vrf_id)
490 struct nexthop *nexthop;
491 struct route_node *rn;
496 /* Get output stream. */
500 zserv_create_header (s, ZEBRA_NEXTHOP_UPDATE, vrf_id);
502 stream_putw(s, rn->p.family);
503 stream_put_prefix (s, &rn->p);
507 stream_putl (s, rib->metric);
509 nump = stream_get_endp(s);
511 for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
512 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) &&
513 ! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) &&
514 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
516 stream_putc (s, nexthop->type);
517 switch (nexthop->type)
519 case ZEBRA_NEXTHOP_IPV4:
520 stream_put_in_addr (s, &nexthop->gate.ipv4);
522 case ZEBRA_NEXTHOP_IFINDEX:
523 case ZEBRA_NEXTHOP_IFNAME:
524 stream_putl (s, nexthop->ifindex);
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);
532 case ZEBRA_NEXTHOP_IPV6:
533 stream_put (s, &nexthop->gate.ipv6, 16);
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);
540 #endif /* HAVE_IPV6 */
547 stream_putc_at (s, nump, num);
554 stream_putw_at (s, 0, stream_get_endp (s));
556 client->nh_last_upd_time = quagga_time(NULL);
557 client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
558 return zebra_server_send_message(client);
562 print_nh (struct nexthop *nexthop, struct vty *vty)
566 switch (nexthop->type)
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));
574 case NEXTHOP_TYPE_IPV6:
575 case NEXTHOP_TYPE_IPV6_IFINDEX:
576 case NEXTHOP_TYPE_IPV6_IFNAME:
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));
584 case NEXTHOP_TYPE_IFINDEX:
585 vty_out (vty, " is directly connected, %s",
586 ifindex2ifname (nexthop->ifindex));
588 case NEXTHOP_TYPE_IFNAME:
589 vty_out (vty, " is directly connected, %s", nexthop->ifname);
591 case NEXTHOP_TYPE_BLACKHOLE:
592 vty_out (vty, " is directly connected, Null0");
597 vty_out(vty, "%s", VTY_NEWLINE);
601 print_rnh (struct route_node *rn, struct vty *vty)
604 struct nexthop *nexthop;
605 struct listnode *node;
606 struct zserv *client;
610 vty_out(vty, "%s%s", inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
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);
620 vty_out(vty, " unresolved%s%s",
621 CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" : "",
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),
628 vty_out(vty, "%s", VTY_NEWLINE);