This diff replaces most of the rttimer with a timeout(9) call. Instead of running a 1 second timer all the time it runs idividual timeouts for each rttimer object.
rt_timer_remove_all() needs to be careful to not remove the rttimer object while the timeout callback is running or up to be run. It uses the return value of timeout_del() to know if it owns the object or if the timeout owns it. If timeout_del() returns 1 then the code know that it can safely free the rttimer object. In the other case the code depends on the timeout to remove the object but it clears the rtt_rt pointer and removes the rttimer from the route entry list. This way the route can be deleted. I also added a funtion to get the expiry time for rtsock.c but to be honest rt_expire is a bit of a strange beast which should be replaced. -- :wq Claudio Index: net/route.c =================================================================== RCS file: /cvs/src/sys/net/route.c,v retrieving revision 1.410 diff -u -p -r1.410 route.c --- net/route.c 5 May 2022 13:57:40 -0000 1.410 +++ net/route.c 13 May 2022 11:49:00 -0000 @@ -1361,7 +1361,16 @@ rt_ifa_purge_walker(struct rtentry *rt, */ struct mutex rttimer_mtx; -LIST_HEAD(, rttimer_queue) rttimer_queue_head; /* [T] */ + +struct rttimer { + TAILQ_ENTRY(rttimer) rtt_next; /* [T] entry on timer queue */ + LIST_ENTRY(rttimer) rtt_link; /* [T] timers per rtentry */ + struct timeout rtt_timeout; /* [I] timeout for this entry */ + struct rttimer_queue *rtt_queue; /* [I] back pointer to queue */ + struct rtentry *rtt_rt; /* [T] back pointer to route */ + time_t rtt_expire; /* [I] rt expire time */ + u_int rtt_tableid; /* [I] rtable id of rtt_rt */ +}; #define RTTIMER_CALLOUT(r) { \ if (r->rtt_queue->rtq_func != NULL) { \ @@ -1388,15 +1397,9 @@ LIST_HEAD(, rttimer_queue) rttimer_queue void rt_timer_init(void) { - static struct timeout rt_timer_timeout; - pool_init(&rttimer_pool, sizeof(struct rttimer), 0, IPL_MPFLOOR, 0, "rttmr", NULL); - mtx_init(&rttimer_mtx, IPL_MPFLOOR); - LIST_INIT(&rttimer_queue_head); - timeout_set_proc(&rt_timer_timeout, rt_timer_timer, &rt_timer_timeout); - timeout_add_sec(&rt_timer_timeout, 1); } void @@ -1407,10 +1410,6 @@ rt_timer_queue_init(struct rttimer_queue rtq->rtq_count = 0; rtq->rtq_func = func; TAILQ_INIT(&rtq->rtq_head); - - mtx_enter(&rttimer_mtx); - LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link); - mtx_leave(&rttimer_mtx); } void @@ -1453,6 +1452,25 @@ rt_timer_queue_count(struct rttimer_queu return (rtq->rtq_count); } +static inline struct rttimer * +rt_timer_unlink(struct rttimer *r) +{ + MUTEX_ASSERT_LOCKED(&rttimer_mtx); + + LIST_REMOVE(r, rtt_link); + r->rtt_rt = NULL; + + if (timeout_del(&r->rtt_timeout) == 0) { + /* timeout fired, so rt_timer_timer will do the cleanup */ + return NULL; + } + + TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); + KASSERT(r->rtt_queue->rtq_count > 0); + r->rtt_queue->rtq_count--; + return r; +} + void rt_timer_remove_all(struct rtentry *rt) { @@ -1462,11 +1480,9 @@ rt_timer_remove_all(struct rtentry *rt) TAILQ_INIT(&rttlist); mtx_enter(&rttimer_mtx); while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) { - LIST_REMOVE(r, rtt_link); - TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); - TAILQ_INSERT_TAIL(&rttlist, r, rtt_next); - KASSERT(r->rtt_queue->rtq_count > 0); - r->rtt_queue->rtq_count--; + r = rt_timer_unlink(r); + if (r != NULL) + TAILQ_INSERT_TAIL(&rttlist, r, rtt_next); } mtx_leave(&rttimer_mtx); @@ -1476,41 +1492,52 @@ rt_timer_remove_all(struct rtentry *rt) } } +time_t +rt_timer_get_expire(const struct rtentry *rt) +{ + const struct rttimer *r; + time_t expire = 0; + + mtx_enter(&rttimer_mtx); + LIST_FOREACH(r, &rt->rt_timer, rtt_link) { + if (expire == 0 || expire > r->rtt_expire) + expire = r->rtt_expire; + } + mtx_leave(&rttimer_mtx); + + return expire; +} + int rt_timer_add(struct rtentry *rt, struct rttimer_queue *queue, u_int rtableid) { struct rttimer *r, *rnew; - time_t current_time; rnew = pool_get(&rttimer_pool, PR_NOWAIT | PR_ZERO); if (rnew == NULL) return (ENOBUFS); - current_time = getuptime(); - rnew->rtt_rt = rt; - rnew->rtt_time = current_time; rnew->rtt_queue = queue; rnew->rtt_tableid = rtableid; + rnew->rtt_expire = getuptime() + queue->rtq_timeout; + timeout_set_proc(&rnew->rtt_timeout, rt_timer_timer, rnew); mtx_enter(&rttimer_mtx); - rt->rt_expire = current_time + queue->rtq_timeout; /* * If there's already a timer with this action, destroy it before * we add a new one. */ LIST_FOREACH(r, &rt->rt_timer, rtt_link) { if (r->rtt_queue == queue) { - LIST_REMOVE(r, rtt_link); - TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); - KASSERT(r->rtt_queue->rtq_count > 0); - r->rtt_queue->rtq_count--; + r = rt_timer_unlink(r); break; /* only one per list, so we can quit... */ } } LIST_INSERT_HEAD(&rt->rt_timer, rnew, rtt_link); TAILQ_INSERT_TAIL(&queue->rtq_head, rnew, rtt_next); + timeout_add_sec(&rnew->rtt_timeout, queue->rtq_timeout); rnew->rtt_queue->rtq_count++; mtx_leave(&rttimer_mtx); @@ -1523,37 +1550,25 @@ rt_timer_add(struct rtentry *rt, struct void rt_timer_timer(void *arg) { - struct timeout *to = (struct timeout *)arg; - struct rttimer_queue *rtq; - struct rttimer *r; - TAILQ_HEAD(, rttimer) rttlist; - time_t current_time; - - current_time = getuptime(); - TAILQ_INIT(&rttlist); + struct rttimer *r = arg; + struct rttimer_queue *rtq = r->rtt_queue; NET_LOCK(); mtx_enter(&rttimer_mtx); - LIST_FOREACH(rtq, &rttimer_queue_head, 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); - TAILQ_INSERT_TAIL(&rttlist, r, rtt_next); - KASSERT(rtq->rtq_count > 0); - rtq->rtq_count--; - } - } + + if (r->rtt_rt != NULL) + LIST_REMOVE(r, rtt_link); + TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); + KASSERT(rtq->rtq_count > 0); + rtq->rtq_count--; + mtx_leave(&rttimer_mtx); - while ((r = TAILQ_FIRST(&rttlist)) != NULL) { - TAILQ_REMOVE(&rttlist, r, rtt_next); + if (r->rtt_rt != NULL) RTTIMER_CALLOUT(r); - pool_put(&rttimer_pool, r); - } NET_UNLOCK(); - timeout_add_sec(to, 1); + pool_put(&rttimer_pool, r); } #ifdef MPLS Index: net/route.h =================================================================== RCS file: /cvs/src/sys/net/route.h,v retrieving revision 1.194 diff -u -p -r1.194 route.h --- net/route.h 5 May 2022 13:57:40 -0000 1.194 +++ net/route.h 13 May 2022 11:49:18 -0000 @@ -92,6 +92,8 @@ struct rt_metrics { #include <sys/queue.h> #include <net/rtable.h> +struct rttimer; + /* * We distinguish between routes to hosts and routes to networks, * preferring the former if available. For each route we infer @@ -405,15 +407,6 @@ rtstat_inc(enum rtstat_counters c) * add,timer} functions all used with the kind permission of BSDI. * These allow functions to be called for routes at specific times. */ -struct rttimer { - TAILQ_ENTRY(rttimer) rtt_next; /* [T] entry on timer queue */ - LIST_ENTRY(rttimer) rtt_link; /* [T] timers per rtentry */ - struct rttimer_queue *rtt_queue; /* [T] back pointer to queue */ - struct rtentry *rtt_rt; /* [I] back pointer to route */ - time_t rtt_time; /* [I] when timer registered */ - u_int rtt_tableid; /* [I] rtable id of rtt_rt */ -}; - struct rttimer_queue { TAILQ_HEAD(, rttimer) rtq_head; /* [T] */ LIST_ENTRY(rttimer_queue) rtq_link; /* [T] */ @@ -461,6 +454,7 @@ void rt_timer_init(void); int rt_timer_add(struct rtentry *, struct rttimer_queue *, u_int); void rt_timer_remove_all(struct rtentry *); +time_t rt_timer_get_expire(const struct rtentry *); void rt_timer_queue_init(struct rttimer_queue *, int, void(*)(struct rtentry *, u_int)); void rt_timer_queue_change(struct rttimer_queue *, int); Index: net/rtsock.c =================================================================== RCS file: /cvs/src/sys/net/rtsock.c,v retrieving revision 1.327 diff -u -p -r1.327 rtsock.c --- net/rtsock.c 9 Mar 2022 17:29:52 -0000 1.327 +++ net/rtsock.c 13 May 2022 11:50:44 -0000 @@ -131,7 +131,7 @@ int rtm_xaddrs(caddr_t, caddr_t, struc int rtm_validate_proposal(struct rt_addrinfo *); void rtm_setmetrics(u_long, const struct rt_metrics *, struct rt_kmetrics *); -void rtm_getmetrics(const struct rt_kmetrics *, +void rtm_getmetrics(const struct rtentry *, struct rt_metrics *); int sysctl_iflist(int, struct walkarg *); @@ -675,7 +675,7 @@ rtm_report(struct rtentry *rt, u_char ty rtm->rtm_flags = rt->rt_flags; rtm->rtm_pid = curproc->p_p->ps_pid; rtm->rtm_seq = seq; - rtm_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); + rtm_getmetrics(rt, &rtm->rtm_rmx); rtm->rtm_addrs = info.rti_addrs; #ifdef MPLS rtm->rtm_mpls = info.rti_mpls; @@ -1392,11 +1392,14 @@ rtm_setmetrics(u_long which, const struc } void -rtm_getmetrics(const struct rt_kmetrics *in, struct rt_metrics *out) +rtm_getmetrics(const struct rtentry *rt, struct rt_metrics *out) { + const struct rt_kmetrics *in = &rt->rt_rmx; int64_t expire; expire = in->rmx_expire; + if (expire == 0) + expire = rt_timer_get_expire(rt); if (expire != 0) { expire -= getuptime(); expire += gettime(); @@ -1991,7 +1994,7 @@ sysctl_dumpentry(struct rtentry *rt, voi rtm->rtm_pid = curproc->p_p->ps_pid; rtm->rtm_flags = rt->rt_flags; rtm->rtm_priority = rt->rt_priority & RTP_MASK; - rtm_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx); + rtm_getmetrics(rt, &rtm->rtm_rmx); /* Do not account the routing table's reference. */ rtm->rtm_rmx.rmx_refcnt = rt->rt_refcnt - 1; rtm->rtm_index = rt->rt_ifidx;