Skip to content

Commit

Permalink
Merge branch 'mptcp-RM_ADDR-ADD_ADDR-enhancements'
Browse files Browse the repository at this point in the history
Geliang Tang says:

====================
mptcp: RM_ADDR/ADD_ADDR enhancements

This series include two enhancements for the MPTCP path management,
namely RM_ADDR support and ADD_ADDR echo support, as specified by RFC
sections 3.4.1 and 3.4.2.

1 RM_ADDR support include 9 patches (1-3 and 8-13):

Patch 1 is the helper for patch 2, these two patches add the RM_ADDR
outgoing functions, which are derived from ADD_ADDR's corresponding
functions.

Patch 3 adds the RM_ADDR incoming logic, when RM_ADDR suboption is
received, close the subflow matching the rm_id, and update PM counter.

Patch 8 is the main remove routine. When the PM netlink removes an address,
we traverse all the existing msk sockets to find the relevant sockets. Then
trigger the RM_ADDR signal and remove the subflow which using this local
address, this subflow removing functions has been implemented in patch 9.

Finally, patches 10-13 are the self-tests for RM_ADDR.

2 ADD_ADDR echo support include 7 patches (4-7 and 14-16).

Patch 4 adds the ADD_ADDR echo logic, when the ADD_ADDR suboption has been
received, send out the same ADD_ADDR suboption with echo-flag, and no HMAC
included.

Patches 5 and 6 are the self-tests for ADD_ADDR echo. Patch 7 is a little
cleaning up.

