From: Geliang Tang <tanggeliang@kylinos.cn>
The helper mptcp_pm_is_userspace() is used to distinguish userspace PM
operations from in-kernel PM in mptcp_pm_subflow_check_next(). It seems
reasonable to add a mandatory .subflow_check_next interface for struct
mptcp_pm_ops.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/net/mptcp.h | 3 +++
net/mptcp/pm.c | 31 +++----------------------------
net/mptcp/pm_kernel.c | 20 ++++++++++++++++++++
net/mptcp/pm_userspace.c | 15 +++++++++++++++
4 files changed, 41 insertions(+), 28 deletions(-)
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 6f9bc0ca4d37..5f2d94b2f97f 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -15,6 +15,7 @@
struct mptcp_info;
struct mptcp_sock;
struct mptcp_pm_addr_entry;
+struct mptcp_subflow_context;
struct seq_file;
/* MPTCP sk_buff extension data */
@@ -125,6 +126,8 @@ struct mptcp_pm_ops {
bool (*allow_new_subflow)(struct mptcp_sock *msk);
bool (*accept_new_subflow)(const struct mptcp_sock *msk);
+ void (*subflow_check_next)(struct mptcp_sock *msk,
+ const struct mptcp_subflow_context *subflow);
char name[MPTCP_PM_NAME_MAX];
struct module *owner;
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 31a2c66a1af3..d8a5c2c06500 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -526,33 +526,7 @@ void mptcp_pm_subflow_established(struct mptcp_sock *msk)
void mptcp_pm_subflow_check_next(struct mptcp_sock *msk,
const struct mptcp_subflow_context *subflow)
{
- struct mptcp_pm_data *pm = &msk->pm;
- bool update_subflows;
-
- update_subflows = subflow->request_join || subflow->mp_join;
- if (mptcp_pm_is_userspace(msk)) {
- if (update_subflows) {
- spin_lock_bh(&pm->lock);
- pm->subflows--;
- spin_unlock_bh(&pm->lock);
- }
- return;
- }
-
- if (!READ_ONCE(pm->work_pending) && !update_subflows)
- return;
-
- spin_lock_bh(&pm->lock);
- if (update_subflows)
- __mptcp_pm_close_subflow(msk);
-
- /* Even if this subflow is not really established, tell the PM to try
- * to pick the next ones, if possible.
- */
- if (mptcp_pm_nl_check_work_pending(msk))
- mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED);
-
- spin_unlock_bh(&pm->lock);
+ msk->pm.ops->subflow_check_next(msk, subflow);
}
void mptcp_pm_add_addr_received(const struct sock *ssk,
@@ -1017,7 +991,8 @@ struct mptcp_pm_ops *mptcp_pm_find(const char *name)
int mptcp_pm_validate(struct mptcp_pm_ops *pm_ops)
{
if (!pm_ops->get_local_id || !pm_ops->get_priority ||
- !pm_ops->allow_new_subflow || !pm_ops->accept_new_subflow) {
+ !pm_ops->allow_new_subflow || !pm_ops->accept_new_subflow ||
+ !pm_ops->subflow_check_next) {
pr_err("%s does not implement required ops\n", pm_ops->name);
return -EINVAL;
}
diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c
index 708a96951cba..b40d39232f70 100644
--- a/net/mptcp/pm_kernel.c
+++ b/net/mptcp/pm_kernel.c
@@ -1430,6 +1430,25 @@ static bool mptcp_pm_kernel_accept_new_subflow(const struct mptcp_sock *msk)
return READ_ONCE(msk->pm.accept_subflow);
}
+static void mptcp_pm_kernel_subflow_check_next(struct mptcp_sock *msk,
+ const struct mptcp_subflow_context *subflow)
+{
+ struct mptcp_pm_data *pm = &msk->pm;
+ bool update_subflows;
+
+ update_subflows = subflow->request_join || subflow->mp_join;
+
+ if (!READ_ONCE(pm->work_pending) && !update_subflows)
+ return;
+
+ spin_lock_bh(&pm->lock);
+ if (update_subflows)
+ __mptcp_pm_close_subflow(msk);
+ spin_unlock_bh(&pm->lock);
+
+ mptcp_pm_subflow_established(msk);
+}
+
static void mptcp_pm_kernel_init(struct mptcp_sock *msk)
{
bool subflows_allowed = !!mptcp_pm_get_subflows_max(msk);
@@ -1455,6 +1474,7 @@ struct mptcp_pm_ops mptcp_pm_kernel = {
.get_priority = mptcp_pm_kernel_get_priority,
.allow_new_subflow = mptcp_pm_kernel_allow_new_subflow,
.accept_new_subflow = mptcp_pm_kernel_accept_new_subflow,
+ .subflow_check_next = mptcp_pm_kernel_subflow_check_next,
.init = mptcp_pm_kernel_init,
.name = "kernel",
.owner = THIS_MODULE,
diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c
index 4cd9a84477c8..68247ec4cdaa 100644
--- a/net/mptcp/pm_userspace.c
+++ b/net/mptcp/pm_userspace.c
@@ -701,6 +701,20 @@ static bool mptcp_pm_userspace_accept_new_subflow(const struct mptcp_sock *msk)
return mptcp_userspace_pm_active(msk);
}
+static void mptcp_pm_userspace_subflow_check_next(struct mptcp_sock *msk,
+ const struct mptcp_subflow_context *subflow)
+{
+ struct mptcp_pm_data *pm = &msk->pm;
+ bool update_subflows;
+
+ update_subflows = subflow->request_join || subflow->mp_join;
+ if (update_subflows) {
+ spin_lock_bh(&pm->lock);
+ pm->subflows--;
+ spin_unlock_bh(&pm->lock);
+ }
+}
+
static void mptcp_pm_userspace_release(struct mptcp_sock *msk)
{
mptcp_userspace_pm_free_local_addr_list(msk);
@@ -711,6 +725,7 @@ static struct mptcp_pm_ops mptcp_pm_userspace = {
.get_priority = mptcp_pm_userspace_get_priority,
.allow_new_subflow = mptcp_pm_userspace_allow_new_subflow,
.accept_new_subflow = mptcp_pm_userspace_accept_new_subflow,
+ .subflow_check_next = mptcp_pm_userspace_subflow_check_next,
.release = mptcp_pm_userspace_release,
.name = "userspace",
.owner = THIS_MODULE,
--
2.43.0
Hi Geliang, On 11/03/2025 10:32, Geliang Tang wrote: > From: Geliang Tang <tanggeliang@kylinos.cn> > > The helper mptcp_pm_is_userspace() is used to distinguish userspace PM > operations from in-kernel PM in mptcp_pm_subflow_check_next(). It seems > reasonable to add a mandatory .subflow_check_next interface for struct > mptcp_pm_ops. > > Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn> > --- > include/net/mptcp.h | 3 +++ > net/mptcp/pm.c | 31 +++---------------------------- > net/mptcp/pm_kernel.c | 20 ++++++++++++++++++++ > net/mptcp/pm_userspace.c | 15 +++++++++++++++ > 4 files changed, 41 insertions(+), 28 deletions(-) > > diff --git a/include/net/mptcp.h b/include/net/mptcp.h > index 6f9bc0ca4d37..5f2d94b2f97f 100644 > --- a/include/net/mptcp.h > +++ b/include/net/mptcp.h > @@ -15,6 +15,7 @@ > struct mptcp_info; > struct mptcp_sock; > struct mptcp_pm_addr_entry; > +struct mptcp_subflow_context; > struct seq_file; > > /* MPTCP sk_buff extension data */ > @@ -125,6 +126,8 @@ struct mptcp_pm_ops { > > bool (*allow_new_subflow)(struct mptcp_sock *msk); > bool (*accept_new_subflow)(const struct mptcp_sock *msk); > + void (*subflow_check_next)(struct mptcp_sock *msk, Maybe we should rename this: subflow_established? 'check_next' is not really explicit. > + const struct mptcp_subflow_context *subflow); > > char name[MPTCP_PM_NAME_MAX]; > struct module *owner; > diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c > index 31a2c66a1af3..d8a5c2c06500 100644 > --- a/net/mptcp/pm.c > +++ b/net/mptcp/pm.c > @@ -526,33 +526,7 @@ void mptcp_pm_subflow_established(struct mptcp_sock *msk) > void mptcp_pm_subflow_check_next(struct mptcp_sock *msk, > const struct mptcp_subflow_context *subflow) > { > - struct mptcp_pm_data *pm = &msk->pm; > - bool update_subflows; > - > - update_subflows = subflow->request_join || subflow->mp_join; > - if (mptcp_pm_is_userspace(msk)) { > - if (update_subflows) { > - spin_lock_bh(&pm->lock); > - pm->subflows--; > - spin_unlock_bh(&pm->lock); > - } I wonder if... this 'if' should not be done for all PMs here. I guess mptcp_pm_close_subflow(msk) could then be called. Then I suggest scheduling the worker if msk->pm.ops->subflow_established is set, and ... I'm not sure how to deal with work_pending. Maybe a new callback? Or maybe we can deal with that later, but the current name is not good :) Anyway: then msk->pm.ops->subflow_check_next(), when the msk lock is held. I think all these ops should only be called when the msk lock is held, no? I don't think a BPF PM should schedule the worker. > - return; > - } > - > - if (!READ_ONCE(pm->work_pending) && !update_subflows) > - return; > - > - spin_lock_bh(&pm->lock); > - if (update_subflows) > - __mptcp_pm_close_subflow(msk); > - > - /* Even if this subflow is not really established, tell the PM to try > - * to pick the next ones, if possible. > - */ > - if (mptcp_pm_nl_check_work_pending(msk)) > - mptcp_pm_schedule_work(msk, MPTCP_PM_SUBFLOW_ESTABLISHED); > - > - spin_unlock_bh(&pm->lock); > + msk->pm.ops->subflow_check_next(msk, subflow); > } > > void mptcp_pm_add_addr_received(const struct sock *ssk, > @@ -1017,7 +991,8 @@ struct mptcp_pm_ops *mptcp_pm_find(const char *name) > int mptcp_pm_validate(struct mptcp_pm_ops *pm_ops) > { > if (!pm_ops->get_local_id || !pm_ops->get_priority || > - !pm_ops->allow_new_subflow || !pm_ops->accept_new_subflow) { > + !pm_ops->allow_new_subflow || !pm_ops->accept_new_subflow || > + !pm_ops->subflow_check_next) { See above: this new callback would not be mandatory then. Cheers, Matt -- Sponsored by the NGI0 Core fund.
© 2016 - 2025 Red Hat, Inc.