summaryrefslogtreecommitdiff
path: root/ospf6d/ospf6_route.c
diff options
context:
space:
mode:
Diffstat (limited to 'ospf6d/ospf6_route.c')
-rw-r--r--ospf6d/ospf6_route.c1791
1 files changed, 896 insertions, 895 deletions
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index b3abedc3..73bdac2d 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
*
* This file is part of GNU Zebra.
*
@@ -19,1118 +19,1119 @@
* Boston, MA 02111-1307, USA.
*/
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+
#include "ospf6d.h"
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_route.h"
-char *
-dtype_name[OSPF6_DEST_TYPE_MAX] =
-{
- "Unknown", "Router", "Network", "Discard"
-};
-#define DTYPE_NAME(x) \
- (0 < (x) && (x) < sizeof (dtype_name) ? \
- dtype_name[(x)] : dtype_name[0])
-
-char *
-dtype_abname[OSPF6_DEST_TYPE_MAX] =
-{
- "?", "R", "N", "D"
-};
-#define DTYPE_ABNAME(x) \
- (0 < (x) && (x) < sizeof (dtype_abname) ? \
- dtype_abname[(x)] : dtype_abname[0])
-
-char *
-ptype_name[OSPF6_PATH_TYPE_MAX] =
-{
- "Unknown", "Intra", "Inter", "External-1", "External-2",
- "System", "Kernel", "Connect", "Static", "RIP", "RIPng",
- "OSPF", "OSPF6", "BGP"
-};
-#define PTYPE_NAME(x) \
- (0 < (x) && (x) < sizeof (ptype_name) ? \
- ptype_name[(x)] : ptype_name[0])
-
-char *
-ptype_abname[OSPF6_PATH_TYPE_MAX] =
-{
- "??", "Ia", "Ie", "E1", "E2",
- "-X", "-K", "-C", "-S", "-R", "-R",
- "-O", "-O", "-B"
-};
-#define PTYPE_ABNAME(x) \
- (0 < (x) && (x) < sizeof (ptype_abname) ? \
- ptype_abname[(x)] : ptype_abname[0])
+unsigned char conf_debug_ospf6_route = 0;
-
+void
+ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
+ struct prefix *prefix)
+{
+ memset (prefix, 0, sizeof (struct prefix));
+ prefix->family = AF_INET6;
+ prefix->prefixlen = 64;
+ memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4);
+ memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4);
+}
-int
-ospf6_path_cmp (void *arg1, void *arg2)
+void
+ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size)
{
- struct ospf6_path_node *pn1 = arg1;
- struct ospf6_path_node *pn2 = arg2;
- struct ospf6_path *p1 = &pn1->path;
- struct ospf6_path *p2 = &pn2->path;
+ u_int32_t adv_router, id;
+ char adv_router_str[16];
+ memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4);
+ memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4);
+ inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str));
+ snprintf (buf, size, "%s(%lu)", adv_router_str, (u_long) ntohl (id));
+}
- if (p1->type < p2->type)
- return -1;
- else if (p1->type > p2->type)
- return 1;
+/* Global strings for logging */
+char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] =
+{ "Unknown", "Router", "Network", "Discard", "Linkstate", };
- if (p1->type == OSPF6_PATH_TYPE_EXTERNAL2)
- {
- if (p1->cost_e2 < p2->cost_e2)
- return -1;
- else if (p1->cost_e2 > p2->cost_e2)
- return 1;
- }
+char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] =
+{ "?", "R", "N", "D", "L", };
- if (p1->cost < p2->cost)
- return -1;
- else if (p1->cost > p2->cost)
- return 1;
+char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] =
+{ "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", };
- /* if from the same source, recognize as identical
- (and treat this as update) */
- if (! memcmp (&p1->origin, &p2->origin, sizeof (struct ls_origin)) &&
- p1->area_id == p2->area_id)
- return 0;
+char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
+{ "??", "Ia", "Ie", "E1", "E2", };
- /* else, always prefer left */
- return -1;
-}
-int
-ospf6_nexthop_cmp (void *arg1, void *arg2)
+struct ospf6_route *
+ospf6_route_create ()
{
- int i, ret = 0;
- struct ospf6_nexthop_node *nn1 = arg1;
- struct ospf6_nexthop_node *nn2 = arg2;
- struct ospf6_nexthop *n1 = &nn1->nexthop;
- struct ospf6_nexthop *n2 = &nn2->nexthop;
-
- if (memcmp (n1, n2, sizeof (struct ospf6_nexthop)) == 0)
- return 0;
-
- for (i = 0; i < sizeof (struct in6_addr); i++)
- {
- if (nn1->nexthop.address.s6_addr[i] != nn2->nexthop.address.s6_addr[i])
- {
- ret = nn1->nexthop.address.s6_addr[i] -
- nn2->nexthop.address.s6_addr[i];
- break;
- }
- }
-
- if (ret == 0)
- ret = -1;
+ struct ospf6_route *route;
+ route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
+ return route;
+}
- return ret;
+void
+ospf6_route_delete (struct ospf6_route *route)
+{
+ XFREE (MTYPE_OSPF6_ROUTE, route);
}
-static void
-ospf6_route_request (struct ospf6_route_req *request,
- struct ospf6_route_node *rn,
- struct ospf6_path_node *pn,
- struct ospf6_nexthop_node *nn)
+struct ospf6_route *
+ospf6_route_copy (struct ospf6_route *route)
{
- assert (request);
- assert (rn && pn && nn);
+ struct ospf6_route *new;
+
+ new = ospf6_route_create ();
+ memcpy (new, route, sizeof (struct ospf6_route));
+ new->rnode = NULL;
+ new->prev = NULL;
+ new->next = NULL;
+ new->lock = 0;
+ return new;
+}
- request->route_node = rn->route_node;
+void
+ospf6_route_lock (struct ospf6_route *route)
+{
+ route->lock++;
+}
- linklist_head (rn->path_list, &request->path_lnode);
- while (request->path_lnode.data != pn)
- {
- //assert (! linklist_end (&request->path_lnode));
- if (linklist_end (&request->path_lnode))
- {
- struct linklist_node node;
+void
+ospf6_route_unlock (struct ospf6_route *route)
+{
+ assert (route->lock > 0);
+ route->lock--;
+ if (route->lock == 0)
+ ospf6_route_delete (route);
+}
- zlog_info ("rn: %p, pn: %p", rn, pn);
- zlog_info ("origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost %d %d %d",
- pn->path.origin.type, pn->path.origin.id, pn->path.origin.adv_router, (int)pn->path.router_bits, (int)pn->path.capability[0],
- (int)pn->path.capability[1], (int)pn->path.capability[2],
- (int)pn->path.prefix_options, pn->path.area_id,
- pn->path.type, pn->path.metric_type, pn->path.cost, pn->path.cost_e2);
+/* Route compare function. If ra is more preferred, it returns
+ less than 0. If rb is more preferred returns greater than 0.
+ Otherwise (neither one is preferred), returns 0 */
+static int
+ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
+{
+ assert (ospf6_route_is_same (ra, rb));
+ assert (OSPF6_PATH_TYPE_NONE < ra->path.type &&
+ ra->path.type < OSPF6_PATH_TYPE_MAX);
+ assert (OSPF6_PATH_TYPE_NONE < rb->path.type &&
+ rb->path.type < OSPF6_PATH_TYPE_MAX);
- for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
- linklist_next (&node))
- {
- struct ospf6_path_node *pn2 = node.data;
+ if (ra->type != rb->type)
+ return (ra->type - rb->type);
- zlog_info (" %p: path data with pn(%p): %s", pn2, pn,
- (memcmp (&pn->path, &pn2->path,
- sizeof (struct ospf6_path)) ?
- "different" : "same"));
+ if (ra->path.area_id != rb->path.area_id)
+ return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id));
- zlog_info (" origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost %d %d %d",
- pn2->path.origin.type, pn2->path.origin.id, pn2->path.origin.adv_router, (int)pn2->path.router_bits, (int)pn2->path.capability[0],
- (int)pn2->path.capability[1], (int)pn2->path.capability[2],
- (int)pn2->path.prefix_options, pn2->path.area_id,
- pn2->path.type, pn2->path.metric_type, pn2->path.cost, pn2->path.cost_e2);
+ if (ra->path.type != rb->path.type)
+ return (ra->path.type - rb->path.type);
- if (! memcmp (&pn->path, &pn2->path, sizeof (struct ospf6_path)))
- {
- pn = pn2;
- request->nexthop_lnode.data = pn2;
- }
- }
- break;
- }
- linklist_next (&request->path_lnode);
+ if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
+ {
+ if (ra->path.cost_e2 != rb->path.cost_e2)
+ return (ra->path.cost_e2 - rb->path.cost_e2);
}
- assert (request->path_lnode.data == pn);
-
- linklist_head (pn->nexthop_list, &request->nexthop_lnode);
- while (request->nexthop_lnode.data != nn)
+ else
{
- assert (! linklist_end (&request->nexthop_lnode));
- linklist_next (&request->nexthop_lnode);
+ if (ra->path.cost != rb->path.cost)
+ return (ra->path.cost - rb->path.cost);
}
- assert (request->nexthop_lnode.data == nn);
-
- request->table = rn->table;
- request->count = rn->count;
- request->route_id = rn->route_id;
- memcpy (&request->route, &rn->route, sizeof (struct ospf6_route));
- memcpy (&request->path, &pn->path, sizeof (struct ospf6_path));
- memcpy (&request->nexthop, &nn->nexthop, sizeof (struct ospf6_nexthop));
-}
-int
-ospf6_route_count (struct ospf6_route_req *request)
-{
- return request->count;
+ return 0;
}
-int
-ospf6_route_lookup (struct ospf6_route_req *request,
- struct prefix *prefix,
+struct ospf6_route *
+ospf6_route_lookup (struct prefix *prefix,
struct ospf6_route_table *table)
{
struct route_node *node;
- struct ospf6_route_node *rn = NULL;
- struct ospf6_path_node *pn = NULL;
- struct ospf6_nexthop_node *nn = NULL;
- struct linklist_node lnode;
-
- if (request)
- memset ((void *) request, 0, sizeof (struct ospf6_route_req));
+ struct ospf6_route *route;
node = route_node_lookup (table->table, prefix);
- if (! node)
- return 0;
+ if (node == NULL)
+ return NULL;
+
+ route = (struct ospf6_route *) node->info;
+ return route;
+}
- rn = (struct ospf6_route_node *) node->info;
- if (! rn)
- return 0;
+struct ospf6_route *
+ospf6_route_lookup_identical (struct ospf6_route *route,
+ struct ospf6_route_table *table)
+{
+ struct ospf6_route *target;
- if (request)
+ for (target = ospf6_route_lookup (&route->prefix, table);
+ target; target = target->next)
{
- linklist_head (rn->path_list, &lnode);
- pn = lnode.data;
- linklist_head (pn->nexthop_list, &lnode);
- nn = lnode.data;
-
- ospf6_route_request (request, rn, pn, nn);
+ if (ospf6_route_is_identical (target, route))
+ return target;
}
-
- return 1;
+ return NULL;
}
-void
-ospf6_route_head (struct ospf6_route_req *request,
- struct ospf6_route_table *table)
+struct ospf6_route *
+ospf6_route_lookup_bestmatch (struct prefix *prefix,
+ struct ospf6_route_table *table)
{
struct route_node *node;
- struct ospf6_route_node *rn = NULL;
- struct ospf6_path_node *pn = NULL;
- struct ospf6_nexthop_node *nn = NULL;
- struct linklist_node lnode;
+ struct ospf6_route *route;
- if (request)
- memset (request, 0, sizeof (struct ospf6_route_req));
+ node = route_node_match (table->table, prefix);
+ if (node == NULL)
+ return NULL;
+ route_unlock_node (node);
- node = route_top (table->table);
- if (! node)
- return;
-
- while (node && node->info == NULL)
- node = route_next (node);
- if (! node)
- return;
-
- rn = (struct ospf6_route_node *) node->info;
- linklist_head (rn->path_list, &lnode);
- pn = lnode.data;
- linklist_head (pn->nexthop_list, &lnode);
- nn = lnode.data;
-
- ospf6_route_request (request, rn, pn, nn);
+ route = (struct ospf6_route *) node->info;
+ return route;
}
-int
-ospf6_route_end (struct ospf6_route_req *request)
+#ifndef NDEBUG
+static void
+_route_count_assert (struct ospf6_route_table *table)
{
- if (request->route_node == NULL &&
- linklist_end (&request->path_lnode) &&
- linklist_end (&request->nexthop_lnode) &&
- request->nexthop.ifindex == 0 &&
- IN6_IS_ADDR_UNSPECIFIED (&request->nexthop.address))
- return 1;
- return 0;
+ struct ospf6_route *debug;
+ int num = 0;
+ for (debug = ospf6_route_head (table); debug;
+ debug = ospf6_route_next (debug))
+ num++;
+ assert (num == table->count);
}
+#define ospf6_route_count_assert(t) (_route_count_assert (t))
+#else
+#define ospf6_route_count_assert(t) ((void) 0)
+#endif /*NDEBUG*/
-void
-ospf6_route_next (struct ospf6_route_req *request)
+struct ospf6_route *
+ospf6_route_add (struct ospf6_route *route,
+ struct ospf6_route_table *table)
{
- struct ospf6_route_node *route_node = NULL;
- struct ospf6_path_node *path_node = NULL;
- struct ospf6_nexthop_node *nexthop_node = NULL;
+ struct route_node *node, *nextnode, *prevnode;
+ struct ospf6_route *current = NULL;
+ struct ospf6_route *prev = NULL, *old = NULL, *next = NULL;
+ char buf[64];
+ struct timeval now;
+
+ assert (route->rnode == NULL);
+ assert (route->lock == 0);
+ assert (route->next == NULL);
+ assert (route->prev == NULL);
+
+ if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+ ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
+ else
+ prefix2str (&route->prefix, buf, sizeof (buf));
- linklist_next (&request->nexthop_lnode);
- if (linklist_end (&request->nexthop_lnode))
- {
- linklist_next (&request->path_lnode);
- if (linklist_end (&request->path_lnode))
- {
- request->route_node = route_next (request->route_node);
- while (request->route_node && request->route_node->info == NULL)
- request->route_node = route_next (request->route_node);
- if (request->route_node)
- {
- route_node = request->route_node->info;
- if (route_node)
- linklist_head (route_node->path_list, &request->path_lnode);
- }
- }
+ if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+ zlog_info ("route add %s", buf);
- path_node = request->path_lnode.data;
- if (path_node)
- linklist_head (path_node->nexthop_list, &request->nexthop_lnode);
- }
+ gettimeofday (&now, NULL);
- nexthop_node = request->nexthop_lnode.data;
+ node = route_node_get (table->table, &route->prefix);
+ route->rnode = node;
- if (nexthop_node == NULL)
+ /* find place to insert */
+ for (current = node->info; current; current = current->next)
{
- assert (path_node == NULL);
- assert (route_node == NULL);
+ if (! ospf6_route_is_same (current, route))
+ next = current;
+ else if (current->type != route->type)
+ prev = current;
+ else if (ospf6_route_is_same_origin (current, route))
+ old = current;
+ else if (ospf6_route_cmp (current, route) > 0)
+ next = current;
+ else
+ prev = current;
- memset (&request->route, 0, sizeof (struct ospf6_route));
- memset (&request->path, 0, sizeof (struct ospf6_path));
- memset (&request->nexthop, 0, sizeof (struct ospf6_nexthop));
+ if (old || next)
+ break;
}
- else
+
+ if (old)
{
- path_node = request->path_lnode.data;
- route_node = request->route_node->info;
-
- assert (path_node != NULL);
- assert (route_node != NULL);
-
- memcpy (&request->route, &route_node->route,
- sizeof (struct ospf6_route));
- memcpy (&request->path, &path_node->path,
- sizeof (struct ospf6_path));
- memcpy (&request->nexthop, &nexthop_node->nexthop,
- sizeof (struct ospf6_nexthop));
- }
-}
+ /* if route does not actually change, return unchanged */
+ if (ospf6_route_is_identical (old, route))
+ {
+ if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+ zlog_info (" identical route found, ignore");
-#define ADD 0
-#define CHANGE 1
-#define REMOVE 2
+ ospf6_route_delete (route);
+ SET_FLAG (old->flag, OSPF6_ROUTE_ADD);
+ ospf6_route_count_assert (table);
+ return old;
+ }
-void
-ospf6_route_hook_call (int type,
- struct ospf6_route_req *request,
- struct ospf6_route_table *table)
-{
- struct linklist_node node;
- void (*func) (struct ospf6_route_req *);
+ if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+ zlog_info (" old route found, replace");
- for (linklist_head (table->hook_list[type], &node);
- ! linklist_end (&node);
- linklist_next (&node))
- {
- func = node.data;
- (*func) (request);
- }
-}
+ /* replace old one if exists */
+ if (node->info == old)
+ {
+ node->info = route;
+ SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+ }
-void
-ospf6_route_hook_register (void (*add) (struct ospf6_route_req *),
- void (*change) (struct ospf6_route_req *),
- void (*remove) (struct ospf6_route_req *),
- struct ospf6_route_table *table)
-{
- linklist_add (add, table->hook_list[ADD]);
- linklist_add (change, table->hook_list[CHANGE]);
- linklist_add (remove, table->hook_list[REMOVE]);
-}
+ if (old->prev)
+ old->prev->next = route;
+ route->prev = old->prev;
+ if (old->next)
+ old->next->prev = route;
+ route->next = old->next;
-void
-ospf6_route_hook_unregister (void (*add) (struct ospf6_route_req *),
- void (*change) (struct ospf6_route_req *),
- void (*remove) (struct ospf6_route_req *),
- struct ospf6_route_table *table)
-{
- linklist_remove (add, table->hook_list[ADD]);
- linklist_remove (change, table->hook_list[CHANGE]);
- linklist_remove (remove, table->hook_list[REMOVE]);
-}
+ route->installed = old->installed;
+ route->changed = now;
+ ospf6_route_unlock (old); /* will be deleted later */
+ ospf6_route_lock (route);
-int
-prefix_ls2str (struct prefix *p, char *str, int size)
-{
- char id[BUFSIZ], adv_router[BUFSIZ];
- struct prefix_ls *pl = (struct prefix_ls *) p;
+ SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE);
+ if (table->hook_add)
+ (*table->hook_add) (route);
- inet_ntop (AF_INET, &pl->id, id, BUFSIZ);
- inet_ntop (AF_INET, &pl->adv_router, adv_router, BUFSIZ);
- snprintf (str, size, "%s-%s", adv_router, id);
- return 0;
-}
+ ospf6_route_count_assert (table);
+ return route;
+ }
-void
-ospf6_route_log_request (char *what, char *where,
- struct ospf6_route_req *request)
-{
- char prefix[64];
- char area_id[16];
- char type[16], id[16], adv[16];
- char address[64], ifname[IFNAMSIZ];
-
- if (request->route.prefix.family != AF_INET &&
- request->route.prefix.family != AF_INET6)
- prefix_ls2str (&request->route.prefix, prefix, sizeof (prefix));
- else
- prefix2str (&request->route.prefix, prefix, sizeof (prefix));
-
- inet_ntop (AF_INET, &request->path.area_id, area_id, sizeof (area_id));
-
- ospf6_lsa_type_string (request->path.origin.type, type, sizeof (type));
- inet_ntop (AF_INET, &request->path.origin.id, id, sizeof (id));
- inet_ntop (AF_INET, &request->path.origin.adv_router, adv, sizeof (adv));
-
- inet_ntop (AF_INET6, &request->nexthop.address, address, sizeof (address));
-
- zlog_info ("ROUTE: %s %s %s %s %s",
- what, DTYPE_ABNAME (request->route.type), prefix,
- ((strcmp ("Add", what) == 0) ? "to" : "from"), where);
- zlog_info ("ROUTE: Area: %s type: %s cost: %lu (E2: %lu)",
- area_id, PTYPE_NAME (request->path.type),
- (u_long) request->path.cost, (u_long) request->path.cost_e2);
- zlog_info ("ROUTE: Origin: Type: %s", type);
- zlog_info ("ROUTE: Origin: Id: %s Adv: %s", id, adv);
- zlog_info ("ROUTE: Nexthop: %s", address);
- zlog_info ("ROUTE: Nexthop: Ifindex: %u (%s)",
- request->nexthop.ifindex,
- if_indextoname (request->nexthop.ifindex, ifname));
-}
+ /* insert if previous or next node found */
+ if (prev || next)
+ {
+ if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+ zlog_info (" another path found, insert");
+
+ if (prev == NULL)
+ prev = next->prev;
+ if (next == NULL)
+ next = prev->next;
+
+ if (prev)
+ prev->next = route;
+ route->prev = prev;
+ if (next)
+ next->prev = route;
+ route->next = next;
+
+ if (node->info == next)
+ {
+ assert (next->rnode == node);
+ node->info = route;
+ UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST);
+ SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+ }
-struct ospf6_path_node *
-ospf6_route_find_path_node (struct ospf6_route_req *request,
- struct ospf6_route_node *rn)
-{
- struct linklist_node node;
+ route->installed = now;
+ route->changed = now;
- for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
- linklist_next (&node))
- {
- struct ospf6_path_node *path_node = node.data;
+ ospf6_route_lock (route);
+ table->count++;
+
+ SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
+ if (table->hook_add)
+ (*table->hook_add) (route);
- if (path_node->path.area_id == request->path.area_id &&
- path_node->path.origin.type == request->path.origin.type &&
- path_node->path.origin.id == request->path.origin.id &&
- path_node->path.origin.adv_router == request->path.origin.adv_router)
- return path_node;
+ ospf6_route_count_assert (table);
+ return route;
}
-#if 0
- zlog_info ("req path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
- request->path.area_id, request->path.origin.type,
- request->path.origin.id, request->path.origin.adv_router);
- for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
- linklist_next (&node))
+ /* Else, this is the brand new route regarding to the prefix */
+ if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+ zlog_info (" brand new route, add");
+
+ assert (node->info == NULL);
+ node->info = route;
+ SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+ ospf6_route_lock (route);
+ route->installed = now;
+ route->changed = now;
+
+ /* lookup real existing next route */
+ nextnode = node;
+ route_lock_node (nextnode);
+ do {
+ nextnode = route_next (nextnode);
+ } while (nextnode && nextnode->info == NULL);
+
+ /* set next link */
+ if (nextnode == NULL)
+ route->next = NULL;
+ else
{
- struct ospf6_path_node *path_node = node.data;
- zlog_info (" path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
- path_node->path.area_id, path_node->path.origin.type,
- path_node->path.origin.id, path_node->path.origin.adv_router);
+ route_unlock_node (nextnode);
+
+ next = nextnode->info;
+ route->next = next;
+ next->prev = route;
}
-#endif
- return NULL;
-}
+ /* lookup real existing prev route */
+ prevnode = node;
+ route_lock_node (prevnode);
+ do {
+ prevnode = route_prev (prevnode);
+ } while (prevnode && prevnode->info == NULL);
-struct ospf6_nexthop_node *
-ospf6_route_find_nexthop_node (struct ospf6_route_req *request,
- struct ospf6_path_node *pn)
-{
- struct linklist_node node;
- for (linklist_head (pn->nexthop_list, &node); ! linklist_end (&node);
- linklist_next (&node))
+ /* set prev link */
+ if (prevnode == NULL)
+ route->prev = NULL;
+ else
{
- struct ospf6_nexthop_node *nexthop_node = node.data;
+ route_unlock_node (prevnode);
- if (! memcmp (&nexthop_node->nexthop, &request->nexthop,
- sizeof (struct ospf6_nexthop)))
- return nexthop_node;
+ prev = prevnode->info;
+ while (prev->next && ospf6_route_is_same (prev, prev->next))
+ prev = prev->next;
+ route->prev = prev;
+ prev->next = route;
}
- return NULL;
+
+ table->count++;
+
+ SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
+ if (table->hook_add)
+ (*table->hook_add) (route);
+
+ ospf6_route_count_assert (table);
+ return route;
}
void
-ospf6_route_add (struct ospf6_route_req *request,
- struct ospf6_route_table *table)
+ospf6_route_remove (struct ospf6_route *route,
+ struct ospf6_route_table *table)
{
- struct ospf6_route_node *rn;
- struct ospf6_path_node *pn;
- struct ospf6_nexthop_node *nn;
- struct route_node *route_node;
+ struct route_node *node;
+ struct ospf6_route *current;
+ char buf[64];
- struct ospf6_route_req route;
+ if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+ ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
+ else
+ prefix2str (&route->prefix, buf, sizeof (buf));
- int route_change = 0;
- int path_change = 0;
- int nexthop_change = 0;
+ if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+ zlog_info ("route remove: %s", buf);
- /* find the requested route */
- route_node = route_node_get (table->table, &request->route.prefix);
- rn = (struct ospf6_route_node *) route_node->info;
+ node = route_node_lookup (table->table, &route->prefix);
+ assert (node);
- if (rn)
+ /* find the route to remove, making sure that the route pointer
+ is from the route table. */
+ current = node->info;
+ while (current && ospf6_route_is_same (current, route))
{
- if (memcmp (&rn->route, &request->route, sizeof (struct ospf6_route)))
- {
- memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
- route_change++;
- }
- }
- else
- {
- rn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_node));
- rn->table = table;
- rn->route_node = route_node;
- rn->route_id = table->route_id++;
- rn->path_list = linklist_create ();
- rn->path_list->cmp = ospf6_path_cmp;
- memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
- route_node->info = rn;
+ if (current == route)
+ break;
+ current = current->next;
}
+ assert (current == route);
- /* find the same path */
- pn = ospf6_route_find_path_node (request, rn);
+ /* adjust doubly linked list */
+ if (route->prev)
+ route->prev->next = route->next;
+ if (route->next)
+ route->next->prev = route->prev;
- if (pn)
+ if (node->info == route)
{
- if (memcmp (&pn->path, &request->path, sizeof (struct ospf6_path)))
+ if (route->next && ospf6_route_is_same (route->next, route))
{
- memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
- path_change++;
+ node->info = route->next;
+ SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
}
- }
- else
- {
- pn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_path_node));
- pn->route_node = rn;
- pn->nexthop_list = linklist_create ();
- pn->nexthop_list->cmp = ospf6_nexthop_cmp;
- memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
- linklist_add (pn, rn->path_list);
+ else
+ node->info = NULL; /* should unlock route_node here ? */
}
- /* find the same nexthop */
- nn = ospf6_route_find_nexthop_node (request, pn);
+ if (table->hook_remove)
+ (*table->hook_remove) (route);
- if (nn)
- {
- if (memcmp (&nn->nexthop, &request->nexthop,
- sizeof (struct ospf6_nexthop)))
- {
- memcpy (&nn->nexthop, &request->nexthop,
- sizeof (struct ospf6_nexthop));
- nexthop_change++;
- gettimeofday (&nn->installed, (struct timezone *) NULL);
- }
- }
- else
- {
- nn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_nexthop_node));
- nn->path_node = pn;
- memcpy (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop));
- linklist_add (nn, pn->nexthop_list);
- rn->count++;
- gettimeofday (&nn->installed, (struct timezone *) NULL);
- }
+ ospf6_route_unlock (route);
+ table->count--;
- SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD);
- if (route_change)
- SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE);
- if (path_change)
- SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE);
- if (nexthop_change)
- SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
+ ospf6_route_count_assert (table);
+}
- if (table->freeze)
- return;
+struct ospf6_route *
+ospf6_route_head (struct ospf6_route_table *table)
+{
+ struct route_node *node;
+ struct ospf6_route *route;
- if (IS_OSPF6_DUMP_ROUTE)
- {
- ospf6_route_log_request ("Add", table->name, request);
-
- if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE))
- zlog_info ("ROUTE: route attribute change");
- if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
- zlog_info ("ROUTE: path attribute change");
- if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
- zlog_info ("ROUTE: nexthop attribute change");
- }
+ node = route_top (table->table);
+ if (node == NULL)
+ return NULL;
+
+ /* skip to the real existing entry */
+ while (node && node->info == NULL)
+ node = route_next (node);
+ if (node == NULL)
+ return NULL;
- if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE) ||
- CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
- SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
-
- /* Call hooks */
- ospf6_route_request (&route, rn, pn, nn);
- if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
- ospf6_route_hook_call (ADD, &route, table);
- else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
- ospf6_route_hook_call (CHANGE, &route, table);
-
- if (table->hook_add &&
- CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
- (*table->hook_add) (&route);
- else if (table->hook_change &&
- CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
- (*table->hook_change) (&route);
-
- /* clear flag */
- nn->flag = 0;
+ route_unlock_node (node);
+ assert (node->info);
+
+ route = (struct ospf6_route *) node->info;
+ assert (route->prev == NULL);
+ ospf6_route_lock (route);
+ return route;
}
-void
-ospf6_route_remove (struct ospf6_route_req *request,
- struct ospf6_route_table *table)
+struct ospf6_route *
+ospf6_route_next (struct ospf6_route *route)
{
- struct ospf6_route_node *rn;
- struct ospf6_path_node *pn;
- struct ospf6_nexthop_node *nn;
- struct route_node *route_node;
- struct ospf6_route_req route;
+ struct ospf6_route *next = route->next;
- /* find the requested route */
- route_node = route_node_get (table->table, &request->route.prefix);
- rn = (struct ospf6_route_node *) route_node->info;
+ ospf6_route_unlock (route);
+ if (next)
+ ospf6_route_lock (next);
- if (! rn)
- {
- if (IS_OSPF6_DUMP_ROUTE)
- {
- ospf6_route_log_request ("Remove", table->name, request);
- zlog_info ("ROUTE: Can't remove: No such route");
- }
- return;
- }
+ return next;
+}
- pn = ospf6_route_find_path_node (request, rn);
- if (! pn)
- {
- if (IS_OSPF6_DUMP_ROUTE)
- {
- ospf6_route_log_request ("Remove", table->name, request);
- zlog_info ("ROUTE: Can't remove: No such path");
- }
- return;
- }
+struct ospf6_route *
+ospf6_route_best_next (struct ospf6_route *route)
+{
+ struct route_node *rnode;
+ struct ospf6_route *next;
+
+ rnode = route->rnode;
+ route_lock_node (rnode);
+ rnode = route_next (rnode);
+ while (rnode && rnode->info == NULL)
+ rnode = route_next (rnode);
+ if (rnode == NULL)
+ return NULL;
+ route_unlock_node (rnode);
+
+ assert (rnode->info);
+ next = (struct ospf6_route *) rnode->info;
+ ospf6_route_unlock (route);
+ ospf6_route_lock (next);
+ return next;
+}
- if (pn->path.area_id != request->path.area_id ||
- pn->path.origin.type != request->path.origin.type ||
- pn->path.origin.id != request->path.origin.id ||
- pn->path.origin.adv_router != request->path.origin.adv_router)
- {
- if (IS_OSPF6_DUMP_ROUTE)
- {
- ospf6_route_log_request ("Remove", table->name, request);
- zlog_info ("ROUTE: Can't remove: Path differ");
- {
- char *s, *e, *c;
- char line[512], *p;
-
- p = line;
- s = (char *) &pn->path;
- e = s + sizeof (struct ospf6_path);
- for (c = s; c < e; c++)
- {
- if ((c - s) % 4 == 0)
- {
- snprintf (p, line + sizeof (line) - p, " ");
- p++;
- }
- snprintf (p, line + sizeof (line) - p, "%02x", *c);
- p += 2;
- }
- zlog_info ("ROUTE: path: %s", line);
-
- p = line;
- s = (char *) &request->path;
- e = s + sizeof (struct ospf6_path);
- for (c = s; c < e; c++)
- {
- if ((c - s) % 4 == 0)
- {
- snprintf (p, line + sizeof (line) - p, " ");
- p++;
- }
- snprintf (p, line + sizeof (line) - p, "%02x", *c);
- p += 2;
- }
- zlog_info ("ROUTE: req : %s", line);
-
- }
- }
- return;
- }
+/* Macro version of check_bit (). */
+#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
- nn = ospf6_route_find_nexthop_node (request, pn);
- if (! nn)
- {
- if (IS_OSPF6_DUMP_ROUTE)
- {
- ospf6_route_log_request ("Remove", table->name, request);
- zlog_info ("ROUTE: Can't remove: No such nexthop");
- }
- return;
- }
+struct ospf6_route *
+ospf6_route_match_head (struct prefix *prefix,
+ struct ospf6_route_table *table)
+{
+ struct route_node *node;
+ struct ospf6_route *route;
- if (memcmp (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop)))
- {
- if (IS_OSPF6_DUMP_ROUTE)
- {
- ospf6_route_log_request ("Remove", table->name, request);
- zlog_info ("ROUTE: Can't remove: Nexthop differ");
- }
- return;
- }
+ /* Walk down tree. */
+ node = table->table->top;
+ while (node && node->p.prefixlen < prefix->prefixlen &&
+ prefix_match (&node->p, prefix))
+ node = node->link[CHECK_BIT(&prefix->u.prefix, node->p.prefixlen)];
- SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE);
+ if (node)
+ route_lock_node (node);
+ while (node && node->info == NULL)
+ node = route_next (node);
+ if (node == NULL)
+ return NULL;
+ route_unlock_node (node);
- if (table->freeze)
- return;
+ if (! prefix_match (prefix, &node->p))
+ return NULL;
- if (IS_OSPF6_DUMP_ROUTE)
- ospf6_route_log_request ("Remove", table->name, request);
+ route = node->info;
+ ospf6_route_lock (route);
+ return route;
+}
- ospf6_route_request (&route, rn, pn, nn);
- ospf6_route_hook_call (REMOVE, &route, table);
- if (table->hook_remove)
- (*table->hook_remove) (&route);
-
- /* clear flag */
- nn->flag = 0;
-
- /* remove nexthop */
- linklist_remove (nn, pn->nexthop_list);
- rn->count--;
- XFREE (MTYPE_OSPF6_ROUTE, nn);
-
- /* remove path if there's no nexthop for the path */
- if (pn->nexthop_list->count != 0)
- return;
- linklist_remove (pn, rn->path_list);
- linklist_delete (pn->nexthop_list);
- XFREE (MTYPE_OSPF6_ROUTE, pn);
-
- /* remove route if there's no path for the route */
- if (rn->path_list->count != 0)
- return;
- route_node->info = NULL;
- linklist_delete (rn->path_list);
- XFREE (MTYPE_OSPF6_ROUTE, rn);
+struct ospf6_route *
+ospf6_route_match_next (struct prefix *prefix,
+ struct ospf6_route *route)
+{
+ struct ospf6_route *next;
+
+ next = ospf6_route_next (route);
+ if (next && ! prefix_match (prefix, &next->prefix))
+ {
+ ospf6_route_unlock (next);
+ next = NULL;
+ }
+
+ return next;
}
void
ospf6_route_remove_all (struct ospf6_route_table *table)
{
- struct ospf6_route_req request;
-
- for (ospf6_route_head (&request, table); ! ospf6_route_end (&request);
- ospf6_route_next (&request))
- ospf6_route_remove (&request, table);
+ struct ospf6_route *route;
+ for (route = ospf6_route_head (table); route;
+ route = ospf6_route_next (route))
+ ospf6_route_remove (route, table);
}
-
struct ospf6_route_table *
-ospf6_route_table_create (char *name)
+ospf6_route_table_create ()
{
- int i;
struct ospf6_route_table *new;
-
new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
- snprintf (new->name, sizeof (new->name), "%s", name);
-
new->table = route_table_init ();
- for (i = 0; i < 3; i++)
- new->hook_list[i] = linklist_create ();
-
return new;
}
void
ospf6_route_table_delete (struct ospf6_route_table *table)
{
- int i;
-
ospf6_route_remove_all (table);
route_table_finish (table->table);
- for (i = 0; i < 3; i++)
- linklist_delete (table->hook_list[i]);
XFREE (MTYPE_OSPF6_ROUTE, table);
}
-void
-ospf6_route_table_freeze (struct ospf6_route_table *route_table)
-{
- if (IS_OSPF6_DUMP_ROUTE)
- zlog_info ("ROUTE: Table freeze: %s", route_table->name);
- assert (route_table->freeze == 0);
- route_table->freeze = 1;
-}
+
+/* VTY commands */
void
-ospf6_route_table_thaw (struct ospf6_route_table *route_table)
+ospf6_route_show (struct vty *vty, struct ospf6_route *route)
{
- struct route_node *node;
- struct linklist_node pnode;
- struct linklist_node nnode;
-
- struct ospf6_route_node *rn;
- struct ospf6_path_node *pn;
- struct ospf6_nexthop_node *nn;
-
- struct ospf6_route_req request;
-
- if (IS_OSPF6_DUMP_ROUTE)
- zlog_info ("ROUTE: Table thaw: %s", route_table->name);
+ int i;
+ char destination[64], nexthop[64];
+ char duration[16], ifname[IFNAMSIZ];
+ struct timeval now, res;
- assert (route_table->freeze == 1);
- route_table->freeze = 0;
+ gettimeofday (&now, (struct timezone *) NULL);
+ timersub (&now, &route->changed, &res);
+ timerstring (&res, duration, sizeof (duration));
- for (node = route_top (route_table->table); node;
- node = route_next (node))
+ /* destination */
+ if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+ ospf6_linkstate_prefix2str (&route->prefix, destination,
+ sizeof (destination));
+ else if (route->type == OSPF6_DEST_TYPE_ROUTER)
+ inet_ntop (route->prefix.family, &route->prefix.u.prefix,
+ destination, sizeof (destination));
+ else
+ prefix2str (&route->prefix, destination, sizeof (destination));
+
+ /* nexthop */
+ inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
+ sizeof (nexthop));
+ if (! if_indextoname (route->nexthop[0].ifindex, ifname))
+ snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex);
+
+ vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
+ (ospf6_route_is_best (route) ? '*' : ' '),
+ OSPF6_DEST_TYPE_SUBSTR (route->type),
+ OSPF6_PATH_TYPE_SUBSTR (route->path.type),
+ destination, nexthop, ifname, duration, VTY_NEWLINE);
+
+ for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
+ i < OSPF6_MULTI_PATH_LIMIT; i++)
{
- rn = node->info;
- if (! rn)
- continue;
-
- for (linklist_head (rn->path_list, &pnode);
- ! linklist_end (&pnode);
- linklist_next (&pnode))
- {
- pn = pnode.data;
-
- for (linklist_head (pn->nexthop_list, &nnode);
- ! linklist_end (&nnode);
- linklist_next (&nnode))
- {
- nn = nnode.data;
-
- /* if the add and remove flag set without change flag,
- do nothing with this route */
- if (! CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE) &&
- CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) &&
- CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
- {
- nn->flag = 0;
- continue;
- }
-
- memset (&request, 0, sizeof (request));
- memcpy (&request.route, &rn->route, sizeof (rn->route));
- memcpy (&request.path, &pn->path, sizeof (pn->path));
- memcpy (&request.nexthop, &nn->nexthop, sizeof (nn->nexthop));
-
- if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) ||
- CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
- ospf6_route_add (&request, route_table);
- else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
- ospf6_route_remove (&request, route_table);
- }
- }
+ /* nexthop */
+ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+ sizeof (nexthop));
+ if (! if_indextoname (route->nexthop[i].ifindex, ifname))
+ snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
+
+ vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
+ ' ', "", "", "", nexthop, ifname, "", VTY_NEWLINE);
}
}
-
-/* VTY commands */
-
void
-ospf6_route_show (struct vty *vty, struct ospf6_route_node *rn)
+ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
{
- struct linklist_node pnode;
- struct linklist_node nnode;
- struct ospf6_path_node *pn;
- struct ospf6_nexthop_node *nn;
-
+ char destination[64], nexthop[64], ifname[IFNAMSIZ];
+ char area_id[16], id[16], adv_router[16], capa[16], options[16];
struct timeval now, res;
char duration[16];
-
- u_int pc = 0;
- u_int nc = 0;
-#define HEAD (pc == 0 && nc == 0)
-
- char prefix[64], nexthop[64], ifname[IFNAMSIZ];
+ int i;
gettimeofday (&now, (struct timezone *) NULL);
/* destination */
- if (rn->route.prefix.family == AF_INET ||
- rn->route.prefix.family == AF_INET6)
- prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
+ if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+ ospf6_linkstate_prefix2str (&route->prefix, destination,
+ sizeof (destination));
+ else if (route->type == OSPF6_DEST_TYPE_ROUTER)
+ inet_ntop (route->prefix.family, &route->prefix.u.prefix,
+ destination, sizeof (destination));
else
- prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
+ prefix2str (&route->prefix, destination, sizeof (destination));
+ vty_out (vty, "Destination: %s%s", destination, VTY_NEWLINE);
+
+ /* destination type */
+ vty_out (vty, "Destination type: %s%s",
+ OSPF6_DEST_TYPE_NAME (route->type),
+ VTY_NEWLINE);
+
+ /* Time */
+ timersub (&now, &route->installed, &res);
+ timerstring (&res, duration, sizeof (duration));
+ vty_out (vty, "Installed Time: %s ago%s", duration, VTY_NEWLINE);
+
+ timersub (&now, &route->changed, &res);
+ timerstring (&res, duration, sizeof (duration));
+ vty_out (vty, " Changed Time: %s ago%s", duration, VTY_NEWLINE);
+
+ /* Debugging info */
+ vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock,
+ (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
+ (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
+ (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
+ (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"),
+ VTY_NEWLINE);
+ vty_out (vty, "Memory: prev: %p this: %p next: %p%s",
+ route->prev, route, route->next, VTY_NEWLINE);
+
+ /* Path section */
+
+ /* Area-ID */
+ inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id));
+ vty_out (vty, "Associated Area: %s%s", area_id, VTY_NEWLINE);
+
+ /* Path type */
+ vty_out (vty, "Path Type: %s%s",
+ OSPF6_PATH_TYPE_NAME (route->path.type), VTY_NEWLINE);
+
+ /* LS Origin */
+ inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id));
+ inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router,
+ sizeof (adv_router));
+ vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s",
+ OSPF6_LSTYPE_NAME (route->path.origin.type),
+ id, adv_router, VTY_NEWLINE);
+
+ /* Options */
+ ospf6_options_printbuf (route->path.options, options, sizeof (options));
+ vty_out (vty, "Options: %s%s", options, VTY_NEWLINE);
+
+ /* Router Bits */
+ ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa));
+ vty_out (vty, "Router Bits: %s%s", capa, VTY_NEWLINE);
+
+ /* Prefix Options */
+ vty_out (vty, "Prefix Options: xxx%s", VTY_NEWLINE);
+
+ /* Metrics */
+ vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
+ VTY_NEWLINE);
+ vty_out (vty, "Metric: %d (%d)%s",
+ route->path.cost, route->path.cost_e2, VTY_NEWLINE);
+
+ /* Nexthops */
+ vty_out (vty, "Nexthop:%s", VTY_NEWLINE);
+ for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
+ i < OSPF6_MULTI_PATH_LIMIT; i++)
+ {
+ /* nexthop */
+ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+ sizeof (nexthop));
+ if (! if_indextoname (route->nexthop[i].ifindex, ifname))
+ snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
+ vty_out (vty, " %s %s%s", nexthop, ifname, VTY_NEWLINE);
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+}
- for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
- linklist_next (&pnode))
+void
+ospf6_route_show_table_summary (struct vty *vty,
+ struct ospf6_route_table *table)
+{
+ struct ospf6_route *route, *prev = NULL;
+ int i, pathtype[OSPF6_PATH_TYPE_MAX];
+ int number = 0;
+ int nhinval = 0, ecmp = 0;
+ int multipath = 0, destination = 0;
+ int desttype = 0, desttype_mismatch = 0;
+
+ for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
+ pathtype[i] = 0;
+
+ for (route = ospf6_route_head (table); route;
+ route = ospf6_route_next (route))
{
- pn = pnode.data;
+ if (desttype == 0)
+ desttype = route->type;
+ else if (desttype != route->type)
+ desttype_mismatch++;
- for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
- linklist_next (&nnode))
- {
- nn = nnode.data;
+ if (prev == NULL || ! ospf6_route_is_same (prev, route))
+ destination++;
+ else
+ multipath++;
- inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
- sizeof (nexthop));
- if (! if_indextoname (nn->nexthop.ifindex, ifname))
- snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
+ if (! ospf6_nexthop_is_set (&route->nexthop[0]))
+ nhinval++;
+ else if (ospf6_nexthop_is_set (&route->nexthop[1]))
+ ecmp++;
- ospf6_timeval_sub (&now, &nn->installed, &res);
- ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+ if (prev == NULL || ! ospf6_route_is_same (prev, route))
+ pathtype[route->path.type]++;
- vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
- (HEAD ? '*' : ' '),
- DTYPE_ABNAME (rn->route.type),
- PTYPE_ABNAME (pn->path.type),
- prefix, nexthop, ifname, duration, VTY_NEWLINE);
+ number++;
+ prev = route;
+ }
- nc++;
- }
- pc++;
+ assert (number == table->count);
+ vty_out (vty, "Number of Destination: %d (%d routes)%s",
+ destination, number, VTY_NEWLINE);
+ if (multipath)
+ vty_out (vty, " Number of Multi-path: %d%s", multipath, VTY_NEWLINE);
+ if (desttype_mismatch)
+ vty_out (vty, " Number of Different Dest-type: %d%s",
+ desttype_mismatch, VTY_NEWLINE);
+ if (ecmp)
+ vty_out (vty, " Number of Equal Cost Multi Path: %d%s",
+ ecmp, VTY_NEWLINE);
+ if (ecmp)
+ vty_out (vty, " Number of Invalid Nexthop: %d%s",
+ nhinval, VTY_NEWLINE);
+
+ for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
+ {
+ if (pathtype[i])
+ vty_out (vty, " Number of %s routes: %d%s",
+ OSPF6_PATH_TYPE_NAME (i), pathtype[i], VTY_NEWLINE);
}
}
-void
-ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn)
+int
+ospf6_route_table_show (struct vty *vty, int argc, char **argv,
+ struct ospf6_route_table *table)
{
- struct linklist_node pnode;
- struct linklist_node nnode;
- struct ospf6_path_node *pn;
- struct ospf6_nexthop_node *nn;
+ unsigned char flag = 0;
+#define MATCH 0x01
+#define DETAIL 0x02
+#define PREFIX 0x04
+#define SUMMARY 0x08
+ int i, ret;
+ struct prefix prefix, *p;
+ struct ospf6_route *route;
- u_int pc = 0;
- u_int nc = 0;
+ memset (&prefix, 0, sizeof (struct prefix));
- char prefix[64], nexthop[64], ifname[IFNAMSIZ];
- char area_id[16], type[16], id[16], adv[16];
- char capa[64];
+ for (i = 0; i < argc; i++)
+ {
+ /* set "detail" */
+ if (! strcmp (argv[i], "summary"))
+ {
+ SET_FLAG (flag, SUMMARY);
+ continue;
+ }
- /* destination */
- if (rn->route.prefix.family == AF_INET ||
- rn->route.prefix.family == AF_INET6)
- prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
- else
- prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
+ /* set "detail" */
+ if (! strcmp (argv[i], "detail"))
+ {
+ SET_FLAG (flag, DETAIL);
+ continue;
+ }
+
+ /* set "match" */
+ if (! strcmp (argv[i], "match"))
+ {
+ SET_FLAG (flag, MATCH);
+ continue;
+ }
- vty_out (vty, "%s%s%s", VTY_NEWLINE, prefix, VTY_NEWLINE);
- vty_out (vty, " Destination Type: %s%s",
- DTYPE_NAME (rn->route.type), VTY_NEWLINE);
+ if (prefix.family)
+ {
+ vty_out (vty, "Invalid argument: %s%s", argv[i], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
- for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
- linklist_next (&pnode))
- {
- pn = pnode.data;
-
- inet_ntop (AF_INET, &pn->path.area_id, area_id, sizeof (area_id));
- ospf6_lsa_type_string (pn->path.origin.type, type, sizeof (type));
- inet_ntop (AF_INET, &pn->path.origin.id, id, sizeof (id));
- inet_ntop (AF_INET, &pn->path.origin.adv_router, adv, sizeof (adv));
- ospf6_options_string (pn->path.capability, capa, sizeof (capa));
-
- vty_out (vty, " Path:%s", VTY_NEWLINE);
- vty_out (vty, " Associated Area: %s%s", area_id, VTY_NEWLINE);
- vty_out (vty, " LS Origin: %s ID: %s Adv: %s%s",
- type, id, adv, VTY_NEWLINE);
- vty_out (vty, " Path Type: %s%s",
- PTYPE_NAME (pn->path.type), VTY_NEWLINE);
- vty_out (vty, " Metric Type: %d%s",
- pn->path.metric_type, VTY_NEWLINE);
- vty_out (vty, " Cost: Type-1: %lu Type-2: %lu%s",
- (u_long) pn->path.cost, (u_long) pn->path.cost_e2,
- VTY_NEWLINE);
- vty_out (vty, " Router Bits: %s|%s|%s|%s%s",
- (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_W) ?
- "W" : "-"),
- (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_V) ?
- "V" : "-"),
- (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_E) ?
- "E" : "-"),
- (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ?
- "B" : "-"), VTY_NEWLINE);
- vty_out (vty, " Optional Capabilities: %s%s", capa, VTY_NEWLINE);
- vty_out (vty, " Prefix Options: %s%s", "xxx", VTY_NEWLINE);
- vty_out (vty, " Next Hops:%s", VTY_NEWLINE);
-
- for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
- linklist_next (&nnode))
+ ret = str2prefix (argv[i], &prefix);
+ if (ret != 1 || prefix.family != AF_INET6)
{
- nn = nnode.data;
+ vty_out (vty, "Malformed argument: %s%s", argv[i], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
- inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
- sizeof (nexthop));
- if (! if_indextoname (nn->nexthop.ifindex, ifname))
- snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
+ if (strchr (argv[i], '/'))
+ SET_FLAG (flag, PREFIX);
+ }
- vty_out (vty, " %c%s%%%s%s",
- (HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE);
+ /* Give summary of this route table */
+ if (CHECK_FLAG (flag, SUMMARY))
+ {
+ ospf6_route_show_table_summary (vty, table);
+ return CMD_SUCCESS;
+ }
- nc++;
+ /* Give exact prefix-match route */
+ if (prefix.family && ! CHECK_FLAG (flag, MATCH))
+ {
+ /* If exact address, give best matching route */
+ if (! CHECK_FLAG (flag, PREFIX))
+ route = ospf6_route_lookup_bestmatch (&prefix, table);
+ else
+ route = ospf6_route_lookup (&prefix, table);
+
+ if (route)
+ {
+ ospf6_route_lock (route);
+ p = &route->prefix;
+ }
+
+ while (route && ospf6_route_is_prefix (p, route))
+ {
+ /* Seaching an entry will always display details */
+ if (route)
+ ospf6_route_show_detail (vty, route);
+
+ route = ospf6_route_next (route);
}
- pc++;
+
+ return CMD_SUCCESS;
}
- vty_out (vty, "%s", VTY_NEWLINE);
+
+ if (prefix.family == 0)
+ route = ospf6_route_head (table);
+ else
+ route = ospf6_route_match_head (&prefix, table);
+
+ while (route)
+ {
+ if (CHECK_FLAG (flag, DETAIL))
+ ospf6_route_show_detail (vty, route);
+ else
+ ospf6_route_show (vty, route);
+
+ if (prefix.family == 0)
+ route = ospf6_route_next (route);
+ else
+ route = ospf6_route_match_next (&prefix, route);
+ }
+
+ return CMD_SUCCESS;
}
+
int
-ospf6_route_table_show (struct vty *vty, int argc, char **argv,
- struct ospf6_route_table *table)
+ospf6_lsentry_table_show (struct vty *vty, int argc, char **argv,
+ struct ospf6_route_table *table)
{
+ unsigned char flag = 0;
+#define MATCH 0x01
+#define DETAIL 0x02
int i, ret;
- unsigned long ret_ul;
- char *endptr;
- struct prefix prefix;
- int detail = 0;
- int arg_ipv6 = 0;
- int arg_ipv4 = 0;
- int arg_digit = 0;
- struct prefix_ipv6 *p6 = (struct prefix_ipv6 *) &prefix;
- struct prefix_ls *pl = (struct prefix_ls *) &prefix;
- struct route_node *node;
-
- u_int route_count = 0;
- u_int path_count = 0;
- u_int route_redundant = 0;
+ struct prefix adv_router, id, prefix;
+ struct ospf6_route *route;
- memset (&prefix, 0, sizeof (struct prefix));
+ memset (&adv_router, 0, sizeof (struct prefix));
+ memset (&id, 0, sizeof (struct prefix));
for (i = 0; i < argc; i++)
{
+ /* set "detail" */
if (! strcmp (argv[i], "detail"))
{
- detail++;
- break;
+ SET_FLAG (flag, DETAIL);
+ continue;
}
- if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit)
+ /* set "match" */
+ if (! strcmp (argv[i], "match"))
{
+ SET_FLAG (flag, MATCH);
+ continue;
+ }
- if ((ret = inet_pton (AF_INET6, argv[i], &p6->prefix)) == 1)
+ if (adv_router.family && id.family)
+ {
+ vty_out (vty, "Invalid argument: %s%s", argv[i], VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ if (adv_router.family == 0)
+ {
+ ret = str2prefix (argv[i], &adv_router);
+ if (ret != 1)
{
- p6->family = AF_INET6;
- p6->prefixlen = 128;
- arg_ipv6++;
- continue;
+ if (! strcmp (argv[i], "*"))
+ {
+ adv_router.family = AF_INET;
+ adv_router.prefixlen = 0;
+ ret = 1;
+ }
}
- else if ((ret = inet_pton (AF_INET, argv[i], &pl->adv_router)) == 1)
+ if (ret != 1)
{
- pl->family = AF_UNSPEC;
- pl->prefixlen = 64; /* xxx */
- arg_ipv4++;
- continue;
+ vty_out (vty, "Invalid Router-ID: %s%s", argv[i], VTY_NEWLINE);
+ return CMD_SUCCESS;
}
- else
+ }
+ else if (id.family == 0)
+ {
+ unsigned long val;
+ char *endptr;
+
+ ret = str2prefix (argv[i], &id);
+ if (ret != 1)
{
- ret_ul = strtoul (argv[i], &endptr, 10);
- if (*endptr == '\0')
- {
- pl->adv_router.s_addr = htonl (ret_ul);
- pl->family = AF_UNSPEC;
- pl->prefixlen = 64; /* xxx */
- arg_digit++;
- continue;
- }
- else
+ val = strtoul (argv[i], &endptr, 0);
+ if (val != ULONG_MAX && *endptr == '\0')
{
- vty_out (vty, "Malformed argument: %s%s",
- argv[i], VTY_NEWLINE);
- return CMD_SUCCESS;
+ id.u.prefix4.s_addr = val;
+ ret = 1;
}
}
- }
- if (arg_ipv4 || arg_digit)
- {
- if ((ret = inet_pton (AF_INET, argv[i], &pl->id)) == 1)
+ if (ret != 1)
{
- arg_ipv4++;
- }
- else
- {
- ret_ul = strtoul (argv[i], &endptr, 10);
- if (*endptr == '\0')
- {
- pl->id.s_addr = htonl (ret_ul);
- arg_digit++;
- }
- else
- {
- vty_out (vty, "Malformed argument: %s%s",
- argv[i], VTY_NEWLINE);
- return CMD_SUCCESS;
- }
+ vty_out (vty, "Invalid Link state ID: %s%s", argv[i],
+ VTY_NEWLINE);
+ return CMD_WARNING;
}
}
}
- if (arg_ipv4 || arg_ipv6 || arg_digit)
+ /* Encode to linkstate prefix */
+ if (adv_router.family)
{
- node = route_node_match (table->table, &prefix);
- if (node && node->info)
- ospf6_route_show_detail (vty, node->info);
- return CMD_SUCCESS;
+ if (adv_router.prefixlen == 0 &&
+ id.family && id.prefixlen != IPV4_MAX_BITLEN)
+ {
+ vty_out (vty, "Specifying Link State ID by prefix is not allowed%s"
+ "when specifying Router-ID as wildcard%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+ else if (adv_router.prefixlen != 0 &&
+ adv_router.prefixlen != IPV4_MAX_BITLEN && id.family)
+ {
+ vty_out (vty, "Specifying Link State ID is not allowed%s"
+ "when specifying Router-ID by prefix%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ if (adv_router.prefixlen == 0)
+ ospf6_linkstate_prefix (0, id.u.prefix4.s_addr, &prefix);
+ else if (adv_router.prefixlen != IPV4_MAX_BITLEN)
+ {
+ ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr, 0, &prefix);
+ prefix.prefixlen = adv_router.prefixlen;
+ SET_FLAG (flag, MATCH);
+ }
+ else
+ {
+ ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr,
+ id.u.prefix4.s_addr, &prefix);
+ prefix.prefixlen = adv_router.prefixlen + id.prefixlen;
+ if (prefix.prefixlen != 64)
+ SET_FLAG (flag, MATCH);
+ }
}
- if (! detail)
+ /* give exact match entry */
+ if (adv_router.family && adv_router.prefixlen == IPV4_MAX_BITLEN &&
+ id.family && id.prefixlen == IPV4_MAX_BITLEN)
{
- vty_out (vty, "%s%c%1s %2s %-30s %-25s %6s%s", VTY_NEWLINE,
- ' ', " ", " ", "Destination", "Gateway", "I/F", VTY_NEWLINE);
- vty_out (vty, "---------------------------%s", VTY_NEWLINE);
+ route = ospf6_route_lookup (&prefix, table);
+ if (route)
+ ospf6_route_show_detail (vty, route);
+ return CMD_SUCCESS;
}
- for (node = route_top (table->table); node; node = route_next (node))
- {
- struct ospf6_route_node *route = node->info;
+ if (CHECK_FLAG (flag, MATCH))
+ route = ospf6_route_match_head (&prefix, table);
+ else
+ route = ospf6_route_head (table);
- if (! route)
- continue;
+ while (route)
+ {
+ if (! adv_router.family ||
+ (CHECK_FLAG (flag, MATCH) &&
+ prefix_match (&prefix, &route->prefix)) ||
+ (adv_router.prefixlen == 0 && id.family &&
+ ospf6_linkstate_prefix_id (&prefix) ==
+ ospf6_linkstate_prefix_id (&route->prefix)))
+ {
+ if (CHECK_FLAG (flag, DETAIL))
+ ospf6_route_show_detail (vty, route);
+ else
+ ospf6_route_show (vty, route);
+ }
- if (detail)
- ospf6_route_show_detail (vty, route);
+ if (CHECK_FLAG (flag, MATCH))
+ route = ospf6_route_match_next (&prefix, route);
else
- ospf6_route_show (vty, route);
-
- route_count++;
- path_count += route->path_list->count;
- if (route->path_list->count > 1)
- route_redundant++;
+ route = ospf6_route_next (route);
}
- vty_out (vty, "===========%s", VTY_NEWLINE);
- vty_out (vty, "Route: %d Path: %d Redundant: %d%s",
- route_count, path_count, route_redundant, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+DEFUN (debug_ospf6_route,
+ debug_ospf6_route_cmd,
+ "debug ospf6 route (table|intra-area|inter-area)",
+ DEBUG_STR
+ OSPF6_STR
+ "Debug route table calculation\n"
+ "Debug detail\n"
+ "Debug intra-area route calculation\n"
+ "Debug inter-area route calculation\n"
+ )
+{
+ unsigned char level = 0;
+
+ if (! strncmp (argv[0], "table", 5))
+ level = OSPF6_DEBUG_ROUTE_TABLE;
+ else if (! strncmp (argv[0], "intra", 5))
+ level = OSPF6_DEBUG_ROUTE_INTRA;
+ else if (! strncmp (argv[0], "inter", 5))
+ level = OSPF6_DEBUG_ROUTE_INTER;
+ OSPF6_DEBUG_ROUTE_ON (level);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_route,
+ no_debug_ospf6_route_cmd,
+ "no debug ospf6 route (table|intra-area|inter-area)",
+ NO_STR
+ DEBUG_STR
+ OSPF6_STR
+ "Debug route table calculation\n"
+ "Debug intra-area route calculation\n")
+{
+ unsigned char level = 0;
+
+ if (! strncmp (argv[0], "table", 5))
+ level = OSPF6_DEBUG_ROUTE_TABLE;
+ else if (! strncmp (argv[0], "intra", 5))
+ level = OSPF6_DEBUG_ROUTE_INTRA;
+ else if (! strncmp (argv[0], "inter", 5))
+ level = OSPF6_DEBUG_ROUTE_INTER;
+ OSPF6_DEBUG_ROUTE_OFF (level);
return CMD_SUCCESS;
}
+int
+config_write_ospf6_debug_route (struct vty *vty)
+{
+ if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+ vty_out (vty, "debug ospf6 route table%s", VTY_NEWLINE);
+ if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+ vty_out (vty, "debug ospf6 route intra-area%s", VTY_NEWLINE);
+ if (IS_OSPF6_DEBUG_ROUTE (INTER))
+ vty_out (vty, "debug ospf6 route inter-area%s", VTY_NEWLINE);
+ return 0;
+}
+
+void
+install_element_ospf6_debug_route ()
+{
+ install_element (ENABLE_NODE, &debug_ospf6_route_cmd);
+ install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd);
+ install_element (CONFIG_NODE, &debug_ospf6_route_cmd);
+ install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd);
+}
+
+
+