Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -4098,6 +4098,7 @@ net/raw_cb.c standard net/raw_usrreq.c standard net/route.c standard +net/route_temporal.c standard net/rss_config.c optional inet rss | inet6 rss net/rtsock.c standard net/slcompress.c optional netgraph_vjc | sppp | \ Index: sys/net/radix_mpath.h =================================================================== --- sys/net/radix_mpath.h +++ sys/net/radix_mpath.h @@ -57,8 +57,8 @@ void rtalloc_mpath_fib(struct route *, u_int32_t, u_int); struct rtentry *rt_mpath_select(struct rtentry *, uint32_t); int rt_mpath_deldup(struct rtentry *, struct rtentry *); -int rn4_mpath_inithead(void **, int); -int rn6_mpath_inithead(void **, int); +int rn4_mpath_inithead(void **, int, u_int); +int rn6_mpath_inithead(void **, int, u_int); #endif Index: sys/net/radix_mpath.c =================================================================== --- sys/net/radix_mpath.c +++ sys/net/radix_mpath.c @@ -290,17 +290,17 @@ RT_UNLOCK(ro->ro_rt); } -extern int in6_inithead(void **head, int off); -extern int in_inithead(void **head, int off); +extern int in6_inithead(void **head, int off, u_int fibnum); +extern int in_inithead(void **head, int off, u_int fibnum); #ifdef INET int -rn4_mpath_inithead(void **head, int off) +rn4_mpath_inithead(void **head, int off, u_int fibnum) { struct rib_head *rnh; hashjitter = arc4random(); - if (in_inithead(head, off) == 1) { + if (in_inithead(head, off, fibnum) == 1) { rnh = (struct rib_head *)*head; rnh->rnh_multipath = 1; return 1; @@ -311,12 +311,12 @@ #ifdef INET6 int -rn6_mpath_inithead(void **head, int off) +rn6_mpath_inithead(void **head, int off, u_int fibnum) { struct rib_head *rnh; hashjitter = arc4random(); - if (in6_inithead(head, off) == 1) { + if (in6_inithead(head, off, fibnum) == 1) { rnh = (struct rib_head *)*head; rnh->rnh_multipath = 1; return 1; Index: sys/net/route.h =================================================================== --- sys/net/route.h +++ sys/net/route.h @@ -455,7 +455,7 @@ void rt_newmaddrmsg(int, struct ifmultiaddr *); int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *); void rt_maskedcopy(struct sockaddr *, struct sockaddr *, struct sockaddr *); -struct rib_head *rt_table_init(int); +struct rib_head *rt_table_init(int, int, u_int); void rt_table_destroy(struct rib_head *); u_int rt_tables_get_gen(int table, int fam); @@ -477,6 +477,8 @@ typedef int rt_walktree_f_t(struct rtentry *, void *); typedef void rt_setwarg_t(struct rib_head *, uint32_t, int, void *); +void rib_walk_del(u_int fibnum, int family, rt_filter_f_t *filter_f, + void *arg, int report); void rt_foreach_fib_walk(int af, rt_setwarg_t *, rt_walktree_f_t *, void *); void rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg); void rt_flushifroutes_af(struct ifnet *, int); @@ -494,8 +496,8 @@ void rtalloc_ign_fib(struct route *ro, u_long ignflags, u_int fibnum); struct rtentry *rtalloc1_fib(struct sockaddr *, int, u_long, u_int); int rtioctl_fib(u_long, caddr_t, u_int); -void rtredirect_fib(struct sockaddr *, struct sockaddr *, - struct sockaddr *, int, struct sockaddr *, u_int); +int rtredirect_fib(struct sockaddr *, struct sockaddr *, + int, struct sockaddr *, int, u_int); int rtrequest_fib(int, struct sockaddr *, struct sockaddr *, struct sockaddr *, int, struct rtentry **, u_int); int rtrequest1_fib(int, struct rt_addrinfo *, struct rtentry **, u_int); Index: sys/net/route.c =================================================================== --- sys/net/route.c +++ sys/net/route.c @@ -187,10 +187,11 @@ { struct rib_head **rnh; - KASSERT(table >= 0 && table < rt_numfibs, ("%s: table out of bounds.", - __func__)); - KASSERT(fam >= 0 && fam < (AF_MAX+1), ("%s: fam out of bounds.", - __func__)); + KASSERT(table >= 0 && table < rt_numfibs, + ("%s: table out of bounds (0 < %d < %d)", __func__, table, + rt_numfibs)); + KASSERT(fam >= 0 && fam < (AF_MAX + 1), + ("%s: fam out of bounds (0 < %d < %d)", __func__, fam, AF_MAX + 1)); /* rnh is [fib=0][af=0]. */ rnh = (struct rib_head **)V_rt_tables; @@ -304,7 +305,7 @@ rnh = rt_tables_get_rnh_ptr(table, fam); if (rnh == NULL) panic("%s: rnh NULL", __func__); - dom->dom_rtattach((void **)rnh, 0); + dom->dom_rtattach((void **)rnh, 0, table); } } } @@ -345,7 +346,7 @@ #endif struct rib_head * -rt_table_init(int offset) +rt_table_init(int offset, int family, u_int fibnum) { struct rib_head *rh; @@ -357,9 +358,19 @@ rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0); rh->head.rnh_masks = &rh->rmhead; + rh->rib_family = family; + rh->rib_fibnum = fibnum; + /* Init locks */ RIB_LOCK_INIT(rh); + tmproutes_init(rh); + + /* Save vnet pointer for callouts */ +#ifdef VIMAGE + rh->rib_vnet = curvnet; +#endif + /* Finally, set base callbacks */ rh->rnh_addaddr = rn_addroute; rh->rnh_deladdr = rn_delete; @@ -387,6 +398,8 @@ rt_table_destroy(struct rib_head *rh) { + tmproutes_destroy(rh); + rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); /* Assume table is already empty */ @@ -578,131 +591,125 @@ } -/* - * Force a routing table entry to the specified - * destination to go through the given gateway. - * Normally called as a result of a routing redirect - * message from the network layer. - */ -void -rtredirect_fib(struct sockaddr *dst, - struct sockaddr *gateway, - struct sockaddr *netmask, - int flags, - struct sockaddr *src, - u_int fibnum) +static int +verify_redirect_gateway(struct sockaddr *src, struct sockaddr *dst, + struct sockaddr *gateway, int flags, u_int fibnum) { struct rtentry *rt; - int error = 0; - struct rt_addrinfo info; struct ifaddr *ifa; - struct rib_head *rnh; NET_EPOCH_ASSERT(); - ifa = NULL; - rnh = rt_tables_get_rnh(fibnum, dst->sa_family); - if (rnh == NULL) { - error = EAFNOSUPPORT; - goto out; - } /* verify the gateway is directly reachable */ - if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL) { - error = ENETUNREACH; - goto out; - } - rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */ + if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL) + return (ENETUNREACH); + + /* TODO: fib-aware */ + if ((flags & RTF_GATEWAY) && ifa_ifwithaddr_check(gateway)) + return (EHOSTUNREACH); + + rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */ + /* * If the redirect isn't from our current router for this dst, * it's either old or wrong. If it redirects us to ourselves, * we have a routing loop, perhaps as a result of an interface * going down recently. */ - if (!(flags & RTF_DONE) && rt) { + if (rt != NULL) { if (!sa_equal(src, rt->rt_gateway)) { - error = EINVAL; - goto done; + RTFREE(rt); + return (EINVAL); } if (rt->rt_ifa != ifa && ifa->ifa_addr->sa_family != AF_LINK) { - error = EINVAL; - goto done; + RTFREE(rt); + return (EINVAL); } } - if ((flags & RTF_GATEWAY) && ifa_ifwithaddr_check(gateway)) { - error = EHOSTUNREACH; - goto done; + + /* If host route already exists, ignore redirect. */ + if (rt != NULL && (rt->rt_flags & RTF_HOST)) { + RTFREE(rt); + return (EEXIST); } - /* - * Create a new entry if we just got back a wildcard entry - * or the lookup failed. This is necessary for hosts - * which use routing redirects generated by smart gateways - * to dynamically build the routing tables. - */ - if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) - goto create; - /* - * Don't listen to the redirect if it's - * for a route to an interface. - */ - if (rt->rt_flags & RTF_GATEWAY) { - if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { - /* - * Changing from route to net => route to host. - * Create new route, rather than smashing route to net. - */ - create: - if (rt != NULL) - RTFREE_LOCKED(rt); - - flags |= RTF_DYNAMIC; - bzero((caddr_t)&info, sizeof(info)); - info.rti_info[RTAX_DST] = dst; - info.rti_info[RTAX_GATEWAY] = gateway; - info.rti_info[RTAX_NETMASK] = netmask; - ifa_ref(ifa); - info.rti_ifa = ifa; - info.rti_flags = flags; - error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); - if (rt != NULL) { - RT_LOCK(rt); - flags = rt->rt_flags; - } - if (error == 0) - RTSTAT_INC(rts_dynamic); - } else { - /* - * Smash the current notion of the gateway to - * this destination. Should check about netmask!!! - */ - if ((flags & RTF_GATEWAY) == 0) - rt->rt_flags &= ~RTF_GATEWAY; - rt->rt_flags |= RTF_MODIFIED; - flags |= RTF_MODIFIED; - RTSTAT_INC(rts_newgateway); - /* - * add the key and gateway (in one malloc'd chunk). - */ - RT_UNLOCK(rt); - RIB_WLOCK(rnh); - RT_LOCK(rt); - rt_setgate(rt, rt_key(rt), gateway); - RIB_WUNLOCK(rnh); - } - } else - error = EHOSTUNREACH; -done: - if (rt) - RTFREE_LOCKED(rt); - out: - if (error) + /* If the prefix is directly reachable, ignore redirect */ + if (rt != NULL && !(rt->rt_flags & RTF_GATEWAY)) { + RTFREE(rt); + return (EEXIST); + } + + RTFREE(rt); + return (0); +} + + +/* + * Force a routing table entry to the specified + * destination to go through the given gateway. + * Normally called as a result of a routing redirect + * message from the network layer. + */ +int +rtredirect_fib(struct sockaddr *dst, struct sockaddr *gateway, + int flags, struct sockaddr *src, int expire_sec, u_int fibnum) +{ + struct rtentry *rt; + int error = 0; + struct rt_addrinfo info; + struct rt_metrics rti_rmx; + struct ifaddr *ifa; + + NET_EPOCH_ASSERT(); + + if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL) + return (error); + + error = verify_redirect_gateway(src, dst, gateway, flags, fibnum); + if (error != 0) + return (error); + + /* verify the gateway is directly reachable */ + if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL) + return (ENETUNREACH); + ifa_ref(ifa); + + flags |= RTF_DYNAMIC; + + bzero(&info, sizeof(info)); + info.rti_info[RTAX_DST] = dst; + info.rti_info[RTAX_GATEWAY] = gateway; + info.rti_ifa = ifa; + info.rti_flags = flags; + + /* Setup route metrics to define expire time */ + bzero(&rti_rmx, sizeof(rti_rmx)); + /* Define expire time as absolute */ + rti_rmx.rmx_expire = expire_sec + time_second; + info.rti_mflags |= RTV_EXPIRE; + info.rti_rmx = &rti_rmx; + + error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); + ifa_free(ifa); + + if (error != 0) { RTSTAT_INC(rts_badredirect); - bzero((caddr_t)&info, sizeof(info)); + return (error); + } + + RT_LOCK(rt); + flags = rt->rt_flags; + RTFREE_LOCKED(rt); + + RTSTAT_INC(rts_dynamic); + + bzero(&info, sizeof(info)); info.rti_info[RTAX_DST] = dst; info.rti_info[RTAX_GATEWAY] = gateway; - info.rti_info[RTAX_NETMASK] = netmask; info.rti_info[RTAX_AUTHOR] = src; rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum); + + return (0); } /* @@ -1052,6 +1059,56 @@ } /* + * Iterates over rtable specified by @fibnum and @af and deletes elements + * marked by @filter_f. + * @fibnum: rtable id + * @family: AF_ address family + * @filter_f: lambda function returning non-zero value for items to delete + * @arg: data to pass to the @filter_f + * @report: true if rtsock notification is needed. + */ +void +rib_walk_del(u_int fibnum, int family, rt_filter_f_t *filter_f, void *arg, int report) +{ + struct rib_head *rnh; + struct rt_delinfo di; + struct rtentry *rt; + + rnh = rt_tables_get_rnh(fibnum, family); + if (rnh == NULL) + return; + + bzero(&di, sizeof(di)); + di.info.rti_filter = filter_f; + di.info.rti_filterdata = arg; + di.rnh = rnh; + + RIB_WLOCK(rnh); + rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di); + RIB_WUNLOCK(rnh); + + if (di.head == NULL) + return; + + /* We might have something to reclaim */ + while (di.head != NULL) { + rt = di.head; + di.head = rt->rt_chain; + rt->rt_chain = NULL; + + /* TODO std rt -> rt_addrinfo export */ + di.info.rti_info[RTAX_DST] = rt_key(rt); + di.info.rti_info[RTAX_NETMASK] = rt_mask(rt); + + rt_notifydelete(rt, &di.info); + + if (report) + rt_routemsg(RTM_DELETE, rt->rt_ifp, 0, rt, fibnum); + RTFREE_LOCKED(rt); + } +} + +/* * Iterates over all existing fibs in system. * Deletes each element for which @filter_f function returned * non-zero value. @@ -1061,16 +1118,9 @@ void rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg) { - struct rib_head *rnh; - struct rt_delinfo di; - struct rtentry *rt; uint32_t fibnum; int i, start, end; - bzero(&di, sizeof(di)); - di.info.rti_filter = filter_f; - di.info.rti_filterdata = arg; - for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { /* Do we want some specific family? */ if (af != AF_UNSPEC) { @@ -1082,32 +1132,10 @@ } for (i = start; i <= end; i++) { - rnh = rt_tables_get_rnh(fibnum, i); - if (rnh == NULL) + if (rt_tables_get_rnh(fibnum, i) == NULL) continue; - di.rnh = rnh; - RIB_WLOCK(rnh); - rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di); - RIB_WUNLOCK(rnh); - - if (di.head == NULL) - continue; - - /* We might have something to reclaim */ - while (di.head != NULL) { - rt = di.head; - di.head = rt->rt_chain; - rt->rt_chain = NULL; - - /* TODO std rt -> rt_addrinfo export */ - di.info.rti_info[RTAX_DST] = rt_key(rt); - di.info.rti_info[RTAX_NETMASK] = rt_mask(rt); - - rt_notifydelete(rt, &di.info); - RTFREE_LOCKED(rt); - } - + rib_walk_del(fibnum, i, filter_f, arg, 0); } } } @@ -1692,6 +1720,9 @@ /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes); + + if (rn != NULL && rt->rt_expire > 0) + tmproutes_update(rnh, rt); rt_old = NULL; if (rn == NULL && (info->rti_flags & RTF_PINNED) != 0) { Index: sys/net/route_temporal.c =================================================================== --- /dev/null +++ sys/net/route_temporal.c @@ -0,0 +1,156 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Alexander V. Chernikov + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/* + * This file contains code responsible for expiring temporal routes + * (typically, redirect-originated) from the route tables. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Callback returning 1 for the expired routes. + * Updates time of the next nearest route expiration + * as a side effect. + */ +static int +expire_route(const struct rtentry *rt, void *arg) +{ + time_t *next_callout = (time_t *)arg; + + if (rt->rt_expire == 0) + return (0); + + if (rt->rt_expire <= time_uptime) { + printf("expiring %p, ts %lu\n", rt, rt->rt_expire); + return (1); + } + + /* + * Update next_callout to determine the next ts to + * run the callback at. + */ + if (*next_callout == 0 || *next_callout > rt->rt_expire) + *next_callout = rt->rt_expire; + + return (0); +} + +/* + * Per-rnh callout function traversing the tree and deleting + * expired routes. Calculates next callout run by looking at + * the rt_expire time for the remaining temporal routes. + */ +static void +expire_callout(void *arg) +{ + struct rib_head *rnh = (struct rib_head *)arg; + time_t next_expire = 0; + int ticks; + + CURVNET_SET(rnh->rib_vnet); + + rib_walk_del(rnh->rib_fibnum, rnh->rib_family, expire_route, + (void *)&next_expire, 1); + + RIB_WLOCK(rnh); + if (next_expire > 0) { + ticks = (next_expire - time_uptime) * hz; + if (ticks < 0) + ticks = 0; + callout_reset(&rnh->expire_callout, ticks, expire_callout, rnh); + rnh->next_expire = next_expire; + } else { + /* + * Before resetting next_expire, check that tmproutes_update() + * has not kicked in and scheduled another invocation. + */ + if (callout_pending(&rnh->expire_callout) == 0) + rnh->next_expire = 0; + } + RIB_WUNLOCK(rnh); + CURVNET_RESTORE(); +} + +/* + * Function responsible for updating the time of the next calllout + * w.r.t. new temporal routes insertion. + * + * Called by the routing code upon adding new temporal route + * to the tree. RIB_WLOCK must be held. + */ +void +tmproutes_update(struct rib_head *rnh, struct rtentry *rt) +{ + int ticks; + + RIB_WLOCK_ASSERT(rnh); + + if (rnh->next_expire == 0 || rnh->next_expire > rt->rt_expire) { + /* + * Callback is not scheduled, is executing, + * or is scheduled for a later time than we need. + * + * Schedule the one for the current @rt expiration time. + */ + ticks = (rt->rt_expire - time_uptime) * hz; + if (ticks < 0) + ticks = 0; + callout_reset(&rnh->expire_callout, ticks, expire_callout, rnh); + + rnh->next_expire = rt->rt_expire; + } +} + +void +tmproutes_init(struct rib_head *rh) +{ + + callout_init(&rh->expire_callout, 1); +} + + +void +tmproutes_destroy(struct rib_head *rh) +{ + + callout_drain(&rh->expire_callout); +} + Index: sys/net/route_var.h =================================================================== --- sys/net/route_var.h +++ sys/net/route_var.h @@ -46,6 +46,11 @@ struct radix_node rnh_nodes[3]; /* empty tree for common case */ struct rmlock rib_lock; /* config/data path lock */ struct radix_mask_head rmhead; /* masks radix head */ + struct vnet *rib_vnet; /* vnet pointer */ + int rib_family; /* AF of the rtable */ + u_int rib_fibnum; /* tableid */ + struct callout expire_callout; /* Callout for expiring dynamic routes */ + time_t next_expire; /* Next expire run ts */ }; #define RIB_RLOCK_TRACKER struct rm_priotracker _rib_tracker @@ -76,5 +81,8 @@ return (res); } +void tmproutes_update(struct rib_head *rnh, struct rtentry *rt); +void tmproutes_init(struct rib_head *rh); +void tmproutes_destroy(struct rib_head *rh); #endif Index: sys/netinet/in_proto.c =================================================================== --- sys/netinet/in_proto.c +++ sys/netinet/in_proto.c @@ -297,7 +297,7 @@ }, }; -extern int in_inithead(void **, int); +extern int in_inithead(void **, int, u_int); extern int in_detachhead(void **, int); struct domain inetdomain = { Index: sys/netinet/in_rmx.c =================================================================== --- sys/netinet/in_rmx.c +++ sys/netinet/in_rmx.c @@ -49,7 +49,7 @@ #include #include -extern int in_inithead(void **head, int off); +extern int in_inithead(void **head, int off, u_int fibnum); #ifdef VIMAGE extern int in_detachhead(void **head, int off); #endif @@ -116,11 +116,11 @@ * Initialize our routing tree. */ int -in_inithead(void **head, int off) +in_inithead(void **head, int off, u_int fibnum) { struct rib_head *rh; - rh = rt_table_init(32); + rh = rt_table_init(32, AF_INET, fibnum); if (rh == NULL) return (0); @@ -197,14 +197,3 @@ rtalloc_ign_fib(ro, ignflags, fibnum); } -void -in_rtredirect(struct sockaddr *dst, - struct sockaddr *gateway, - struct sockaddr *netmask, - int flags, - struct sockaddr *src, - u_int fibnum) -{ - rtredirect_fib(dst, gateway, netmask, flags, src, fibnum); -} - Index: sys/netinet/in_var.h =================================================================== --- sys/netinet/in_var.h +++ sys/netinet/in_var.h @@ -474,8 +474,6 @@ /* XXX */ void in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum); -void in_rtredirect(struct sockaddr *, struct sockaddr *, - struct sockaddr *, int, struct sockaddr *, u_int); #endif /* _KERNEL */ /* INET6 stuff */ Index: sys/netinet/ip_icmp.c =================================================================== --- sys/netinet/ip_icmp.c +++ sys/netinet/ip_icmp.c @@ -128,6 +128,12 @@ &VNET_NAME(log_redirect), 0, "Log ICMP redirects to the console"); +VNET_DEFINE_STATIC(int, redirtimeout) = 60 * 10; /* 10 minutes */ +#define V_redirtimeout VNET(redirtimeout) +SYSCTL_INT(_net_inet_icmp, OID_AUTO, redirtimeout, CTLFLAG_VNET | CTLFLAG_RW, + &VNET_NAME(redirtimeout), 0, + "Delay in seconds before expiring redirect route"); + VNET_DEFINE_STATIC(char, reply_src[IFNAMSIZ]); #define V_reply_src VNET(reply_src) SYSCTL_STRING(_net_inet_icmp, OID_AUTO, reply_src, CTLFLAG_VNET | CTLFLAG_RW, @@ -690,10 +696,10 @@ #endif icmpsrc.sin_addr = icp->icmp_ip.ip_dst; for ( fibnum = 0; fibnum < rt_numfibs; fibnum++) { - in_rtredirect((struct sockaddr *)&icmpsrc, + rtredirect_fib((struct sockaddr *)&icmpsrc, (struct sockaddr *)&icmpdst, - (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST, - (struct sockaddr *)&icmpgw, fibnum); + RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&icmpgw, + V_redirtimeout, fibnum); } pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc); break; Index: sys/netinet6/icmp6.c =================================================================== --- sys/netinet6/icmp6.c +++ sys/netinet6/icmp6.c @@ -2387,9 +2387,9 @@ } else gw = ifp->if_addr->ifa_addr; for (fibnum = 0; fibnum < rt_numfibs; fibnum++) - in6_rtredirect((struct sockaddr *)&sdst, gw, - (struct sockaddr *)NULL, rt_flags, - (struct sockaddr *)&ssrc, fibnum); + rtredirect_fib((struct sockaddr *)&sdst, gw, + rt_flags, (struct sockaddr *)&ssrc, + V_icmp6_redirtimeout, fibnum); } /* finally update cached route in each socket via pfctlinput */ { Index: sys/netinet6/in6_proto.c =================================================================== --- sys/netinet6/in6_proto.c +++ sys/netinet6/in6_proto.c @@ -336,7 +336,7 @@ }, }; -extern int in6_inithead(void **, int); +extern int in6_inithead(void **, int, u_int); #ifdef VIMAGE extern int in6_detachhead(void **, int); #endif @@ -566,7 +566,7 @@ "Accept ICMPv6 redirect messages"); SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRTIMEOUT, redirtimeout, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6_redirtimeout), 0, - ""); /* XXX unused */ + "Delay in seconds before expiring redirect route"); SYSCTL_VNET_PCPUSTAT(_net_inet6_icmp6, ICMPV6CTL_STATS, stats, struct icmp6stat, icmp6stat, "ICMPv6 statistics (struct icmp6stat, netinet/icmp6.h)"); Index: sys/netinet6/in6_rmx.c =================================================================== --- sys/netinet6/in6_rmx.c +++ sys/netinet6/in6_rmx.c @@ -96,7 +96,7 @@ #include #include -extern int in6_inithead(void **head, int off); +extern int in6_inithead(void **head, int off, u_int fibnum); #ifdef VIMAGE extern int in6_detachhead(void **head, int off); #endif @@ -157,11 +157,12 @@ */ int -in6_inithead(void **head, int off) +in6_inithead(void **head, int off, u_int fibnum) { struct rib_head *rh; - rh = rt_table_init(offsetof(struct sockaddr_in6, sin6_addr) << 3); + rh = rt_table_init(offsetof(struct sockaddr_in6, sin6_addr) << 3, + AF_INET6, fibnum); if (rh == NULL) return (0); @@ -185,14 +186,6 @@ /* * 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) Index: sys/netinet6/in6_var.h =================================================================== --- sys/netinet6/in6_var.h +++ sys/netinet6/in6_var.h @@ -917,8 +917,6 @@ * Extended API for IPv6 FIB support. */ struct mbuf *ip6_tryforward(struct mbuf *); -void in6_rtredirect(struct sockaddr *, struct sockaddr *, struct sockaddr *, - int, struct sockaddr *, u_int); int in6_rtrequest(int, struct sockaddr *, struct sockaddr *, struct sockaddr *, int, struct rtentry **, u_int); void in6_rtalloc(struct route_in6 *, u_int); Index: sys/sys/domain.h =================================================================== --- sys/sys/domain.h +++ sys/sys/domain.h @@ -60,7 +60,7 @@ struct protosw *dom_protosw, *dom_protoswNPROTOSW; struct domain *dom_next; int (*dom_rtattach) /* initialize routing table */ - (void **, int); + (void **, int, u_int); int (*dom_rtdetach) /* clean up routing table */ (void **, int); void *(*dom_ifattach)(struct ifnet *); Index: usr.bin/netstat/route.c =================================================================== --- usr.bin/netstat/route.c +++ usr.bin/netstat/route.c @@ -104,7 +104,7 @@ }; static struct ifmap_entry *ifmap; static int ifmap_size; -static struct timespec uptime; +static struct timeval curr_time; static const char *netname4(in_addr_t, in_addr_t); #ifdef INET6 @@ -142,12 +142,11 @@ if (fibnum < 0 || fibnum > numfibs - 1) errx(EX_USAGE, "%d: invalid fib", fibnum); /* - * Since kernel & userland use different timebase - * (time_uptime vs time_second) and we are reading kernel memory - * directly we should do rt_expire --> expire_time conversion. + * Kernel returns route expiration time as absolute time, + * cache current time to fasten conversion. */ - if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) - err(EX_OSERR, "clock_gettime() failed"); + if (gettimeofday(&curr_time, NULL) < 0) + err(EX_OSERR, "gettimeofday() failed"); xo_open_container("route-information"); xo_emit("{T:Routing tables}"); @@ -401,7 +400,7 @@ if (rtm->rtm_rmx.rmx_expire) { time_t expire_time; - if ((expire_time = rtm->rtm_rmx.rmx_expire - uptime.tv_sec) > 0) + if ((expire_time = rtm->rtm_rmx.rmx_expire - curr_time.tv_sec) > 0) xo_emit(" {:expire-time/%*d}", wid_expire, (int)expire_time); }