blob: 3054b59b0600dd20908508f540efe2774cf05fc0 [file] [log] [blame]
/*
* Copyright (C) 2003 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 <zebra.h>
#include "log.h"
#include "linklist.h"
#include "thread.h"
#include "memory.h"
#include "if.h"
#include "prefix.h"
#include "table.h"
#include "vty.h"
#include "command.h"
#include "ospf6_proto.h"
#include "ospf6_message.h"
#include "ospf6_route.h"
#include "ospf6_lsa.h"
#include "ospf6_lsdb.h"
#include "ospf6_top.h"
#include "ospf6_area.h"
#include "ospf6_interface.h"
#include "ospf6_neighbor.h"
#include "ospf6_intra.h"
#include "ospf6_asbr.h"
#include "ospf6_abr.h"
#include "ospf6_flood.h"
#include "ospf6d.h"
#include "ospf6_spf.h"
unsigned char conf_debug_ospf6_brouter = 0;
u_int32_t conf_debug_ospf6_brouter_specific_router_id;
u_int32_t conf_debug_ospf6_brouter_specific_area_id;
/******************************/
/* RFC2740 3.4.3.1 Router-LSA */
/******************************/
static char *
ospf6_router_lsa_get_nbr_id (struct ospf6_lsa *lsa, char *buf, int buflen,
int pos)
{
struct ospf6_router_lsa *router_lsa;
struct ospf6_router_lsdesc *lsdesc;
char *start, *end;
char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN];
if (lsa)
{
router_lsa = (struct ospf6_router_lsa *)
((char *) lsa->header + sizeof (struct ospf6_lsa_header));
start = (char *) router_lsa + sizeof (struct ospf6_router_lsa);
end = (char *) lsa->header + ntohs (lsa->header->length);
lsdesc = (struct ospf6_router_lsdesc *)
(start + pos*(sizeof (struct ospf6_router_lsdesc)));
if ((char *)lsdesc < end)
{
if (buf && (buflen > INET_ADDRSTRLEN*2))
{
inet_ntop (AF_INET, &lsdesc->neighbor_interface_id,
buf1, sizeof(buf1));
inet_ntop (AF_INET, &lsdesc->neighbor_router_id,
buf2, sizeof(buf2));
sprintf (buf, "%s/%s", buf2, buf1);
}
}
else
return NULL;
}
return buf;
}
static int
ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
{
char *start, *end, *current;
char buf[32], name[32], bits[16], options[32];
struct ospf6_router_lsa *router_lsa;
struct ospf6_router_lsdesc *lsdesc;
router_lsa = (struct ospf6_router_lsa *)
((char *) lsa->header + sizeof (struct ospf6_lsa_header));
ospf6_capability_printbuf (router_lsa->bits, bits, sizeof (bits));
ospf6_options_printbuf (router_lsa->options, options, sizeof (options));
vty_out (vty, " Bits: %s Options: %s%s", bits, options, VNL);
start = (char *) router_lsa + sizeof (struct ospf6_router_lsa);
end = (char *) lsa->header + ntohs (lsa->header->length);
for (current = start; current + sizeof (struct ospf6_router_lsdesc) <= end;
current += sizeof (struct ospf6_router_lsdesc))
{
lsdesc = (struct ospf6_router_lsdesc *) current;
if (lsdesc->type == OSPF6_ROUTER_LSDESC_POINTTOPOINT)
snprintf (name, sizeof (name), "Point-To-Point");
else if (lsdesc->type == OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK)
snprintf (name, sizeof (name), "Transit-Network");
else if (lsdesc->type == OSPF6_ROUTER_LSDESC_STUB_NETWORK)
snprintf (name, sizeof (name), "Stub-Network");
else if (lsdesc->type == OSPF6_ROUTER_LSDESC_VIRTUAL_LINK)
snprintf (name, sizeof (name), "Virtual-Link");
else
snprintf (name, sizeof (name), "Unknown (%#x)", lsdesc->type);
vty_out (vty, " Type: %s Metric: %d%s",
name, ntohs (lsdesc->metric), VNL);
vty_out (vty, " Interface ID: %s%s",
inet_ntop (AF_INET, &lsdesc->interface_id,
buf, sizeof (buf)), VNL);
vty_out (vty, " Neighbor Interface ID: %s%s",
inet_ntop (AF_INET, &lsdesc->neighbor_interface_id,
buf, sizeof (buf)), VNL);
vty_out (vty, " Neighbor Router ID: %s%s",
inet_ntop (AF_INET, &lsdesc->neighbor_router_id,
buf, sizeof (buf)), VNL);
}
return 0;
}
int
ospf6_router_is_stub_router (struct ospf6_lsa *lsa)
{
struct ospf6_router_lsa *rtr_lsa;
if (lsa != NULL && OSPF6_LSA_IS_TYPE (ROUTER, lsa))
{
rtr_lsa = (struct ospf6_router_lsa *)
((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_R))
{
return (OSPF6_IS_STUB_ROUTER);
}
else if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_V6))
{
return (OSPF6_IS_STUB_ROUTER_V6);
}
}
return (OSPF6_NOT_STUB_ROUTER);
}
int
ospf6_router_lsa_originate (struct thread *thread)
{
struct ospf6_area *oa;
char buffer [OSPF6_MAX_LSASIZE];
struct ospf6_lsa_header *lsa_header;
struct ospf6_lsa *lsa;
u_int32_t link_state_id = 0;
struct listnode *node, *nnode;
struct listnode *j;
struct ospf6_interface *oi;
struct ospf6_neighbor *on, *drouter = NULL;
struct ospf6_router_lsa *router_lsa;
struct ospf6_router_lsdesc *lsdesc;
u_int16_t type;
u_int32_t router;
int count;
oa = (struct ospf6_area *) THREAD_ARG (thread);
oa->thread_router_lsa = NULL;
if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER))
zlog_debug ("Originate Router-LSA for Area %s", oa->name);
memset (buffer, 0, sizeof (buffer));
lsa_header = (struct ospf6_lsa_header *) buffer;
router_lsa = (struct ospf6_router_lsa *)
((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6);
OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E);
OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC);
OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N);
OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R);
OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC);
if (ospf6_is_router_abr (ospf6))
SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
else
UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
if (ospf6_asbr_is_asbr (ospf6))
SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
else
UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V);
UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W);
/* describe links for each interfaces */
lsdesc = (struct ospf6_router_lsdesc *)
((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa));
for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi))
{
/* Interfaces in state Down or Loopback are not described */
if (oi->state == OSPF6_INTERFACE_DOWN ||
oi->state == OSPF6_INTERFACE_LOOPBACK)
continue;
/* Nor are interfaces without any full adjacencies described */
count = 0;
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
count++;
if (count == 0)
continue;
/* Multiple Router-LSA instance according to size limit setting */
if ( (oa->router_lsa_size_limit != 0)
&& ((size_t)((char *)lsdesc - buffer)
+ sizeof (struct ospf6_router_lsdesc)
> oa->router_lsa_size_limit))
{
if ((caddr_t) lsdesc == (caddr_t) router_lsa +
sizeof (struct ospf6_router_lsa))
{
if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER))
zlog_debug ("Size limit setting for Router-LSA too short");
return 0;
}
link_state_id ++;
}
/* Point-to-Point interfaces */
if (oi->type == OSPF_IFTYPE_POINTOPOINT)
{
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on))
{
if (on->state != OSPF6_NEIGHBOR_FULL)
continue;
lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT;
lsdesc->metric = htons (oi->cost);
lsdesc->interface_id = htonl (oi->interface->ifindex);
lsdesc->neighbor_interface_id = htonl (on->ifindex);
lsdesc->neighbor_router_id = on->router_id;
lsdesc++;
}
}
/* Broadcast and NBMA interfaces */
else if (oi->type == OSPF_IFTYPE_BROADCAST)
{
/* If this router is not DR,
and If this router not fully adjacent with DR,
this interface is not transit yet: ignore. */
if (oi->state != OSPF6_INTERFACE_DR)
{
drouter = ospf6_neighbor_lookup (oi->drouter, oi);
if (drouter == NULL || drouter->state != OSPF6_NEIGHBOR_FULL)
continue;
}
lsdesc->type = OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK;
lsdesc->metric = htons (oi->cost);
lsdesc->interface_id = htonl (oi->interface->ifindex);
if (oi->state != OSPF6_INTERFACE_DR)
{
lsdesc->neighbor_interface_id = htonl (drouter->ifindex);
lsdesc->neighbor_router_id = drouter->router_id;
}
else
{
lsdesc->neighbor_interface_id = htonl (oi->interface->ifindex);
lsdesc->neighbor_router_id = oi->area->ospf6->router_id;
}
lsdesc++;
}
else
{
assert (0); /* Unknown interface type */
}
/* Virtual links */
/* xxx */
/* Point-to-Multipoint interfaces */
/* xxx */
}
/* Fill LSA Header */
lsa_header->age = 0;
lsa_header->type = htons (OSPF6_LSTYPE_ROUTER);
lsa_header->id = htonl (link_state_id);
lsa_header->adv_router = oa->ospf6->router_id;
lsa_header->seqnum =
ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
lsa_header->adv_router, oa->lsdb);
lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
/* LSA checksum */
ospf6_lsa_checksum (lsa_header);
/* create LSA */
lsa = ospf6_lsa_create (lsa_header);
/* Originate */
ospf6_lsa_originate_area (lsa, oa);
link_state_id ++;
/* Do premature-aging of rest, undesired Router-LSAs */
type = ntohs (OSPF6_LSTYPE_ROUTER);
router = oa->ospf6->router_id;
for (lsa = ospf6_lsdb_type_router_head (type, router, oa->lsdb); lsa;
lsa = ospf6_lsdb_type_router_next (type, router, lsa))
{
if (ntohl (lsa->header->id) < link_state_id)
continue;
ospf6_lsa_purge (lsa);
}
return 0;
}
/*******************************/
/* RFC2740 3.4.3.2 Network-LSA */
/*******************************/
static char *
ospf6_network_lsa_get_ar_id (struct ospf6_lsa *lsa, char *buf, int buflen,
int pos)
{
char *start, *end, *current;
struct ospf6_network_lsa *network_lsa;
struct ospf6_network_lsdesc *lsdesc;
if (lsa)
{
network_lsa = (struct ospf6_network_lsa *)
((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
start = (char *) network_lsa + sizeof (struct ospf6_network_lsa);
end = (char *) lsa->header + ntohs (lsa->header->length);
current = start + pos*(sizeof (struct ospf6_network_lsdesc));
if ((current + sizeof(struct ospf6_network_lsdesc)) <= end)
{
lsdesc = (struct ospf6_network_lsdesc *)current;
if (buf)
inet_ntop (AF_INET, &lsdesc->router_id, buf, buflen);
}
else
return NULL;
}
return (buf);
}
static int
ospf6_network_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
{
char *start, *end, *current;
struct ospf6_network_lsa *network_lsa;
struct ospf6_network_lsdesc *lsdesc;
char buf[128], options[32];
network_lsa = (struct ospf6_network_lsa *)
((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
ospf6_options_printbuf (network_lsa->options, options, sizeof (options));
vty_out (vty, " Options: %s%s", options, VNL);
start = (char *) network_lsa + sizeof (struct ospf6_network_lsa);
end = (char *) lsa->header + ntohs (lsa->header->length);
for (current = start; current + sizeof (struct ospf6_network_lsdesc) <= end;
current += sizeof (struct ospf6_network_lsdesc))
{
lsdesc = (struct ospf6_network_lsdesc *) current;
inet_ntop (AF_INET, &lsdesc->router_id, buf, sizeof (buf));
vty_out (vty, " Attached Router: %s%s", buf, VNL);
}
return 0;
}
int
ospf6_network_lsa_originate (struct thread *thread)
{
struct ospf6_interface *oi;
char buffer [OSPF6_MAX_LSASIZE];
struct ospf6_lsa_header *lsa_header;
int count;
struct ospf6_lsa *old, *lsa;
struct ospf6_network_lsa *network_lsa;
struct ospf6_network_lsdesc *lsdesc;
struct ospf6_neighbor *on;
struct ospf6_link_lsa *link_lsa;
struct listnode *i;
u_int16_t type;
oi = (struct ospf6_interface *) THREAD_ARG (thread);
oi->thread_network_lsa = NULL;
/* The interface must be enabled until here. A Network-LSA of a
disabled interface (but was once enabled) should be flushed
by ospf6_lsa_refresh (), and does not come here. */
assert (oi->area);
old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_NETWORK),
htonl (oi->interface->ifindex),
oi->area->ospf6->router_id, oi->area->lsdb);
/* Do not originate Network-LSA if not DR */
if (oi->state != OSPF6_INTERFACE_DR)
{
if (old)
ospf6_lsa_purge (old);
return 0;
}
if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK))
zlog_debug ("Originate Network-LSA for Interface %s", oi->interface->name);
/* If none of neighbor is adjacent to us */
count = 0;
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
count++;
if (count == 0)
{
if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK))
zlog_debug ("Interface stub, ignore");
if (old)
ospf6_lsa_purge (old);
return 0;
}
/* prepare buffer */
memset (buffer, 0, sizeof (buffer));
lsa_header = (struct ospf6_lsa_header *) buffer;
network_lsa = (struct ospf6_network_lsa *)
((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
/* Collect the interface's Link-LSAs to describe
network's optional capabilities */
type = htons (OSPF6_LSTYPE_LINK);
for (lsa = ospf6_lsdb_type_head (type, oi->lsdb); lsa;
lsa = ospf6_lsdb_type_next (type, lsa))
{
link_lsa = (struct ospf6_link_lsa *)
((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
network_lsa->options[0] |= link_lsa->options[0];
network_lsa->options[1] |= link_lsa->options[1];
network_lsa->options[2] |= link_lsa->options[2];
}
lsdesc = (struct ospf6_network_lsdesc *)
((caddr_t) network_lsa + sizeof (struct ospf6_network_lsa));
/* set Link Description to the router itself */
lsdesc->router_id = oi->area->ospf6->router_id;
lsdesc++;
/* Walk through the neighbors */
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on))
{
if (on->state != OSPF6_NEIGHBOR_FULL)
continue;
/* set this neighbor's Router-ID to LSA */
lsdesc->router_id = on->router_id;
lsdesc++;
}
/* Fill LSA Header */
lsa_header->age = 0;
lsa_header->type = htons (OSPF6_LSTYPE_NETWORK);
lsa_header->id = htonl (oi->interface->ifindex);
lsa_header->adv_router = oi->area->ospf6->router_id;
lsa_header->seqnum =
ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
lsa_header->adv_router, oi->area->lsdb);
lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
/* LSA checksum */
ospf6_lsa_checksum (lsa_header);
/* create LSA */
lsa = ospf6_lsa_create (lsa_header);
/* Originate */
ospf6_lsa_originate_area (lsa, oi->area);
return 0;
}
/****************************/
/* RFC2740 3.4.3.6 Link-LSA */
/****************************/
static char *
ospf6_link_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen,
int pos)
{
char *start, *end, *current;
struct ospf6_link_lsa *link_lsa;
struct in6_addr in6;
struct ospf6_prefix *prefix;
int cnt = 0, prefixnum;
if (lsa)
{
link_lsa = (struct ospf6_link_lsa *)
((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
if (pos == 0) {
inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, buflen);
return (buf);
}
prefixnum = ntohl (link_lsa->prefix_num);
if (pos > prefixnum)
return (NULL);
start = (char *) link_lsa + sizeof (struct ospf6_link_lsa);
end = (char *) lsa->header + ntohs (lsa->header->length);
current = start;
do
{
prefix = (struct ospf6_prefix *) current;
if (prefix->prefix_length == 0 ||
current + OSPF6_PREFIX_SIZE (prefix) > end)
{
return (NULL);
}
if (cnt < pos)
{
current = start + pos*OSPF6_PREFIX_SIZE(prefix);
cnt++;
}
else
{
memset (&in6, 0, sizeof (in6));
memcpy (&in6, OSPF6_PREFIX_BODY (prefix),
OSPF6_PREFIX_SPACE (prefix->prefix_length));
inet_ntop (AF_INET6, &in6, buf, buflen);
return (buf);
}
} while (current <= end);
}
return (NULL);
}
static int
ospf6_link_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
{
char *start, *end, *current;
struct ospf6_link_lsa *link_lsa;
int prefixnum;
char buf[128], options[32];
struct ospf6_prefix *prefix;
const char *p, *mc, *la, *nu;
struct in6_addr in6;
link_lsa = (struct ospf6_link_lsa *)
((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
ospf6_options_printbuf (link_lsa->options, options, sizeof (options));
inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
prefixnum = ntohl (link_lsa->prefix_num);
vty_out (vty, " Priority: %d Options: %s%s",
link_lsa->priority, options, VNL);
vty_out (vty, " LinkLocal Address: %s%s", buf, VNL);
vty_out (vty, " Number of Prefix: %d%s", prefixnum, VNL);
start = (char *) link_lsa + sizeof (struct ospf6_link_lsa);
end = (char *) lsa->header + ntohs (lsa->header->length);
for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
{
prefix = (struct ospf6_prefix *) current;
if (prefix->prefix_length == 0 ||
current + OSPF6_PREFIX_SIZE (prefix) > end)
break;
p = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_P) ?
"P" : "--");
mc = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) ?
"MC" : "--");
la = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) ?
"LA" : "--");
nu = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) ?
"NU" : "--");
vty_out (vty, " Prefix Options: %s|%s|%s|%s%s",
p, mc, la, nu, VNL);
memset (&in6, 0, sizeof (in6));
memcpy (&in6, OSPF6_PREFIX_BODY (prefix),
OSPF6_PREFIX_SPACE (prefix->prefix_length));
inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
vty_out (vty, " Prefix: %s/%d%s",
buf, prefix->prefix_length, VNL);
}
return 0;
}
int
ospf6_link_lsa_originate (struct thread *thread)
{
struct ospf6_interface *oi;
char buffer[OSPF6_MAX_LSASIZE];
struct ospf6_lsa_header *lsa_header;
struct ospf6_lsa *old, *lsa;
struct ospf6_link_lsa *link_lsa;
struct ospf6_route *route;
struct ospf6_prefix *op;
oi = (struct ospf6_interface *) THREAD_ARG (thread);
oi->thread_link_lsa = NULL;
assert (oi->area);
/* find previous LSA */
old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_LINK),
htonl (oi->interface->ifindex),
oi->area->ospf6->router_id, oi->lsdb);
if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE))
{
if (old)
ospf6_lsa_purge (old);
return 0;
}
if (IS_OSPF6_DEBUG_ORIGINATE (LINK))
zlog_debug ("Originate Link-LSA for Interface %s", oi->interface->name);
/* can't make Link-LSA if linklocal address not set */
if (oi->linklocal_addr == NULL)
{
if (IS_OSPF6_DEBUG_ORIGINATE (LINK))
zlog_debug ("No Linklocal address on %s, defer originating",
oi->interface->name);
if (old)
ospf6_lsa_purge (old);
return 0;
}
/* prepare buffer */
memset (buffer, 0, sizeof (buffer));
lsa_header = (struct ospf6_lsa_header *) buffer;
link_lsa = (struct ospf6_link_lsa *)
((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
/* Fill Link-LSA */
link_lsa->priority = oi->priority;
memcpy (link_lsa->options, oi->area->options, 3);
memcpy (&link_lsa->linklocal_addr, oi->linklocal_addr,
sizeof (struct in6_addr));
link_lsa->prefix_num = htonl (oi->route_connected->count);
op = (struct ospf6_prefix *)
((caddr_t) link_lsa + sizeof (struct ospf6_link_lsa));
/* connected prefix to advertise */
for (route = ospf6_route_head (oi->route_connected); route;
route = ospf6_route_next (route))
{
op->prefix_length = route->prefix.prefixlen;
op->prefix_options = route->path.prefix_options;
op->prefix_metric = htons (0);
memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6,
OSPF6_PREFIX_SPACE (op->prefix_length));
op = OSPF6_PREFIX_NEXT (op);
}
/* Fill LSA Header */
lsa_header->age = 0;
lsa_header->type = htons (OSPF6_LSTYPE_LINK);
lsa_header->id = htonl (oi->interface->ifindex);
lsa_header->adv_router = oi->area->ospf6->router_id;
lsa_header->seqnum =
ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
lsa_header->adv_router, oi->lsdb);
lsa_header->length = htons ((caddr_t) op - (caddr_t) buffer);
/* LSA checksum */
ospf6_lsa_checksum (lsa_header);
/* create LSA */
lsa = ospf6_lsa_create (lsa_header);
/* Originate */
ospf6_lsa_originate_interface (lsa, oi);
return 0;
}
/*****************************************/
/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
/*****************************************/
static char *
ospf6_intra_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf,
int buflen, int pos)
{
char *start, *end, *current;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct in6_addr in6;
int prefixnum, cnt = 0;
struct ospf6_prefix *prefix;
if (lsa)
{
intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
prefixnum = ntohs (intra_prefix_lsa->prefix_num);
if (pos > prefixnum)
return (NULL);
start = (char *) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa);
end = (char *) lsa->header + ntohs (lsa->header->length);
current = start;
do
{
prefix = (struct ospf6_prefix *) current;
if (prefix->prefix_length == 0 ||
current + OSPF6_PREFIX_SIZE (prefix) > end)
{
return NULL;
}
if (cnt < pos)
{
current = start + pos*OSPF6_PREFIX_SIZE(prefix);
cnt++;
}
else
{
memset (&in6, 0, sizeof (in6));
memcpy (&in6, OSPF6_PREFIX_BODY (prefix),
OSPF6_PREFIX_SPACE (prefix->prefix_length));
inet_ntop (AF_INET6, &in6, buf, buflen);
sprintf(&buf[strlen(buf)], "/%d", prefix->prefix_length);
return (buf);
}
} while (current <= end);
}
return (buf);
}
static int
ospf6_intra_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
{
char *start, *end, *current;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
int prefixnum;
char buf[128];
struct ospf6_prefix *prefix;
char id[16], adv_router[16];
const char *p, *mc, *la, *nu;
struct in6_addr in6;
intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
prefixnum = ntohs (intra_prefix_lsa->prefix_num);
vty_out (vty, " Number of Prefix: %d%s", prefixnum, VNL);
inet_ntop (AF_INET, &intra_prefix_lsa->ref_id, id, sizeof (id));
inet_ntop (AF_INET, &intra_prefix_lsa->ref_adv_router,
adv_router, sizeof (adv_router));
vty_out (vty, " Reference: %s Id: %s Adv: %s%s",
ospf6_lstype_name (intra_prefix_lsa->ref_type), id, adv_router,
VNL);
start = (char *) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa);
end = (char *) lsa->header + ntohs (lsa->header->length);
for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
{
prefix = (struct ospf6_prefix *) current;
if (prefix->prefix_length == 0 ||
current + OSPF6_PREFIX_SIZE (prefix) > end)
break;
p = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_P) ?
"P" : "--");
mc = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) ?
"MC" : "--");
la = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) ?
"LA" : "--");
nu = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) ?
"NU" : "--");
vty_out (vty, " Prefix Options: %s|%s|%s|%s%s",
p, mc, la, nu, VNL);
memset (&in6, 0, sizeof (in6));
memcpy (&in6, OSPF6_PREFIX_BODY (prefix),
OSPF6_PREFIX_SPACE (prefix->prefix_length));
inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
vty_out (vty, " Prefix: %s/%d%s",
buf, prefix->prefix_length, VNL);
}
return 0;
}
int
ospf6_intra_prefix_lsa_originate_stub (struct thread *thread)
{
struct ospf6_area *oa;
char buffer[OSPF6_MAX_LSASIZE];
struct ospf6_lsa_header *lsa_header;
struct ospf6_lsa *old, *lsa;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct ospf6_interface *oi;
struct ospf6_neighbor *on;
struct ospf6_route *route;
struct ospf6_prefix *op;
struct listnode *i, *j;
int full_count = 0;
unsigned short prefix_num = 0;
char buf[BUFSIZ];
struct ospf6_route_table *route_advertise;
oa = (struct ospf6_area *) THREAD_ARG (thread);
oa->thread_intra_prefix_lsa = NULL;
/* find previous LSA */
old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_INTRA_PREFIX),
htonl (0), oa->ospf6->router_id, oa->lsdb);
if (! IS_AREA_ENABLED (oa))
{
if (old)
ospf6_lsa_purge (old);
return 0;
}
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug ("Originate Intra-Area-Prefix-LSA for area %s's stub prefix",
oa->name);
/* prepare buffer */
memset (buffer, 0, sizeof (buffer));
lsa_header = (struct ospf6_lsa_header *) buffer;
intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
/* Fill Intra-Area-Prefix-LSA */
intra_prefix_lsa->ref_type = htons (OSPF6_LSTYPE_ROUTER);
intra_prefix_lsa->ref_id = htonl (0);
intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
route_advertise = ospf6_route_table_create (0, 0);
for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi))
{
if (oi->state == OSPF6_INTERFACE_DOWN)
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug (" Interface %s is down, ignore", oi->interface->name);
continue;
}
full_count = 0;
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
full_count++;
if (oi->state != OSPF6_INTERFACE_LOOPBACK &&
oi->state != OSPF6_INTERFACE_POINTTOPOINT &&
full_count != 0)
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug (" Interface %s is not stub, ignore",
oi->interface->name);
continue;
}
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug (" Interface %s:", oi->interface->name);
/* connected prefix to advertise */
for (route = ospf6_route_head (oi->route_connected); route;
route = ospf6_route_best_next (route))
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
{
prefix2str (&route->prefix, buf, sizeof (buf));
zlog_debug (" include %s", buf);
}
ospf6_route_add (ospf6_route_copy (route), route_advertise);
}
}
if (route_advertise->count == 0)
{
if (old)
ospf6_lsa_purge (old);
ospf6_route_table_delete (route_advertise);
return 0;
}
/* put prefixes to advertise */
prefix_num = 0;
op = (struct ospf6_prefix *)
((caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa));
for (route = ospf6_route_head (route_advertise); route;
route = ospf6_route_best_next (route))
{
op->prefix_length = route->prefix.prefixlen;
op->prefix_options = route->path.prefix_options;
op->prefix_metric = htons (route->path.cost);
memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6,
OSPF6_PREFIX_SPACE (op->prefix_length));
op = OSPF6_PREFIX_NEXT (op);
prefix_num++;
}
ospf6_route_table_delete (route_advertise);
if (prefix_num == 0)
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug ("Quit to Advertise Intra-Prefix: no route to advertise");
return 0;
}
intra_prefix_lsa->prefix_num = htons (prefix_num);
/* Fill LSA Header */
lsa_header->age = 0;
lsa_header->type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
lsa_header->id = htonl (0);
lsa_header->adv_router = oa->ospf6->router_id;
lsa_header->seqnum =
ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
lsa_header->adv_router, oa->lsdb);
lsa_header->length = htons ((caddr_t) op - (caddr_t) lsa_header);
/* LSA checksum */
ospf6_lsa_checksum (lsa_header);
/* create LSA */
lsa = ospf6_lsa_create (lsa_header);
/* Originate */
ospf6_lsa_originate_area (lsa, oa);
return 0;
}
int
ospf6_intra_prefix_lsa_originate_transit (struct thread *thread)
{
struct ospf6_interface *oi;
char buffer[OSPF6_MAX_LSASIZE];
struct ospf6_lsa_header *lsa_header;
struct ospf6_lsa *old, *lsa;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct ospf6_neighbor *on;
struct ospf6_route *route;
struct ospf6_prefix *op;
struct listnode *i;
int full_count = 0;
unsigned short prefix_num = 0;
struct ospf6_route_table *route_advertise;
struct ospf6_link_lsa *link_lsa;
char *start, *end, *current;
u_int16_t type;
char buf[BUFSIZ];
oi = (struct ospf6_interface *) THREAD_ARG (thread);
oi->thread_intra_prefix_lsa = NULL;
assert (oi->area);
/* find previous LSA */
old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_INTRA_PREFIX),
htonl (oi->interface->ifindex),
oi->area->ospf6->router_id, oi->area->lsdb);
if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE))
{
if (old)
ospf6_lsa_purge (old);
return 0;
}
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug ("Originate Intra-Area-Prefix-LSA for interface %s's prefix",
oi->interface->name);
/* prepare buffer */
memset (buffer, 0, sizeof (buffer));
lsa_header = (struct ospf6_lsa_header *) buffer;
intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
/* Fill Intra-Area-Prefix-LSA */
intra_prefix_lsa->ref_type = htons (OSPF6_LSTYPE_NETWORK);
intra_prefix_lsa->ref_id = htonl (oi->interface->ifindex);
intra_prefix_lsa->ref_adv_router = oi->area->ospf6->router_id;
if (oi->state != OSPF6_INTERFACE_DR)
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug (" Interface is not DR");
if (old)
ospf6_lsa_purge (old);
return 0;
}
full_count = 0;
for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on))
if (on->state == OSPF6_NEIGHBOR_FULL)
full_count++;
if (full_count == 0)
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug (" Interface is stub");
if (old)
ospf6_lsa_purge (old);
return 0;
}
/* connected prefix to advertise */
route_advertise = ospf6_route_table_create (0, 0);
type = ntohs (OSPF6_LSTYPE_LINK);
for (lsa = ospf6_lsdb_type_head (type, oi->lsdb); lsa;
lsa = ospf6_lsdb_type_next (type, lsa))
{
if (OSPF6_LSA_IS_MAXAGE (lsa))
continue;
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug (" include prefix from %s", lsa->name);
if (lsa->header->adv_router != oi->area->ospf6->router_id)
{
on = ospf6_neighbor_lookup (lsa->header->adv_router, oi);
if (on == NULL || on->state != OSPF6_NEIGHBOR_FULL)
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug (" Neighbor not found or not Full, ignore");
continue;
}
}
link_lsa = (struct ospf6_link_lsa *)
((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
prefix_num = (unsigned short) ntohl (link_lsa->prefix_num);
start = (char *) link_lsa + sizeof (struct ospf6_link_lsa);
end = (char *) lsa->header + ntohs (lsa->header->length);
for (current = start; current < end && prefix_num;
current += OSPF6_PREFIX_SIZE (op))
{
op = (struct ospf6_prefix *) current;
if (op->prefix_length == 0 ||
current + OSPF6_PREFIX_SIZE (op) > end)
break;
route = ospf6_route_create ();
route->type = OSPF6_DEST_TYPE_NETWORK;
route->prefix.family = AF_INET6;
route->prefix.prefixlen = op->prefix_length;
memset (&route->prefix.u.prefix6, 0, sizeof (struct in6_addr));
memcpy (&route->prefix.u.prefix6, OSPF6_PREFIX_BODY (op),
OSPF6_PREFIX_SPACE (op->prefix_length));
route->path.origin.type = lsa->header->type;
route->path.origin.id = lsa->header->id;
route->path.origin.adv_router = lsa->header->adv_router;
route->path.options[0] = link_lsa->options[0];
route->path.options[1] = link_lsa->options[1];
route->path.options[2] = link_lsa->options[2];
route->path.prefix_options = op->prefix_options;
route->path.area_id = oi->area->area_id;
route->path.type = OSPF6_PATH_TYPE_INTRA;
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
{
prefix2str (&route->prefix, buf, sizeof (buf));
zlog_debug (" include %s", buf);
}
ospf6_route_add (route, route_advertise);
prefix_num--;
}
if (current != end && IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug ("Trailing garbage in %s", lsa->name);
}
op = (struct ospf6_prefix *)
((caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa));
prefix_num = 0;
for (route = ospf6_route_head (route_advertise); route;
route = ospf6_route_best_next (route))
{
op->prefix_length = route->prefix.prefixlen;
op->prefix_options = route->path.prefix_options;
op->prefix_metric = htons (0);
memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6,
OSPF6_PREFIX_SPACE (op->prefix_length));
op = OSPF6_PREFIX_NEXT (op);
prefix_num++;
}
ospf6_route_table_delete (route_advertise);
if (prefix_num == 0)
{
if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX))
zlog_debug ("Quit to Advertise Intra-Prefix: no route to advertise");
return 0;
}
intra_prefix_lsa->prefix_num = htons (prefix_num);
/* Fill LSA Header */
lsa_header->age = 0;
lsa_header->type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
lsa_header->id = htonl (oi->interface->ifindex);
lsa_header->adv_router = oi->area->ospf6->router_id;
lsa_header->seqnum =
ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id,
lsa_header->adv_router, oi->area->lsdb);
lsa_header->length = htons ((caddr_t) op - (caddr_t) lsa_header);
/* LSA checksum */
ospf6_lsa_checksum (lsa_header);
/* create LSA */
lsa = ospf6_lsa_create (lsa_header);
/* Originate */
ospf6_lsa_originate_area (lsa, oi->area);
return 0;
}
void
ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
{
struct ospf6_area *oa;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct prefix ls_prefix;
struct ospf6_route *route, *ls_entry;
int i, prefix_num;
struct ospf6_prefix *op;
char *start, *current, *end;
char buf[64];
struct interface *ifp;
int direct_connect = 0;
if (OSPF6_LSA_IS_MAXAGE (lsa))
return;
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
zlog_debug ("%s found", lsa->name);
oa = OSPF6_AREA (lsa->lsdb->data);
intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
OSPF6_LSA_HEADER_END (lsa->header);
if (intra_prefix_lsa->ref_type == htons (OSPF6_LSTYPE_ROUTER))
ospf6_linkstate_prefix (intra_prefix_lsa->ref_adv_router,
htonl (0), &ls_prefix);
else if (intra_prefix_lsa->ref_type == htons (OSPF6_LSTYPE_NETWORK))
ospf6_linkstate_prefix (intra_prefix_lsa->ref_adv_router,
intra_prefix_lsa->ref_id, &ls_prefix);
else
{
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
zlog_debug ("Unknown reference LS-type: %#hx",
ntohs (intra_prefix_lsa->ref_type));
return;
}
ls_entry = ospf6_route_lookup (&ls_prefix, oa->spf_table);
if (ls_entry == NULL)
{
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
{
ospf6_linkstate_prefix2str (&ls_prefix, buf, sizeof (buf));
zlog_debug ("LS entry does not exist: %s", buf);
}
return;
}
if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id)
{
/* the intra-prefix are directly connected */
direct_connect = 1;
}
prefix_num = ntohs (intra_prefix_lsa->prefix_num);
start = (caddr_t) intra_prefix_lsa +
sizeof (struct ospf6_intra_prefix_lsa);
end = OSPF6_LSA_END (lsa->header);
for (current = start; current < end; current += OSPF6_PREFIX_SIZE (op))
{
op = (struct ospf6_prefix *) current;
if (prefix_num == 0)
break;
if (end < current + OSPF6_PREFIX_SIZE (op))
break;
/* Appendix A.4.1.1 */
if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU))
{
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
{
ospf6_linkstate_prefix2str ((struct prefix *)OSPF6_PREFIX_BODY(op),
buf, sizeof (buf));
zlog_debug ("%s: Skipping Prefix %s has NU option set",
__func__, buf);
}
continue;
}
route = ospf6_route_create ();
memset (&route->prefix, 0, sizeof (struct prefix));
route->prefix.family = AF_INET6;
route->prefix.prefixlen = op->prefix_length;
ospf6_prefix_in6_addr (&route->prefix.u.prefix6, op);
route->type = OSPF6_DEST_TYPE_NETWORK;
route->path.origin.type = lsa->header->type;
route->path.origin.id = lsa->header->id;
route->path.origin.adv_router = lsa->header->adv_router;
route->path.prefix_options = op->prefix_options;
route->path.area_id = oa->area_id;
route->path.type = OSPF6_PATH_TYPE_INTRA;
route->path.metric_type = 1;
route->path.cost = ls_entry->path.cost +
ntohs (op->prefix_metric);
if (direct_connect)
{
ifp = if_lookup_prefix(&route->prefix);
if (ifp)
route->nexthop[0].ifindex = ifp->ifindex;
}
else
{
for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) &&
i < OSPF6_MULTI_PATH_LIMIT; i++)
ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]);
}
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
{
prefix2str (&route->prefix, buf, sizeof (buf));
zlog_debug (" add %s", buf);
}
ospf6_route_add (route, oa->route_table);
prefix_num--;
}
if (current != end && IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
zlog_debug ("Trailing garbage ignored");
}
void
ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa)
{
struct ospf6_area *oa;
struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
struct prefix prefix;
struct ospf6_route *route, *nroute;
int prefix_num;
struct ospf6_prefix *op;
char *start, *current, *end;
char buf[64];
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
zlog_debug ("%s disappearing", lsa->name);
oa = OSPF6_AREA (lsa->lsdb->data);
intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
OSPF6_LSA_HEADER_END (lsa->header);
prefix_num = ntohs (intra_prefix_lsa->prefix_num);
start = (caddr_t) intra_prefix_lsa +
sizeof (struct ospf6_intra_prefix_lsa);
end = OSPF6_LSA_END (lsa->header);
for (current = start; current < end; current += OSPF6_PREFIX_SIZE (op))
{
op = (struct ospf6_prefix *) current;
if (prefix_num == 0)
break;
if (end < current + OSPF6_PREFIX_SIZE (op))
break;
prefix_num--;
memset (&prefix, 0, sizeof (struct prefix));
prefix.family = AF_INET6;
prefix.prefixlen = op->prefix_length;
ospf6_prefix_in6_addr (&prefix.u.prefix6, op);
route = ospf6_route_lookup (&prefix, oa->route_table);
if (route == NULL)
continue;
for (ospf6_route_lock (route);
route && ospf6_route_is_prefix (&prefix, route);
route = nroute)
{
nroute = ospf6_route_next (route);
if (route->type != OSPF6_DEST_TYPE_NETWORK)
continue;
if (route->path.area_id != oa->area_id)
continue;
if (route->path.type != OSPF6_PATH_TYPE_INTRA)
continue;
if (route->path.origin.type != lsa->header->type ||
route->path.origin.id != lsa->header->id ||
route->path.origin.adv_router != lsa->header->adv_router)
continue;
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
{
prefix2str (&route->prefix, buf, sizeof (buf));
zlog_debug ("remove %s", buf);
}
ospf6_route_remove (route, oa->route_table);
}
if (route)
ospf6_route_unlock (route);
}
if (current != end && IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
zlog_debug ("Trailing garbage ignored");
}
void
ospf6_intra_route_calculation (struct ospf6_area *oa)
{
struct ospf6_route *route, *nroute;
u_int16_t type;
struct ospf6_lsa *lsa;
void (*hook_add) (struct ospf6_route *) = NULL;
void (*hook_remove) (struct ospf6_route *) = NULL;
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
zlog_debug ("Re-examin intra-routes for area %s", oa->name);
hook_add = oa->route_table->hook_add;
hook_remove = oa->route_table->hook_remove;
oa->route_table->hook_add = NULL;
oa->route_table->hook_remove = NULL;
for (route = ospf6_route_head (oa->route_table); route;
route = ospf6_route_next (route))
route->flag = OSPF6_ROUTE_REMOVE;
type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa;
lsa = ospf6_lsdb_type_next (type, lsa))
ospf6_intra_prefix_lsa_add (lsa);
oa->route_table->hook_add = hook_add;
oa->route_table->hook_remove = hook_remove;
for (route = ospf6_route_head (oa->route_table); route;
route = nroute)
{
nroute = ospf6_route_next (route);
if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) &&
CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD))
{
UNSET_FLAG (route->flag, OSPF6_ROUTE_REMOVE);
UNSET_FLAG (route->flag, OSPF6_ROUTE_ADD);
}
if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE))
ospf6_route_remove (route, oa->route_table);
else if (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ||
CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE))
{
if (hook_add)
(*hook_add) (route);
}
route->flag = 0;
}
if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX))
zlog_debug ("Re-examin intra-routes for area %s: Done", oa->name);
}
static void
ospf6_brouter_debug_print (struct ospf6_route *brouter)
{
u_int32_t brouter_id;
char brouter_name[16];
char area_name[16];
char destination[64];
char installed[16], changed[16];
struct timeval now, res;
char id[16], adv_router[16];
char capa[16], options[16];
brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix);
inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
inet_ntop (AF_INET, &brouter->path.area_id, area_name, sizeof (area_name));
ospf6_linkstate_prefix2str (&brouter->prefix, destination,
sizeof (destination));
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
timersub (&now, &brouter->installed, &res);
timerstring (&res, installed, sizeof (installed));
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
timersub (&now, &brouter->changed, &res);
timerstring (&res, changed, sizeof (changed));
inet_ntop (AF_INET, &brouter->path.origin.id, id, sizeof (id));
inet_ntop (AF_INET, &brouter->path.origin.adv_router, adv_router,
sizeof (adv_router));
ospf6_options_printbuf (brouter->path.options, options, sizeof (options));
ospf6_capability_printbuf (brouter->path.router_bits, capa, sizeof (capa));
zlog_info ("Brouter: %s via area %s", brouter_name, area_name);
zlog_info (" memory: prev: %p this: %p next: %p parent rnode: %p",
(void *)brouter->prev, (void *)brouter, (void *)brouter->next,
(void *)brouter->rnode);
zlog_info (" type: %d prefix: %s installed: %s changed: %s",
brouter->type, destination, installed, changed);
zlog_info (" lock: %d flags: %s%s%s%s", brouter->lock,
(CHECK_FLAG (brouter->flag, OSPF6_ROUTE_BEST) ? "B" : "-"),
(CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD) ? "A" : "-"),
(CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
(CHECK_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"));
zlog_info (" path type: %s ls-origin %s id: %s adv-router %s",
OSPF6_PATH_TYPE_NAME (brouter->path.type),
ospf6_lstype_name (brouter->path.origin.type),
id, adv_router);
zlog_info (" options: %s router-bits: %s metric-type: %d metric: %d/%d",
options, capa, brouter->path.metric_type,
brouter->path.cost, brouter->path.cost_e2);
}
void
ospf6_intra_brouter_calculation (struct ospf6_area *oa)
{
struct ospf6_route *brouter, *nbrouter, *copy;
void (*hook_add) (struct ospf6_route *) = NULL;
void (*hook_remove) (struct ospf6_route *) = NULL;
u_int32_t brouter_id;
char brouter_name[16];
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
zlog_info ("border-router calculation for area %s", oa->name);
hook_add = oa->ospf6->brouter_table->hook_add;
hook_remove = oa->ospf6->brouter_table->hook_remove;
oa->ospf6->brouter_table->hook_add = NULL;
oa->ospf6->brouter_table->hook_remove = NULL;
/* withdraw the previous router entries for the area */
for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter;
brouter = ospf6_route_next (brouter))
{
brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix);
inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
if (brouter->path.area_id != oa->area_id)
continue;
brouter->flag = OSPF6_ROUTE_REMOVE;
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
IS_OSPF6_DEBUG_ROUTE (MEMORY))
{
zlog_info ("%p: mark as removing: area %s brouter %s",
(void *)brouter, oa->name, brouter_name);
ospf6_brouter_debug_print (brouter);
}
}
for (brouter = ospf6_route_head (oa->spf_table); brouter;
brouter = ospf6_route_next (brouter))
{
brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix);
inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
if (brouter->type != OSPF6_DEST_TYPE_LINKSTATE)
continue;
if (ospf6_linkstate_prefix_id (&brouter->prefix) != htonl (0))
continue;
if (! CHECK_FLAG (brouter->path.router_bits, OSPF6_ROUTER_BIT_E) &&
! CHECK_FLAG (brouter->path.router_bits, OSPF6_ROUTER_BIT_B))
continue;
if (! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_V6) ||
! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_R))
continue;
copy = ospf6_route_copy (brouter);
copy->type = OSPF6_DEST_TYPE_ROUTER;
copy->path.area_id = oa->area_id;
ospf6_route_add (copy, oa->ospf6->brouter_table);
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
IS_OSPF6_DEBUG_ROUTE (MEMORY))
{
zlog_info ("%p: transfer: area %s brouter %s",
(void *)brouter, oa->name, brouter_name);
ospf6_brouter_debug_print (brouter);
}
}
oa->ospf6->brouter_table->hook_add = hook_add;
oa->ospf6->brouter_table->hook_remove = hook_remove;
for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter;
brouter = nbrouter)
{
nbrouter = ospf6_route_next (brouter);
brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix);
inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name));
if (brouter->path.area_id != oa->area_id)
continue;
if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_WAS_REMOVED))
continue;
if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE) &&
CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD))
{
UNSET_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE);
UNSET_FLAG (brouter->flag, OSPF6_ROUTE_ADD);
}
if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE))
{
if (IS_OSPF6_DEBUG_BROUTER ||
IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
zlog_info ("brouter %s disappears via area %s",
brouter_name, oa->name);
ospf6_route_remove (brouter, oa->ospf6->brouter_table);
}
else if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD) ||
CHECK_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE))
{
if (IS_OSPF6_DEBUG_BROUTER ||
IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
zlog_info ("brouter %s appears via area %s",
brouter_name, oa->name);
/* newly added */
if (hook_add)
(*hook_add) (brouter);
}
else
{
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) ||
IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
zlog_info ("brouter %s still exists via area %s",
brouter_name, oa->name);
}
brouter->flag = 0;
}
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id))
zlog_info ("border-router calculation for area %s: done", oa->name);
}
struct ospf6_lsa_handler router_handler =
{
OSPF6_LSTYPE_ROUTER,
"Router",
"Rtr",
ospf6_router_lsa_show,
ospf6_router_lsa_get_nbr_id
};
struct ospf6_lsa_handler network_handler =
{
OSPF6_LSTYPE_NETWORK,
"Network",
"Net",
ospf6_network_lsa_show,
ospf6_network_lsa_get_ar_id
};
struct ospf6_lsa_handler link_handler =
{
OSPF6_LSTYPE_LINK,
"Link",
"Lnk",
ospf6_link_lsa_show,
ospf6_link_lsa_get_prefix_str
};
struct ospf6_lsa_handler intra_prefix_handler =
{
OSPF6_LSTYPE_INTRA_PREFIX,
"Intra-Prefix",
"INP",
ospf6_intra_prefix_lsa_show,
ospf6_intra_prefix_lsa_get_prefix_str
};
void
ospf6_intra_init (void)
{
ospf6_install_lsa_handler (&router_handler);
ospf6_install_lsa_handler (&network_handler);
ospf6_install_lsa_handler (&link_handler);
ospf6_install_lsa_handler (&intra_prefix_handler);
}
DEFUN (debug_ospf6_brouter,
debug_ospf6_brouter_cmd,
"debug ospf6 border-routers",
DEBUG_STR
OSPF6_STR
"Debug border router\n"
)
{
OSPF6_DEBUG_BROUTER_ON ();
return CMD_SUCCESS;
}
DEFUN (no_debug_ospf6_brouter,
no_debug_ospf6_brouter_cmd,
"no debug ospf6 border-routers",
NO_STR
DEBUG_STR
OSPF6_STR
"Debug border router\n"
)
{
OSPF6_DEBUG_BROUTER_OFF ();
return CMD_SUCCESS;
}
DEFUN (debug_ospf6_brouter_router,
debug_ospf6_brouter_router_cmd,
"debug ospf6 border-routers router-id A.B.C.D",
DEBUG_STR
OSPF6_STR
"Debug border router\n"
"Debug specific border router\n"
"Specify border-router's router-id\n"
)
{
u_int32_t router_id;
inet_pton (AF_INET, argv[0], &router_id);
OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ON (router_id);
return CMD_SUCCESS;
}
DEFUN (no_debug_ospf6_brouter_router,
no_debug_ospf6_brouter_router_cmd,
"no debug ospf6 border-routers router-id",
NO_STR
DEBUG_STR
OSPF6_STR
"Debug border router\n"
"Debug specific border router\n"
)
{
OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF ();
return CMD_SUCCESS;
}
DEFUN (debug_ospf6_brouter_area,
debug_ospf6_brouter_area_cmd,
"debug ospf6 border-routers area-id A.B.C.D",
DEBUG_STR
OSPF6_STR
"Debug border router\n"
"Debug border routers in specific Area\n"
"Specify Area-ID\n"
)
{
u_int32_t area_id;
inet_pton (AF_INET, argv[0], &area_id);
OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ON (area_id);
return CMD_SUCCESS;
}
DEFUN (no_debug_ospf6_brouter_area,
no_debug_ospf6_brouter_area_cmd,
"no debug ospf6 border-routers area-id",
NO_STR
DEBUG_STR
OSPF6_STR
"Debug border router\n"
"Debug border routers in specific Area\n"
)
{
OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF ();
return CMD_SUCCESS;
}
int
config_write_ospf6_debug_brouter (struct vty *vty)
{
char buf[16];
if (IS_OSPF6_DEBUG_BROUTER)
vty_out (vty, "debug ospf6 border-routers%s", VNL);
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER)
{
inet_ntop (AF_INET, &conf_debug_ospf6_brouter_specific_router_id,
buf, sizeof (buf));
vty_out (vty, "debug ospf6 border-routers router-id %s%s", buf, VNL);
}
if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA)
{
inet_ntop (AF_INET, &conf_debug_ospf6_brouter_specific_area_id,
buf, sizeof (buf));
vty_out (vty, "debug ospf6 border-routers area-id %s%s", buf, VNL);
}
return 0;
}
void
install_element_ospf6_debug_brouter (void)
{
install_element (ENABLE_NODE, &debug_ospf6_brouter_cmd);
install_element (ENABLE_NODE, &debug_ospf6_brouter_router_cmd);
install_element (ENABLE_NODE, &debug_ospf6_brouter_area_cmd);
install_element (ENABLE_NODE, &no_debug_ospf6_brouter_cmd);
install_element (ENABLE_NODE, &no_debug_ospf6_brouter_router_cmd);
install_element (ENABLE_NODE, &no_debug_ospf6_brouter_area_cmd);
install_element (CONFIG_NODE, &debug_ospf6_brouter_cmd);
install_element (CONFIG_NODE, &debug_ospf6_brouter_router_cmd);
install_element (CONFIG_NODE, &debug_ospf6_brouter_area_cmd);
install_element (CONFIG_NODE, &no_debug_ospf6_brouter_cmd);
install_element (CONFIG_NODE, &no_debug_ospf6_brouter_router_cmd);
install_element (CONFIG_NODE, &no_debug_ospf6_brouter_area_cmd);
}