1/*
2 * OSPF LSDB support.
3 * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "prefix.h"
26#include "table.h"
27#include "memory.h"
28
29#include "ospfd/ospfd.h"
30#include "ospfd/ospf_asbr.h"
31#include "ospfd/ospf_lsa.h"
32#include "ospfd/ospf_lsdb.h"
33
34struct ospf_lsdb *
35ospf_lsdb_new ()
36{
37  struct ospf_lsdb *new;
38
39  new = XCALLOC (MTYPE_OSPF_LSDB, sizeof (struct ospf_lsdb));
40  ospf_lsdb_init (new);
41
42  return new;
43}
44
45void
46ospf_lsdb_init (struct ospf_lsdb *lsdb)
47{
48  int i;
49
50  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
51    lsdb->type[i].db = route_table_init ();
52}
53
54void
55ospf_lsdb_free (struct ospf_lsdb *lsdb)
56{
57  ospf_lsdb_cleanup (lsdb);
58  XFREE (MTYPE_OSPF_LSDB, lsdb);
59}
60
61void
62ospf_lsdb_cleanup (struct ospf_lsdb *lsdb)
63{
64  int i;
65  assert (lsdb);
66  assert (lsdb->total == 0);
67
68  ospf_lsdb_delete_all (lsdb);
69
70  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
71    route_table_finish (lsdb->type[i].db);
72}
73
74void
75lsdb_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa)
76{
77  memset (lp, 0, sizeof (struct prefix_ls));
78  lp->family = 0;
79  lp->prefixlen = 64;
80  lp->id = lsa->data->id;
81  lp->adv_router = lsa->data->adv_router;
82}
83
84/* Add new LSA to lsdb. */
85void
86ospf_lsdb_add (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
87{
88  struct route_table *table;
89  struct prefix_ls lp;
90  struct route_node *rn;
91
92  table = lsdb->type[lsa->data->type].db;
93  lsdb_prefix_set (&lp, lsa);
94  rn = route_node_get (table, (struct prefix *)&lp);
95  if (!rn->info)
96    {
97      if (IS_LSA_SELF (lsa))
98	lsdb->type[lsa->data->type].count_self++;
99      lsdb->type[lsa->data->type].count++;
100      lsdb->total++;
101    }
102  else
103    {
104      if (rn->info == lsa)
105	return;
106
107      ospf_lsa_unlock (rn->info);
108      route_unlock_node (rn);
109    }
110
111#ifdef MONITOR_LSDB_CHANGE
112  if (lsdb->new_lsa_hook != NULL)
113    (* lsdb->new_lsa_hook)(lsa);
114#endif /* MONITOR_LSDB_CHANGE */
115  rn->info = ospf_lsa_lock (lsa);
116}
117
118void
119ospf_lsdb_delete (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
120{
121  struct route_table *table;
122  struct prefix_ls lp;
123  struct route_node *rn;
124
125  table = lsdb->type[lsa->data->type].db;
126  lsdb_prefix_set (&lp, lsa);
127  rn = route_node_lookup (table, (struct prefix *) &lp);
128  if (rn)
129    if (rn->info == lsa)
130      {
131	if (IS_LSA_SELF (lsa))
132	  lsdb->type[lsa->data->type].count_self--;
133	lsdb->type[lsa->data->type].count--;
134	lsdb->total--;
135	rn->info = NULL;
136	route_unlock_node (rn);
137	route_unlock_node (rn);
138#ifdef MONITOR_LSDB_CHANGE
139        if (lsdb->del_lsa_hook != NULL)
140          (* lsdb->del_lsa_hook)(lsa);
141#endif /* MONITOR_LSDB_CHANGE */
142	ospf_lsa_unlock (lsa);
143	return;
144      }
145}
146
147void
148ospf_lsdb_delete_all (struct ospf_lsdb *lsdb)
149{
150  struct route_table *table;
151  struct route_node *rn;
152  struct ospf_lsa *lsa;
153  int i;
154
155  for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
156    {
157      table = lsdb->type[i].db;
158      for (rn = route_top (table); rn; rn = route_next (rn))
159	if ((lsa = (rn->info)) != NULL)
160	  {
161	    if (IS_LSA_SELF (lsa))
162	      lsdb->type[i].count_self--;
163	    lsdb->type[i].count--;
164	    lsdb->total--;
165	    rn->info = NULL;
166	    route_unlock_node (rn);
167#ifdef MONITOR_LSDB_CHANGE
168            if (lsdb->del_lsa_hook != NULL)
169              (* lsdb->del_lsa_hook)(lsa);
170#endif /* MONITOR_LSDB_CHANGE */
171	    ospf_lsa_unlock (lsa);
172	  }
173    }
174}
175
176struct ospf_lsa *
177ospf_lsdb_lookup (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
178{
179  struct route_table *table;
180  struct prefix_ls lp;
181  struct route_node *rn;
182  struct ospf_lsa *find;
183
184  table = lsdb->type[lsa->data->type].db;
185  lsdb_prefix_set (&lp, lsa);
186  rn = route_node_lookup (table, (struct prefix *) &lp);
187  if (rn)
188    {
189      find = rn->info;
190      route_unlock_node (rn);
191      return find;
192    }
193  return NULL;
194}
195
196struct ospf_lsa *
197ospf_lsdb_lookup_by_id (struct ospf_lsdb *lsdb, u_char type,
198		       struct in_addr id, struct in_addr adv_router)
199{
200  struct route_table *table;
201  struct prefix_ls lp;
202  struct route_node *rn;
203  struct ospf_lsa *find;
204
205  table = lsdb->type[type].db;
206
207  memset (&lp, 0, sizeof (struct prefix_ls));
208  lp.family = 0;
209  lp.prefixlen = 64;
210  lp.id = id;
211  lp.adv_router = adv_router;
212
213  rn = route_node_lookup (table, (struct prefix *) &lp);
214  if (rn)
215    {
216      find = rn->info;
217      route_unlock_node (rn);
218      return find;
219    }
220  return NULL;
221}
222
223struct ospf_lsa *
224ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *lsdb, u_char type,
225			    struct in_addr id, struct in_addr adv_router,
226			    int first)
227{
228  struct route_table *table;
229  struct prefix_ls lp;
230  struct route_node *rn;
231  struct ospf_lsa *find;
232
233  table = lsdb->type[type].db;
234
235  memset (&lp, 0, sizeof (struct prefix_ls));
236  lp.family = 0;
237  lp.prefixlen = 64;
238  lp.id = id;
239  lp.adv_router = adv_router;
240
241  if (first)
242      rn = route_top (table);
243  else
244    {
245      rn = route_node_get (table, (struct prefix *) &lp);
246      rn = route_next (rn);
247    }
248
249  for (; rn; rn = route_next (rn))
250    if (rn->info)
251      break;
252
253  if (rn && rn->info)
254    {
255      find = rn->info;
256      route_unlock_node (rn);
257      return find;
258    }
259  return NULL;
260}
261
262unsigned long
263ospf_lsdb_count_all (struct ospf_lsdb *lsdb)
264{
265  return lsdb->total;
266}
267
268unsigned long
269ospf_lsdb_count (struct ospf_lsdb *lsdb, int type)
270{
271  return lsdb->type[type].count;
272}
273
274unsigned long
275ospf_lsdb_count_self (struct ospf_lsdb *lsdb, int type)
276{
277  return lsdb->type[type].count_self;
278}
279
280unsigned long
281ospf_lsdb_isempty (struct ospf_lsdb *lsdb)
282{
283  return (lsdb->total == 0);
284}
285
286struct ospf_lsa *
287foreach_lsa (struct route_table *table, void *p_arg, int int_arg,
288	     int (*callback) (struct ospf_lsa *, void *, int))
289{
290  struct route_node *rn;
291  struct ospf_lsa *lsa;
292
293  for (rn = route_top (table); rn; rn = route_next (rn))
294    if ((lsa = rn->info) != NULL)
295      if (callback (lsa, p_arg, int_arg))
296	return lsa;
297
298  return NULL;
299}
300