Add generic route timeout functionality; used by path MTU discovery code

This commit is contained in:
kml 1998-04-29 03:41:49 +00:00
parent 9e97d1cc17
commit 8cdafd0efb
2 changed files with 262 additions and 2 deletions

View File

@ -1,4 +1,41 @@
/* $NetBSD: route.c,v 1.17 1997/04/02 21:17:28 christos Exp $ */ /* $NetBSD: route.c,v 1.18 1998/04/29 03:41:49 kml Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Kevin M. Lahey of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* /*
* Copyright (c) 1980, 1986, 1991, 1993 * Copyright (c) 1980, 1986, 1991, 1993
@ -43,6 +80,7 @@
#include <sys/socketvar.h> #include <sys/socketvar.h>
#include <sys/domain.h> #include <sys/domain.h>
#include <sys/protosw.h> #include <sys/protosw.h>
#include <sys/kernel.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <net/if.h> #include <net/if.h>
@ -149,6 +187,7 @@ rtfree(rt)
printf("rtfree: %p not freed (neg refs)\n", rt); printf("rtfree: %p not freed (neg refs)\n", rt);
return; return;
} }
rt_timer_remove_all(rt);
ifa = rt->rt_ifa; ifa = rt->rt_ifa;
IFAFREE(ifa); IFAFREE(ifa);
Free(rt_key(rt)); Free(rt_key(rt));
@ -385,6 +424,7 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
senderr(ENOBUFS); senderr(ENOBUFS);
Bzero(rt, sizeof(*rt)); Bzero(rt, sizeof(*rt));
rt->rt_flags = RTF_UP | flags; rt->rt_flags = RTF_UP | flags;
LIST_INIT(&rt->rt_timer);
if (rt_setgate(rt, dst, gateway)) { if (rt_setgate(rt, dst, gateway)) {
Free(rt); Free(rt);
senderr(ENOBUFS); senderr(ENOBUFS);
@ -538,3 +578,189 @@ rtinit(ifa, cmd, flags)
} }
return (error); return (error);
} }
/*
* Route timer routines. These routes allow functions to be called
* for various routes at any time. This is useful in supporting
* path MTU discovery and redirect route deletion.
*
* This is similar to some BSDI internal functions, but it provides
* for multiple queues for efficiency's sake...
*/
LIST_HEAD(, rttimer_queue) rttimer_queue_head;
static int rt_init_done = 0;
#define RTTIMER_CALLOUT(r) { \
if (r->rtt_func != NULL) { \
r->rtt_func(r->rtt_rt, r); \
} else { \
rtrequest((int) RTM_DELETE, \
(struct sockaddr *)rt_key(r->rtt_rt), \
0, 0, 0, 0); \
} \
}
/*
* Some subtle order problems with domain initialization mean that
* we cannot count on this being run from rt_init before various
* protocol initializations are done. Therefore, we make sure
* that this is run when the first queue is added...
*/
void
rt_timer_init()
{
assert(rt_init_done == 0);
LIST_INIT(&rttimer_queue_head);
timeout(rt_timer_timer, NULL, hz); /* every second */
rt_init_done = 1;
}
struct rttimer_queue *
rt_timer_queue_create(timeout)
u_int timeout;
{
struct rttimer_queue *rtq;
if (rt_init_done == 0)
rt_timer_init();
R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
if (rtq == NULL)
return NULL;
rtq->rtq_timeout = timeout;
CIRCLEQ_INIT(&rtq->rtq_head);
LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
return rtq;
}
void
rt_timer_queue_change(rtq, timeout)
struct rttimer_queue *rtq;
long timeout;
{
rtq->rtq_timeout = timeout;
}
void
rt_timer_queue_destroy(rtq, destroy)
struct rttimer_queue *rtq;
int destroy;
{
struct rttimer *r, *r0;
r = CIRCLEQ_FIRST(&rtq->rtq_head);
while (r != (struct rttimer *) &rtq->rtq_head) {
r0 = CIRCLEQ_NEXT(r, rtt_next);
CIRCLEQ_REMOVE(&rtq->rtq_head, r, rtt_next);
LIST_REMOVE(r, rtt_link);
if (destroy != 0)
RTTIMER_CALLOUT(r);
Free(r);
r = r0;
}
LIST_REMOVE(rtq, rtq_link);
}
void
rt_timer_remove_all(rt)
struct rtentry *rt;
{
struct rttimer *r, *r0;
r = LIST_FIRST(&rt->rt_timer);
while (r) {
r0 = LIST_NEXT(r, rtt_link);
LIST_REMOVE(r, rtt_link);
CIRCLEQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
Free(r);
r = r0;
}
}
int
rt_timer_add(rt, func, queue)
struct rtentry *rt;
void(*func) __P((struct rtentry *, struct rttimer *));
struct rttimer_queue *queue;
{
struct rttimer *r, *rttimer;
int s;
long current_time;
s = splclock();
current_time = mono_time.tv_sec;
splx(s);
for (r = LIST_FIRST(&rt->rt_timer); r; r = LIST_NEXT(r, rtt_link)) {
if (r->rtt_func == func) {
LIST_REMOVE(r, rtt_link);
CIRCLEQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
Free(r);
break; /* only one per list, so we can quit... */
}
}
R_Malloc(rttimer, struct rttimer *, sizeof *rttimer);
if (rttimer == NULL)
return ENOBUFS;
rttimer->rtt_rt = rt;
rttimer->rtt_time = current_time;
rttimer->rtt_func = func;
rttimer->rtt_queue = queue;
LIST_INSERT_HEAD(&rt->rt_timer, rttimer, rtt_link);
r = CIRCLEQ_LAST(&queue->rtq_head);
while (r && r != (struct rttimer *) &queue->rtq_head &&
r->rtt_time > current_time)
r = CIRCLEQ_PREV(r, rtt_next);
if (r)
CIRCLEQ_INSERT_AFTER(&queue->rtq_head, r, rttimer, rtt_next);
else
CIRCLEQ_INSERT_HEAD(&queue->rtq_head, rttimer, rtt_next);
return 0;
}
/* ARGSUSED */
void
rt_timer_timer(arg)
void *arg;
{
struct rttimer *r, *rttimer;
struct rttimer_queue *rtq;
long current_time;
int s;
s = splclock();
current_time = mono_time.tv_sec;
splx(s);
for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL;
rtq = LIST_NEXT(rtq, rtq_link)) {
rttimer = CIRCLEQ_FIRST(&rtq->rtq_head);
while (rttimer != (struct rttimer *) &rtq->rtq_head &&
(rttimer->rtt_time + rtq->rtq_timeout) < current_time) {
r = CIRCLEQ_NEXT(rttimer, rtt_next);
CIRCLEQ_REMOVE(&rtq->rtq_head, rttimer, rtt_next);
LIST_REMOVE(rttimer, rtt_link);
RTTIMER_CALLOUT(rttimer);
Free(rttimer);
rttimer = r;
}
}
timeout(rt_timer_timer, NULL, hz); /* every second */
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: route.h,v 1.11 1997/04/02 21:17:29 christos Exp $ */ /* $NetBSD: route.h,v 1.12 1998/04/29 03:41:49 kml Exp $ */
/* /*
* Copyright (c) 1980, 1986, 1993 * Copyright (c) 1980, 1986, 1993
@ -104,6 +104,7 @@ struct rtentry {
caddr_t rt_llinfo; /* pointer to link level info cache */ caddr_t rt_llinfo; /* pointer to link level info cache */
struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */ struct rt_metrics rt_rmx; /* metrics used by rx'ing protocols */
struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */ struct rtentry *rt_gwroute; /* implied entry for gatewayed routes */
LIST_HEAD(, rttimer) rt_timer; /* queue of timeouts for misc funcs */
}; };
/* /*
@ -228,6 +229,29 @@ struct route_cb {
int any_count; int any_count;
}; };
/*
* This structure, and the prototypes for the rt_timer_{init,remove_all,
* add,timer} functions all used with the kind permission of BSDI.
* These allow functions to be called for routes at specific times.
*/
struct rttimer {
CIRCLEQ_ENTRY(rttimer) rtt_next;
LIST_ENTRY(rttimer) rtt_link; /* Multiple timers on single route */
struct rttimer_queue *rtt_queue;
struct rtentry *rtt_rt; /* Back pointer to the route */
void (*rtt_func) __P((struct rtentry *,
struct rttimer *));
time_t rtt_time; /* When this timer was registered */
};
struct rttimer_queue {
long rtq_timeout;
CIRCLEQ_HEAD(, rttimer) rtq_head;
LIST_ENTRY(rttimer_queue) rtq_link;
};
#ifdef _KERNEL #ifdef _KERNEL
#define RTFREE(rt) \ #define RTFREE(rt) \
if ((rt)->rt_refcnt <= 1) \ if ((rt)->rt_refcnt <= 1) \
@ -253,6 +277,16 @@ void rt_newaddrmsg __P((int, struct ifaddr *, int, struct rtentry *));
int rt_setgate __P((struct rtentry *, int rt_setgate __P((struct rtentry *,
struct sockaddr *, struct sockaddr *)); struct sockaddr *, struct sockaddr *));
void rt_setmetrics __P((u_long, struct rt_metrics *, struct rt_metrics *)); void rt_setmetrics __P((u_long, struct rt_metrics *, struct rt_metrics *));
int rt_timer_add __P((struct rtentry *,
void(*)(struct rtentry *, struct rttimer *),
struct rttimer_queue *));
void rt_timer_init __P((void));
struct rttimer_queue *
rt_timer_queue_create __P((u_int));
void rt_timer_queue_change __P((struct rttimer_queue *, long));
void rt_timer_queue_destroy __P((struct rttimer_queue *, int));
void rt_timer_remove_all __P((struct rtentry *));
void rt_timer_timer __P((void *));
void rtable_init __P((void **)); void rtable_init __P((void **));
void rtalloc __P((struct route *)); void rtalloc __P((struct route *));
struct rtentry * struct rtentry *