Skip to content

Commit

Permalink
mptcp: implement userspace pm subflow interfaces
Browse files Browse the repository at this point in the history
This patch implements subflow_create() and subflow_destroy() interfaces
of the userspace PM.

Extract subflow_create() interface from the handler of netlink commond
MPTCP_PM_CMD_SUBFLOW_CREATE mptcp_pm_nl_subflow_create_doit(), only leave
the code for obtaining msk through "info", parsing local address entry
and parsing remote address info in the handler.

Extract subflow_destroy() interface from the handler of netlink commond
MPTCP_PM_CMD_SUBFLOW_DESTROY mptcp_pm_nl_subflow_destroy_doit(), only leave
the code for obtaining msk through "info", parsing local address entry and
parsing remote address info in the handler.

Both interfaces are invoked under holding the msk socket lock.

Signed-off-by: Geliang Tang <[email protected]>
  • Loading branch information
Geliang Tang authored and intel-lab-lkp committed Oct 16, 2024
1 parent aba88de commit 292fda9
Showing 1 changed file with 75 additions and 63 deletions.
138 changes: 75 additions & 63 deletions net/mptcp/pm_userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,35 @@ int mptcp_pm_nl_remove_doit(struct sk_buff *skb, struct genl_info *info)
return err;
}

static int userspace_pm_subflow_create(struct mptcp_sock *msk,
struct mptcp_pm_addr_entry *local,
struct mptcp_addr_info *remote)
{
struct sock *sk = (struct sock *)msk;
int err;

if (local->flags & MPTCP_PM_ADDR_FLAG_SIGNAL)
return -EINVAL;
local->flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW;

if (!mptcp_pm_addr_families_match(sk, &local->addr, remote))
return -EINVAL;

err = mptcp_userspace_pm_append_new_local_addr(msk, local, false);
if (err < 0)
return err;

err = __mptcp_subflow_connect(sk, local, remote);
spin_lock_bh(&msk->pm.lock);
if (err)
mptcp_userspace_pm_delete_local_addr(msk, local);
else
msk->pm.subflows++;
spin_unlock_bh(&msk->pm.lock);

return err;
}

int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *raddr = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE];
Expand Down Expand Up @@ -368,41 +397,17 @@ int mptcp_pm_nl_subflow_create_doit(struct sk_buff *skb, struct genl_info *info)
goto create_err;
}

if (entry.flags & MPTCP_PM_ADDR_FLAG_SIGNAL) {
GENL_SET_ERR_MSG(info, "invalid addr flags");
err = -EINVAL;
goto create_err;
}
entry.flags |= MPTCP_PM_ADDR_FLAG_SUBFLOW;

err = mptcp_pm_parse_addr(raddr, info, &addr_r);
if (err < 0) {
NL_SET_ERR_MSG_ATTR(info->extack, raddr, "error parsing remote addr");
goto create_err;
}

if (!mptcp_pm_addr_families_match(sk, &entry.addr, &addr_r)) {
GENL_SET_ERR_MSG(info, "families mismatch");
err = -EINVAL;
goto create_err;
}

err = mptcp_userspace_pm_append_new_local_addr(msk, &entry, false);
if (err < 0) {
GENL_SET_ERR_MSG(info, "did not match address and id");
goto create_err;
}

lock_sock(sk);
err = __mptcp_subflow_connect(sk, &entry, &addr_r);
err = userspace_pm_subflow_create(msk, &entry, &addr_r);
release_sock(sk);

spin_lock_bh(&msk->pm.lock);
if (err)
mptcp_userspace_pm_delete_local_addr(msk, &entry);
else
msk->pm.subflows++;
spin_unlock_bh(&msk->pm.lock);
GENL_SET_ERR_MSG(info, "subflow_create failed");

create_err:
sock_put(sk);
Expand Down Expand Up @@ -457,15 +462,55 @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk,
return NULL;
}

static int userspace_pm_subflow_destroy(struct mptcp_sock *msk,
struct mptcp_pm_addr_entry *local,
struct mptcp_addr_info *remote)
{
struct sock *sk = (struct sock *)msk;
struct sock *ssk;
int err = -ESRCH;

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
if (local->addr.family == AF_INET && ipv6_addr_v4mapped(&remote->addr6)) {
ipv6_addr_set_v4mapped(local->addr.addr.s_addr, &remote->addr6);
local->addr.family = AF_INET6;
}
if (remote->family == AF_INET && ipv6_addr_v4mapped(&local->addr.addr6)) {
ipv6_addr_set_v4mapped(remote->addr.s_addr, &local->addr.addr6);
remote->family = AF_INET6;
}
#endif
if (local->addr.family != remote->family)
return -EINVAL;

if (!local->addr.port || !remote->port)
return -EINVAL;

ssk = mptcp_nl_find_ssk(msk, &local->addr, remote);
if (ssk) {
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);

spin_lock_bh(&msk->pm.lock);
mptcp_userspace_pm_delete_local_addr(msk, local);
spin_unlock_bh(&msk->pm.lock);
mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN);
mptcp_close_ssk(sk, ssk, subflow);
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW);
err = 0;
}

return err;
}

int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *raddr = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE];
struct nlattr *laddr = info->attrs[MPTCP_PM_ATTR_ADDR];
struct mptcp_pm_addr_entry local;
struct mptcp_addr_info addr_r;
struct mptcp_sock *msk;
struct sock *sk, *ssk;
int err = -EINVAL;
struct sock *sk;

if (!laddr || !raddr) {
GENL_SET_ERR_MSG(info, "missing required inputs");
Expand All @@ -490,44 +535,11 @@ int mptcp_pm_nl_subflow_destroy_doit(struct sk_buff *skb, struct genl_info *info
goto destroy_err;
}

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
if (local.addr.family == AF_INET && ipv6_addr_v4mapped(&addr_r.addr6)) {
ipv6_addr_set_v4mapped(local.addr.addr.s_addr, &local.addr.addr6);
local.addr.family = AF_INET6;
}
if (addr_r.family == AF_INET && ipv6_addr_v4mapped(&local.addr.addr6)) {
ipv6_addr_set_v4mapped(addr_r.addr.s_addr, &local.addr.addr6);
addr_r.family = AF_INET6;
}
#endif
if (local.addr.family != addr_r.family) {
GENL_SET_ERR_MSG(info, "address families do not match");
err = -EINVAL;
goto destroy_err;
}

if (!local.addr.port || !addr_r.port) {
GENL_SET_ERR_MSG(info, "missing local or remote port");
err = -EINVAL;
goto destroy_err;
}

lock_sock(sk);
ssk = mptcp_nl_find_ssk(msk, &local.addr, &addr_r);
if (ssk) {
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);

spin_lock_bh(&msk->pm.lock);
mptcp_userspace_pm_delete_local_addr(msk, &local);
spin_unlock_bh(&msk->pm.lock);
mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN);
mptcp_close_ssk(sk, ssk, subflow);
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW);
err = 0;
} else {
err = -ESRCH;
}
err = userspace_pm_subflow_destroy(msk, &local, &addr_r);
release_sock(sk);
if (err)
GENL_SET_ERR_MSG(info, "subflow_destroy failed");

destroy_err:
sock_put(sk);
Expand Down

0 comments on commit 292fda9

Please sign in to comment.