Patch 14 and 15 are the helpers for patch 16. These three patches add
the ADD_ADDR retransmition when no ADD_ADDR echo is received.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed Sep 25, 2020
2 parents 075c156 + 00cfd77 commit a1a3552
Show file tree
Hide file tree
Showing 12 changed files with 674 additions and 70 deletions.
2 changes: 2 additions & 0 deletions include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -2195,6 +2195,8 @@ void sk_reset_timer(struct sock *sk, struct timer_list *timer,

void sk_stop_timer(struct sock *sk, struct timer_list *timer);

void sk_stop_timer_sync(struct sock *sk, struct timer_list *timer);

int __sk_queue_drop_skb(struct sock *sk, struct sk_buff_head *sk_queue,
struct sk_buff *skb, unsigned int flags,
void (*destructor)(struct sock *sk,
Expand Down
7 changes: 7 additions & 0 deletions net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -2947,6 +2947,13 @@ void sk_stop_timer(struct sock *sk, struct timer_list* timer)
}
EXPORT_SYMBOL(sk_stop_timer);

void sk_stop_timer_sync(struct sock *sk, struct timer_list *timer)
{
if (del_timer_sync(timer))
__sock_put(sk);
}
EXPORT_SYMBOL(sk_stop_timer_sync);

void sock_init_data(struct socket *sock, struct sock *sk)
{
sk_init_common(sk);
Expand Down
4 changes: 4 additions & 0 deletions net/mptcp/mib.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ static const struct snmp_mib mptcp_snmp_list[] = {
SNMP_MIB_ITEM("OFOMerge", MPTCP_MIB_OFOMERGE),
SNMP_MIB_ITEM("NoDSSInWindow", MPTCP_MIB_NODSSWINDOW),
SNMP_MIB_ITEM("DuplicateData", MPTCP_MIB_DUPDATA),
SNMP_MIB_ITEM("AddAddr", MPTCP_MIB_ADDADDR),
SNMP_MIB_ITEM("EchoAdd", MPTCP_MIB_ECHOADD),
SNMP_MIB_ITEM("RmAddr", MPTCP_MIB_RMADDR),
SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW),
SNMP_MIB_SENTINEL
};

Expand Down
4 changes: 4 additions & 0 deletions net/mptcp/mib.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ enum linux_mptcp_mib_field {
MPTCP_MIB_OFOMERGE, /* Segments merged in OoO queue */
MPTCP_MIB_NODSSWINDOW, /* Segments not in MPTCP windows */
MPTCP_MIB_DUPDATA, /* Segments discarded due to duplicate DSS */
MPTCP_MIB_ADDADDR, /* Received ADD_ADDR with echo-flag=0 */
MPTCP_MIB_ECHOADD, /* Received ADD_ADDR with echo-flag=1 */
MPTCP_MIB_RMADDR, /* Received RM_ADDR */
MPTCP_MIB_RMSUBFLOW, /* Remove a subflow */
__MPTCP_MIB_MAX
};

Expand Down
81 changes: 63 additions & 18 deletions net/mptcp/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <net/tcp.h>
#include <net/mptcp.h>
#include "protocol.h"
#include "mib.h"

static bool mptcp_cap_flag_sha256(u8 flags)
{
Expand Down Expand Up @@ -242,7 +243,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
mp_opt->add_addr = 1;
mp_opt->port = 0;
mp_opt->addr_id = *ptr++;
pr_debug("ADD_ADDR: id=%d", mp_opt->addr_id);
pr_debug("ADD_ADDR: id=%d, echo=%d", mp_opt->addr_id, mp_opt->echo);
if (mp_opt->family == MPTCP_ADDR_IPVERSION_4) {
memcpy((u8 *)&mp_opt->addr.s_addr, (u8 *)ptr, 4);
ptr += 4;
Expand Down Expand Up @@ -571,18 +572,19 @@ static u64 add_addr6_generate_hmac(u64 key1, u64 key2, u8 addr_id,
}
#endif

static bool mptcp_established_options_addr(struct sock *sk,
unsigned int *size,
unsigned int remaining,
struct mptcp_out_options *opts)
static bool mptcp_established_options_add_addr(struct sock *sk,
unsigned int *size,
unsigned int remaining,
struct mptcp_out_options *opts)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
struct mptcp_addr_info saddr;
bool echo;
int len;

if (!mptcp_pm_should_signal(msk) ||
!(mptcp_pm_addr_signal(msk, remaining, &saddr)))
if (!mptcp_pm_should_add_signal(msk) ||
!(mptcp_pm_add_addr_signal(msk, remaining, &saddr, &echo)))
return false;

len = mptcp_add_addr_len(saddr.family);
Expand All @@ -594,22 +596,51 @@ static bool mptcp_established_options_addr(struct sock *sk,
if (saddr.family == AF_INET) {
opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
opts->addr = saddr.addr;
opts->ahmac = add_addr_generate_hmac(msk->local_key,
msk->remote_key,
opts->addr_id,
&opts->addr);
if (!echo) {
opts->ahmac = add_addr_generate_hmac(msk->local_key,
msk->remote_key,
opts->addr_id,
&opts->addr);
}
}
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
else if (saddr.family == AF_INET6) {
opts->suboptions |= OPTION_MPTCP_ADD_ADDR6;
opts->addr6 = saddr.addr6;
opts->ahmac = add_addr6_generate_hmac(msk->local_key,
msk->remote_key,
opts->addr_id,
&opts->addr6);
if (!echo) {
opts->ahmac = add_addr6_generate_hmac(msk->local_key,
msk->remote_key,
opts->addr_id,
&opts->addr6);
}
}
#endif
pr_debug("addr_id=%d, ahmac=%llu", opts->addr_id, opts->ahmac);
pr_debug("addr_id=%d, ahmac=%llu, echo=%d", opts->addr_id, opts->ahmac, echo);

return true;
}

static bool mptcp_established_options_rm_addr(struct sock *sk,
unsigned int *size,
unsigned int remaining,
struct mptcp_out_options *opts)
{
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
u8 rm_id;

if (!mptcp_pm_should_rm_signal(msk) ||
!(mptcp_pm_rm_addr_signal(msk, remaining, &rm_id)))
return false;

if (remaining < TCPOLEN_MPTCP_RM_ADDR_BASE)
return false;

*size = TCPOLEN_MPTCP_RM_ADDR_BASE;
opts->suboptions |= OPTION_MPTCP_RM_ADDR;
opts->rm_id = rm_id;

pr_debug("rm_id=%d", opts->rm_id);

return true;
}
Expand Down Expand Up @@ -640,7 +671,11 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,

*size += opt_size;
remaining -= opt_size;
if (mptcp_established_options_addr(sk, &opt_size, remaining, opts)) {
if (mptcp_established_options_add_addr(sk, &opt_size, remaining, opts)) {
*size += opt_size;
remaining -= opt_size;
ret = true;
} else if (mptcp_established_options_rm_addr(sk, &opt_size, remaining, opts)) {
*size += opt_size;
remaining -= opt_size;
ret = true;
Expand Down Expand Up @@ -854,11 +889,21 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb,
addr.addr6 = mp_opt.addr6;
}
#endif
if (!mp_opt.echo)
if (!mp_opt.echo) {
mptcp_pm_add_addr_received(msk, &addr);
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR);
} else {
mptcp_pm_del_add_timer(msk, &addr);
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD);
}
mp_opt.add_addr = 0;
}

if (mp_opt.rm_addr) {
mptcp_pm_rm_addr_received(msk, mp_opt.rm_id);
mp_opt.rm_addr = 0;
}

if (!mp_opt.dss)
return;

Expand Down
91 changes: 70 additions & 21 deletions net/mptcp/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,34 @@
/* path manager command handlers */

int mptcp_pm_announce_addr(struct mptcp_sock *msk,
const struct mptcp_addr_info *addr)
const struct mptcp_addr_info *addr,
bool echo)
{
pr_debug("msk=%p, local_id=%d", msk, addr->id);

msk->pm.local = *addr;
WRITE_ONCE(msk->pm.addr_signal, true);
WRITE_ONCE(msk->pm.add_addr_echo, echo);
WRITE_ONCE(msk->pm.add_addr_signal, true);
return 0;
}

int mptcp_pm_remove_addr(struct mptcp_sock *msk, u8 local_id)
{
return -ENOTSUPP;
pr_debug("msk=%p, local_id=%d", msk, local_id);

msk->pm.rm_id = local_id;
WRITE_ONCE(msk->pm.rm_addr_signal, true);
return 0;
}

int mptcp_pm_remove_subflow(struct mptcp_sock *msk, u8 remote_id)
int mptcp_pm_remove_subflow(struct mptcp_sock *msk, u8 local_id)
{
return -ENOTSUPP;
pr_debug("msk=%p, local_id=%d", msk, local_id);

spin_lock_bh(&msk->pm.lock);
mptcp_pm_nl_rm_subflow_received(msk, local_id);
spin_unlock_bh(&msk->pm.lock);
return 0;
}

/* path manager event handlers */
Expand All @@ -46,7 +57,7 @@ void mptcp_pm_new_connection(struct mptcp_sock *msk, int server_side)
bool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk)
{
struct mptcp_pm_data *pm = &msk->pm;
int ret;
int ret = 0;

pr_debug("msk=%p subflows=%d max=%d allow=%d", msk, pm->subflows,
pm->subflows_max, READ_ONCE(pm->accept_subflow));
Expand All @@ -56,9 +67,11 @@ bool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk)
return false;

