On Tue, Apr 19, 2022 at 10:49:44PM +0200, Alexander Bluhm wrote: > Hi, > > I had a look in route timer queues in netinet and netinet6 and found > some inconsistencies. > > - Timeout was a mixture of int, u_int and long. Make timeout > int with sysctl bounds checking and make absolute time time_t. > > - Some code assumes that ..._timeout_q can be NULL and at some > places this is checked. Better make sure that all queues always > exist. The pool_get is only called from initialization and from > syscall, so PR_WAITOK is possible. > > - The only special hack I kept is when ip_mtudisc is set to 0. > Then I destroy the queue and generate an empty one. > > - If redirect timeout is 0, it does not time out. Adopt IPv6 to > behavior of IPv4. > > - sysctl net.inet6.icmp6.redirtimeout had no effect as the queue > timeout was not modified. Make icmp6_sysctl() look like > icmp_sysctl(). > > ok?
Looks good to me. OK claudio@ Btw. the rt_timer implementation of rt_timer_queue_change() has a bug. Actually it is rt_timer_timer() that has the bug. It assumes that the TAILQ of all rttimers on a queue are sorted but that is not true if the timeout is lowered in which case objects may live longer then expected. There are other things in the rt_timer implementation that is questionable like how rt_expire is changed. > bluhm > > Index: net/route.c > =================================================================== > RCS file: /cvs/src/sys/net/route.c,v > retrieving revision 1.404 > diff -u -p -r1.404 route.c > --- net/route.c 19 Apr 2022 19:19:31 -0000 1.404 > +++ net/route.c 19 Apr 2022 20:31:49 -0000 > @@ -1399,13 +1399,11 @@ rt_timer_init(void) > } > > struct rttimer_queue * > -rt_timer_queue_create(u_int timeout) > +rt_timer_queue_create(int timeout) > { > struct rttimer_queue *rtq; > > - rtq = pool_get(&rttimer_queue_pool, PR_NOWAIT | PR_ZERO); > - if (rtq == NULL) > - return (NULL); > + rtq = pool_get(&rttimer_queue_pool, PR_WAITOK | PR_ZERO); > > rtq->rtq_timeout = timeout; > rtq->rtq_count = 0; > @@ -1416,7 +1414,7 @@ rt_timer_queue_create(u_int timeout) > } > > void > -rt_timer_queue_change(struct rttimer_queue *rtq, long timeout) > +rt_timer_queue_change(struct rttimer_queue *rtq, int timeout) > { > rtq->rtq_timeout = timeout; > } > @@ -1470,10 +1468,10 @@ rt_timer_add(struct rtentry *rt, void (* > struct rttimer *), struct rttimer_queue *queue, u_int rtableid) > { > struct rttimer *r; > - long current_time; > + time_t current_time; > > current_time = getuptime(); > - rt->rt_expire = getuptime() + queue->rtq_timeout; > + rt->rt_expire = current_time + queue->rtq_timeout; > > /* > * If there's already a timer with this action, destroy it before > @@ -1514,7 +1512,7 @@ rt_timer_timer(void *arg) > struct timeout *to = (struct timeout *)arg; > struct rttimer_queue *rtq; > struct rttimer *r; > - long current_time; > + time_t current_time; > > current_time = getuptime(); > > Index: net/route.h > =================================================================== > RCS file: /cvs/src/sys/net/route.h,v > retrieving revision 1.188 > diff -u -p -r1.188 route.h > --- net/route.h 19 Apr 2022 15:44:56 -0000 1.188 > +++ net/route.h 19 Apr 2022 20:31:49 -0000 > @@ -411,10 +411,10 @@ struct rttimer { > }; > > struct rttimer_queue { > - long rtq_timeout; > - unsigned long rtq_count; > TAILQ_HEAD(, rttimer) rtq_head; > LIST_ENTRY(rttimer_queue) rtq_link; > + unsigned long rtq_count; > + int rtq_timeout; > }; > > const char *rtlabel_id2name(u_int16_t); > @@ -456,8 +456,8 @@ int rt_timer_add(struct rtentry *, > void(*)(struct rtentry *, struct rttimer *), > struct rttimer_queue *, u_int); > void rt_timer_remove_all(struct rtentry *); > -struct rttimer_queue *rt_timer_queue_create(u_int); > -void rt_timer_queue_change(struct rttimer_queue *, long); > +struct rttimer_queue *rt_timer_queue_create(int); > +void rt_timer_queue_change(struct rttimer_queue *, int); > void rt_timer_queue_destroy(struct rttimer_queue *); > unsigned long rt_timer_queue_count(struct rttimer_queue *); > void rt_timer_timer(void *); > Index: netinet/ip_icmp.c > =================================================================== > RCS file: /cvs/src/sys/netinet/ip_icmp.c,v > retrieving revision 1.187 > diff -u -p -r1.187 ip_icmp.c > --- netinet/ip_icmp.c 26 Jul 2021 20:44:44 -0000 1.187 > +++ netinet/ip_icmp.c 19 Apr 2022 20:31:50 -0000 > @@ -120,7 +120,7 @@ int icmp_redirtimeout = 10 * 60; > static int icmperrpps_count = 0; > static struct timeval icmperrppslim_last; > > -static struct rttimer_queue *icmp_redirect_timeout_q = NULL; > +struct rttimer_queue *icmp_redirect_timeout_q; > struct cpumem *icmpcounters; > > const struct sysctl_bounded_args icmpctl_vars[] = { > @@ -141,15 +141,8 @@ int icmp_sysctl_icmpstat(void *, size_t > void > icmp_init(void) > { > + icmp_redirect_timeout_q = rt_timer_queue_create(icmp_redirtimeout); > icmpcounters = counters_alloc(icps_ncounters); > - /* > - * This is only useful if the user initializes redirtimeout to > - * something other than zero. > - */ > - if (icmp_redirtimeout != 0) { > - icmp_redirect_timeout_q = > - rt_timer_queue_create(icmp_redirtimeout); > - } > } > > struct mbuf * > @@ -640,12 +633,11 @@ reflect: > #endif > rtredirect(sintosa(&sdst), sintosa(&sgw), > sintosa(&ssrc), &newrt, m->m_pkthdr.ph_rtableid); > - if (newrt != NULL && icmp_redirtimeout != 0) { > - (void)rt_timer_add(newrt, icmp_redirect_timeout, > + if (newrt != NULL && icmp_redirtimeout > 0) { > + rt_timer_add(newrt, icmp_redirect_timeout, > icmp_redirect_timeout_q, m->m_pkthdr.ph_rtableid); > } > - if (newrt != NULL) > - rtfree(newrt); > + rtfree(newrt); > pfctlinput(PRC_REDIRECT_HOST, sintosa(&sdst)); > break; > } > @@ -889,21 +881,11 @@ icmp_sysctl(int *name, u_int namelen, vo > > switch (name[0]) { > case ICMPCTL_REDIRTIMEOUT: > - > NET_LOCK(); > - error = sysctl_int(oldp, oldlenp, newp, newlen, > - &icmp_redirtimeout); > - if (icmp_redirect_timeout_q != NULL) { > - if (icmp_redirtimeout == 0) { > - rt_timer_queue_destroy(icmp_redirect_timeout_q); > - icmp_redirect_timeout_q = NULL; > - } else > - rt_timer_queue_change(icmp_redirect_timeout_q, > - icmp_redirtimeout); > - } else if (icmp_redirtimeout > 0) { > - icmp_redirect_timeout_q = > - rt_timer_queue_create(icmp_redirtimeout); > - } > + error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, > + &icmp_redirtimeout, 0, INT_MAX); > + rt_timer_queue_change(icmp_redirect_timeout_q, > + icmp_redirtimeout); > NET_UNLOCK(); > break; > > Index: netinet/ip_input.c > =================================================================== > RCS file: /cvs/src/sys/netinet/ip_input.c,v > retrieving revision 1.366 > diff -u -p -r1.366 ip_input.c > --- netinet/ip_input.c 22 Feb 2022 01:35:40 -0000 1.366 > +++ netinet/ip_input.c 19 Apr 2022 20:31:50 -0000 > @@ -91,10 +91,10 @@ int ipsendredirects = 1; > int ip_dosourceroute = 0; > int ip_defttl = IPDEFTTL; > int ip_mtudisc = 1; > -u_int ip_mtudisc_timeout = IPMTUDISCTIMEOUT; > +int ip_mtudisc_timeout = IPMTUDISCTIMEOUT; > int ip_directedbcast = 0; > > -struct rttimer_queue *ip_mtudisc_timeout_q = NULL; > +struct rttimer_queue *ip_mtudisc_timeout_q; > > /* Protects `ipq' and `ip_frags'. */ > struct mutex ipq_mutex = MUTEX_INITIALIZER(IPL_SOFTNET); > @@ -201,9 +201,7 @@ ip_init(void) > pr->pr_protocol < IPPROTO_MAX) > ip_protox[pr->pr_protocol] = pr - inetsw; > LIST_INIT(&ipq); > - if (ip_mtudisc != 0) > - ip_mtudisc_timeout_q = > - rt_timer_queue_create(ip_mtudisc_timeout); > + ip_mtudisc_timeout_q = rt_timer_queue_create(ip_mtudisc_timeout); > > /* Fill in list of ports not to allocate dynamically. */ > memset(&baddynamicports, 0, sizeof(baddynamicports)); > @@ -1616,24 +1614,20 @@ ip_sysctl(int *name, u_int namelen, void > return (error); > case IPCTL_MTUDISC: > NET_LOCK(); > - error = sysctl_int(oldp, oldlenp, newp, newlen, > - &ip_mtudisc); > - if (ip_mtudisc != 0 && ip_mtudisc_timeout_q == NULL) { > + error = sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtudisc); > + if (ip_mtudisc == 0) { > + rt_timer_queue_destroy(ip_mtudisc_timeout_q); > ip_mtudisc_timeout_q = > rt_timer_queue_create(ip_mtudisc_timeout); > - } else if (ip_mtudisc == 0 && ip_mtudisc_timeout_q != NULL) { > - rt_timer_queue_destroy(ip_mtudisc_timeout_q); > - ip_mtudisc_timeout_q = NULL; > } > NET_UNLOCK(); > return error; > case IPCTL_MTUDISCTIMEOUT: > NET_LOCK(); > - error = sysctl_int(oldp, oldlenp, newp, newlen, > - &ip_mtudisc_timeout); > - if (ip_mtudisc_timeout_q != NULL) > - rt_timer_queue_change(ip_mtudisc_timeout_q, > - ip_mtudisc_timeout); > + error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, > + &ip_mtudisc_timeout, 0, INT_MAX); > + rt_timer_queue_change(ip_mtudisc_timeout_q, > + ip_mtudisc_timeout); > NET_UNLOCK(); > return (error); > #ifdef IPSEC > Index: netinet/ip_var.h > =================================================================== > RCS file: /cvs/src/sys/netinet/ip_var.h,v > retrieving revision 1.90 > diff -u -p -r1.90 ip_var.h > --- netinet/ip_var.h 25 Feb 2022 23:51:03 -0000 1.90 > +++ netinet/ip_var.h 19 Apr 2022 20:31:50 -0000 > @@ -204,7 +204,7 @@ extern int ip_defttl; /* default IP tt > #define IPMTUDISCTIMEOUT (10 * 60) /* as per RFC 1191 */ > > extern int ip_mtudisc; /* mtu discovery */ > -extern u_int ip_mtudisc_timeout; /* seconds to timeout mtu discovery */ > +extern int ip_mtudisc_timeout; /* seconds to timeout mtu > discovery */ > > extern int ipport_firstauto; /* min port for port allocation */ > extern int ipport_lastauto; /* max port for port allocation */ > Index: netinet6/icmp6.c > =================================================================== > RCS file: /cvs/src/sys/netinet6/icmp6.c,v > retrieving revision 1.238 > diff -u -p -r1.238 icmp6.c > --- netinet6/icmp6.c 22 Feb 2022 01:15:02 -0000 1.238 > +++ netinet6/icmp6.c 19 Apr 2022 20:31:52 -0000 > @@ -118,7 +118,7 @@ struct icmp6_mtudisc_callback { > LIST_HEAD(, icmp6_mtudisc_callback) icmp6_mtudisc_callbacks = > LIST_HEAD_INITIALIZER(icmp6_mtudisc_callbacks); > > -struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL; > +struct rttimer_queue *icmp6_mtudisc_timeout_q; > > /* XXX do these values make any sense? */ > static int icmp6_mtudisc_hiwat = 1280; > @@ -127,7 +127,7 @@ static int icmp6_mtudisc_lowat = 256; > /* > * keep track of # of redirect routes. > */ > -static struct rttimer_queue *icmp6_redirect_timeout_q = NULL; > +struct rttimer_queue *icmp6_redirect_timeout_q; > > /* XXX experimental, turned off */ > static int icmp6_redirect_lowat = -1; > @@ -1404,12 +1404,11 @@ icmp6_redirect_input(struct mbuf *m, int > memcpy(&ssrc.sin6_addr, &src6, sizeof(struct in6_addr)); > rtredirect(sin6tosa(&sdst), sin6tosa(&sgw), sin6tosa(&ssrc), > &newrt, m->m_pkthdr.ph_rtableid); > - > - if (newrt) { > - (void)rt_timer_add(newrt, icmp6_redirect_timeout, > + if (newrt != NULL && icmp6_redirtimeout > 0) { > + rt_timer_add(newrt, icmp6_redirect_timeout, > icmp6_redirect_timeout_q, m->m_pkthdr.ph_rtableid); > - rtfree(newrt); > } > + rtfree(newrt); > } > /* finally update cached route in each socket via pfctlinput */ > { > @@ -1881,7 +1880,6 @@ icmp6_redirect_timeout(struct rtentry *r > } > > const struct sysctl_bounded_args icmpv6ctl_vars[] = { > - { ICMPV6CTL_REDIRTIMEOUT, &icmp6_redirtimeout, 0, INT_MAX }, > { ICMPV6CTL_ND6_DELAY, &nd6_delay, 0, INT_MAX }, > { ICMPV6CTL_ND6_UMAXTRIES, &nd6_umaxtries, 0, INT_MAX }, > { ICMPV6CTL_ND6_MMAXTRIES, &nd6_mmaxtries, 0, INT_MAX }, > @@ -1916,19 +1914,30 @@ icmp6_sysctl(int *name, u_int namelen, v > > /* All sysctl names at this level are terminal. */ > if (namelen != 1) > - return ENOTDIR; > + return (ENOTDIR); > > switch (name[0]) { > + case ICMPV6CTL_REDIRTIMEOUT: > + NET_LOCK(); > + error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, > + &icmp6_redirtimeout, 0, INT_MAX); > + rt_timer_queue_change(icmp6_redirect_timeout_q, > + icmp6_redirtimeout); > + NET_UNLOCK(); > + break; > > case ICMPV6CTL_STATS: > - return icmp6_sysctl_icmp6stat(oldp, oldlenp, newp); > + error = icmp6_sysctl_icmp6stat(oldp, oldlenp, newp); > + break; > + > default: > NET_LOCK(); > error = sysctl_bounded_arr(icmpv6ctl_vars, > nitems(icmpv6ctl_vars), name, namelen, oldp, oldlenp, newp, > newlen); > NET_UNLOCK(); > - return (error); > + break; > } > - /* NOTREACHED */ > + > + return (error); > } > Index: netinet6/ip6_input.c > =================================================================== > RCS file: /cvs/src/sys/netinet6/ip6_input.c,v > retrieving revision 1.240 > diff -u -p -r1.240 ip6_input.c > --- netinet6/ip6_input.c 22 Feb 2022 01:35:41 -0000 1.240 > +++ netinet6/ip6_input.c 19 Apr 2022 20:31:52 -0000 > @@ -1454,11 +1454,10 @@ ip6_sysctl(int *name, u_int namelen, voi > #endif > case IPV6CTL_MTUDISCTIMEOUT: > NET_LOCK(); > - error = sysctl_int(oldp, oldlenp, newp, newlen, > - &ip6_mtudisc_timeout); > - if (icmp6_mtudisc_timeout_q != NULL) > - rt_timer_queue_change(icmp6_mtudisc_timeout_q, > - ip6_mtudisc_timeout); > + error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, > + &ip6_mtudisc_timeout, 0, INT_MAX); > + rt_timer_queue_change(icmp6_mtudisc_timeout_q, > + ip6_mtudisc_timeout); > NET_UNLOCK(); > return (error); > case IPV6CTL_IFQUEUE: > -- :wq Claudio