summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/in6_rmx.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet6/in6_rmx.c')
-rw-r--r--freebsd/sys/netinet6/in6_rmx.c249
1 files changed, 69 insertions, 180 deletions
diff --git a/freebsd/sys/netinet6/in6_rmx.c b/freebsd/sys/netinet6/in6_rmx.c
index fee58221..a4bdb3af 100644
--- a/freebsd/sys/netinet6/in6_rmx.c
+++ b/freebsd/sys/netinet6/in6_rmx.c
@@ -61,19 +61,6 @@
*
*/
-/*
- * This code does two things necessary for the enhanced TCP metrics to
- * function in a useful manner:
- * 1) It marks all non-host routes as `cloning', thus ensuring that
- * every actual reference to such a route actually gets turned
- * into a reference to a host route to the specific destination
- * requested.
- * 2) When such routes lose all their references, it arranges for them
- * to be deleted in some random collection of circumstances, so that
- * a large quantity of stale routing data is not kept in kernel memory
- * indefinitely. See in6_rtqtimo() below for the exact mechanism.
- */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -113,8 +100,6 @@ extern int in6_inithead(void **head, int off);
extern int in6_detachhead(void **head, int off);
#endif
-#define RTPRF_OURS RTF_PROTO3 /* set on routes we manage */
-
/*
* Do what we need to do when inserting a route.
*/
@@ -170,7 +155,8 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
* net route entry, 3ffe:0501:: -> if0.
* This case should not raise an error.
*/
- rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED);
+ rt2 = in6_rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED,
+ rt->rt_fibnum);
if (rt2) {
if (((rt2->rt_flags & (RTF_HOST|RTF_GATEWAY)) == 0)
&& rt2->rt_gateway
@@ -184,42 +170,8 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
return (ret);
}
-/*
- * This code is the inverse of in6_clsroute: on first reference, if we
- * were managing the route, stop doing so and set the expiration timer
- * back off again.
- */
-static struct radix_node *
-in6_matroute(void *v_arg, struct radix_node_head *head)
-{
- struct radix_node *rn = rn_match(v_arg, head);
- struct rtentry *rt = (struct rtentry *)rn;
-
- if (rt) {
- RT_LOCK(rt);
- if (rt->rt_flags & RTPRF_OURS) {
- rt->rt_flags &= ~RTPRF_OURS;
- rt->rt_rmx.rmx_expire = 0;
- }
- RT_UNLOCK(rt);
- }
- return rn;
-}
-
SYSCTL_DECL(_net_inet6_ip6);
-static VNET_DEFINE(int, rtq_reallyold6) = 60*60;
- /* one hour is ``really old'' */
-#define V_rtq_reallyold6 VNET(rtq_reallyold6)
-SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_RTEXPIRE, rtexpire, CTLFLAG_RW,
- &VNET_NAME(rtq_reallyold6) , 0, "");
-
-static VNET_DEFINE(int, rtq_minreallyold6) = 10;
- /* never automatically crank down to less */
-#define V_rtq_minreallyold6 VNET(rtq_minreallyold6)
-SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_RTMINEXPIRE, rtminexpire, CTLFLAG_RW,
- &VNET_NAME(rtq_minreallyold6) , 0, "");
-
static VNET_DEFINE(int, rtq_toomany6) = 128;
/* 128 cached routes is ``too many'' */
#define V_rtq_toomany6 VNET(rtq_toomany6)
@@ -237,114 +189,6 @@ struct rtqk_arg {
};
/*
- * Get rid of old routes. When draining, this deletes everything, even when
- * the timeout is not expired yet. When updating, this makes sure that
- * nothing has a timeout longer than the current value of rtq_reallyold6.
- */
-static int
-in6_rtqkill(struct radix_node *rn, void *rock)
-{
- struct rtqk_arg *ap = rock;
- struct rtentry *rt = (struct rtentry *)rn;
- int err;
-
- RADIX_NODE_HEAD_WLOCK_ASSERT(ap->rnh);
-
- if (rt->rt_flags & RTPRF_OURS) {
- ap->found++;
-
- if (ap->draining || rt->rt_rmx.rmx_expire <= time_uptime) {
- if (rt->rt_refcnt > 0)
- panic("rtqkill route really not free");
-
- err = rtrequest(RTM_DELETE,
- (struct sockaddr *)rt_key(rt),
- rt->rt_gateway, rt_mask(rt),
- rt->rt_flags|RTF_RNH_LOCKED, 0);
- if (err) {
- log(LOG_WARNING, "in6_rtqkill: error %d", err);
- } else {
- ap->killed++;
- }
- } else {
- if (ap->updating
- && (rt->rt_rmx.rmx_expire - time_uptime
- > V_rtq_reallyold6)) {
- rt->rt_rmx.rmx_expire = time_uptime
- + V_rtq_reallyold6;
- }
- ap->nextstop = lmin(ap->nextstop,
- rt->rt_rmx.rmx_expire);
- }
- }
-
- return 0;
-}
-
-#define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */
-static VNET_DEFINE(int, rtq_timeout6) = RTQ_TIMEOUT;
-static VNET_DEFINE(struct callout, rtq_timer6);
-
-#define V_rtq_timeout6 VNET(rtq_timeout6)
-#define V_rtq_timer6 VNET(rtq_timer6)
-
-static void
-in6_rtqtimo(void *rock)
-{
- CURVNET_SET_QUIET((struct vnet *) rock);
- struct radix_node_head *rnh;
- struct rtqk_arg arg;
- struct timeval atv;
- static time_t last_adjusted_timeout = 0;
-
- rnh = rt_tables_get_rnh(0, AF_INET6);
- if (rnh == NULL) {
- CURVNET_RESTORE();
- return;
- }
- arg.found = arg.killed = 0;
- arg.rnh = rnh;
- arg.nextstop = time_uptime + V_rtq_timeout6;
- arg.draining = arg.updating = 0;
- RADIX_NODE_HEAD_LOCK(rnh);
- rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
- RADIX_NODE_HEAD_UNLOCK(rnh);
-
- /*
- * Attempt to be somewhat dynamic about this:
- * If there are ``too many'' routes sitting around taking up space,
- * then crank down the timeout, and see if we can't make some more
- * go away. However, we make sure that we will never adjust more
- * than once in rtq_timeout6 seconds, to keep from cranking down too
- * hard.
- */
- if ((arg.found - arg.killed > V_rtq_toomany6)
- && (time_uptime - last_adjusted_timeout >= V_rtq_timeout6)
- && V_rtq_reallyold6 > V_rtq_minreallyold6) {
- V_rtq_reallyold6 = 2*V_rtq_reallyold6 / 3;
- if (V_rtq_reallyold6 < V_rtq_minreallyold6) {
- V_rtq_reallyold6 = V_rtq_minreallyold6;
- }
-
- last_adjusted_timeout = time_uptime;
-#ifdef DIAGNOSTIC
- log(LOG_DEBUG, "in6_rtqtimo: adjusted rtq_reallyold6 to %d",
- V_rtq_reallyold6);
-#endif
- arg.found = arg.killed = 0;
- arg.updating = 1;
- RADIX_NODE_HEAD_LOCK(rnh);
- rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
- RADIX_NODE_HEAD_UNLOCK(rnh);
- }
-
- atv.tv_usec = 0;
- atv.tv_sec = arg.nextstop - time_uptime;
- callout_reset(&V_rtq_timer6, tvtohz(&atv), in6_rtqtimo, rock);
- CURVNET_RESTORE();
-}
-
-/*
* Age old PMTUs.
*/
struct mtuex_arg {
@@ -379,31 +223,33 @@ in6_mtuexpire(struct radix_node *rn, void *rock)
#define MTUTIMO_DEFAULT (60*1)
static void
-in6_mtutimo(void *rock)
+in6_mtutimo_one(struct radix_node_head *rnh)
{
- CURVNET_SET_QUIET((struct vnet *) rock);
- struct radix_node_head *rnh;
struct mtuex_arg arg;
- struct timeval atv;
- rnh = rt_tables_get_rnh(0, AF_INET6);
- if (rnh == NULL) {
- CURVNET_RESTORE();
- return;
- }
arg.rnh = rnh;
arg.nextstop = time_uptime + MTUTIMO_DEFAULT;
RADIX_NODE_HEAD_LOCK(rnh);
rnh->rnh_walktree(rnh, in6_mtuexpire, &arg);
RADIX_NODE_HEAD_UNLOCK(rnh);
+}
- atv.tv_usec = 0;
- atv.tv_sec = arg.nextstop - time_uptime;
- if (atv.tv_sec < 0) {
- printf("invalid mtu expiration time on routing table\n");
- arg.nextstop = time_uptime + 30; /* last resort */
- atv.tv_sec = 30;
+static void
+in6_mtutimo(void *rock)
+{
+ CURVNET_SET_QUIET((struct vnet *) rock);
+ struct radix_node_head *rnh;
+ struct timeval atv;
+ u_int fibnum;
+
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+ if (rnh != NULL)
+ in6_mtutimo_one(rnh);
}
+
+ atv.tv_sec = MTUTIMO_DEFAULT;
+ atv.tv_usec = 0;
callout_reset(&V_rtq_mtutimer, tvtohz(&atv), in6_mtutimo, rock);
CURVNET_RESTORE();
}
@@ -415,6 +261,9 @@ in6_mtutimo(void *rock)
* value should be so just use that).. FIX AFTER RELENG_7 is MFC'd
* see also comments in in_inithead() vfs_export.c and domain.h
*/
+static VNET_DEFINE(int, _in6_rt_was_here);
+#define V__in6_rt_was_here VNET(_in6_rt_was_here)
+
int
in6_inithead(void **head, int off)
{
@@ -427,13 +276,14 @@ in6_inithead(void **head, int off)
return 1; /* only do the rest for the real thing */
rnh = *head;
- KASSERT(rnh == rt_tables_get_rnh(0, AF_INET6), ("rnh?"));
rnh->rnh_addaddr = in6_addroute;
- rnh->rnh_matchaddr = in6_matroute;
- callout_init(&V_rtq_timer6, CALLOUT_MPSAFE);
- callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
- in6_rtqtimo(curvnet); /* kick off timeout first time */
- in6_mtutimo(curvnet); /* kick off timeout first time */
+
+ if (V__in6_rt_was_here == 0) {
+ callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
+ in6_mtutimo(curvnet); /* kick off timeout first time */
+ V__in6_rt_was_here = 1;
+ }
+
return 1;
}
@@ -442,8 +292,47 @@ int
in6_detachhead(void **head, int off)
{
- callout_drain(&V_rtq_timer6);
callout_drain(&V_rtq_mtutimer);
return (1);
}
#endif
+
+/*
+ * Extended API for IPv6 FIB support.
+ */
+void
+in6_rtredirect(struct sockaddr *dst, struct sockaddr *gw, struct sockaddr *nm,
+ int flags, struct sockaddr *src, u_int fibnum)
+{
+
+ rtredirect_fib(dst, gw, nm, flags, src, fibnum);
+}
+
+int
+in6_rtrequest(int req, struct sockaddr *dst, struct sockaddr *gw,
+ struct sockaddr *mask, int flags, struct rtentry **ret_nrt, u_int fibnum)
+{
+
+ return (rtrequest_fib(req, dst, gw, mask, flags, ret_nrt, fibnum));
+}
+
+void
+in6_rtalloc(struct route_in6 *ro, u_int fibnum)
+{
+
+ rtalloc_ign_fib((struct route *)ro, 0ul, fibnum);
+}
+
+void
+in6_rtalloc_ign(struct route_in6 *ro, u_long ignflags, u_int fibnum)
+{
+
+ rtalloc_ign_fib((struct route *)ro, ignflags, fibnum);
+}
+
+struct rtentry *
+in6_rtalloc1(struct sockaddr *dst, int report, u_long ignflags, u_int fibnum)
+{
+
+ return (rtalloc1_fib(dst, report, ignflags, fibnum));
+}