Skip to content

Commit

Permalink
Merge branch 'mptcp-mesh-path-manager'
Browse files Browse the repository at this point in the history
Mat Martineau says:

====================
mptcp: Add full mesh path manager option

The path manager in MPTCP controls the creation of additional subflows
after the initial connection is created. As each peer advertises
available endpoints with the ADD_ADDR MPTCP option, the recipient of
those advertisements must decide which subflows to create from the known
local and remote interfaces that are available for use by MPTCP.

The existing in-kernel path manager will create one additional subflow
when an ADD_ADDR is received, or a local address is newly configured for
MPTCP use. The maximum number of subflows has a configurable limit.

This patch set adds a MPTCP_PM_ADDR_FLAG_FULLMESH flag to the MPTCP
netlink API that enables subflows to be created more aggressively. When
an ADD_ADDR is received from a peer, new subflows are created between
that address/port and all local addresses configured for MPTCP.
Similarly, when a new local address is newly configured for use by
MPTCP, new subflows are created between that local address and all known
remote addresses for that MPTCP connection. The configurable limit on
the number of subflows still applies. If the new flag is not used the
path manager behavior is unchanged.

Patch 1 adds a helper function and refactors another function to prepare
for the rest of the patch series.

Patches 2 and 3 add two mesh connection capabilities: initiating
subflows based on added local addresses, or reacting to incoming
advertisements.

Patches 4-6 add full mesh cases to the self tests.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Aug 18, 2021
2 parents 3349d36 + f7713dd commit 606befc
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 26 deletions.
1 change: 1 addition & 0 deletions include/uapi/linux/mptcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ enum {
#define MPTCP_PM_ADDR_FLAG_SIGNAL (1 << 0)
#define MPTCP_PM_ADDR_FLAG_SUBFLOW (1 << 1)
#define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2)
#define MPTCP_PM_ADDR_FLAG_FULLMESH (1 << 3)

enum {
MPTCP_PM_CMD_UNSPEC,
Expand Down
154 changes: 139 additions & 15 deletions net/mptcp/pm_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,55 @@ void mptcp_pm_free_anno_list(struct mptcp_sock *msk)
}
}

static bool lookup_address_in_vec(struct mptcp_addr_info *addrs, unsigned int nr,
struct mptcp_addr_info *addr)
{
int i;

for (i = 0; i < nr; i++) {
if (addresses_equal(&addrs[i], addr, addr->port))
return true;
}

return false;
}

/* Fill all the remote addresses into the array addrs[],
* and return the array size.
*/
static unsigned int fill_remote_addresses_vec(struct mptcp_sock *msk, bool fullmesh,
struct mptcp_addr_info *addrs)
{
struct sock *sk = (struct sock *)msk, *ssk;
struct mptcp_subflow_context *subflow;
struct mptcp_addr_info remote = { 0 };
unsigned int subflows_max;
int i = 0;

subflows_max = mptcp_pm_get_subflows_max(msk);

/* Non-fullmesh endpoint, fill in the single entry
* corresponding to the primary MPC subflow remote address
*/
if (!fullmesh) {
remote_address((struct sock_common *)sk, &remote);
msk->pm.subflows++;
addrs[i++] = remote;
} else {
mptcp_for_each_subflow(msk, subflow) {
ssk = mptcp_subflow_tcp_sock(subflow);
remote_address((struct sock_common *)ssk, &remote);
if (!lookup_address_in_vec(addrs, i, &remote) &&
msk->pm.subflows < subflows_max) {
msk->pm.subflows++;
addrs[i++] = remote;
}
}
}

return i;
}

static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
{
struct sock *sk = (struct sock *)msk;
Expand Down Expand Up @@ -455,15 +504,16 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
!READ_ONCE(msk->pm.remote_deny_join_id0)) {
local = select_local_address(pernet, msk);
if (local) {
struct mptcp_addr_info remote = { 0 };
bool fullmesh = !!(local->flags & MPTCP_PM_ADDR_FLAG_FULLMESH);
struct mptcp_addr_info addrs[MPTCP_PM_ADDR_MAX];
int i, nr;

msk->pm.local_addr_used++;
msk->pm.subflows++;
check_work_pending(msk);
remote_address((struct sock_common *)sk, &remote);
nr = fill_remote_addresses_vec(msk, fullmesh, addrs);
spin_unlock_bh(&msk->pm.lock);
__mptcp_subflow_connect(sk, &local->addr, &remote,
local->flags, local->ifindex);
for (i = 0; i < nr; i++)
__mptcp_subflow_connect(sk, &local->addr, &addrs[i]);
spin_lock_bh(&msk->pm.lock);
return;
}
Expand All @@ -484,13 +534,67 @@ static void mptcp_pm_nl_subflow_established(struct mptcp_sock *msk)
mptcp_pm_create_subflow_or_signal_addr(msk);
}

