From aa95fb555a4c96d1734957962ba631e6fe724310 Mon Sep 17 00:00:00 2001 From: mvs Date: Tue, 23 Jan 2024 17:57:21 +0000 Subject: [PATCH] Introduce pipex_iterator(), the special thing to perform `pipex_session_list' foreach walkthrough with `pipex_list_mtx' mutex(9) relocking. It inserts special item after acquired `session' and keeps it linked until `session' release. Only owner can unlink it's own item, so the LIST_NEXT(session) is always valid even the `session' was unlinked. The iterator skips special items at the `session' acquisition time, as all other foreach loops where `pipex_list_mtx' mutex(9) is not relocked. ok yasuoka --- sys/net/pipex.c | 77 +++++++++++++++++++++++++++++++------------ sys/net/pipex_local.h | 28 +++++++++++----- 2 files changed, 75 insertions(+), 30 deletions(-) diff --git a/sys/net/pipex.c b/sys/net/pipex.c index c6a4e27bff7..ed038c11d39 100644 --- a/sys/net/pipex.c +++ b/sys/net/pipex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pipex.c,v 1.152 2024/01/23 16:57:52 mvs Exp $ */ +/* $OpenBSD: pipex.c,v 1.153 2024/01/23 17:57:21 mvs Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -151,6 +151,8 @@ pipex_destroy_all_sessions(void *ownersc) LIST_FOREACH_SAFE(session, &pipex_session_list, session_list, session_tmp) { + if (session->flags & PIPEX_SFLAGS_ITERATOR) + continue; if (session->ownersc == ownersc) { KASSERT((session->flags & PIPEX_SFLAGS_PPPX) == 0); pipex_unlink_session_locked(session); @@ -594,6 +596,8 @@ pipex_get_closed(struct pipex_session_list_req *req, void *ownersc) LIST_FOREACH_SAFE(session, &pipex_close_wait_list, state_list, session_tmp) { + if (session->flags & PIPEX_SFLAGS_ITERATOR) + continue; if (session->ownersc != ownersc) continue; req->plr_ppp_id[req->plr_ppp_id_count++] = session->ppp_id; @@ -730,6 +734,8 @@ pipex_timer(void *ignored_arg) /* walk through */ LIST_FOREACH_SAFE(session, &pipex_session_list, session_list, session_tmp) { + if (session->flags & PIPEX_SFLAGS_ITERATOR) + continue; switch (session->state) { case PIPEX_STATE_OPENED: if (session->timeout_sec == 0) @@ -769,6 +775,47 @@ pipex_timer(void *ignored_arg) /*********************************************************************** * Common network I/O functions. (tunnel protocol independent) ***********************************************************************/ + +struct pipex_session * +pipex_iterator(struct pipex_session *session, + struct pipex_session_iterator *iter, void *ownersc) +{ + struct pipex_session *session_tmp; + + mtx_enter(&pipex_list_mtx); + + if (session) + session_tmp = LIST_NEXT(session, session_list); + else + session_tmp = LIST_FIRST(&pipex_session_list); + + while (session_tmp) { + if (session_tmp->flags & PIPEX_SFLAGS_ITERATOR) + goto next; + if (session_tmp->ownersc != ownersc) + goto next; + break; +next: + session_tmp = LIST_NEXT(session_tmp, session_list); + } + + if (session) + LIST_REMOVE(iter, session_list); + + if (session_tmp) { + LIST_INSERT_AFTER(session_tmp, + (struct pipex_session *)&iter, session_list); + refcnt_take(&session_tmp->pxs_refcnt); + } + + mtx_leave(&pipex_list_mtx); + + if (session) + pipex_rele_session(session); + + return (session_tmp); +} + void pipex_ip_output(struct mbuf *m0, struct pipex_session *session) { @@ -803,23 +850,17 @@ pipex_ip_output(struct mbuf *m0, struct pipex_session *session) pipex_ppp_output(m0, session, PPP_IP); } else { + struct pipex_session_iterator iter = { + .flags = PIPEX_SFLAGS_ITERATOR, + }; + struct pipex_session *session_tmp; struct mbuf *m; m0->m_flags &= ~(M_BCAST|M_MCAST); - mtx_enter(&pipex_list_mtx); - - session_tmp = LIST_FIRST(&pipex_session_list); - while (session_tmp != NULL) { - struct pipex_session *session_save = NULL; - - if (session_tmp->ownersc != session->ownersc) - goto next; - - refcnt_take(&session_tmp->pxs_refcnt); - mtx_leave(&pipex_list_mtx); - + session_tmp = pipex_iterator(NULL, &iter, session->ownersc); + while (session_tmp) { m = m_copym(m0, 0, M_COPYALL, M_NOWAIT); if (m != NULL) pipex_ppp_output(m, session_tmp, PPP_IP); @@ -827,16 +868,10 @@ pipex_ip_output(struct mbuf *m0, struct pipex_session *session) counters_inc(session_tmp->stat_counters, pxc_oerrors); - mtx_enter(&pipex_list_mtx); - session_save = session_tmp; -next: - session_tmp = LIST_NEXT(session_tmp, session_list); - if (session_save != NULL) - pipex_rele_session(session_save); + session_tmp = pipex_iterator(session_tmp, + &iter, session->ownersc); } - mtx_leave(&pipex_list_mtx); - m_freem(m0); } diff --git a/sys/net/pipex_local.h b/sys/net/pipex_local.h index 8274bdcbf2f..01b7c457d62 100644 --- a/sys/net/pipex_local.h +++ b/sys/net/pipex_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pipex_local.h,v 1.50 2024/01/23 16:57:53 mvs Exp $ */ +/* $OpenBSD: pipex_local.h,v 1.51 2024/01/23 17:57:21 mvs Exp $ */ /* * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -156,19 +156,32 @@ struct pipex_l2tp_session { struct cpumem; +/* special iterator session */ +struct pipex_session_iterator { + /* Fields below should be in sync with pipex_session structure */ + struct radix_node ps4_rn[2]; + u_int flags; /* [I] flags, see below */ + LIST_ENTRY(pipex_session) session_list; /* [L] all session chain */ +}; + /* pppac ip-extension session table */ struct pipex_session { struct radix_node ps4_rn[2]; /* [L] tree glue, and other values */ - - struct refcnt pxs_refcnt; - struct mutex pxs_mtx; + u_int flags; /* [I] flags, see below */ +#define PIPEX_SFLAGS_MULTICAST 0x01 /* virtual entry for multicast */ +#define PIPEX_SFLAGS_PPPX 0x02 /* interface is + point2point(pppx) */ +#define PIPEX_SFLAGS_ITERATOR 0x04 /* iterator session */ LIST_ENTRY(pipex_session) session_list; /* [L] all session chain */ LIST_ENTRY(pipex_session) state_list; /* [L] state list chain */ LIST_ENTRY(pipex_session) id_chain; /* [L] id hash chain */ LIST_ENTRY(pipex_session) peer_addr_chain; /* [L] peer's address hash chain */ + struct refcnt pxs_refcnt; + struct mutex pxs_mtx; + u_int state; /* [L] pipex session state */ #define PIPEX_STATE_INITIAL 0x0000 #define PIPEX_STATE_OPENED 0x0001 @@ -178,11 +191,6 @@ struct pipex_session { uint32_t idle_time; /* [L] idle time in seconds */ - u_int flags; /* [I] flags, see below */ -#define PIPEX_SFLAGS_MULTICAST 0x01 /* virtual entry for multicast */ -#define PIPEX_SFLAGS_PPPX 0x02 /* interface is - point2point(pppx) */ - uint16_t protocol; /* [I] tunnel protocol (PK) */ uint16_t session_id; /* [I] session-id (PK) */ uint16_t peer_session_id; /* [I] peer's session-id */ @@ -464,3 +472,5 @@ int pipex_ppp_enqueue (struct mbuf *, struct pipex_session *, void pipex_timer_start (void); void pipex_timer_stop (void); void pipex_timer (void *); +struct pipex_session *pipex_iterator(struct pipex_session *, + struct pipex_session_iterator *, void *); -- 2.20.1