diff options
author | hasso <hasso> | 2004-05-18 20:57:06 +0200 |
---|---|---|
committer | hasso <hasso> | 2004-05-18 20:57:06 +0200 |
commit | 508e53e2eef3eefba4c1aa771529027fd4486ea8 (patch) | |
tree | 0e25e1b344a7b8e2c4551cfcb74d5a011dd0865d /ospf6d/ospf6_route.c | |
parent | Start of new ospf6d merge from Zebra. (diff) | |
download | frr-508e53e2eef3eefba4c1aa771529027fd4486ea8.tar.xz frr-508e53e2eef3eefba4c1aa771529027fd4486ea8.zip |
Ospf6d merge from Zebra repository with added privs stuff and merged
zclient changes.
Diffstat (limited to 'ospf6d/ospf6_route.c')
-rw-r--r-- | ospf6d/ospf6_route.c | 1791 |
1 files changed, 896 insertions, 895 deletions
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index b3abedc3c..73bdac2d2 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); +} + + + |