blob: c35efa6e78669d906c8a304b45f138091485134b [file] [log] [blame]
/*
* Copyright (C) 1999 Yasuhiro Ohara
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "ospf6d.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])
int
ospf6_path_cmp (void *arg1, void *arg2)
{
struct ospf6_path_node *pn1 = arg1;
struct ospf6_path_node *pn2 = arg2;
struct ospf6_path *p1 = &pn1->path;
struct ospf6_path *p2 = &pn2->path;
if (p1->type < p2->type)
return -1;
else if (p1->type > p2->type)
return 1;
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;
}
if (p1->cost < p2->cost)
return -1;
else if (p1->cost > p2->cost)
return 1;
/* 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;
/* else, always prefer left */
return -1;
}
int
ospf6_nexthop_cmp (void *arg1, void *arg2)
{
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;
return ret;
}
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)
{
assert (request);
assert (rn && pn && nn);
request->route_node = rn->route_node;
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;
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);
for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
linklist_next (&node))
{
struct ospf6_path_node *pn2 = node.data;
zlog_info (" %p: path data with pn(%p): %s", pn2, pn,
(memcmp (&pn->path, &pn2->path,
sizeof (struct ospf6_path)) ?
"different" : "same"));
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 (! memcmp (&pn->path, &pn2->path, sizeof (struct ospf6_path)))
{
pn = pn2;
request->nexthop_lnode.data = pn2;
}
}
break;
}
linklist_next (&request->path_lnode);
}
assert (request->path_lnode.data == pn);
linklist_head (pn->nexthop_list, &request->nexthop_lnode);
while (request->nexthop_lnode.data != nn)
{
assert (! linklist_end (&request->nexthop_lnode));
linklist_next (&request->nexthop_lnode);
}
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;
}
int
ospf6_route_lookup (struct ospf6_route_req *request,
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));
node = route_node_lookup (table->table, prefix);
if (! node)
return 0;
rn = (struct ospf6_route_node *) node->info;
if (! rn)
return 0;
if (request)
{
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);
}
return 1;
}
void
ospf6_route_head (struct ospf6_route_req *request,
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 (request, 0, sizeof (struct ospf6_route_req));
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);
}
int
ospf6_route_end (struct ospf6_route_req *request)
{
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;
}
void
ospf6_route_next (struct ospf6_route_req *request)
{
struct ospf6_route_node *route_node = NULL;
struct ospf6_path_node *path_node = NULL;
struct ospf6_nexthop_node *nexthop_node = NULL;
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);
}
}
path_node = request->path_lnode.data;
if (path_node)
linklist_head (path_node->nexthop_list, &request->nexthop_lnode);
}
nexthop_node = request->nexthop_lnode.data;
if (nexthop_node == NULL)
{
assert (path_node == NULL);
assert (route_node == NULL);
memset (&request->route, 0, sizeof (struct ospf6_route));
memset (&request->path, 0, sizeof (struct ospf6_path));
memset (&request->nexthop, 0, sizeof (struct ospf6_nexthop));
}
else
{
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));
}
}
#define ADD 0
#define CHANGE 1
#define REMOVE 2
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 *);
for (linklist_head (table->hook_list[type], &node);
! linklist_end (&node);
linklist_next (&node))
{
func = node.data;
(*func) (request);
}
}
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]);
}
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]);
}
int
prefix_ls2str (struct prefix *p, char *str, int size)
{
char id[BUFSIZ], adv_router[BUFSIZ];
struct prefix_ls *pl = (struct prefix_ls *) p;
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;
}
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));
}
struct ospf6_path_node *
ospf6_route_find_path_node (struct ospf6_route_req *request,
struct ospf6_route_node *rn)
{
struct linklist_node node;
for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
linklist_next (&node))
{
struct ospf6_path_node *path_node = node.data;
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;
}
#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))
{
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);
}
#endif
return 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))
{
struct ospf6_nexthop_node *nexthop_node = node.data;
if (! memcmp (&nexthop_node->nexthop, &request->nexthop,
sizeof (struct ospf6_nexthop)))
return nexthop_node;
}
return NULL;
}
void
ospf6_route_add (struct ospf6_route_req *request,
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 ospf6_route_req route;
int route_change = 0;
int path_change = 0;
int nexthop_change = 0;
/* find the requested route */
route_node = route_node_get (table->table, &request->route.prefix);
rn = (struct ospf6_route_node *) route_node->info;
if (rn)
{
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;
}
/* find the same path */
pn = ospf6_route_find_path_node (request, rn);
if (pn)
{
if (memcmp (&pn->path, &request->path, sizeof (struct ospf6_path)))
{
memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
path_change++;
}
}
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);
}
/* find the same nexthop */
nn = ospf6_route_find_nexthop_node (request, pn);
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);
}
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);
if (table->freeze)
return;
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");
}
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;
}
void
ospf6_route_remove (struct ospf6_route_req *request,
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 ospf6_route_req route;
/* find the requested route */
route_node = route_node_get (table->table, &request->route.prefix);
rn = (struct ospf6_route_node *) route_node->info;
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;
}
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;
}
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, " ");
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, " ");
snprintf (p, line + sizeof (line) - p, "%02x", *c);
p += 2;
}
zlog_info ("ROUTE: req : %s", line);
}
}
return;
}
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;
}
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;
}
SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE);
if (table->freeze)
return;
if (IS_OSPF6_DUMP_ROUTE)
ospf6_route_log_request ("Remove", table->name, request);
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);
}
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_table *
ospf6_route_table_create (char *name)
{
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;
}
void
ospf6_route_table_thaw (struct ospf6_route_table *route_table)
{
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);
assert (route_table->freeze == 1);
route_table->freeze = 0;
for (node = route_top (route_table->table); node;
node = route_next (node))
{
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);
}
}
}
}
/* VTY commands */
void
ospf6_route_show (struct vty *vty, struct ospf6_route_node *rn)
{
struct linklist_node pnode;
struct linklist_node nnode;
struct ospf6_path_node *pn;
struct ospf6_nexthop_node *nn;
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];
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));
else
prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
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;
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);
ospf6_timeval_sub (&now, &nn->installed, &res);
ospf6_timeval_string_summary (&res, duration, sizeof (duration));
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);
nc++;
}
pc++;
}
}
void
ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn)
{
struct linklist_node pnode;
struct linklist_node nnode;
struct ospf6_path_node *pn;
struct ospf6_nexthop_node *nn;
u_int pc = 0;
u_int nc = 0;
char prefix[64], nexthop[64], ifname[IFNAMSIZ];
char area_id[16], type[16], id[16], adv[16];
char capa[64];
/* 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));
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);
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))
{
nn = nnode.data;
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);
vty_out (vty, " %c%s%%%s%s",
(HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE);
nc++;
}
pc++;
}
vty_out (vty, "%s", VTY_NEWLINE);
}
int
ospf6_route_table_show (struct vty *vty, int argc, char **argv,
struct ospf6_route_table *table)
{
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;
memset (&prefix, 0, sizeof (struct prefix));
for (i = 0; i < argc; i++)
{
if (! strcmp (argv[i], "detail"))
{
detail++;
break;
}
if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit)
{
if ((ret = inet_pton (AF_INET6, argv[i], &p6->prefix)) == 1)
{
p6->family = AF_INET6;
p6->prefixlen = 128;
arg_ipv6++;
continue;
}
else if ((ret = inet_pton (AF_INET, argv[i], &pl->adv_router)) == 1)
{
pl->family = AF_UNSPEC;
pl->prefixlen = 64; /* xxx */
arg_ipv4++;
continue;
}
else
{
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
{
vty_out (vty, "Malformed argument: %s%s",
argv[i], VTY_NEWLINE);
return CMD_SUCCESS;
}
}
}
if (arg_ipv4 || arg_digit)
{
if ((ret = inet_pton (AF_INET, argv[i], &pl->id)) == 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;
}
}
}
}
if (arg_ipv4 || arg_ipv6 || arg_digit)
{
node = route_node_match (table->table, &prefix);
if (node && node->info)
ospf6_route_show_detail (vty, node->info);
return CMD_SUCCESS;
}
if (! detail)
{
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);
}
for (node = route_top (table->table); node; node = route_next (node))
{
struct ospf6_route_node *route = node->info;
if (! route)
continue;
if (detail)
ospf6_route_show_detail (vty, route);
else
ospf6_route_show (vty, route);
route_count++;
path_count += route->path_list->count;
if (route->path_list->count > 1)
route_redundant++;
}
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;
}