summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2025-02-24 18:23:46 -0800
committerJakub Kicinski <kuba@kernel.org>2025-02-24 18:23:46 -0800
commit7842f3d15a423696ec1066f9be6670b78a100668 (patch)
treea359becb06c3565f8614502426a6ea5a888b3df3
parent8f3f4464ff08f70e959c026fad2f3790abe84be6 (diff)
parent8275ac799ee15e972841eb77b694d63f5e888519 (diff)
Merge branch 'mptcp-pm-misc-cleanups-part-3'
Matthieu Baerts says: ==================== mptcp: pm: misc cleanups, part 3 These cleanups lead the way to the unification of the path-manager interfaces, and allow future extensions. The following patches are not all linked to each others, but are all related to the path-managers, except the last three. - Patch 1: remove unused returned value in mptcp_nl_set_flags(). - Patch 2: new flag: avoid iterating over all connections if not needed. - Patch 3: add a build check making sure there is enough space in cb-ctx. - Patch 4: new mptcp_pm_genl_fill_addr helper to reduce duplicated code. - Patch 5: simplify userspace_pm_append_new_local_addr helper. - Patch 6: drop unneeded inet6_sk(). - Patch 7: use ipv6_addr_equal() instead of !ipv6_addr_cmp() - Patch 8: scheduler: split an interface in two. - Patch 9: scheduler: save 64 bytes of currently unused data. - Patch 10: small optimisation to exit early in case of retransmissions. ==================== Link: https://patch.msgid.link/20250221-net-next-mptcp-pm-misc-cleanup-3-v1-0-2b70ab1cee79@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--include/net/mptcp.h5
-rw-r--r--net/mptcp/ctrl.c30
-rw-r--r--net/mptcp/pm.c21
-rw-r--r--net/mptcp/pm_netlink.c46
-rw-r--r--net/mptcp/pm_userspace.c29
-rw-r--r--net/mptcp/protocol.h3
-rw-r--r--net/mptcp/sched.c39
7 files changed, 93 insertions, 80 deletions
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 814b5f2e3ed5e..2c85ca92bb1c3 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -103,13 +103,14 @@ struct mptcp_out_options {
#define MPTCP_SUBFLOWS_MAX 8
struct mptcp_sched_data {
- bool reinject;
u8 subflows;
struct mptcp_subflow_context *contexts[MPTCP_SUBFLOWS_MAX];
};
struct mptcp_sched_ops {
- int (*get_subflow)(struct mptcp_sock *msk,
+ int (*get_send)(struct mptcp_sock *msk,
+ struct mptcp_sched_data *data);
+ int (*get_retrans)(struct mptcp_sock *msk,
struct mptcp_sched_data *data);
char name[MPTCP_SCHED_NAME_MAX];
diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c
index 2dd81e6c26bdb..be6c0237e10bf 100644
--- a/net/mptcp/ctrl.c
+++ b/net/mptcp/ctrl.c
@@ -401,26 +401,30 @@ void mptcp_active_enable(struct sock *sk)
void mptcp_active_detect_blackhole(struct sock *ssk, bool expired)
{
struct mptcp_subflow_context *subflow;
+ u8 timeouts, to_max;
+ struct net *net;
- if (!sk_is_mptcp(ssk))
+ /* Only check MPTCP SYN ... */
+ if (likely(!sk_is_mptcp(ssk) || ssk->sk_state != TCP_SYN_SENT))
return;
subflow = mptcp_subflow_ctx(ssk);
- if (subflow->request_mptcp && ssk->sk_state == TCP_SYN_SENT) {
- struct net *net = sock_net(ssk);
- u8 timeouts, to_max;
+ /* ... + MP_CAPABLE */
+ if (!subflow->request_mptcp) {
+ /* Mark as blackhole iif the 1st non-MPTCP SYN is accepted */
+ subflow->mpc_drop = 0;
+ return;
+ }
- timeouts = inet_csk(ssk)->icsk_retransmits;
- to_max = mptcp_get_pernet(net)->syn_retrans_before_tcp_fallback;
+ net = sock_net(ssk);
+ timeouts = inet_csk(ssk)->icsk_retransmits;
+ to_max = mptcp_get_pernet(net)->syn_retrans_before_tcp_fallback;
- if (timeouts == to_max || (timeouts < to_max && expired)) {
- MPTCP_INC_STATS(net, MPTCP_MIB_MPCAPABLEACTIVEDROP);
- subflow->mpc_drop = 1;
- mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow);
- }
- } else if (ssk->sk_state == TCP_SYN_SENT) {
- subflow->mpc_drop = 0;
+ if (timeouts == to_max || (timeouts < to_max && expired)) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_MPCAPABLEACTIVEDROP);
+ subflow->mpc_drop = 1;
+ mptcp_subflow_early_fallback(mptcp_sk(subflow->conn), subflow);
}
}
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index b1f36dc1a0911..16cacce6c10fe 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -489,6 +489,27 @@ fail:
return ret;
}
+int mptcp_pm_genl_fill_addr(struct sk_buff *msg,
+ struct netlink_callback *cb,
+ struct mptcp_pm_addr_entry *entry)
+{
+ void *hdr;
+
+ hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, &mptcp_genl_family,
+ NLM_F_MULTI, MPTCP_PM_CMD_GET_ADDR);
+ if (!hdr)
+ return -EINVAL;
+
+ if (mptcp_nl_fill_addr(msg, entry) < 0) {
+ genlmsg_cancel(msg, hdr);
+ return -EINVAL;
+ }
+
+ genlmsg_end(msg, hdr);
+ return 0;
+}
+
static int mptcp_pm_dump_addr(struct sk_buff *msg, struct netlink_callback *cb)
{
const struct genl_info *info = genl_info_dump(cb);
diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index 99705a9c2238c..ef85a60151ad7 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -64,7 +64,7 @@ bool mptcp_addresses_equal(const struct mptcp_addr_info *a,
addr_equals = a->addr.s_addr == b->addr.s_addr;
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
else
- addr_equals = !ipv6_addr_cmp(&a->addr6, &b->addr6);
+ addr_equals = ipv6_addr_equal(&a->addr6, &b->addr6);
} else if (a->family == AF_INET) {
if (ipv6_addr_v4mapped(&b->addr6))
addr_equals = a->addr.s_addr == b->addr6.s6_addr32[3];
@@ -1798,7 +1798,6 @@ int mptcp_pm_nl_dump_addr(struct sk_buff *msg,
struct mptcp_pm_addr_entry *entry;
struct pm_nl_pernet *pernet;
int id = cb->args[0];
- void *hdr;
int i;
pernet = pm_nl_get_pernet(net);
@@ -1813,19 +1812,10 @@ int mptcp_pm_nl_dump_addr(struct sk_buff *msg,
if (entry->addr.id <= id)
continue;
- hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq, &mptcp_genl_family,
- NLM_F_MULTI, MPTCP_PM_CMD_GET_ADDR);
- if (!hdr)
+ if (mptcp_pm_genl_fill_addr(msg, cb, entry) < 0)
break;
- if (mptcp_nl_fill_addr(msg, entry) < 0) {
- genlmsg_cancel(msg, hdr);
- break;
- }
-
id = entry->addr.id;
- genlmsg_end(msg, hdr);
}
}
rcu_read_unlock();
@@ -1922,13 +1912,16 @@ static void mptcp_pm_nl_fullmesh(struct mptcp_sock *msk,
spin_unlock_bh(&msk->pm.lock);
}
-static int mptcp_nl_set_flags(struct net *net,
- struct mptcp_addr_info *addr,
- u8 bkup, u8 changed)
+static void mptcp_nl_set_flags(struct net *net, struct mptcp_addr_info *addr,
+ u8 flags, u8 changed)
{
+ u8 is_subflow = !!(flags & MPTCP_PM_ADDR_FLAG_SUBFLOW);
+ u8 bkup = !!(flags & MPTCP_PM_ADDR_FLAG_BACKUP);
long s_slot = 0, s_num = 0;
struct mptcp_sock *msk;
- int ret = -EINVAL;
+
+ if (changed == MPTCP_PM_ADDR_FLAG_FULLMESH && !is_subflow)
+ return;
while ((msk = mptcp_token_iter_next(net, &s_slot, &s_num)) != NULL) {
struct sock *sk = (struct sock *)msk;
@@ -1938,8 +1931,9 @@ static int mptcp_nl_set_flags(struct net *net,
lock_sock(sk);
if (changed & MPTCP_PM_ADDR_FLAG_BACKUP)
- ret = mptcp_pm_nl_mp_prio_send_ack(msk, addr, NULL, bkup);
- if (changed & MPTCP_PM_ADDR_FLAG_FULLMESH)
+ mptcp_pm_nl_mp_prio_send_ack(msk, addr, NULL, bkup);
+ /* Subflows will only be recreated if the SUBFLOW flag is set */
+ if (is_subflow && (changed & MPTCP_PM_ADDR_FLAG_FULLMESH))
mptcp_pm_nl_fullmesh(msk, addr);
release_sock(sk);
@@ -1948,7 +1942,7 @@ next:
cond_resched();
}
- return ret;
+ return;
}
int mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry *local,
@@ -1961,7 +1955,6 @@ int mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry *local,
struct mptcp_pm_addr_entry *entry;
struct pm_nl_pernet *pernet;
u8 lookup_by_id = 0;
- u8 bkup = 0;
pernet = pm_nl_get_pernet(net);
@@ -1974,9 +1967,6 @@ int mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry *local,
}
}
- if (local->flags & MPTCP_PM_ADDR_FLAG_BACKUP)
- bkup = 1;
-
spin_lock_bh(&pernet->lock);
entry = lookup_by_id ? __lookup_addr_by_id(pernet, local->addr.id) :
__lookup_addr(pernet, &local->addr);
@@ -1998,7 +1988,7 @@ int mptcp_pm_nl_set_flags(struct mptcp_pm_addr_entry *local,
*local = *entry;
spin_unlock_bh(&pernet->lock);
- mptcp_nl_set_flags(net, &local->addr, bkup, changed);
+ mptcp_nl_set_flags(net, &local->addr, entry->flags, changed);
return 0;
}
@@ -2032,9 +2022,7 @@ static int mptcp_event_add_subflow(struct sk_buff *skb, const struct sock *ssk)
break;
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
case AF_INET6: {
- const struct ipv6_pinfo *np = inet6_sk(ssk);
-
- if (nla_put_in6_addr(skb, MPTCP_ATTR_SADDR6, &np->saddr))
+ if (nla_put_in6_addr(skb, MPTCP_ATTR_SADDR6, &issk->pinet6->saddr))
return -EMSGSIZE;
if (nla_put_in6_addr(skb, MPTCP_ATTR_DADDR6, &ssk->sk_v6_daddr))
return -EMSGSIZE;
@@ -2261,9 +2249,7 @@ void mptcp_event_pm_listener(const struct sock *ssk,
break;
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
case AF_INET6: {
- const struct ipv6_pinfo *np = inet6_sk(ssk);
-
- if (nla_put_in6_addr(skb, MPTCP_ATTR_SADDR6, &np->saddr))
+ if (nla_put_in6_addr(skb, MPTCP_ATTR_SADDR6, &issk->pinet6->saddr))
goto nla_put_failure;
break;
}
diff --git a/net/mptcp/pm_userspace.c b/net/mptcp/pm_userspace.c
index 277cf092a8704..6bf6a20ef7f3e 100644
--- a/net/mptcp/pm_userspace.c
+++ b/net/mptcp/pm_userspace.c
@@ -48,7 +48,6 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
bool needs_id)
{
DECLARE_BITMAP(id_bitmap, MPTCP_PM_MAX_ADDR_ID + 1);
- struct mptcp_pm_addr_entry *match = NULL;
struct sock *sk = (struct sock *)msk;
struct mptcp_pm_addr_entry *e;
bool addr_match = false;
@@ -63,16 +62,12 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
if (addr_match && entry->addr.id == 0 && needs_id)
entry->addr.id = e->addr.id;
id_match = (e->addr.id == entry->addr.id);
- if (addr_match && id_match) {
- match = e;
+ if (addr_match || id_match)
break;
- } else if (addr_match || id_match) {
- break;
- }
__set_bit(e->addr.id, id_bitmap);
}
- if (!match && !addr_match && !id_match) {
+ if (!addr_match && !id_match) {
/* Memory for the entry is allocated from the
* sock option buffer.
*/
@@ -90,7 +85,7 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
list_add_tail_rcu(&e->list, &msk->pm.userspace_pm_local_addr_list);
msk->pm.local_addr_used++;
ret = e->addr.id;
- } else if (match) {
+ } else if (addr_match && id_match) {
ret = entry->addr.id;
}
@@ -465,9 +460,7 @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk,
break;
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
case AF_INET6: {
- const struct ipv6_pinfo *pinfo = inet6_sk(ssk);
-
- if (!ipv6_addr_equal(&local->addr6, &pinfo->saddr) ||
+ if (!ipv6_addr_equal(&local->addr6, &issk->pinet6->saddr) ||
!ipv6_addr_equal(&remote->addr6, &ssk->sk_v6_daddr))
continue;
break;
@@ -641,7 +634,8 @@ int mptcp_userspace_pm_dump_addr(struct sk_buff *msg,
struct mptcp_sock *msk;
int ret = -EINVAL;
struct sock *sk;
- void *hdr;
+
+ BUILD_BUG_ON(sizeof(struct id_bitmap) > sizeof(cb->ctx));
bitmap = (struct id_bitmap *)cb->ctx;
@@ -657,19 +651,10 @@ int mptcp_userspace_pm_dump_addr(struct sk_buff *msg,
if (test_bit(entry->addr.id, bitmap->map))
continue;
- hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq, &mptcp_genl_family,
- NLM_F_MULTI, MPTCP_PM_CMD_GET_ADDR);
- if (!hdr)
+ if (mptcp_pm_genl_fill_addr(msg, cb, entry) < 0)
break;
- if (mptcp_nl_fill_addr(msg, entry) < 0) {
- genlmsg_cancel(msg, hdr);
- break;
- }
-
__set_bit(entry->addr.id, bitmap->map);
- genlmsg_end(msg, hdr);
}
spin_unlock_bh(&msk->pm.lock);
release_sock(sk);
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index ca65f8bff632f..256677c43ca65 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -1057,6 +1057,9 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subf
struct request_sock *req);
int mptcp_nl_fill_addr(struct sk_buff *skb,
struct mptcp_pm_addr_entry *entry);
+int mptcp_pm_genl_fill_addr(struct sk_buff *msg,
+ struct netlink_callback *cb,
+ struct mptcp_pm_addr_entry *entry);
static inline bool mptcp_pm_should_add_signal(struct mptcp_sock *msk)
{
diff --git a/net/mptcp/sched.c b/net/mptcp/sched.c
index df7dbcfa3b713..c16c6fbd4ba2f 100644
--- a/net/mptcp/sched.c
+++ b/net/mptcp/sched.c
@@ -16,13 +16,25 @@
static DEFINE_SPINLOCK(mptcp_sched_list_lock);
static LIST_HEAD(mptcp_sched_list);
-static int mptcp_sched_default_get_subflow(struct mptcp_sock *msk,
+static int mptcp_sched_default_get_send(struct mptcp_sock *msk,
+ struct mptcp_sched_data *data)
+{
+ struct sock *ssk;
+
+ ssk = mptcp_subflow_get_send(msk);
+ if (!ssk)
+ return -EINVAL;
+
+ mptcp_subflow_set_scheduled(mptcp_subflow_ctx(ssk), true);
+ return 0;
+}
+
+static int mptcp_sched_default_get_retrans(struct mptcp_sock *msk,
struct mptcp_sched_data *data)
{
struct sock *ssk;
- ssk = data->reinject ? mptcp_subflow_get_retrans(msk) :
- mptcp_subflow_get_send(msk);
+ ssk = mptcp_subflow_get_retrans(msk);
if (!ssk)
return -EINVAL;
@@ -31,7 +43,8 @@ static int mptcp_sched_default_get_subflow(struct mptcp_sock *msk,
}
static struct mptcp_sched_ops mptcp_sched_default = {
- .get_subflow = mptcp_sched_default_get_subflow,
+ .get_send = mptcp_sched_default_get_send,
+ .get_retrans = mptcp_sched_default_get_retrans,
.name = "default",
.owner = THIS_MODULE,
};
@@ -73,7 +86,7 @@ void mptcp_get_available_schedulers(char *buf, size_t maxlen)
int mptcp_register_scheduler(struct mptcp_sched_ops *sched)
{
- if (!sched->get_subflow)
+ if (!sched->get_send)
return -EINVAL;
spin_lock(&mptcp_sched_list_lock);
@@ -144,7 +157,7 @@ void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow,
int mptcp_sched_get_send(struct mptcp_sock *msk)
{
struct mptcp_subflow_context *subflow;
- struct mptcp_sched_data data;
+ struct mptcp_sched_data *data = NULL;
msk_owned_by_me(msk);
@@ -164,16 +177,15 @@ int mptcp_sched_get_send(struct mptcp_sock *msk)
return 0;
}
- data.reinject = false;
if (msk->sched == &mptcp_sched_default || !msk->sched)
- return mptcp_sched_default_get_subflow(msk, &data);
- return msk->sched->get_subflow(msk, &data);
+ return mptcp_sched_default_get_send(msk, data);
+ return msk->sched->get_send(msk, data);
}
int mptcp_sched_get_retrans(struct mptcp_sock *msk)
{
struct mptcp_subflow_context *subflow;
- struct mptcp_sched_data data;
+ struct mptcp_sched_data *data = NULL;
msk_owned_by_me(msk);
@@ -186,8 +198,9 @@ int mptcp_sched_get_retrans(struct mptcp_sock *msk)
return 0;
}
- data.reinject = true;
if (msk->sched == &mptcp_sched_default || !msk->sched)
- return mptcp_sched_default_get_subflow(msk, &data);
- return msk->sched->get_subflow(msk, &data);
+ return mptcp_sched_default_get_retrans(msk, data);
+ if (msk->sched->get_retrans)
+ return msk->sched->get_retrans(msk, data);
+ return msk->sched->get_send(msk, data);
}