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