/* Fill all the local addresses into the array addrs[],
* and return the array size.
*/
static unsigned int fill_local_addresses_vec(struct mptcp_sock *msk,
struct mptcp_addr_info *addrs)
{
struct sock *sk = (struct sock *)msk;
struct mptcp_pm_addr_entry *entry;
struct mptcp_addr_info local;
struct pm_nl_pernet *pernet;
unsigned int subflows_max;
int i = 0;

pernet = net_generic(sock_net(sk), pm_nl_pernet_id);
subflows_max = mptcp_pm_get_subflows_max(msk);

rcu_read_lock();
__mptcp_flush_join_list(msk);
list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
if (!(entry->flags & MPTCP_PM_ADDR_FLAG_FULLMESH))
continue;

if (entry->addr.family != sk->sk_family) {
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
if ((entry->addr.family == AF_INET &&
!ipv6_addr_v4mapped(&sk->sk_v6_daddr)) ||
(sk->sk_family == AF_INET &&
!ipv6_addr_v4mapped(&entry->addr.addr6)))
#endif
continue;
}

if (msk->pm.subflows < subflows_max) {
msk->pm.subflows++;
addrs[i++] = entry->addr;
}
}
rcu_read_unlock();

/* If the array is empty, fill in the single
* 'IPADDRANY' local address
*/
if (!i) {
memset(&local, 0, sizeof(local));
local.family = msk->pm.remote.family;

msk->pm.subflows++;
addrs[i++] = local;
}

return i;
}

static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
{
struct mptcp_addr_info addrs[MPTCP_PM_ADDR_MAX];
struct sock *sk = (struct sock *)msk;
unsigned int add_addr_accept_max;
struct mptcp_addr_info remote;
struct mptcp_addr_info local;
unsigned int subflows_max;
int i, nr;

add_addr_accept_max = mptcp_pm_get_add_addr_accept_max(msk);
subflows_max = mptcp_pm_get_subflows_max(msk);
Expand All @@ -502,23 +606,22 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
if (lookup_subflow_by_daddr(&msk->conn_list, &msk->pm.remote))
goto add_addr_echo;

msk->pm.add_addr_accepted++;
msk->pm.subflows++;
if (msk->pm.add_addr_accepted >= add_addr_accept_max ||
msk->pm.subflows >= subflows_max)
WRITE_ONCE(msk->pm.accept_addr, false);

/* connect to the specified remote address, using whatever
* local address the routing configuration will pick.
*/
remote = msk->pm.remote;
if (!remote.port)
remote.port = sk->sk_dport;
memset(&local, 0, sizeof(local));
local.family = remote.family;
nr = fill_local_addresses_vec(msk, addrs);

msk->pm.add_addr_accepted++;
if (msk->pm.add_addr_accepted >= add_addr_accept_max ||
msk->pm.subflows >= subflows_max)
WRITE_ONCE(msk->pm.accept_addr, false);

spin_unlock_bh(&msk->pm.lock);
__mptcp_subflow_connect(sk, &local, &remote, 0, 0);
for (i = 0; i < nr; i++)
__mptcp_subflow_connect(sk, &addrs[i], &remote);
spin_lock_bh(&msk->pm.lock);

add_addr_echo:
Expand Down Expand Up @@ -1105,6 +1208,27 @@ __lookup_addr_by_id(struct pm_nl_pernet *pernet, unsigned int id)
return NULL;
}

int mptcp_pm_get_flags_and_ifindex_by_id(struct net *net, unsigned int id,
u8 *flags, int *ifindex)
{
struct mptcp_pm_addr_entry *entry;

*flags = 0;
*ifindex = 0;

if (id) {
rcu_read_lock();
entry = __lookup_addr_by_id(net_generic(net, pm_nl_pernet_id), id);
if (entry) {
*flags = entry->flags;
*ifindex = entry->ifindex;
}
rcu_read_unlock();
}

return 0;
}

static bool remove_anno_list_by_saddr(struct mptcp_sock *msk,
struct mptcp_addr_info *addr)
{
Expand Down
5 changes: 3 additions & 2 deletions net/mptcp/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,7 @@ struct socket *__mptcp_nmpc_socket(const struct mptcp_sock *msk);

/* called with sk socket lock held */
int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
const struct mptcp_addr_info *remote,
u8 flags, int ifindex);
const struct mptcp_addr_info *remote);
int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock);
void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
struct sockaddr_storage *addr,
Expand Down Expand Up @@ -733,6 +732,8 @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk,
struct mptcp_pm_add_entry *
mptcp_lookup_anno_list_by_saddr(struct mptcp_sock *msk,
struct mptcp_addr_info *addr);
int mptcp_pm_get_flags_and_ifindex_by_id(struct net *net, unsigned int id,
u8 *flags, int *ifindex);

int mptcp_pm_announce_addr(struct mptcp_sock *msk,
const struct mptcp_addr_info *addr,
Expand Down
7 changes: 5 additions & 2 deletions net/mptcp/subflow.c
Original file line number Diff line number Diff line change
Expand Up @@ -1355,8 +1355,7 @@ void mptcp_info2sockaddr(const struct mptcp_addr_info *info,
}

int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
const struct mptcp_addr_info *remote,
u8 flags, int ifindex)
const struct mptcp_addr_info *remote)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct mptcp_subflow_context *subflow;
Expand All @@ -1367,6 +1366,8 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
struct sock *ssk;
u32 remote_token;
int addrlen;
int ifindex;
u8 flags;
int err;

if (!mptcp_is_fully_established(sk))
Expand All @@ -1390,6 +1391,8 @@ int __mptcp_subflow_connect(struct sock *sk, const struct mptcp_addr_info *loc,
local_id = err;
}

mptcp_pm_get_flags_and_ifindex_by_id(sock_net(sk), local_id,
&flags, &ifindex);
subflow->remote_key = msk->remote_key;
subflow->local_key = msk->local_key;
subflow->token = msk->token;
Expand Down
Loading

0 comments on commit 606befc

Please sign in to comment.