xref: /openbsd-src/usr.sbin/ospf6d/lsupdate.c (revision bf2cf3053df3551d6121df7fcab39bf211c112b2)
1 /*	$OpenBSD: lsupdate.c,v 1.24 2023/07/03 09:51:38 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2004, 2005, 2007 Esben Norby <norby@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netinet/ip6.h>
24 #include <netinet/ip_ah.h>
25 #include <arpa/inet.h>
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <siphash.h>
30 
31 #include "ospf6.h"
32 #include "ospf6d.h"
33 #include "log.h"
34 #include "ospfe.h"
35 #include "rde.h"
36 
37 struct ibuf	*prepare_ls_update(struct iface *, int);
38 int		 add_ls_update(struct ibuf *, struct iface *, void *, u_int16_t,
39 		    u_int16_t);
40 int		 send_ls_update(struct ibuf *, struct iface *, struct in6_addr,
41 		    u_int32_t);
42 
43 void		 ls_retrans_list_insert(struct nbr *, struct lsa_entry *);
44 void		 ls_retrans_list_remove(struct nbr *, struct lsa_entry *);
45 
46 /* link state update packet handling */
47 int
lsa_flood(struct iface * iface,struct nbr * originator,struct lsa_hdr * lsa_hdr,void * data)48 lsa_flood(struct iface *iface, struct nbr *originator, struct lsa_hdr *lsa_hdr,
49     void *data)
50 {
51 	struct nbr		*nbr;
52 	struct lsa_entry	*le = NULL;
53 	int			 queued = 0, dont_ack = 0;
54 	int			 r;
55 
56 	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
57 		if (nbr == iface->self)
58 			continue;
59 		if (!(nbr->state & NBR_STA_FLOOD))
60 			continue;
61 
62 		if (iface->state & IF_STA_DROTHER && !queued)
63 			while ((le = ls_retrans_list_get(iface->self, lsa_hdr)))
64 			    ls_retrans_list_free(iface->self, le);
65 
66 		while ((le = ls_retrans_list_get(nbr, lsa_hdr)))
67 			ls_retrans_list_free(nbr, le);
68 
69 		if (!(nbr->state & NBR_STA_FULL) &&
70 		    (le = ls_req_list_get(nbr, lsa_hdr)) != NULL) {
71 			r = lsa_newer(lsa_hdr, le->le_lsa);
72 			if (r > 0) {
73 				/* to flood LSA is newer than requested */
74 				ls_req_list_free(nbr, le);
75 				/* new needs to be flooded */
76 			} else if (r < 0) {
77 				/* to flood LSA is older than requested */
78 				continue;
79 			} else {
80 				/* LSA are equal */
81 				ls_req_list_free(nbr, le);
82 				continue;
83 			}
84 		}
85 
86 		if (nbr == originator) {
87 			dont_ack++;
88 			continue;
89 		}
90 
91 		/* non DR or BDR router keep all lsa in one retrans list */
92 		if (iface->state & IF_STA_DROTHER) {
93 			if (!queued)
94 				ls_retrans_list_add(iface->self, data,
95 				    iface->rxmt_interval, 0);
96 			queued = 1;
97 		} else {
98 			ls_retrans_list_add(nbr, data, iface->rxmt_interval, 0);
99 			queued = 1;
100 		}
101 	}
102 
103 	if (!queued)
104 		return (0);
105 
106 	if (iface == originator->iface && iface->self != originator) {
107 		if (iface->dr == originator || iface->bdr == originator)
108 			return (0);
109 		if (iface->state & IF_STA_BACKUP)
110 			return (0);
111 		dont_ack++;
112 	}
113 
114 	/*
115 	 * initial flood needs to be queued separately, timeout is zero
116 	 * and oneshot has to be set because the retransimssion queues
117 	 * are already loaded.
118 	 */
119 	switch (iface->type) {
120 	case IF_TYPE_POINTOPOINT:
121 	case IF_TYPE_BROADCAST:
122 		ls_retrans_list_add(iface->self, data, 0, 1);
123 		break;
124 	case IF_TYPE_NBMA:
125 	case IF_TYPE_POINTOMULTIPOINT:
126 	case IF_TYPE_VIRTUALLINK:
127 		LIST_FOREACH(nbr, &iface->nbr_list, entry) {
128 			if (nbr == iface->self)
129 				continue;
130 			if (!(nbr->state & NBR_STA_FLOOD))
131 				continue;
132 			if (!TAILQ_EMPTY(&nbr->ls_retrans_list)) {
133 				le = TAILQ_LAST(&nbr->ls_retrans_list,
134 				    lsa_head);
135 				if (lsa_hdr->type != le->le_lsa->type ||
136 				    lsa_hdr->ls_id != le->le_lsa->ls_id ||
137 				    lsa_hdr->adv_rtr != le->le_lsa->adv_rtr)
138 					continue;
139 			}
140 			ls_retrans_list_add(nbr, data, 0, 1);
141 		}
142 		break;
143 	default:
144 		fatalx("lsa_flood: unknown interface type");
145 	}
146 
147 	return (dont_ack == 2);
148 }
149 
150 struct ibuf *
prepare_ls_update(struct iface * iface,int bigpkt)151 prepare_ls_update(struct iface *iface, int bigpkt)
152 {
153 	struct ibuf		*buf;
154 	size_t			 size;
155 
156 	size = bigpkt ? IPV6_MAXPACKET : iface->mtu;
157 	if (size < IPV6_MMTU)
158 		size = IPV6_MMTU;
159 	size -= sizeof(struct ip6_hdr);
160 
161 	/*
162 	 * Reserve space for optional ah or esp encryption.  The
163 	 * algorithm is taken from ah_output and esp_output, the
164 	 * values are the maxima of crypto/xform.c.
165 	 */
166 	size -= max(
167 	    /* base-ah-header replay authsize */
168 	    AH_FLENGTH + sizeof(u_int32_t) + 32,
169 	    /* spi sequence ivlen blocksize pad-length next-header authsize */
170 	    2 * sizeof(u_int32_t) + 16 + 16 + 2 * sizeof(u_int8_t) + 32);
171 
172 	if ((buf = ibuf_open(size)) == NULL)
173 		fatal("prepare_ls_update");
174 
175 	/* OSPF header */
176 	if (gen_ospf_hdr(buf, iface, PACKET_TYPE_LS_UPDATE))
177 		goto fail;
178 
179 	/* reserve space for number of lsa field */
180 	if (ibuf_add_zero(buf, sizeof(u_int32_t)) == -1)
181 		goto fail;
182 
183 	return (buf);
184 fail:
185 	log_warn("prepare_ls_update");
186 	ibuf_free(buf);
187 	return (NULL);
188 }
189 
190 int
add_ls_update(struct ibuf * buf,struct iface * iface,void * data,u_int16_t len,u_int16_t older)191 add_ls_update(struct ibuf *buf, struct iface *iface, void *data, u_int16_t len,
192     u_int16_t older)
193 {
194 	size_t		ageoff;
195 	u_int16_t	age;
196 
197 	if (len >= ibuf_left(buf))
198 		return (0);
199 
200 	ageoff = ibuf_size(buf);
201 	if (ibuf_add(buf, data, len)) {
202 		log_warn("add_ls_update");
203 		return (0);
204 	}
205 
206 	/* age LSA before sending it out */
207 	memcpy(&age, data, sizeof(age));
208 	age = ntohs(age);
209 	if ((age += older + iface->transmit_delay) >= MAX_AGE)
210 		age = MAX_AGE;
211 	if (ibuf_set_n16(buf, ageoff, age) == -1) {
212 		log_warn("add_ls_update");
213 		return (0);
214 	}
215 
216 	return (1);
217 }
218 
219 int
send_ls_update(struct ibuf * buf,struct iface * iface,struct in6_addr addr,u_int32_t nlsa)220 send_ls_update(struct ibuf *buf, struct iface *iface, struct in6_addr addr,
221     u_int32_t nlsa)
222 {
223 	if (ibuf_set_n32(buf, sizeof(struct ospf_hdr), nlsa) == -1)
224 		goto fail;
225 	/* calculate checksum */
226 	if (upd_ospf_hdr(buf, iface))
227 		goto fail;
228 
229 	if (send_packet(iface, buf, &addr) == -1)
230 		goto fail;
231 
232 	ibuf_free(buf);
233 	return (0);
234 fail:
235 	log_warn("send_ls_update");
236 	ibuf_free(buf);
237 	return (-1);
238 }
239 
240 void
recv_ls_update(struct nbr * nbr,char * buf,u_int16_t len)241 recv_ls_update(struct nbr *nbr, char *buf, u_int16_t len)
242 {
243 	struct lsa_hdr		 lsa;
244 	u_int32_t		 nlsa;
245 
246 	if (len < sizeof(nlsa)) {
247 		log_warnx("recv_ls_update: bad packet size, "
248 		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
249 		    nbr->iface->name);
250 		return;
251 	}
252 	memcpy(&nlsa, buf, sizeof(nlsa));
253 	nlsa = ntohl(nlsa);
254 	buf += sizeof(nlsa);
255 	len -= sizeof(nlsa);
256 
257 	switch (nbr->state) {
258 	case NBR_STA_DOWN:
259 	case NBR_STA_ATTEMPT:
260 	case NBR_STA_INIT:
261 	case NBR_STA_2_WAY:
262 	case NBR_STA_XSTRT:
263 	case NBR_STA_SNAP:
264 		log_debug("recv_ls_update: packet ignored in state %s, "
265 		    "neighbor ID %s (%s)", nbr_state_name(nbr->state),
266 		    inet_ntoa(nbr->id), nbr->iface->name);
267 		break;
268 	case NBR_STA_XCHNG:
269 	case NBR_STA_LOAD:
270 	case NBR_STA_FULL:
271 		for (; nlsa > 0 && len > 0; nlsa--) {
272 			if (len < sizeof(lsa)) {
273 				log_warnx("recv_ls_update: bad packet size, "
274 				    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
275 				    nbr->iface->name);
276 				return;
277 			}
278 			memcpy(&lsa, buf, sizeof(lsa));
279 			if (len < ntohs(lsa.len)) {
280 				log_warnx("recv_ls_update: bad packet size, "
281 				    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
282 				    nbr->iface->name);
283 				return;
284 			}
285 			ospfe_imsg_compose_rde(IMSG_LS_UPD, nbr->peerid, 0,
286 			    buf, ntohs(lsa.len));
287 			buf += ntohs(lsa.len);
288 			len -= ntohs(lsa.len);
289 		}
290 		if (nlsa > 0 || len > 0) {
291 			log_warnx("recv_ls_update: bad packet size, "
292 			    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
293 			    nbr->iface->name);
294 			return;
295 		}
296 		break;
297 	default:
298 		fatalx("recv_ls_update: unknown neighbor state");
299 	}
300 }
301 
302 /* link state retransmit list */
303 void
ls_retrans_list_add(struct nbr * nbr,struct lsa_hdr * lsa,unsigned short timeout,unsigned short oneshot)304 ls_retrans_list_add(struct nbr *nbr, struct lsa_hdr *lsa,
305     unsigned short timeout, unsigned short oneshot)
306 {
307 	struct timeval		 tv;
308 	struct lsa_entry	*le;
309 	struct lsa_ref		*ref;
310 
311 	if ((ref = lsa_cache_get(lsa)) == NULL)
312 		fatalx("King Bula sez: somebody forgot to lsa_cache_add");
313 
314 	if ((le = calloc(1, sizeof(*le))) == NULL)
315 		fatal("ls_retrans_list_add");
316 
317 	le->le_ref = ref;
318 	le->le_when = timeout;
319 	le->le_oneshot = oneshot;
320 
321 	ls_retrans_list_insert(nbr, le);
322 
323 	if (!evtimer_pending(&nbr->ls_retrans_timer, NULL)) {
324 		timerclear(&tv);
325 		tv.tv_sec = TAILQ_FIRST(&nbr->ls_retrans_list)->le_when;
326 
327 		if (evtimer_add(&nbr->ls_retrans_timer, &tv) == -1)
328 			fatal("ls_retrans_list_add");
329 	}
330 }
331 
332 int
ls_retrans_list_del(struct nbr * nbr,struct lsa_hdr * lsa_hdr)333 ls_retrans_list_del(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
334 {
335 	struct lsa_entry	*le;
336 
337 	if ((le = ls_retrans_list_get(nbr, lsa_hdr)) == NULL)
338 		return (-1);
339 	/*
340 	 * Compare LSA with the Ack by comparing not only the seq_num and
341 	 * checksum but also the age field.  Since we only care about MAX_AGE
342 	 * vs. non-MAX_AGE LSA, a simple >= comparison is good enough.  This
343 	 * ensures that a LSA withdrawal is not acked by a previous update.
344 	 */
345 	if (lsa_hdr->seq_num == le->le_ref->hdr.seq_num &&
346 	    lsa_hdr->ls_chksum == le->le_ref->hdr.ls_chksum &&
347 	    ntohs(lsa_hdr->age) >= ntohs(le->le_ref->hdr.age)) {
348 		ls_retrans_list_free(nbr, le);
349 		return (0);
350 	}
351 
352 	return (-1);
353 }
354 
355 struct lsa_entry *
ls_retrans_list_get(struct nbr * nbr,struct lsa_hdr * lsa_hdr)356 ls_retrans_list_get(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
357 {
358 	struct lsa_entry	*le;
359 
360 	TAILQ_FOREACH(le, &nbr->ls_retrans_list, entry) {
361 		if ((lsa_hdr->type == le->le_ref->hdr.type) &&
362 		    (lsa_hdr->ls_id == le->le_ref->hdr.ls_id) &&
363 		    (lsa_hdr->adv_rtr == le->le_ref->hdr.adv_rtr))
364 			return (le);
365 	}
366 	return (NULL);
367 }
368 
369 void
ls_retrans_list_insert(struct nbr * nbr,struct lsa_entry * new)370 ls_retrans_list_insert(struct nbr *nbr, struct lsa_entry *new)
371 {
372 	struct lsa_entry	*le;
373 	unsigned short		 when = new->le_when;
374 
375 	TAILQ_FOREACH(le, &nbr->ls_retrans_list, entry) {
376 		if (when < le->le_when) {
377 			new->le_when = when;
378 			TAILQ_INSERT_BEFORE(le, new, entry);
379 			nbr->ls_ret_cnt++;
380 			return;
381 		}
382 		when -= le->le_when;
383 	}
384 	new->le_when = when;
385 	TAILQ_INSERT_TAIL(&nbr->ls_retrans_list, new, entry);
386 	nbr->ls_ret_cnt++;
387 }
388 
389 void
ls_retrans_list_remove(struct nbr * nbr,struct lsa_entry * le)390 ls_retrans_list_remove(struct nbr *nbr, struct lsa_entry *le)
391 {
392 	struct timeval		 tv;
393 	struct lsa_entry	*next = TAILQ_NEXT(le, entry);
394 	int			 reset = 0;
395 
396 	/* adjust timeout of next entry */
397 	if (next)
398 		next->le_when += le->le_when;
399 
400 	if (TAILQ_FIRST(&nbr->ls_retrans_list) == le &&
401 	    evtimer_pending(&nbr->ls_retrans_timer, NULL))
402 		reset = 1;
403 
404 	TAILQ_REMOVE(&nbr->ls_retrans_list, le, entry);
405 	nbr->ls_ret_cnt--;
406 
407 	if (reset && TAILQ_FIRST(&nbr->ls_retrans_list)) {
408 		if (evtimer_del(&nbr->ls_retrans_timer) == -1)
409 			fatal("ls_retrans_list_remove");
410 
411 		timerclear(&tv);
412 		tv.tv_sec = TAILQ_FIRST(&nbr->ls_retrans_list)->le_when;
413 
414 		if (evtimer_add(&nbr->ls_retrans_timer, &tv) == -1)
415 			fatal("ls_retrans_list_remove");
416 	}
417 }
418 
419 void
ls_retrans_list_free(struct nbr * nbr,struct lsa_entry * le)420 ls_retrans_list_free(struct nbr *nbr, struct lsa_entry *le)
421 {
422 	ls_retrans_list_remove(nbr, le);
423 
424 	lsa_cache_put(le->le_ref, nbr);
425 	free(le);
426 }
427 
428 void
ls_retrans_list_clr(struct nbr * nbr)429 ls_retrans_list_clr(struct nbr *nbr)
430 {
431 	struct lsa_entry	*le;
432 
433 	while ((le = TAILQ_FIRST(&nbr->ls_retrans_list)) != NULL)
434 		ls_retrans_list_free(nbr, le);
435 
436 	nbr->ls_ret_cnt = 0;
437 }
438 
439 void
ls_retrans_timer(int fd,short event,void * bula)440 ls_retrans_timer(int fd, short event, void *bula)
441 {
442 	struct timeval		 tv;
443 	struct timespec		 tp;
444 	struct in6_addr		 addr;
445 	struct nbr		*nbr = bula;
446 	struct lsa_entry	*le;
447 	struct ibuf		*buf;
448 	time_t			 now;
449 	int			 d, bigpkt;
450 	u_int32_t		 nlsa = 0;
451 
452 	if ((le = TAILQ_FIRST(&nbr->ls_retrans_list)) != NULL)
453 		le->le_when = 0;	/* timer fired */
454 	else
455 		return;			/* queue empty, nothing to do */
456 
457 	clock_gettime(CLOCK_MONOTONIC, &tp);
458 	now = tp.tv_sec;
459 
460 	if (nbr->iface->self == nbr) {
461 		/*
462 		 * oneshot needs to be set for lsa queued for flooding,
463 		 * if oneshot is not set then the lsa needs to be converted
464 		 * because the router switched lately to DR or BDR
465 		 */
466 		if (le->le_oneshot && nbr->iface->state & IF_STA_DRORBDR)
467 			inet_pton(AF_INET6, AllSPFRouters, &addr);
468 		else if (nbr->iface->state & IF_STA_DRORBDR) {
469 			/*
470 			 * old retransmission needs to be converted into
471 			 * flood by rerunning the lsa_flood.
472 			 */
473 			lsa_flood(nbr->iface, nbr, &le->le_ref->hdr,
474 			    le->le_ref->data);
475 			ls_retrans_list_free(nbr, le);
476 			/* ls_retrans_list_free retriggers the timer */
477 			return;
478 		} else if (nbr->iface->type == IF_TYPE_POINTOPOINT)
479 			memcpy(&addr, &nbr->addr, sizeof(addr));
480 		else
481 			inet_pton(AF_INET6, AllDRouters, &addr);
482 	} else
483 		memcpy(&addr, &nbr->addr, sizeof(addr));
484 
485 	bigpkt = le->le_ref->len > 1024;
486 	if ((buf = prepare_ls_update(nbr->iface, bigpkt)) == NULL) {
487 		le->le_when = 1;
488 		goto done;
489 	}
490 
491 	while ((le = TAILQ_FIRST(&nbr->ls_retrans_list)) != NULL &&
492 	    le->le_when == 0) {
493 		d = now - le->le_ref->stamp;
494 		if (d < 0)
495 			d = 0;
496 		else if (d > MAX_AGE)
497 			d = MAX_AGE;
498 
499 		if (add_ls_update(buf, nbr->iface, le->le_ref->data,
500 		    le->le_ref->len, d) == 0) {
501 			if (nlsa == 0) {
502 				/* something bad happened retry later */
503 				log_warnx("ls_retrans_timer: sending LS update "
504 				    "to neighbor ID %s (%s) failed",
505 				    inet_ntoa(nbr->id), nbr->iface->name);
506 				log_debug("ls_retrans_timer: type: %04x len: %u",
507 				    ntohs(le->le_ref->hdr.type),
508 				    le->le_ref->len);
509 				TAILQ_REMOVE(&nbr->ls_retrans_list, le, entry);
510 				nbr->ls_ret_cnt--;
511 				le->le_when = nbr->iface->rxmt_interval;
512 				ls_retrans_list_insert(nbr, le);
513 			}
514 			break;
515 		}
516 		nlsa++;
517 		if (le->le_oneshot)
518 			ls_retrans_list_free(nbr, le);
519 		else {
520 			TAILQ_REMOVE(&nbr->ls_retrans_list, le, entry);
521 			nbr->ls_ret_cnt--;
522 			le->le_when = nbr->iface->rxmt_interval;
523 			ls_retrans_list_insert(nbr, le);
524 		}
525 	}
526 	if (nlsa)
527 		send_ls_update(buf, nbr->iface, addr, nlsa);
528 	else
529 		ibuf_free(buf);
530 
531 done:
532 	if ((le = TAILQ_FIRST(&nbr->ls_retrans_list)) != NULL) {
533 		timerclear(&tv);
534 		tv.tv_sec = le->le_when;
535 
536 		if (evtimer_add(&nbr->ls_retrans_timer, &tv) == -1)
537 			fatal("ls_retrans_timer");
538 	}
539 }
540 
541 LIST_HEAD(lsa_cache_head, lsa_ref);
542 
543 struct lsa_cache {
544 	struct lsa_cache_head	*hashtbl;
545 	u_int32_t		 hashmask;
546 } lsacache;
547 
548 SIPHASH_KEY lsacachekey;
549 
550 struct lsa_ref		*lsa_cache_look(struct lsa_hdr *);
551 
552 void
lsa_cache_init(u_int32_t hashsize)553 lsa_cache_init(u_int32_t hashsize)
554 {
555 	u_int32_t        hs, i;
556 
557 	for (hs = 1; hs < hashsize; hs <<= 1)
558 		;
559 	lsacache.hashtbl = calloc(hs, sizeof(struct lsa_cache_head));
560 	if (lsacache.hashtbl == NULL)
561 		fatal("lsa_cache_init");
562 
563 	for (i = 0; i < hs; i++)
564 		LIST_INIT(&lsacache.hashtbl[i]);
565 	arc4random_buf(&lsacachekey, sizeof(lsacachekey));
566 
567 	lsacache.hashmask = hs - 1;
568 }
569 
570 static uint32_t
lsa_hash_hdr(const struct lsa_hdr * hdr)571 lsa_hash_hdr(const struct lsa_hdr *hdr)
572 {
573 	return SipHash24(&lsacachekey, hdr, sizeof(*hdr));
574 }
575 
576 struct lsa_ref *
lsa_cache_add(void * data,u_int16_t len)577 lsa_cache_add(void *data, u_int16_t len)
578 {
579 	struct lsa_cache_head	*head;
580 	struct lsa_ref		*ref, *old;
581 	struct timespec		 tp;
582 
583 	if ((ref = calloc(1, sizeof(*ref))) == NULL)
584 		fatal("lsa_cache_add");
585 	memcpy(&ref->hdr, data, sizeof(ref->hdr));
586 
587 	if ((old = lsa_cache_look(&ref->hdr))) {
588 		free(ref);
589 		old->refcnt++;
590 		return (old);
591 	}
592 
593 	if ((ref->data = malloc(len)) == NULL)
594 		fatal("lsa_cache_add");
595 	memcpy(ref->data, data, len);
596 
597 	clock_gettime(CLOCK_MONOTONIC, &tp);
598 	ref->stamp = tp.tv_sec;
599 	ref->len = len;
600 	ref->refcnt = 1;
601 
602 	head = &lsacache.hashtbl[lsa_hash_hdr(&ref->hdr) & lsacache.hashmask];
603 	LIST_INSERT_HEAD(head, ref, entry);
604 	return (ref);
605 }
606 
607 struct lsa_ref *
lsa_cache_get(struct lsa_hdr * lsa_hdr)608 lsa_cache_get(struct lsa_hdr *lsa_hdr)
609 {
610 	struct lsa_ref		*ref;
611 
612 	ref = lsa_cache_look(lsa_hdr);
613 	if (ref)
614 		ref->refcnt++;
615 
616 	return (ref);
617 }
618 
619 void
lsa_cache_put(struct lsa_ref * ref,struct nbr * nbr)620 lsa_cache_put(struct lsa_ref *ref, struct nbr *nbr)
621 {
622 	if (--ref->refcnt > 0)
623 		return;
624 
625 	if (ntohs(ref->hdr.age) >= MAX_AGE)
626 		ospfe_imsg_compose_rde(IMSG_LS_MAXAGE, nbr->peerid, 0,
627 		    ref->data, sizeof(struct lsa_hdr));
628 
629 	free(ref->data);
630 	LIST_REMOVE(ref, entry);
631 	free(ref);
632 }
633 
634 struct lsa_ref *
lsa_cache_look(struct lsa_hdr * lsa_hdr)635 lsa_cache_look(struct lsa_hdr *lsa_hdr)
636 {
637 	struct lsa_cache_head	*head;
638 	struct lsa_ref		*ref;
639 
640 	head = &lsacache.hashtbl[lsa_hash_hdr(lsa_hdr) & lsacache.hashmask];
641 
642 	LIST_FOREACH(ref, head, entry) {
643 		if (memcmp(&ref->hdr, lsa_hdr, sizeof(*lsa_hdr)) == 0)
644 			/* found match */
645 			return (ref);
646 	}
647 
648 	return (NULL);
649 }
650