spin_lock_bh(&pm->lock);
ret = pm->subflows < pm->subflows_max;
if (ret && ++pm->subflows == pm->subflows_max)
WRITE_ONCE(pm->accept_subflow, false);
if (READ_ONCE(pm->accept_subflow)) {
ret = pm->subflows < pm->subflows_max;
if (ret && ++pm->subflows == pm->subflows_max)
WRITE_ONCE(pm->accept_subflow, false);
}
spin_unlock_bh(&pm->lock);

return ret;
Expand Down Expand Up @@ -135,38 +148,70 @@ void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
pr_debug("msk=%p remote_id=%d accept=%d", msk, addr->id,
READ_ONCE(pm->accept_addr));

/* avoid acquiring the lock if there is no room for fouther addresses */
if (!READ_ONCE(pm->accept_addr))
return;

spin_lock_bh(&pm->lock);

/* be sure there is something to signal re-checking under PM lock */
if (READ_ONCE(pm->accept_addr) &&
mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED))
if (!READ_ONCE(pm->accept_addr))
mptcp_pm_announce_addr(msk, addr, true);
else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED))
pm->remote = *addr;

spin_unlock_bh(&pm->lock);
}

void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, u8 rm_id)
{
struct mptcp_pm_data *pm = &msk->pm;

pr_debug("msk=%p remote_id=%d", msk, rm_id);

spin_lock_bh(&pm->lock);
mptcp_pm_schedule_work(msk, MPTCP_PM_RM_ADDR_RECEIVED);
pm->rm_id = rm_id;
spin_unlock_bh(&pm->lock);
}

/* path manager helpers */

bool mptcp_pm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
struct mptcp_addr_info *saddr)
bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
struct mptcp_addr_info *saddr, bool *echo)
{
int ret = false;

spin_lock_bh(&msk->pm.lock);

/* double check after the lock is acquired */
if (!mptcp_pm_should_signal(msk))
if (!mptcp_pm_should_add_signal(msk))
goto out_unlock;

if (remaining < mptcp_add_addr_len(msk->pm.local.family))
goto out_unlock;

*saddr = msk->pm.local;
WRITE_ONCE(msk->pm.addr_signal, false);
*echo = READ_ONCE(msk->pm.add_addr_echo);
WRITE_ONCE(msk->pm.add_addr_signal, false);
ret = true;

out_unlock:
spin_unlock_bh(&msk->pm.lock);
return ret;
}

bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
u8 *rm_id)
{
int ret = false;

spin_lock_bh(&msk->pm.lock);

/* double check after the lock is acquired */
if (!mptcp_pm_should_rm_signal(msk))
goto out_unlock;

if (remaining < TCPOLEN_MPTCP_RM_ADDR_BASE)
goto out_unlock;

*rm_id = msk->pm.rm_id;
WRITE_ONCE(msk->pm.rm_addr_signal, false);
ret = true;

out_unlock:
Expand All @@ -185,13 +230,17 @@ void mptcp_pm_data_init(struct mptcp_sock *msk)
msk->pm.add_addr_accepted = 0;
msk->pm.local_addr_used = 0;
msk->pm.subflows = 0;
msk->pm.rm_id = 0;
WRITE_ONCE(msk->pm.work_pending, false);
WRITE_ONCE(msk->pm.addr_signal, false);
WRITE_ONCE(msk->pm.add_addr_signal, false);
WRITE_ONCE(msk->pm.rm_addr_signal, false);
WRITE_ONCE(msk->pm.accept_addr, false);
WRITE_ONCE(msk->pm.accept_subflow, false);
WRITE_ONCE(msk->pm.add_addr_echo, false);
msk->pm.status = 0;

spin_lock_init(&msk->pm.lock);
INIT_LIST_HEAD(&msk->pm.anno_list);

mptcp_pm_nl_data_init(msk);
}
Expand Down
Loading

0 comments on commit a1a3552

Please sign in to comment.