GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: rde_lsdb.c,v 1.50 2015/11/22 13:09:10 claudio Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org> |
||
5 |
* |
||
6 |
* Permission to use, copy, modify, and distribute this software for any |
||
7 |
* purpose with or without fee is hereby granted, provided that the above |
||
8 |
* copyright notice and this permission notice appear in all copies. |
||
9 |
* |
||
10 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||
11 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||
12 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||
13 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||
14 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||
15 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||
16 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||
17 |
*/ |
||
18 |
|||
19 |
#include <sys/types.h> |
||
20 |
#include <sys/tree.h> |
||
21 |
#include <stdlib.h> |
||
22 |
#include <string.h> |
||
23 |
#include <unistd.h> |
||
24 |
|||
25 |
#include "ospf.h" |
||
26 |
#include "ospfd.h" |
||
27 |
#include "rde.h" |
||
28 |
#include "log.h" |
||
29 |
|||
30 |
struct vertex *vertex_get(struct lsa *, struct rde_nbr *, struct lsa_tree *); |
||
31 |
|||
32 |
int lsa_router_check(struct lsa *, u_int16_t); |
||
33 |
struct vertex *lsa_find_tree(struct lsa_tree *, u_int16_t, u_int32_t, |
||
34 |
u_int32_t); |
||
35 |
void lsa_timeout(int, short, void *); |
||
36 |
void lsa_refresh(struct vertex *); |
||
37 |
int lsa_equal(struct lsa *, struct lsa *); |
||
38 |
|||
39 |
✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✓✗✗ |
64 |
RB_GENERATE(lsa_tree, vertex, entry, lsa_compare) |
40 |
|||
41 |
void |
||
42 |
lsa_init(struct lsa_tree *t) |
||
43 |
{ |
||
44 |
RB_INIT(t); |
||
45 |
} |
||
46 |
|||
47 |
int |
||
48 |
lsa_compare(struct vertex *a, struct vertex *b) |
||
49 |
{ |
||
50 |
if (a->type < b->type) |
||
51 |
return (-1); |
||
52 |
if (a->type > b->type) |
||
53 |
return (1); |
||
54 |
if (a->adv_rtr < b->adv_rtr) |
||
55 |
return (-1); |
||
56 |
if (a->adv_rtr > b->adv_rtr) |
||
57 |
return (1); |
||
58 |
if (a->ls_id < b->ls_id) |
||
59 |
return (-1); |
||
60 |
if (a->ls_id > b->ls_id) |
||
61 |
return (1); |
||
62 |
return (0); |
||
63 |
} |
||
64 |
|||
65 |
|||
66 |
struct vertex * |
||
67 |
vertex_get(struct lsa *lsa, struct rde_nbr *nbr, struct lsa_tree *tree) |
||
68 |
{ |
||
69 |
struct vertex *v; |
||
70 |
struct timespec tp; |
||
71 |
|||
72 |
if ((v = calloc(1, sizeof(struct vertex))) == NULL) |
||
73 |
fatal(NULL); |
||
74 |
TAILQ_INIT(&v->nexthop); |
||
75 |
v->area = nbr->area; |
||
76 |
v->peerid = nbr->peerid; |
||
77 |
v->lsa = lsa; |
||
78 |
clock_gettime(CLOCK_MONOTONIC, &tp); |
||
79 |
v->changed = v->stamp = tp.tv_sec; |
||
80 |
v->cost = LS_INFINITY; |
||
81 |
v->ls_id = ntohl(lsa->hdr.ls_id); |
||
82 |
v->adv_rtr = ntohl(lsa->hdr.adv_rtr); |
||
83 |
v->type = lsa->hdr.type; |
||
84 |
v->lsa_tree = tree; |
||
85 |
|||
86 |
if (!nbr->self) |
||
87 |
v->flooded = 1; /* XXX fix me */ |
||
88 |
v->self = nbr->self; |
||
89 |
|||
90 |
evtimer_set(&v->ev, lsa_timeout, v); |
||
91 |
|||
92 |
return (v); |
||
93 |
} |
||
94 |
|||
95 |
void |
||
96 |
vertex_free(struct vertex *v) |
||
97 |
{ |
||
98 |
RB_REMOVE(lsa_tree, v->lsa_tree, v); |
||
99 |
|||
100 |
(void)evtimer_del(&v->ev); |
||
101 |
vertex_nexthop_clear(v); |
||
102 |
free(v->lsa); |
||
103 |
free(v); |
||
104 |
} |
||
105 |
|||
106 |
void |
||
107 |
vertex_nexthop_clear(struct vertex *v) |
||
108 |
{ |
||
109 |
struct v_nexthop *vn; |
||
110 |
|||
111 |
while ((vn = TAILQ_FIRST(&v->nexthop))) { |
||
112 |
TAILQ_REMOVE(&v->nexthop, vn, entry); |
||
113 |
free(vn); |
||
114 |
} |
||
115 |
} |
||
116 |
|||
117 |
void |
||
118 |
vertex_nexthop_add(struct vertex *dst, struct vertex *parent, u_int32_t nexthop) |
||
119 |
{ |
||
120 |
struct v_nexthop *vn; |
||
121 |
|||
122 |
if ((vn = calloc(1, sizeof(*vn))) == NULL) |
||
123 |
fatal("vertex_nexthop_add"); |
||
124 |
|||
125 |
vn->prev = parent; |
||
126 |
vn->nexthop.s_addr = nexthop; |
||
127 |
|||
128 |
TAILQ_INSERT_TAIL(&dst->nexthop, vn, entry); |
||
129 |
} |
||
130 |
|||
131 |
/* returns -1 if a is older, 1 if newer and 0 if equal to b */ |
||
132 |
int |
||
133 |
lsa_newer(struct lsa_hdr *a, struct lsa_hdr *b) |
||
134 |
{ |
||
135 |
int32_t a32, b32; |
||
136 |
u_int16_t a16, b16; |
||
137 |
int i; |
||
138 |
|||
139 |
if (a == NULL) |
||
140 |
return (-1); |
||
141 |
if (b == NULL) |
||
142 |
return (1); |
||
143 |
|||
144 |
/* |
||
145 |
* The sequence number is defined as signed 32-bit integer, |
||
146 |
* no idea how IETF came up with such a stupid idea. |
||
147 |
*/ |
||
148 |
a32 = (int32_t)ntohl(a->seq_num); |
||
149 |
b32 = (int32_t)ntohl(b->seq_num); |
||
150 |
|||
151 |
if (a32 > b32) |
||
152 |
return (1); |
||
153 |
if (a32 < b32) |
||
154 |
return (-1); |
||
155 |
|||
156 |
a16 = ntohs(a->ls_chksum); |
||
157 |
b16 = ntohs(b->ls_chksum); |
||
158 |
|||
159 |
if (a16 > b16) |
||
160 |
return (1); |
||
161 |
if (a16 < b16) |
||
162 |
return (-1); |
||
163 |
|||
164 |
a16 = ntohs(a->age); |
||
165 |
b16 = ntohs(b->age); |
||
166 |
|||
167 |
if (a16 >= MAX_AGE && b16 >= MAX_AGE) |
||
168 |
return (0); |
||
169 |
if (b16 >= MAX_AGE) |
||
170 |
return (-1); |
||
171 |
if (a16 >= MAX_AGE) |
||
172 |
return (1); |
||
173 |
|||
174 |
i = b16 - a16; |
||
175 |
if (abs(i) > MAX_AGE_DIFF) |
||
176 |
return (i > 0 ? 1 : -1); |
||
177 |
|||
178 |
return (0); |
||
179 |
} |
||
180 |
|||
181 |
int |
||
182 |
lsa_check(struct rde_nbr *nbr, struct lsa *lsa, u_int16_t len) |
||
183 |
{ |
||
184 |
struct area *area = nbr->area; |
||
185 |
u_int32_t metric; |
||
186 |
|||
187 |
if (len < sizeof(lsa->hdr)) { |
||
188 |
log_warnx("lsa_check: bad packet size"); |
||
189 |
return (0); |
||
190 |
} |
||
191 |
if (ntohs(lsa->hdr.len) != len) { |
||
192 |
log_warnx("lsa_check: bad packet size"); |
||
193 |
return (0); |
||
194 |
} |
||
195 |
|||
196 |
if (iso_cksum(lsa, len, 0)) { |
||
197 |
log_warnx("lsa_check: bad packet checksum"); |
||
198 |
return (0); |
||
199 |
} |
||
200 |
|||
201 |
/* invalid ages */ |
||
202 |
if ((ntohs(lsa->hdr.age) < 1 && !nbr->self) || |
||
203 |
ntohs(lsa->hdr.age) > MAX_AGE) { |
||
204 |
log_warnx("lsa_check: bad age"); |
||
205 |
return (0); |
||
206 |
} |
||
207 |
|||
208 |
/* invalid sequence number */ |
||
209 |
if (ntohl(lsa->hdr.seq_num) == RESV_SEQ_NUM) { |
||
210 |
log_warnx("ls_check: bad seq num"); |
||
211 |
return (0); |
||
212 |
} |
||
213 |
|||
214 |
switch (lsa->hdr.type) { |
||
215 |
case LSA_TYPE_ROUTER: |
||
216 |
if (!lsa_router_check(lsa, len)) |
||
217 |
return (0); |
||
218 |
break; |
||
219 |
case LSA_TYPE_NETWORK: |
||
220 |
if ((len % sizeof(u_int32_t)) || |
||
221 |
len < sizeof(lsa->hdr) + sizeof(u_int32_t)) { |
||
222 |
log_warnx("lsa_check: bad LSA network packet"); |
||
223 |
return (0); |
||
224 |
} |
||
225 |
break; |
||
226 |
case LSA_TYPE_SUM_NETWORK: |
||
227 |
case LSA_TYPE_SUM_ROUTER: |
||
228 |
if ((len % sizeof(u_int32_t)) || |
||
229 |
len < sizeof(lsa->hdr) + sizeof(lsa->data.sum)) { |
||
230 |
log_warnx("lsa_check: bad LSA summary packet"); |
||
231 |
return (0); |
||
232 |
} |
||
233 |
metric = ntohl(lsa->data.sum.metric); |
||
234 |
if (metric & ~LSA_METRIC_MASK) { |
||
235 |
log_warnx("lsa_check: bad LSA summary metric"); |
||
236 |
return (0); |
||
237 |
} |
||
238 |
break; |
||
239 |
case LSA_TYPE_EXTERNAL: |
||
240 |
if ((len % (3 * sizeof(u_int32_t))) || |
||
241 |
len < sizeof(lsa->hdr) + sizeof(lsa->data.asext)) { |
||
242 |
log_warnx("lsa_check: bad LSA as-external packet"); |
||
243 |
return (0); |
||
244 |
} |
||
245 |
metric = ntohl(lsa->data.asext.metric); |
||
246 |
if (metric & ~(LSA_METRIC_MASK | LSA_ASEXT_E_FLAG)) { |
||
247 |
log_warnx("lsa_check: bad LSA as-external metric"); |
||
248 |
return (0); |
||
249 |
} |
||
250 |
/* AS-external-LSA are silently discarded in stub areas */ |
||
251 |
if (area->stub) |
||
252 |
return (0); |
||
253 |
break; |
||
254 |
case LSA_TYPE_LINK_OPAQ: |
||
255 |
case LSA_TYPE_AREA_OPAQ: |
||
256 |
case LSA_TYPE_AS_OPAQ: |
||
257 |
if (len % sizeof(u_int32_t)) { |
||
258 |
log_warnx("lsa_check: bad opaque LSA packet"); |
||
259 |
return (0); |
||
260 |
} |
||
261 |
/* Type-11 Opaque-LSA are silently discarded in stub areas */ |
||
262 |
if (lsa->hdr.type == LSA_TYPE_AS_OPAQ && area->stub) |
||
263 |
return (0); |
||
264 |
break; |
||
265 |
default: |
||
266 |
log_warnx("lsa_check: unknown type %u", lsa->hdr.type); |
||
267 |
return (0); |
||
268 |
} |
||
269 |
|||
270 |
/* MaxAge handling */ |
||
271 |
if (lsa->hdr.age == htons(MAX_AGE) && !nbr->self && lsa_find(nbr->iface, |
||
272 |
lsa->hdr.type, lsa->hdr.ls_id, lsa->hdr.adv_rtr) == NULL && |
||
273 |
!rde_nbr_loading(area)) { |
||
274 |
/* |
||
275 |
* if no neighbor in state Exchange or Loading |
||
276 |
* ack LSA but don't add it. Needs to be a direct ack. |
||
277 |
*/ |
||
278 |
rde_imsg_compose_ospfe(IMSG_LS_ACK, nbr->peerid, 0, &lsa->hdr, |
||
279 |
sizeof(struct lsa_hdr)); |
||
280 |
return (0); |
||
281 |
} |
||
282 |
|||
283 |
return (1); |
||
284 |
} |
||
285 |
|||
286 |
int |
||
287 |
lsa_router_check(struct lsa *lsa, u_int16_t len) |
||
288 |
{ |
||
289 |
struct lsa_rtr_link *rtr_link; |
||
290 |
char *buf = (char *)lsa; |
||
291 |
u_int16_t i, off, nlinks; |
||
292 |
|||
293 |
off = sizeof(lsa->hdr) + sizeof(struct lsa_rtr); |
||
294 |
if (off > len) { |
||
295 |
log_warnx("lsa_check: invalid LSA router packet"); |
||
296 |
return (0); |
||
297 |
} |
||
298 |
|||
299 |
if (lsa->hdr.ls_id != lsa->hdr.adv_rtr) { |
||
300 |
log_warnx("lsa_check: invalid LSA router packet, bad adv_rtr"); |
||
301 |
return (0); |
||
302 |
} |
||
303 |
|||
304 |
nlinks = ntohs(lsa->data.rtr.nlinks); |
||
305 |
if (nlinks == 0) { |
||
306 |
log_warnx("lsa_check: invalid LSA router packet"); |
||
307 |
return (0); |
||
308 |
} |
||
309 |
for (i = 0; i < nlinks; i++) { |
||
310 |
rtr_link = (struct lsa_rtr_link *)(buf + off); |
||
311 |
off += sizeof(struct lsa_rtr_link); |
||
312 |
if (off > len) { |
||
313 |
log_warnx("lsa_check: invalid LSA router packet"); |
||
314 |
return (0); |
||
315 |
} |
||
316 |
off += rtr_link->num_tos * sizeof(u_int32_t); |
||
317 |
if (off > len) { |
||
318 |
log_warnx("lsa_check: invalid LSA router packet"); |
||
319 |
return (0); |
||
320 |
} |
||
321 |
} |
||
322 |
|||
323 |
if (i != nlinks) { |
||
324 |
log_warnx("lsa_check: invalid LSA router packet"); |
||
325 |
return (0); |
||
326 |
} |
||
327 |
return (1); |
||
328 |
} |
||
329 |
|||
330 |
int |
||
331 |
lsa_self(struct rde_nbr *nbr, struct lsa *new, struct vertex *v) |
||
332 |
{ |
||
333 |
struct iface *iface; |
||
334 |
struct lsa *dummy; |
||
335 |
|||
336 |
if (nbr->self) |
||
337 |
return (0); |
||
338 |
|||
339 |
if (rde_router_id() == new->hdr.adv_rtr) |
||
340 |
goto self; |
||
341 |
|||
342 |
if (new->hdr.type == LSA_TYPE_NETWORK) |
||
343 |
LIST_FOREACH(iface, &nbr->area->iface_list, entry) |
||
344 |
if (iface->addr.s_addr == new->hdr.ls_id) |
||
345 |
goto self; |
||
346 |
|||
347 |
return (0); |
||
348 |
|||
349 |
self: |
||
350 |
if (v == NULL) { |
||
351 |
/* |
||
352 |
* LSA is no longer announced, remove by premature aging. |
||
353 |
* The problem is that new may not be altered so a copy |
||
354 |
* needs to be added to the LSA DB first. |
||
355 |
*/ |
||
356 |
if ((dummy = malloc(ntohs(new->hdr.len))) == NULL) |
||
357 |
fatal("lsa_self"); |
||
358 |
memcpy(dummy, new, ntohs(new->hdr.len)); |
||
359 |
dummy->hdr.age = htons(MAX_AGE); |
||
360 |
/* |
||
361 |
* The clue is that by using the remote nbr as originator |
||
362 |
* the dummy LSA will be reflooded via the default timeout |
||
363 |
* handler. |
||
364 |
*/ |
||
365 |
(void)lsa_add(rde_nbr_self(nbr->area), dummy); |
||
366 |
return (1); |
||
367 |
} |
||
368 |
|||
369 |
/* |
||
370 |
* LSA is still originated, just reflood it. But we need to create |
||
371 |
* a new instance by setting the LSA sequence number equal to the |
||
372 |
* one of new and calling lsa_refresh(). Flooding will be done by the |
||
373 |
* caller. |
||
374 |
*/ |
||
375 |
v->lsa->hdr.seq_num = new->hdr.seq_num; |
||
376 |
lsa_refresh(v); |
||
377 |
return (1); |
||
378 |
} |
||
379 |
|||
380 |
int |
||
381 |
lsa_add(struct rde_nbr *nbr, struct lsa *lsa) |
||
382 |
{ |
||
383 |
struct lsa_tree *tree; |
||
384 |
struct vertex *new, *old; |
||
385 |
struct timeval tv, now, res; |
||
386 |
|||
387 |
if (lsa->hdr.type == LSA_TYPE_EXTERNAL || |
||
388 |
lsa->hdr.type == LSA_TYPE_AS_OPAQ) |
||
389 |
tree = &asext_tree; |
||
390 |
else if (lsa->hdr.type == LSA_TYPE_LINK_OPAQ) |
||
391 |
tree = &nbr->iface->lsa_tree; |
||
392 |
else |
||
393 |
tree = &nbr->area->lsa_tree; |
||
394 |
|||
395 |
new = vertex_get(lsa, nbr, tree); |
||
396 |
old = RB_INSERT(lsa_tree, tree, new); |
||
397 |
|||
398 |
if (old != NULL) { |
||
399 |
if (old->deleted && evtimer_pending(&old->ev, &tv)) { |
||
400 |
/* new update added before hold time expired */ |
||
401 |
gettimeofday(&now, NULL); |
||
402 |
timersub(&tv, &now, &res); |
||
403 |
|||
404 |
/* remove old LSA and insert new LSA with delay */ |
||
405 |
vertex_free(old); |
||
406 |
RB_INSERT(lsa_tree, tree, new); |
||
407 |
new->deleted = 1; |
||
408 |
|||
409 |
if (evtimer_add(&new->ev, &res) != 0) |
||
410 |
fatal("lsa_add"); |
||
411 |
return (1); |
||
412 |
} |
||
413 |
if (!lsa_equal(new->lsa, old->lsa)) { |
||
414 |
if (lsa->hdr.type != LSA_TYPE_EXTERNAL && |
||
415 |
lsa->hdr.type != LSA_TYPE_AS_OPAQ) |
||
416 |
nbr->area->dirty = 1; |
||
417 |
start_spf_timer(); |
||
418 |
} |
||
419 |
vertex_free(old); |
||
420 |
RB_INSERT(lsa_tree, tree, new); |
||
421 |
} else { |
||
422 |
if (lsa->hdr.type != LSA_TYPE_EXTERNAL && |
||
423 |
lsa->hdr.type != LSA_TYPE_AS_OPAQ) |
||
424 |
nbr->area->dirty = 1; |
||
425 |
start_spf_timer(); |
||
426 |
} |
||
427 |
|||
428 |
/* timeout handling either MAX_AGE or LS_REFRESH_TIME */ |
||
429 |
timerclear(&tv); |
||
430 |
|||
431 |
if (nbr->self && ntohs(new->lsa->hdr.age) == DEFAULT_AGE) |
||
432 |
tv.tv_sec = LS_REFRESH_TIME; |
||
433 |
else |
||
434 |
tv.tv_sec = MAX_AGE - ntohs(new->lsa->hdr.age); |
||
435 |
|||
436 |
if (evtimer_add(&new->ev, &tv) != 0) |
||
437 |
fatal("lsa_add"); |
||
438 |
return (0); |
||
439 |
} |
||
440 |
|||
441 |
void |
||
442 |
lsa_del(struct rde_nbr *nbr, struct lsa_hdr *lsa) |
||
443 |
{ |
||
444 |
struct vertex *v; |
||
445 |
struct timeval tv; |
||
446 |
|||
447 |
v = lsa_find(nbr->iface, lsa->type, lsa->ls_id, lsa->adv_rtr); |
||
448 |
if (v == NULL) |
||
449 |
return; |
||
450 |
|||
451 |
v->deleted = 1; |
||
452 |
/* hold time to make sure that a new lsa is not added premature */ |
||
453 |
timerclear(&tv); |
||
454 |
tv.tv_sec = MIN_LS_INTERVAL; |
||
455 |
if (evtimer_add(&v->ev, &tv) == -1) |
||
456 |
fatal("lsa_del"); |
||
457 |
} |
||
458 |
|||
459 |
void |
||
460 |
lsa_age(struct vertex *v) |
||
461 |
{ |
||
462 |
struct timespec tp; |
||
463 |
time_t now; |
||
464 |
int d; |
||
465 |
u_int16_t age; |
||
466 |
|||
467 |
clock_gettime(CLOCK_MONOTONIC, &tp); |
||
468 |
now = tp.tv_sec; |
||
469 |
|||
470 |
d = now - v->stamp; |
||
471 |
/* set stamp so that at least new calls work */ |
||
472 |
v->stamp = now; |
||
473 |
|||
474 |
if (d < 0) { |
||
475 |
log_warnx("lsa_age: time went backwards"); |
||
476 |
return; |
||
477 |
} |
||
478 |
|||
479 |
age = ntohs(v->lsa->hdr.age); |
||
480 |
if (age + d > MAX_AGE) |
||
481 |
age = MAX_AGE; |
||
482 |
else |
||
483 |
age += d; |
||
484 |
|||
485 |
v->lsa->hdr.age = htons(age); |
||
486 |
} |
||
487 |
|||
488 |
struct vertex * |
||
489 |
lsa_find(struct iface *iface, u_int8_t type, u_int32_t ls_id, u_int32_t adv_rtr) |
||
490 |
{ |
||
491 |
struct lsa_tree *tree; |
||
492 |
|||
493 |
if (type == LSA_TYPE_EXTERNAL || |
||
494 |
type == LSA_TYPE_AS_OPAQ) |
||
495 |
tree = &asext_tree; |
||
496 |
else if (type == LSA_TYPE_LINK_OPAQ) |
||
497 |
tree = &iface->lsa_tree; |
||
498 |
else |
||
499 |
tree = &iface->area->lsa_tree; |
||
500 |
|||
501 |
return lsa_find_tree(tree, type, ls_id, adv_rtr); |
||
502 |
} |
||
503 |
|||
504 |
struct vertex * |
||
505 |
lsa_find_area(struct area *area, u_int8_t type, u_int32_t ls_id, |
||
506 |
u_int32_t adv_rtr) |
||
507 |
{ |
||
508 |
return lsa_find_tree(&area->lsa_tree, type, ls_id, adv_rtr); |
||
509 |
} |
||
510 |
|||
511 |
struct vertex * |
||
512 |
lsa_find_tree(struct lsa_tree *tree, u_int16_t type, u_int32_t ls_id, |
||
513 |
u_int32_t adv_rtr) |
||
514 |
{ |
||
515 |
struct vertex key; |
||
516 |
struct vertex *v; |
||
517 |
|||
518 |
key.ls_id = ntohl(ls_id); |
||
519 |
key.adv_rtr = ntohl(adv_rtr); |
||
520 |
key.type = type; |
||
521 |
|||
522 |
v = RB_FIND(lsa_tree, tree, &key); |
||
523 |
|||
524 |
/* LSA that are deleted are not findable */ |
||
525 |
if (v && v->deleted) |
||
526 |
return (NULL); |
||
527 |
|||
528 |
if (v) |
||
529 |
lsa_age(v); |
||
530 |
|||
531 |
return (v); |
||
532 |
} |
||
533 |
|||
534 |
struct vertex * |
||
535 |
lsa_find_net(struct area *area, u_int32_t ls_id) |
||
536 |
{ |
||
537 |
struct lsa_tree *tree = &area->lsa_tree; |
||
538 |
struct vertex *v; |
||
539 |
|||
540 |
/* XXX speed me up */ |
||
541 |
RB_FOREACH(v, lsa_tree, tree) { |
||
542 |
if (v->lsa->hdr.type == LSA_TYPE_NETWORK && |
||
543 |
v->lsa->hdr.ls_id == ls_id) { |
||
544 |
/* LSA that are deleted are not findable */ |
||
545 |
if (v->deleted) |
||
546 |
return (NULL); |
||
547 |
lsa_age(v); |
||
548 |
return (v); |
||
549 |
} |
||
550 |
} |
||
551 |
|||
552 |
return (NULL); |
||
553 |
} |
||
554 |
|||
555 |
u_int16_t |
||
556 |
lsa_num_links(struct vertex *v) |
||
557 |
{ |
||
558 |
switch (v->type) { |
||
559 |
case LSA_TYPE_ROUTER: |
||
560 |
return (ntohs(v->lsa->data.rtr.nlinks)); |
||
561 |
case LSA_TYPE_NETWORK: |
||
562 |
return ((ntohs(v->lsa->hdr.len) - sizeof(struct lsa_hdr) |
||
563 |
- sizeof(u_int32_t)) / sizeof(struct lsa_net_link)); |
||
564 |
default: |
||
565 |
fatalx("lsa_num_links: invalid LSA type"); |
||
566 |
} |
||
567 |
} |
||
568 |
|||
569 |
void |
||
570 |
lsa_snap(struct rde_nbr *nbr) |
||
571 |
{ |
||
572 |
struct lsa_tree *tree = &nbr->area->lsa_tree; |
||
573 |
struct vertex *v; |
||
574 |
|||
575 |
do { |
||
576 |
RB_FOREACH(v, lsa_tree, tree) { |
||
577 |
if (v->deleted) |
||
578 |
continue; |
||
579 |
switch (v->type) { |
||
580 |
case LSA_TYPE_LINK_OPAQ: |
||
581 |
case LSA_TYPE_AREA_OPAQ: |
||
582 |
case LSA_TYPE_AS_OPAQ: |
||
583 |
if (nbr->capa_options & OSPF_OPTION_O) |
||
584 |
break; |
||
585 |
continue; |
||
586 |
} |
||
587 |
lsa_age(v); |
||
588 |
if (ntohs(v->lsa->hdr.age) >= MAX_AGE) |
||
589 |
rde_imsg_compose_ospfe(IMSG_LS_SNAP, nbr->peerid, |
||
590 |
0, &v->lsa->hdr, ntohs(v->lsa->hdr.len)); |
||
591 |
else |
||
592 |
rde_imsg_compose_ospfe(IMSG_DB_SNAPSHOT, |
||
593 |
nbr->peerid, 0, &v->lsa->hdr, |
||
594 |
sizeof(struct lsa_hdr)); |
||
595 |
} |
||
596 |
if (tree == &asext_tree) |
||
597 |
break; |
||
598 |
if (tree == &nbr->area->lsa_tree) |
||
599 |
tree = &nbr->iface->lsa_tree; |
||
600 |
else if (nbr->area->stub) |
||
601 |
break; |
||
602 |
else |
||
603 |
tree = &asext_tree; |
||
604 |
} while (1); |
||
605 |
} |
||
606 |
|||
607 |
void |
||
608 |
lsa_dump(struct lsa_tree *tree, int imsg_type, pid_t pid) |
||
609 |
{ |
||
610 |
struct vertex *v; |
||
611 |
|||
612 |
RB_FOREACH(v, lsa_tree, tree) { |
||
613 |
if (v->deleted) |
||
614 |
continue; |
||
615 |
lsa_age(v); |
||
616 |
switch (imsg_type) { |
||
617 |
case IMSG_CTL_SHOW_DATABASE: |
||
618 |
break; |
||
619 |
case IMSG_CTL_SHOW_DB_SELF: |
||
620 |
if (v->lsa->hdr.adv_rtr == rde_router_id()) |
||
621 |
break; |
||
622 |
continue; |
||
623 |
case IMSG_CTL_SHOW_DB_EXT: |
||
624 |
if (v->type == LSA_TYPE_EXTERNAL) |
||
625 |
break; |
||
626 |
continue; |
||
627 |
case IMSG_CTL_SHOW_DB_NET: |
||
628 |
if (v->type == LSA_TYPE_NETWORK) |
||
629 |
break; |
||
630 |
continue; |
||
631 |
case IMSG_CTL_SHOW_DB_RTR: |
||
632 |
if (v->type == LSA_TYPE_ROUTER) |
||
633 |
break; |
||
634 |
continue; |
||
635 |
case IMSG_CTL_SHOW_DB_SUM: |
||
636 |
if (v->type == LSA_TYPE_SUM_NETWORK) |
||
637 |
break; |
||
638 |
continue; |
||
639 |
case IMSG_CTL_SHOW_DB_ASBR: |
||
640 |
if (v->type == LSA_TYPE_SUM_ROUTER) |
||
641 |
break; |
||
642 |
continue; |
||
643 |
case IMSG_CTL_SHOW_DB_OPAQ: |
||
644 |
if (v->type == LSA_TYPE_LINK_OPAQ || |
||
645 |
v->type == LSA_TYPE_AREA_OPAQ || |
||
646 |
v->type == LSA_TYPE_AS_OPAQ) |
||
647 |
break; |
||
648 |
continue; |
||
649 |
default: |
||
650 |
log_warnx("lsa_dump: unknown imsg type"); |
||
651 |
return; |
||
652 |
} |
||
653 |
rde_imsg_compose_ospfe(imsg_type, 0, pid, &v->lsa->hdr, |
||
654 |
ntohs(v->lsa->hdr.len)); |
||
655 |
} |
||
656 |
} |
||
657 |
|||
658 |
/* ARGSUSED */ |
||
659 |
void |
||
660 |
lsa_timeout(int fd, short event, void *bula) |
||
661 |
{ |
||
662 |
struct vertex *v = bula; |
||
663 |
struct timeval tv; |
||
664 |
|||
665 |
lsa_age(v); |
||
666 |
|||
667 |
if (v->deleted) { |
||
668 |
if (ntohs(v->lsa->hdr.age) >= MAX_AGE) { |
||
669 |
vertex_free(v); |
||
670 |
} else { |
||
671 |
v->deleted = 0; |
||
672 |
|||
673 |
/* schedule recalculation of the RIB */ |
||
674 |
if (v->type != LSA_TYPE_EXTERNAL && |
||
675 |
v->type != LSA_TYPE_AS_OPAQ) |
||
676 |
v->area->dirty = 1; |
||
677 |
start_spf_timer(); |
||
678 |
|||
679 |
rde_imsg_compose_ospfe(IMSG_LS_FLOOD, v->peerid, 0, |
||
680 |
v->lsa, ntohs(v->lsa->hdr.len)); |
||
681 |
|||
682 |
/* timeout handling either MAX_AGE or LS_REFRESH_TIME */ |
||
683 |
timerclear(&tv); |
||
684 |
if (v->self) |
||
685 |
tv.tv_sec = LS_REFRESH_TIME; |
||
686 |
else |
||
687 |
tv.tv_sec = MAX_AGE - ntohs(v->lsa->hdr.age); |
||
688 |
|||
689 |
if (evtimer_add(&v->ev, &tv) != 0) |
||
690 |
fatal("lsa_timeout"); |
||
691 |
} |
||
692 |
return; |
||
693 |
} |
||
694 |
|||
695 |
if (v->self && ntohs(v->lsa->hdr.age) < MAX_AGE) |
||
696 |
lsa_refresh(v); |
||
697 |
|||
698 |
rde_imsg_compose_ospfe(IMSG_LS_FLOOD, v->peerid, 0, |
||
699 |
v->lsa, ntohs(v->lsa->hdr.len)); |
||
700 |
} |
||
701 |
|||
702 |
void |
||
703 |
lsa_refresh(struct vertex *v) |
||
704 |
{ |
||
705 |
struct timeval tv; |
||
706 |
struct timespec tp; |
||
707 |
u_int32_t seqnum; |
||
708 |
u_int16_t len; |
||
709 |
|||
710 |
/* refresh LSA by increasing sequence number by one */ |
||
711 |
if (v->self && ntohs(v->lsa->hdr.age) >= MAX_AGE) |
||
712 |
/* self originated network that is currently beeing removed */ |
||
713 |
v->lsa->hdr.age = htons(MAX_AGE); |
||
714 |
else |
||
715 |
v->lsa->hdr.age = htons(DEFAULT_AGE); |
||
716 |
seqnum = ntohl(v->lsa->hdr.seq_num); |
||
717 |
if (seqnum++ == MAX_SEQ_NUM) |
||
718 |
/* XXX fix me */ |
||
719 |
fatalx("sequence number wrapping"); |
||
720 |
v->lsa->hdr.seq_num = htonl(seqnum); |
||
721 |
|||
722 |
/* recalculate checksum */ |
||
723 |
len = ntohs(v->lsa->hdr.len); |
||
724 |
v->lsa->hdr.ls_chksum = 0; |
||
725 |
v->lsa->hdr.ls_chksum = htons(iso_cksum(v->lsa, len, LS_CKSUM_OFFSET)); |
||
726 |
|||
727 |
clock_gettime(CLOCK_MONOTONIC, &tp); |
||
728 |
v->changed = v->stamp = tp.tv_sec; |
||
729 |
|||
730 |
timerclear(&tv); |
||
731 |
tv.tv_sec = LS_REFRESH_TIME; |
||
732 |
if (evtimer_add(&v->ev, &tv) == -1) |
||
733 |
fatal("lsa_refresh"); |
||
734 |
} |
||
735 |
|||
736 |
void |
||
737 |
lsa_merge(struct rde_nbr *nbr, struct lsa *lsa, struct vertex *v) |
||
738 |
{ |
||
739 |
struct timeval tv; |
||
740 |
struct timespec tp; |
||
741 |
time_t now; |
||
742 |
u_int16_t len; |
||
743 |
|||
744 |
if (v == NULL) { |
||
745 |
if (lsa_add(nbr, lsa)) |
||
746 |
/* delayed update */ |
||
747 |
return; |
||
748 |
rde_imsg_compose_ospfe(IMSG_LS_FLOOD, nbr->peerid, 0, |
||
749 |
lsa, ntohs(lsa->hdr.len)); |
||
750 |
return; |
||
751 |
} |
||
752 |
|||
753 |
/* set the seq_num to the current one. lsa_refresh() will do the ++ */ |
||
754 |
lsa->hdr.seq_num = v->lsa->hdr.seq_num; |
||
755 |
/* recalculate checksum */ |
||
756 |
len = ntohs(lsa->hdr.len); |
||
757 |
lsa->hdr.ls_chksum = 0; |
||
758 |
lsa->hdr.ls_chksum = htons(iso_cksum(lsa, len, LS_CKSUM_OFFSET)); |
||
759 |
|||
760 |
/* compare LSA most header fields are equal so don't check them */ |
||
761 |
if (lsa_equal(lsa, v->lsa)) { |
||
762 |
free(lsa); |
||
763 |
return; |
||
764 |
} |
||
765 |
|||
766 |
/* overwrite the lsa all other fields are unaffected */ |
||
767 |
free(v->lsa); |
||
768 |
v->lsa = lsa; |
||
769 |
start_spf_timer(); |
||
770 |
if (v->type != LSA_TYPE_EXTERNAL && |
||
771 |
v->type != LSA_TYPE_AS_OPAQ) |
||
772 |
nbr->area->dirty = 1; |
||
773 |
|||
774 |
/* set correct timeout for reflooding the LSA */ |
||
775 |
clock_gettime(CLOCK_MONOTONIC, &tp); |
||
776 |
now = tp.tv_sec; |
||
777 |
timerclear(&tv); |
||
778 |
if (v->changed + MIN_LS_INTERVAL >= now) |
||
779 |
tv.tv_sec = MIN_LS_INTERVAL; |
||
780 |
if (evtimer_add(&v->ev, &tv) == -1) |
||
781 |
fatal("lsa_merge"); |
||
782 |
} |
||
783 |
|||
784 |
void |
||
785 |
lsa_remove_invalid_sums(struct area *area) |
||
786 |
{ |
||
787 |
struct lsa_tree *tree = &area->lsa_tree; |
||
788 |
struct vertex *v, *nv; |
||
789 |
|||
790 |
/* XXX speed me up */ |
||
791 |
for (v = RB_MIN(lsa_tree, tree); v != NULL; v = nv) { |
||
792 |
nv = RB_NEXT(lsa_tree, tree, v); |
||
793 |
if ((v->type == LSA_TYPE_SUM_NETWORK || |
||
794 |
v->type == LSA_TYPE_SUM_ROUTER) && |
||
795 |
v->self && v->cost == LS_INFINITY && |
||
796 |
v->deleted == 0) { |
||
797 |
/* |
||
798 |
* age the lsa and call lsa_timeout() which will |
||
799 |
* actually remove it from the database. |
||
800 |
*/ |
||
801 |
v->lsa->hdr.age = htons(MAX_AGE); |
||
802 |
lsa_timeout(0, 0, v); |
||
803 |
} |
||
804 |
} |
||
805 |
} |
||
806 |
|||
807 |
void |
||
808 |
lsa_generate_stub_sums(struct area *area) |
||
809 |
{ |
||
810 |
struct rt_node rn; |
||
811 |
struct redistribute *r; |
||
812 |
struct vertex *v; |
||
813 |
struct lsa *lsa; |
||
814 |
struct area *back; |
||
815 |
|||
816 |
if (!area->stub) |
||
817 |
return; |
||
818 |
|||
819 |
back = rde_backbone_area(); |
||
820 |
if (!back || !back->active) |
||
821 |
return; |
||
822 |
|||
823 |
SIMPLEQ_FOREACH(r, &area->redist_list, entry) { |
||
824 |
bzero(&rn, sizeof(rn)); |
||
825 |
if (r->type == REDIST_DEFAULT) { |
||
826 |
/* setup fake rt_node */ |
||
827 |
rn.prefixlen = 0; |
||
828 |
rn.prefix.s_addr = INADDR_ANY; |
||
829 |
rn.cost = r->metric & LSA_METRIC_MASK; |
||
830 |
|||
831 |
/* update lsa but only if it was changed */ |
||
832 |
v = lsa_find_area(area, LSA_TYPE_SUM_NETWORK, |
||
833 |
rn.prefix.s_addr, rde_router_id()); |
||
834 |
lsa = orig_sum_lsa(&rn, area, LSA_TYPE_SUM_NETWORK, 0); |
||
835 |
lsa_merge(rde_nbr_self(area), lsa, v); |
||
836 |
|||
837 |
if (v == NULL) |
||
838 |
v = lsa_find_area(area, LSA_TYPE_SUM_NETWORK, |
||
839 |
rn.prefix.s_addr, rde_router_id()); |
||
840 |
|||
841 |
/* |
||
842 |
* suppressed/deleted routes are not found in the |
||
843 |
* second lsa_find |
||
844 |
*/ |
||
845 |
if (v) |
||
846 |
v->cost = rn.cost; |
||
847 |
return; |
||
848 |
} else if (r->type == (REDIST_DEFAULT | REDIST_NO)) |
||
849 |
return; |
||
850 |
} |
||
851 |
} |
||
852 |
|||
853 |
int |
||
854 |
lsa_equal(struct lsa *a, struct lsa *b) |
||
855 |
{ |
||
856 |
/* |
||
857 |
* compare LSA that already have same type, adv_rtr and ls_id |
||
858 |
* so not all header need to be compared |
||
859 |
*/ |
||
860 |
if (a == NULL || b == NULL) |
||
861 |
return (0); |
||
862 |
if (a->hdr.len != b->hdr.len) |
||
863 |
return (0); |
||
864 |
if (a->hdr.opts != b->hdr.opts) |
||
865 |
return (0); |
||
866 |
/* LSAs with age MAX_AGE are never equal */ |
||
867 |
if (a->hdr.age == htons(MAX_AGE) || b->hdr.age == htons(MAX_AGE)) |
||
868 |
return (0); |
||
869 |
if (memcmp(&a->data, &b->data, ntohs(a->hdr.len) - |
||
870 |
sizeof(struct lsa_hdr))) |
||
871 |
return (0); |
||
872 |
|||
873 |
return (1); |
||
874 |
} |
Generated by: GCOVR (Version 3.3) |