mirror_frr/ospfd/ospf_lsdb.c
Paul Jakma 1fe6ed38cd [ospfd] Allow ospf_lsa_unlock to NULL out callers' LSA pointers upon free
2006-07-26 Paul Jakma <paul.jakma@sun.com>

	* ospf_lsa.{c,h}: (ospf_lsa_unlock) Change to take a double pointer
	  to the LSA to be 'unlocked', so that, if the LSA is freed, the
	  callers pointer to the LSA can be NULLed out, allowing any further
	  use of that pointer to provoke a crash sooner rather than later.
	* ospf_*.c: (general) Adjust callers of ospf_lsa_unlock to match
	  previous. Try annotate 'locking' somewhat to show which 'locks'
	  are protecting what LSA reference, if not obvious.
	* ospf_opaque.c: (ospf_opaque_lsa_install) Trivial: remove useless
	  goto, replace with return.
	* ospf_packet.c: (ospf_make_ls_ack) Trivial: merge two list loops,
	  the dual-loop predated the delete-safe list-loop macro.
2006-07-26 09:37:26 +00:00

331 lines
7.2 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* OSPF LSDB support.
* Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada
*
* 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 "prefix.h"
#include "table.h"
#include "memory.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_asbr.h"
#include "ospfd/ospf_lsa.h"
#include "ospfd/ospf_lsdb.h"
struct ospf_lsdb *
ospf_lsdb_new ()
{
struct ospf_lsdb *new;
new = XCALLOC (MTYPE_OSPF_LSDB, sizeof (struct ospf_lsdb));
ospf_lsdb_init (new);
return new;
}
void
ospf_lsdb_init (struct ospf_lsdb *lsdb)
{
int i;
for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
lsdb->type[i].db = route_table_init ();
}
void
ospf_lsdb_free (struct ospf_lsdb *lsdb)
{
ospf_lsdb_cleanup (lsdb);
XFREE (MTYPE_OSPF_LSDB, lsdb);
}
void
ospf_lsdb_cleanup (struct ospf_lsdb *lsdb)
{
int i;
assert (lsdb);
assert (lsdb->total == 0);
ospf_lsdb_delete_all (lsdb);
for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
route_table_finish (lsdb->type[i].db);
}
static void
lsdb_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa)
{
memset (lp, 0, sizeof (struct prefix_ls));
lp->family = 0;
lp->prefixlen = 64;
lp->id = lsa->data->id;
lp->adv_router = lsa->data->adv_router;
}
/* Add new LSA to lsdb. */
void
ospf_lsdb_add (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
{
struct route_table *table;
struct prefix_ls lp;
struct route_node *rn;
struct ospf_lsa *old;
table = lsdb->type[lsa->data->type].db;
lsdb_prefix_set (&lp, lsa);
rn = route_node_get (table, (struct prefix *)&lp);
if (!rn->info)
{
if (IS_LSA_SELF (lsa))
lsdb->type[lsa->data->type].count_self++;
lsdb->type[lsa->data->type].count++;
lsdb->total++;
}
else
{
if (rn->info == lsa)
return;
old = rn->info;
lsdb->type[old->data->type].checksum -= ntohs(old->data->checksum);
ospf_lsa_unlock (&rn->info);
route_unlock_node (rn);
}
#ifdef MONITOR_LSDB_CHANGE
if (lsdb->new_lsa_hook != NULL)
(* lsdb->new_lsa_hook)(lsa);
#endif /* MONITOR_LSDB_CHANGE */
lsdb->type[lsa->data->type].checksum += ntohs(lsa->data->checksum);
rn->info = ospf_lsa_lock (lsa);
}
void
ospf_lsdb_delete (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
{
struct route_table *table;
struct prefix_ls lp;
struct route_node *rn;
if (!lsdb)
{
zlog_warn ("%s: Called with NULL LSDB", __func__);
if (lsa)
zlog_warn ("LSA[Type%d:%s]: LSA %p, lsa->lsdb %p",
lsa->data->type, inet_ntoa (lsa->data->id),
lsa, lsa->lsdb);
return;
}
if (!lsa)
{
zlog_warn ("%s: Called with NULL LSA", __func__);
return;
}
table = lsdb->type[lsa->data->type].db;
lsdb_prefix_set (&lp, lsa);
rn = route_node_lookup (table, (struct prefix *) &lp);
if (rn)
if (rn->info == lsa)
{
if (IS_LSA_SELF (lsa))
lsdb->type[lsa->data->type].count_self--;
lsdb->type[lsa->data->type].count--;
lsdb->type[lsa->data->type].checksum -= ntohs(lsa->data->checksum);
lsdb->total--;
rn->info = NULL;
route_unlock_node (rn);
route_unlock_node (rn);
#ifdef MONITOR_LSDB_CHANGE
if (lsdb->del_lsa_hook != NULL)
(* lsdb->del_lsa_hook)(lsa);
#endif /* MONITOR_LSDB_CHANGE */
ospf_lsa_unlock (&lsa);
return;
}
}
void
ospf_lsdb_delete_all (struct ospf_lsdb *lsdb)
{
struct route_table *table;
struct route_node *rn;
struct ospf_lsa *lsa;
int i;
for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
{
table = lsdb->type[i].db;
for (rn = route_top (table); rn; rn = route_next (rn))
if ((lsa = (rn->info)) != NULL)
{
if (IS_LSA_SELF (lsa))
lsdb->type[i].count_self--;
lsdb->type[i].count--;
lsdb->type[i].checksum -= ntohs(lsa->data->checksum);
lsdb->total--;
rn->info = NULL;
route_unlock_node (rn);
#ifdef MONITOR_LSDB_CHANGE
if (lsdb->del_lsa_hook != NULL)
(* lsdb->del_lsa_hook)(lsa);
#endif /* MONITOR_LSDB_CHANGE */
ospf_lsa_unlock (&lsa);
}
}
}
void
ospf_lsdb_clean_stat (struct ospf_lsdb *lsdb)
{
struct route_table *table;
struct route_node *rn;
struct ospf_lsa *lsa;
int i;
for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
{
table = lsdb->type[i].db;
for (rn = route_top (table); rn; rn = route_next (rn))
if ((lsa = (rn->info)) != NULL)
lsa->stat = LSA_SPF_NOT_EXPLORED;
}
}
struct ospf_lsa *
ospf_lsdb_lookup (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
{
struct route_table *table;
struct prefix_ls lp;
struct route_node *rn;
struct ospf_lsa *find;
table = lsdb->type[lsa->data->type].db;
lsdb_prefix_set (&lp, lsa);
rn = route_node_lookup (table, (struct prefix *) &lp);
if (rn)
{
find = rn->info;
route_unlock_node (rn);
return find;
}
return NULL;
}
struct ospf_lsa *
ospf_lsdb_lookup_by_id (struct ospf_lsdb *lsdb, u_char type,
struct in_addr id, struct in_addr adv_router)
{
struct route_table *table;
struct prefix_ls lp;
struct route_node *rn;
struct ospf_lsa *find;
table = lsdb->type[type].db;
memset (&lp, 0, sizeof (struct prefix_ls));
lp.family = 0;
lp.prefixlen = 64;
lp.id = id;
lp.adv_router = adv_router;
rn = route_node_lookup (table, (struct prefix *) &lp);
if (rn)
{
find = rn->info;
route_unlock_node (rn);
return find;
}
return NULL;
}
struct ospf_lsa *
ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *lsdb, u_char type,
struct in_addr id, struct in_addr adv_router,
int first)
{
struct route_table *table;
struct prefix_ls lp;
struct route_node *rn;
struct ospf_lsa *find;
table = lsdb->type[type].db;
memset (&lp, 0, sizeof (struct prefix_ls));
lp.family = 0;
lp.prefixlen = 64;
lp.id = id;
lp.adv_router = adv_router;
if (first)
rn = route_top (table);
else
{
rn = route_node_get (table, (struct prefix *) &lp);
rn = route_next (rn);
}
for (; rn; rn = route_next (rn))
if (rn->info)
break;
if (rn && rn->info)
{
find = rn->info;
route_unlock_node (rn);
return find;
}
return NULL;
}
unsigned long
ospf_lsdb_count_all (struct ospf_lsdb *lsdb)
{
return lsdb->total;
}
unsigned long
ospf_lsdb_count (struct ospf_lsdb *lsdb, int type)
{
return lsdb->type[type].count;
}
unsigned long
ospf_lsdb_count_self (struct ospf_lsdb *lsdb, int type)
{
return lsdb->type[type].count_self;
}
unsigned int
ospf_lsdb_checksum (struct ospf_lsdb *lsdb, int type)
{
return lsdb->type[type].checksum;
}
unsigned long
ospf_lsdb_isempty (struct ospf_lsdb *lsdb)
{
return (lsdb->total == 0);
}