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;