| /* |
| * 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 "log.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); |
| } |
| |
| void |
| ls_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa) |
| { |
| if (lp && lsa && lsa->data) |
| { |
| lp->family = 0; |
| lp->prefixlen = 64; |
| lp->id = lsa->data->id; |
| lp->adv_router = lsa->data->adv_router; |
| } |
| } |
| |
| static void |
| ospf_lsdb_delete_entry (struct ospf_lsdb *lsdb, struct route_node *rn) |
| { |
| struct ospf_lsa *lsa = rn->info; |
| |
| if (!lsa) |
| return; |
| |
| assert (rn->table == lsdb->type[lsa->data->type].db); |
| |
| 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); |
| #ifdef MONITOR_LSDB_CHANGE |
| if (lsdb->del_lsa_hook != NULL) |
| (* lsdb->del_lsa_hook)(lsa); |
| #endif /* MONITOR_LSDB_CHANGE */ |
| ospf_lsa_unlock (&lsa); /* lsdb */ |
| return; |
| } |
| |
| /* 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; |
| |
| table = lsdb->type[lsa->data->type].db; |
| ls_prefix_set (&lp, lsa); |
| rn = route_node_get (table, (struct prefix *)&lp); |
| |
| /* nothing to do? */ |
| if (rn->info && rn->info == lsa) |
| { |
| route_unlock_node (rn); |
| return; |
| } |
| |
| /* purge old entry? */ |
| if (rn->info) |
| ospf_lsdb_delete_entry (lsdb, rn); |
| |
| if (IS_LSA_SELF (lsa)) |
| lsdb->type[lsa->data->type].count_self++; |
| lsdb->type[lsa->data->type].count++; |
| lsdb->total++; |
| |
| #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); /* lsdb */ |
| } |
| |
| 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), |
| (void *)lsa, (void *)lsa->lsdb); |
| return; |
| } |
| |
| if (!lsa) |
| { |
| zlog_warn ("%s: Called with NULL LSA", __func__); |
| return; |
| } |
| |
| assert (lsa->data->type < OSPF_MAX_LSA); |
| table = lsdb->type[lsa->data->type].db; |
| ls_prefix_set (&lp, lsa); |
| if ((rn = route_node_lookup (table, (struct prefix *) &lp))) |
| { |
| if (rn->info == lsa) |
| ospf_lsdb_delete_entry (lsdb, rn); |
| route_unlock_node (rn); /* route_node_lookup */ |
| } |
| } |
| |
| void |
| ospf_lsdb_delete_all (struct ospf_lsdb *lsdb) |
| { |
| struct route_table *table; |
| struct route_node *rn; |
| 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 (rn->info != NULL) |
| ospf_lsdb_delete_entry (lsdb, rn); |
| } |
| } |
| |
| 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; |
| ls_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 |
| { |
| if ((rn = route_node_lookup (table, (struct prefix *) &lp)) == NULL) |
| return NULL; |
| 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); |
| } |