summaryrefslogtreecommitdiff
path: root/sys/net/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/route.c')
-rw-r--r--sys/net/route.c248
1 files changed, 246 insertions, 2 deletions
diff --git a/sys/net/route.c b/sys/net/route.c
index 6602c31f2fa..23fab89eea2 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,7 +1,36 @@
-/* $OpenBSD: route.c,v 1.15 1999/09/13 22:33:51 niklas Exp $ */
+/* $OpenBSD: route.c,v 1.16 1999/12/08 06:50:18 itojun Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * 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. Neither the name of the project 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 PROJECT 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 PROJECT 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
* The Regents of the University of California. All rights reserved.
*
@@ -57,6 +86,7 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/ioctl.h>
+#include <sys/kernel.h>
#include <net/if.h>
#include <net/route.h>
@@ -250,6 +280,7 @@ rtfree(rt)
printf("rtfree: %p not freed (neg refs)\n", rt);
return;
}
+ rt_timer_remove_all(rt);
ifa = rt->rt_ifa;
if (ifa)
IFAFREE(ifa);
@@ -496,12 +527,18 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
case RTM_ADD:
if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == NULL)
senderr(ENETUNREACH);
+
+ /* The interface found in the previous statement may
+ * be overridden later by rt_setif. See the code
+ * for case RTM_ADD in rtsock.c:route_output.
+ */
makeroute:
R_Malloc(rt, struct rtentry *, sizeof(*rt));
if (rt == NULL)
senderr(ENOBUFS);
Bzero(rt, sizeof(*rt));
rt->rt_flags = RTF_UP | flags;
+ LIST_INIT(&rt->rt_timer);
if (rt_setgate(rt, dst, gateway)) {
Free(rt);
senderr(ENOBUFS);
@@ -511,6 +548,9 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
rt_maskedcopy(dst, ndst, netmask);
} else
Bcopy(dst, ndst, dst->sa_len);
+if (!rt->rt_rmx.rmx_mtu && !(rt->rt_rmx.rmx_locks & RTV_MTU)) { /* XXX */
+ rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu;
+}
rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
rnh, rt->rt_nodes);
if (rn == NULL) {
@@ -646,7 +686,9 @@ rtinit(ifa, cmd, flags)
dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
if (cmd == RTM_DELETE) {
if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
- m = m_get(M_WAIT, MT_SONAME);
+ m = m_get(M_DONTWAIT, MT_SONAME);
+ if (m == NULL)
+ return(ENOBUFS);
deldst = mtod(m, struct sockaddr *);
rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
dst = deldst;
@@ -689,6 +731,7 @@ rtinit(ifa, cmd, flags)
IFAFREE(rt->rt_ifa);
rt->rt_ifa = ifa;
rt->rt_ifp = ifa->ifa_ifp;
+ rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu; /*XXX*/
ifa->ifa_refcnt++;
if (ifa->ifa_rtrequest)
ifa->ifa_rtrequest(RTM_ADD, rt, SA(NULL));
@@ -697,3 +740,204 @@ rtinit(ifa, cmd, flags)
}
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);
+
+#if 0
+ pool_init(&rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl",
+ 0, NULL, NULL, M_RTABLE);
+#endif
+
+ 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;
+ TAILQ_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;
+
+ while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {
+ LIST_REMOVE(r, rtt_link);
+ TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
+ if (destroy)
+ RTTIMER_CALLOUT(r);
+#if 0
+ pool_put(&rttimer_pool, r);
+#else
+ free(r, M_RTABLE);
+#endif
+ }
+
+ LIST_REMOVE(rtq, rtq_link);
+
+ /*
+ * Caller is responsible for freeing the rttimer_queue structure.
+ */
+}
+
+void
+rt_timer_remove_all(rt)
+ struct rtentry *rt;
+{
+ struct rttimer *r;
+
+ while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {
+ LIST_REMOVE(r, rtt_link);
+ TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
+#if 0
+ pool_put(&rttimer_pool, r);
+#else
+ free(r, M_RTABLE);
+#endif
+ }
+}
+
+int
+rt_timer_add(rt, func, queue)
+ struct rtentry *rt;
+ void(*func) __P((struct rtentry *, struct rttimer *));
+ struct rttimer_queue *queue;
+{
+ struct rttimer *r;
+ long current_time;
+ int s;
+
+ s = splclock();
+ current_time = mono_time.tv_sec;
+ splx(s);
+
+ /*
+ * If there's already a timer with this action, destroy it before
+ * we add a new one.
+ */
+ for (r = LIST_FIRST(&rt->rt_timer); r != NULL;
+ r = LIST_NEXT(r, rtt_link)) {
+ if (r->rtt_func == func) {
+ LIST_REMOVE(r, rtt_link);
+ TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
+#if 0
+ pool_put(&rttimer_pool, r);
+#else
+ free(r, M_RTABLE);
+#endif
+ break; /* only one per list, so we can quit... */
+ }
+ }
+
+#if 0
+ r = pool_get(&rttimer_pool, PR_NOWAIT);
+#else
+ r = (struct rttimer *)malloc(sizeof(*r), M_RTABLE, M_NOWAIT);
+#endif
+ if (r == NULL)
+ return (ENOBUFS);
+
+ r->rtt_rt = rt;
+ r->rtt_time = current_time;
+ r->rtt_func = func;
+ r->rtt_queue = queue;
+ LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
+ TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
+
+ return (0);
+}
+
+/* ARGSUSED */
+void
+rt_timer_timer(arg)
+ void *arg;
+{
+ struct rttimer_queue *rtq;
+ struct rttimer *r;
+ long current_time;
+ int s;
+
+ s = splclock();
+ current_time = mono_time.tv_sec;
+ splx(s);
+
+ s = splsoftnet();
+ for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL;
+ rtq = LIST_NEXT(rtq, rtq_link)) {
+ while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
+ (r->rtt_time + rtq->rtq_timeout) < current_time) {
+ LIST_REMOVE(r, rtt_link);
+ TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
+ RTTIMER_CALLOUT(r);
+#if 0
+ pool_put(&rttimer_pool, r);
+#else
+ free(r, M_RTABLE);
+#endif
+ }
+ }
+ splx(s);
+
+ timeout(rt_timer_timer, NULL, hz); /* every second */
+}