/src/frr/ospfd/ospf_lsdb.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * OSPF LSDB support. |
4 | | * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada |
5 | | */ |
6 | | |
7 | | #include <zebra.h> |
8 | | |
9 | | #include "prefix.h" |
10 | | #include "table.h" |
11 | | #include "memory.h" |
12 | | #include "log.h" |
13 | | |
14 | | #include "ospfd/ospfd.h" |
15 | | #include "ospfd/ospf_asbr.h" |
16 | | #include "ospfd/ospf_lsa.h" |
17 | | #include "ospfd/ospf_lsdb.h" |
18 | | |
19 | | struct ospf_lsdb *ospf_lsdb_new(void) |
20 | 2 | { |
21 | 2 | struct ospf_lsdb *new; |
22 | | |
23 | 2 | new = XCALLOC(MTYPE_OSPF_LSDB, sizeof(struct ospf_lsdb)); |
24 | 2 | ospf_lsdb_init(new); |
25 | | |
26 | 2 | return new; |
27 | 2 | } |
28 | | |
29 | | void ospf_lsdb_init(struct ospf_lsdb *lsdb) |
30 | 740 | { |
31 | 740 | int i; |
32 | | |
33 | 8.88k | for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) |
34 | 8.14k | lsdb->type[i].db = route_table_init(); |
35 | 740 | } |
36 | | |
37 | | void ospf_lsdb_free(struct ospf_lsdb *lsdb) |
38 | 0 | { |
39 | 0 | ospf_lsdb_cleanup(lsdb); |
40 | 0 | XFREE(MTYPE_OSPF_LSDB, lsdb); |
41 | 0 | } |
42 | | |
43 | | void ospf_lsdb_cleanup(struct ospf_lsdb *lsdb) |
44 | 0 | { |
45 | 0 | int i; |
46 | 0 | assert(lsdb); |
47 | 0 | assert(lsdb->total == 0); |
48 | | |
49 | 0 | ospf_lsdb_delete_all(lsdb); |
50 | |
|
51 | 0 | for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) |
52 | 0 | route_table_finish(lsdb->type[i].db); |
53 | 0 | } |
54 | | |
55 | | void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa) |
56 | 16.6k | { |
57 | 16.6k | if (lp && lsa && lsa->data) { |
58 | 16.6k | lp->family = AF_UNSPEC; |
59 | 16.6k | lp->prefixlen = 64; |
60 | 16.6k | lp->id = lsa->data->id; |
61 | 16.6k | lp->adv_router = lsa->data->adv_router; |
62 | 16.6k | } |
63 | 16.6k | } |
64 | | |
65 | | static void ospf_lsdb_delete_entry(struct ospf_lsdb *lsdb, |
66 | | struct route_node *rn) |
67 | 2.15k | { |
68 | 2.15k | struct ospf_lsa *lsa = rn->info; |
69 | | |
70 | 2.15k | if (!lsa) |
71 | 0 | return; |
72 | | |
73 | 2.15k | assert(rn->table == lsdb->type[lsa->data->type].db); |
74 | | |
75 | 2.15k | if (IS_LSA_SELF(lsa)) |
76 | 0 | lsdb->type[lsa->data->type].count_self--; |
77 | 2.15k | lsdb->type[lsa->data->type].count--; |
78 | 2.15k | lsdb->type[lsa->data->type].checksum -= ntohs(lsa->data->checksum); |
79 | 2.15k | lsdb->total--; |
80 | | |
81 | | /* Decrement number of router LSAs received with DC bit set */ |
82 | 2.15k | if (lsa->area && (lsa->area->lsdb == lsdb) && !IS_LSA_SELF(lsa) && |
83 | 2.15k | (lsa->data->type == OSPF_ROUTER_LSA) && |
84 | 2.15k | CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC)) |
85 | 0 | lsa->area->fr_info.router_lsas_recv_dc_bit--; |
86 | | |
87 | | /* |
88 | | * If the LSA being deleted is indication LSA, then set the |
89 | | * pointer to NULL. |
90 | | */ |
91 | 2.15k | if (lsa->area && lsa->area->fr_info.indication_lsa_self && |
92 | 2.15k | (lsa->area->fr_info.indication_lsa_self == lsa)) |
93 | 0 | lsa->area->fr_info.indication_lsa_self = NULL; |
94 | | |
95 | 2.15k | rn->info = NULL; |
96 | 2.15k | route_unlock_node(rn); |
97 | 2.15k | #ifdef MONITOR_LSDB_CHANGE |
98 | 2.15k | if (lsdb->del_lsa_hook != NULL) |
99 | 0 | (*lsdb->del_lsa_hook)(lsa); |
100 | 2.15k | #endif /* MONITOR_LSDB_CHANGE */ |
101 | 2.15k | ospf_lsa_unlock(&lsa); /* lsdb */ |
102 | 2.15k | return; |
103 | 2.15k | } |
104 | | |
105 | | /* Add new LSA to lsdb. */ |
106 | | void ospf_lsdb_add(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) |
107 | 6.01k | { |
108 | 6.01k | struct route_table *table; |
109 | 6.01k | struct prefix_ls lp; |
110 | 6.01k | struct route_node *rn; |
111 | | |
112 | 6.01k | table = lsdb->type[lsa->data->type].db; |
113 | 6.01k | ls_prefix_set(&lp, lsa); |
114 | 6.01k | rn = route_node_get(table, (struct prefix *)&lp); |
115 | | |
116 | | /* nothing to do? */ |
117 | 6.01k | if (rn->info && rn->info == lsa) { |
118 | 0 | route_unlock_node(rn); |
119 | 0 | return; |
120 | 0 | } |
121 | | |
122 | | /* purge old entry? */ |
123 | 6.01k | if (rn->info) |
124 | 2.15k | ospf_lsdb_delete_entry(lsdb, rn); |
125 | | |
126 | 6.01k | if (IS_LSA_SELF(lsa)) |
127 | 385 | lsdb->type[lsa->data->type].count_self++; |
128 | 6.01k | lsdb->type[lsa->data->type].count++; |
129 | 6.01k | lsdb->total++; |
130 | | |
131 | | /* Increment number of router LSAs received with DC bit set */ |
132 | 6.01k | if (lsa->area && (lsa->area->lsdb == lsdb) && !IS_LSA_SELF(lsa) && |
133 | 6.01k | (lsa->data->type == OSPF_ROUTER_LSA) && |
134 | 6.01k | CHECK_FLAG(lsa->data->options, OSPF_OPTION_DC)) |
135 | 13 | lsa->area->fr_info.router_lsas_recv_dc_bit++; |
136 | | |
137 | 6.01k | #ifdef MONITOR_LSDB_CHANGE |
138 | 6.01k | if (lsdb->new_lsa_hook != NULL) |
139 | 1.15k | (*lsdb->new_lsa_hook)(lsa); |
140 | 6.01k | #endif /* MONITOR_LSDB_CHANGE */ |
141 | 6.01k | lsdb->type[lsa->data->type].checksum += ntohs(lsa->data->checksum); |
142 | 6.01k | rn->info = ospf_lsa_lock(lsa); /* lsdb */ |
143 | 6.01k | } |
144 | | |
145 | | void ospf_lsdb_delete(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) |
146 | 212 | { |
147 | 212 | struct route_table *table; |
148 | 212 | struct prefix_ls lp; |
149 | 212 | struct route_node *rn; |
150 | | |
151 | 212 | if (!lsdb || !lsa) |
152 | 0 | return; |
153 | | |
154 | 212 | assert(lsa->data->type < OSPF_MAX_LSA); |
155 | 212 | table = lsdb->type[lsa->data->type].db; |
156 | 212 | ls_prefix_set(&lp, lsa); |
157 | 212 | if ((rn = route_node_lookup(table, (struct prefix *)&lp))) { |
158 | 0 | if (rn->info == lsa) |
159 | 0 | ospf_lsdb_delete_entry(lsdb, rn); |
160 | 0 | route_unlock_node(rn); /* route_node_lookup */ |
161 | 0 | } |
162 | 212 | } |
163 | | |
164 | | void ospf_lsdb_delete_all(struct ospf_lsdb *lsdb) |
165 | 0 | { |
166 | 0 | struct route_table *table; |
167 | 0 | struct route_node *rn; |
168 | 0 | int i; |
169 | |
|
170 | 0 | for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { |
171 | 0 | table = lsdb->type[i].db; |
172 | 0 | for (rn = route_top(table); rn; rn = route_next(rn)) |
173 | 0 | if (rn->info != NULL) |
174 | 0 | ospf_lsdb_delete_entry(lsdb, rn); |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | | struct ospf_lsa *ospf_lsdb_lookup(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) |
179 | 10.4k | { |
180 | 10.4k | struct route_table *table; |
181 | 10.4k | struct prefix_ls lp; |
182 | 10.4k | struct route_node *rn; |
183 | 10.4k | struct ospf_lsa *find; |
184 | | |
185 | 10.4k | table = lsdb->type[lsa->data->type].db; |
186 | 10.4k | ls_prefix_set(&lp, lsa); |
187 | 10.4k | rn = route_node_lookup(table, (struct prefix *)&lp); |
188 | 10.4k | if (rn) { |
189 | 5 | find = rn->info; |
190 | 5 | route_unlock_node(rn); |
191 | 5 | return find; |
192 | 5 | } |
193 | 10.4k | return NULL; |
194 | 10.4k | } |
195 | | |
196 | | struct ospf_lsa *ospf_lsdb_lookup_by_id(struct ospf_lsdb *lsdb, uint8_t type, |
197 | | struct in_addr id, |
198 | | struct in_addr adv_router) |
199 | 38.1k | { |
200 | 38.1k | struct route_table *table; |
201 | 38.1k | struct prefix_ls lp; |
202 | 38.1k | struct route_node *rn; |
203 | 38.1k | struct ospf_lsa *find; |
204 | | |
205 | 38.1k | table = lsdb->type[type].db; |
206 | | |
207 | 38.1k | memset(&lp, 0, sizeof(lp)); |
208 | 38.1k | lp.family = AF_UNSPEC; |
209 | 38.1k | lp.prefixlen = 64; |
210 | 38.1k | lp.id = id; |
211 | 38.1k | lp.adv_router = adv_router; |
212 | | |
213 | 38.1k | rn = route_node_lookup(table, (struct prefix *)&lp); |
214 | 38.1k | if (rn) { |
215 | 13.6k | find = rn->info; |
216 | 13.6k | route_unlock_node(rn); |
217 | 13.6k | return find; |
218 | 13.6k | } |
219 | 24.5k | return NULL; |
220 | 38.1k | } |
221 | | |
222 | | struct ospf_lsa *ospf_lsdb_lookup_by_id_next(struct ospf_lsdb *lsdb, |
223 | | uint8_t type, struct in_addr id, |
224 | | struct in_addr adv_router, |
225 | | int first) |
226 | 0 | { |
227 | 0 | struct route_table *table; |
228 | 0 | struct prefix_ls lp; |
229 | 0 | struct route_node *rn; |
230 | 0 | struct ospf_lsa *find; |
231 | |
|
232 | 0 | table = lsdb->type[type].db; |
233 | |
|
234 | 0 | memset(&lp, 0, sizeof(lp)); |
235 | 0 | lp.family = AF_UNSPEC; |
236 | 0 | lp.prefixlen = 64; |
237 | 0 | lp.id = id; |
238 | 0 | lp.adv_router = adv_router; |
239 | |
|
240 | 0 | if (first) |
241 | 0 | rn = route_top(table); |
242 | 0 | else { |
243 | 0 | if ((rn = route_node_lookup(table, (struct prefix *)&lp)) |
244 | 0 | == NULL) |
245 | 0 | return NULL; |
246 | 0 | rn = route_next(rn); |
247 | 0 | } |
248 | | |
249 | 0 | for (; rn; rn = route_next(rn)) |
250 | 0 | if (rn->info) |
251 | 0 | break; |
252 | |
|
253 | 0 | if (rn && rn->info) { |
254 | 0 | find = rn->info; |
255 | 0 | route_unlock_node(rn); |
256 | 0 | return find; |
257 | 0 | } |
258 | 0 | return NULL; |
259 | 0 | } |
260 | | |
261 | | unsigned long ospf_lsdb_count_all(struct ospf_lsdb *lsdb) |
262 | 0 | { |
263 | 0 | return lsdb->total; |
264 | 0 | } |
265 | | |
266 | | unsigned long ospf_lsdb_count(struct ospf_lsdb *lsdb, int type) |
267 | 0 | { |
268 | 0 | return lsdb->type[type].count; |
269 | 0 | } |
270 | | |
271 | | unsigned long ospf_lsdb_count_self(struct ospf_lsdb *lsdb, int type) |
272 | 0 | { |
273 | 0 | return lsdb->type[type].count_self; |
274 | 0 | } |
275 | | |
276 | | unsigned int ospf_lsdb_checksum(struct ospf_lsdb *lsdb, int type) |
277 | 0 | { |
278 | 0 | return lsdb->type[type].checksum; |
279 | 0 | } |
280 | | |
281 | | unsigned long ospf_lsdb_isempty(struct ospf_lsdb *lsdb) |
282 | 59 | { |
283 | 59 | return (lsdb->total == 0); |
284 | 59 | } |