Commit 5a40cce2 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mptcp-Add-port-parameter-to-ADD_ADDR-option'



Mat Martineau says:

====================
mptcp: Add port parameter to ADD_ADDR option

The ADD_ADDR MPTCP option is used to announce available IP addresses
that a peer may connect to when adding more TCP subflows to an existing
MPTCP connection. There is an optional port number field in that
ADD_ADDR header, and this patch set adds capability for that port number
to be sent and received.

Patches 1, 2, and 4 refactor existing ADD_ADDR code to simplify implementation
of port number support.

Patches 3 and 5 are the main functional changes, for sending and
receiving the port number in the MPTCP ADD_ADDR option.

Patch 6 sends the ADD_ADDR option with port number on a bare TCP ACK,
since the extra length of the option may run in to cases where
sufficient TCP option space is not available on a data packet.

Patch 7 plumbs in port number support for the in-kernel MPTCP path
manager.

Patches 8-11 add some optional debug output and a little more cleanup
refactoring.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents dc528d5b 432d9e74
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ struct mptcp_out_options {
#endif
	};
	u8 addr_id;
	u16 port;
	u64 ahmac;
	u8 rm_id;
	u8 join_id;
+65 −38
Original line number Diff line number Diff line
@@ -242,9 +242,6 @@ static void mptcp_parse_option(const struct sk_buff *skb,

		mp_opt->add_addr = 1;
		mp_opt->addr_id = *ptr++;
		pr_debug("ADD_ADDR%s: id=%d, echo=%d",
			 (mp_opt->family == MPTCP_ADDR_IPVERSION_6) ? "6" : "",
			 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;
@@ -269,6 +266,9 @@ static void mptcp_parse_option(const struct sk_buff *skb,
			mp_opt->ahmac = get_unaligned_be64(ptr);
			ptr += 8;
		}
		pr_debug("ADD_ADDR%s: id=%d, ahmac=%llu, echo=%d, port=%d",
			 (mp_opt->family == MPTCP_ADDR_IPVERSION_6) ? "6" : "",
			 mp_opt->addr_id, mp_opt->ahmac, mp_opt->echo, mp_opt->port);
		break;

	case MPTCPOPT_RM_ADDR:
@@ -587,9 +587,11 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
	unsigned int opt_size = *size;
	struct mptcp_addr_info saddr;
	bool echo;
	bool port;
	int len;

	if (mptcp_pm_should_add_signal_ipv6(msk) &&
	if ((mptcp_pm_should_add_signal_ipv6(msk) ||
	     mptcp_pm_should_add_signal_port(msk)) &&
	    skb && skb_is_tcp_pure_ack(skb)) {
		pr_debug("drop other suboptions");
		opts->suboptions = 0;
@@ -598,10 +600,10 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
	}

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

	len = mptcp_add_addr_len(saddr.family, echo);
	len = mptcp_add_addr_len(saddr.family, echo, port);
	if (remaining < len)
		return false;

@@ -609,6 +611,8 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
	if (drop_other_suboptions)
		*size -= opt_size;
	opts->addr_id = saddr.id;
	if (port)
		opts->port = ntohs(saddr.port);
	if (saddr.family == AF_INET) {
		opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
		opts->addr = saddr.addr;
@@ -631,7 +635,8 @@ static bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *
		}
	}
#endif
	pr_debug("addr_id=%d, ahmac=%llu, echo=%d", opts->addr_id, opts->ahmac, echo);
	pr_debug("addr_id=%d, ahmac=%llu, echo=%d, port=%d",
		 opts->addr_id, opts->ahmac, echo, opts->port);

	return true;
}
@@ -1070,43 +1075,65 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp,
	}

mp_capable_done:
	if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
		if (opts->ahmac)
			*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
					      TCPOLEN_MPTCP_ADD_ADDR, 0,
					      opts->addr_id);
		else
	if ((OPTION_MPTCP_ADD_ADDR
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
	     | OPTION_MPTCP_ADD_ADDR6
#endif
	    ) & opts->suboptions) {
		u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;
		u8 echo = MPTCP_ADDR_ECHO;

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
		if (OPTION_MPTCP_ADD_ADDR6 & opts->suboptions)
			len = TCPOLEN_MPTCP_ADD_ADDR6_BASE;
#endif

		if (opts->port)
			len += TCPOLEN_MPTCP_PORT_LEN;

		if (opts->ahmac) {
			len += sizeof(opts->ahmac);
			echo = 0;
		}

		*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
					      TCPOLEN_MPTCP_ADD_ADDR_BASE,
					      MPTCP_ADDR_ECHO,
					      opts->addr_id);
				      len, echo, opts->addr_id);
		if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
			memcpy((u8 *)ptr, (u8 *)&opts->addr.s_addr, 4);
			ptr += 1;
		if (opts->ahmac) {
			put_unaligned_be64(opts->ahmac, ptr);
			ptr += 2;
		}
		}

#if IS_ENABLED(CONFIG_MPTCP_IPV6)
	if (OPTION_MPTCP_ADD_ADDR6 & opts->suboptions) {
		if (opts->ahmac)
			*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
					      TCPOLEN_MPTCP_ADD_ADDR6, 0,
					      opts->addr_id);
		else
			*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
					      TCPOLEN_MPTCP_ADD_ADDR6_BASE,
					      MPTCP_ADDR_ECHO,
					      opts->addr_id);
		else if (OPTION_MPTCP_ADD_ADDR6 & opts->suboptions) {
			memcpy((u8 *)ptr, opts->addr6.s6_addr, 16);
			ptr += 4;
		}
#endif

		if (!opts->port) {
			if (opts->ahmac) {
				put_unaligned_be64(opts->ahmac, ptr);
				ptr += 2;
			}
		} else {
			if (opts->ahmac) {
				u8 *bptr = (u8 *)ptr;

				put_unaligned_be16(opts->port, bptr);
				bptr += 2;
				put_unaligned_be64(opts->ahmac, bptr);
				bptr += 8;
				put_unaligned_be16(TCPOPT_NOP << 8 |
						   TCPOPT_NOP, bptr);

				ptr += 3;
			} else {
				put_unaligned_be32(opts->port << 16 |
						   TCPOPT_NOP << 8 |
						   TCPOPT_NOP, ptr);
				ptr += 1;
			}
		}
	}
#endif

	if (OPTION_MPTCP_RM_ADDR & opts->suboptions) {
		*ptr++ = mptcp_option(MPTCPOPT_RM_ADDR,
+28 −12
Original line number Diff line number Diff line
@@ -14,28 +14,43 @@

int mptcp_pm_announce_addr(struct mptcp_sock *msk,
			   const struct mptcp_addr_info *addr,
			   bool echo)
			   bool echo, bool port)
{
	u8 add_addr = READ_ONCE(msk->pm.add_addr_signal);
	u8 add_addr = READ_ONCE(msk->pm.addr_signal);

	pr_debug("msk=%p, local_id=%d", msk, addr->id);

	if (add_addr) {
		pr_warn("addr_signal error, add_addr=%d", add_addr);
		return -EINVAL;
	}

	msk->pm.local = *addr;
	add_addr |= BIT(MPTCP_ADD_ADDR_SIGNAL);
	if (echo)
		add_addr |= BIT(MPTCP_ADD_ADDR_ECHO);
	if (addr->family == AF_INET6)
		add_addr |= BIT(MPTCP_ADD_ADDR_IPV6);
	WRITE_ONCE(msk->pm.add_addr_signal, add_addr);
	if (port)
		add_addr |= BIT(MPTCP_ADD_ADDR_PORT);
	WRITE_ONCE(msk->pm.addr_signal, add_addr);
	return 0;
}

int mptcp_pm_remove_addr(struct mptcp_sock *msk, u8 local_id)
{
	u8 rm_addr = READ_ONCE(msk->pm.addr_signal);

	pr_debug("msk=%p, local_id=%d", msk, local_id);

	if (rm_addr) {
		pr_warn("addr_signal error, rm_addr=%d", rm_addr);
		return -EINVAL;
	}

	msk->pm.rm_id = local_id;
	WRITE_ONCE(msk->pm.rm_addr_signal, true);
	rm_addr |= BIT(MPTCP_RM_ADDR_SIGNAL);
	WRITE_ONCE(msk->pm.addr_signal, rm_addr);
	return 0;
}

@@ -156,7 +171,7 @@ void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
	spin_lock_bh(&pm->lock);

	if (!READ_ONCE(pm->accept_addr)) {
		mptcp_pm_announce_addr(msk, addr, true);
		mptcp_pm_announce_addr(msk, addr, true, addr->port);
		mptcp_pm_add_addr_send_ack(msk);
	} else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED)) {
		pm->remote = *addr;
@@ -167,7 +182,8 @@ void mptcp_pm_add_addr_received(struct mptcp_sock *msk,

void mptcp_pm_add_addr_send_ack(struct mptcp_sock *msk)
{
	if (!mptcp_pm_should_add_signal_ipv6(msk))
	if (!mptcp_pm_should_add_signal_ipv6(msk) &&
	    !mptcp_pm_should_add_signal_port(msk))
		return;

	mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_SEND_ACK);
@@ -188,7 +204,7 @@ void mptcp_pm_rm_addr_received(struct mptcp_sock *msk, u8 rm_id)
/* path manager helpers */

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

@@ -199,12 +215,13 @@ bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
		goto out_unlock;

	*echo = mptcp_pm_should_add_signal_echo(msk);
	*port = mptcp_pm_should_add_signal_port(msk);

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

	*saddr = msk->pm.local;
	WRITE_ONCE(msk->pm.add_addr_signal, 0);
	WRITE_ONCE(msk->pm.addr_signal, 0);
	ret = true;

out_unlock:
@@ -227,7 +244,7 @@ bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
		goto out_unlock;

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

out_unlock:
@@ -248,8 +265,7 @@ void mptcp_pm_data_init(struct mptcp_sock *msk)
	msk->pm.subflows = 0;
	msk->pm.rm_id = 0;
	WRITE_ONCE(msk->pm.work_pending, false);
	WRITE_ONCE(msk->pm.add_addr_signal, 0);
	WRITE_ONCE(msk->pm.rm_addr_signal, false);
	WRITE_ONCE(msk->pm.addr_signal, 0);
	WRITE_ONCE(msk->pm.accept_addr, false);
	WRITE_ONCE(msk->pm.accept_subflow, false);
	msk->pm.status = 0;
+21 −10
Original line number Diff line number Diff line
@@ -227,7 +227,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer)

	if (!mptcp_pm_should_add_signal(msk)) {
		pr_debug("retransmit ADD_ADDR id=%d", entry->addr.id);
		mptcp_pm_announce_addr(msk, &entry->addr, false);
		mptcp_pm_announce_addr(msk, &entry->addr, false, entry->addr.port);
		mptcp_pm_add_addr_send_ack(msk);
		entry->retrans_times++;
	}
@@ -313,7 +313,7 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
	struct mptcp_pm_addr_entry *local;
	struct pm_nl_pernet *pernet;

	pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);
	pernet = net_generic(sock_net(sk), pm_nl_pernet_id);

	pr_debug("local %d:%d signal %d:%d subflows %d:%d\n",
		 msk->pm.local_addr_used, msk->pm.local_addr_max,
@@ -328,7 +328,7 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
		if (local) {
			if (mptcp_pm_alloc_anno_list(msk, local)) {
				msk->pm.add_addr_signaled++;
				mptcp_pm_announce_addr(msk, &local->addr, false);
				mptcp_pm_announce_addr(msk, &local->addr, false, local->addr.port);
				mptcp_pm_nl_add_addr_send_ack(msk);
			}
		} else {
@@ -376,6 +376,7 @@ void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
	struct sock *sk = (struct sock *)msk;
	struct mptcp_addr_info remote;
	struct mptcp_addr_info local;
	bool use_port = false;

	pr_debug("accepted %d:%d remote family %d",
		 msk->pm.add_addr_accepted, msk->pm.add_addr_accept_max,
@@ -392,14 +393,16 @@ void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
	remote = msk->pm.remote;
	if (!remote.port)
		remote.port = sk->sk_dport;
	else
		use_port = true;
	memset(&local, 0, sizeof(local));
	local.family = remote.family;

	spin_unlock_bh(&msk->pm.lock);
	__mptcp_subflow_connect((struct sock *)msk, &local, &remote);
	__mptcp_subflow_connect(sk, &local, &remote);
	spin_lock_bh(&msk->pm.lock);

	mptcp_pm_announce_addr(msk, &remote, true);
	mptcp_pm_announce_addr(msk, &remote, true, use_port);
	mptcp_pm_nl_add_addr_send_ack(msk);
}

@@ -407,7 +410,8 @@ void mptcp_pm_nl_add_addr_send_ack(struct mptcp_sock *msk)
{
	struct mptcp_subflow_context *subflow;

	if (!mptcp_pm_should_add_signal_ipv6(msk))
	if (!mptcp_pm_should_add_signal_ipv6(msk) &&
	    !mptcp_pm_should_add_signal_port(msk))
		return;

	__mptcp_flush_join_list(msk);
@@ -417,15 +421,22 @@ void mptcp_pm_nl_add_addr_send_ack(struct mptcp_sock *msk)
		u8 add_addr;

		spin_unlock_bh(&msk->pm.lock);
		if (mptcp_pm_should_add_signal_ipv6(msk))
			pr_debug("send ack for add_addr6");
		if (mptcp_pm_should_add_signal_port(msk))
			pr_debug("send ack for add_addr_port");

		lock_sock(ssk);
		tcp_send_ack(ssk);
		release_sock(ssk);
		spin_lock_bh(&msk->pm.lock);

		add_addr = READ_ONCE(msk->pm.add_addr_signal);
		add_addr = READ_ONCE(msk->pm.addr_signal);
		if (mptcp_pm_should_add_signal_ipv6(msk))
			add_addr &= ~BIT(MPTCP_ADD_ADDR_IPV6);
		WRITE_ONCE(msk->pm.add_addr_signal, add_addr);
		if (mptcp_pm_should_add_signal_port(msk))
			add_addr &= ~BIT(MPTCP_ADD_ADDR_PORT);
		WRITE_ONCE(msk->pm.addr_signal, add_addr);
	}
}

+31 −19
Original line number Diff line number Diff line
@@ -49,14 +49,14 @@
#define TCPOLEN_MPTCP_DSS_MAP64		14
#define TCPOLEN_MPTCP_DSS_CHECKSUM	2
#define TCPOLEN_MPTCP_ADD_ADDR		16
#define TCPOLEN_MPTCP_ADD_ADDR_PORT	18
#define TCPOLEN_MPTCP_ADD_ADDR_PORT	20
#define TCPOLEN_MPTCP_ADD_ADDR_BASE	8
#define TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT	10
#define TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT	12
#define TCPOLEN_MPTCP_ADD_ADDR6		28
#define TCPOLEN_MPTCP_ADD_ADDR6_PORT	30
#define TCPOLEN_MPTCP_ADD_ADDR6_PORT	32
#define TCPOLEN_MPTCP_ADD_ADDR6_BASE	20
#define TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT	22
#define TCPOLEN_MPTCP_PORT_LEN		2
#define TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT	24
#define TCPOLEN_MPTCP_PORT_LEN		4
#define TCPOLEN_MPTCP_RM_ADDR_BASE	4

/* MPTCP MP_JOIN flags */
@@ -168,10 +168,12 @@ enum mptcp_pm_status {
	MPTCP_PM_SUBFLOW_ESTABLISHED,
};

enum mptcp_add_addr_status {
enum mptcp_addr_signal_status {
	MPTCP_ADD_ADDR_SIGNAL,
	MPTCP_ADD_ADDR_ECHO,
	MPTCP_ADD_ADDR_IPV6,
	MPTCP_ADD_ADDR_PORT,
	MPTCP_RM_ADDR_SIGNAL,
};

struct mptcp_pm_data {
@@ -181,8 +183,7 @@ struct mptcp_pm_data {

	spinlock_t	lock;		/*protects the whole PM data */

	u8		add_addr_signal;
	bool		rm_addr_signal;
	u8		addr_signal;
	bool		server_side;
	bool		work_pending;
	bool		accept_addr;
@@ -551,40 +552,51 @@ mptcp_pm_del_add_timer(struct mptcp_sock *msk,

int mptcp_pm_announce_addr(struct mptcp_sock *msk,
			   const struct mptcp_addr_info *addr,
			   bool echo);
			   bool echo, bool port);
int mptcp_pm_remove_addr(struct mptcp_sock *msk, u8 local_id);
int mptcp_pm_remove_subflow(struct mptcp_sock *msk, u8 local_id);

static inline bool mptcp_pm_should_add_signal(struct mptcp_sock *msk)
{
	return READ_ONCE(msk->pm.add_addr_signal) & BIT(MPTCP_ADD_ADDR_SIGNAL);
	return READ_ONCE(msk->pm.addr_signal) & BIT(MPTCP_ADD_ADDR_SIGNAL);
}

static inline bool mptcp_pm_should_add_signal_echo(struct mptcp_sock *msk)
{
	return READ_ONCE(msk->pm.add_addr_signal) & BIT(MPTCP_ADD_ADDR_ECHO);
	return READ_ONCE(msk->pm.addr_signal) & BIT(MPTCP_ADD_ADDR_ECHO);
}

static inline bool mptcp_pm_should_add_signal_ipv6(struct mptcp_sock *msk)
{
	return READ_ONCE(msk->pm.add_addr_signal) & BIT(MPTCP_ADD_ADDR_IPV6);
	return READ_ONCE(msk->pm.addr_signal) & BIT(MPTCP_ADD_ADDR_IPV6);
}

static inline bool mptcp_pm_should_add_signal_port(struct mptcp_sock *msk)
{
	return READ_ONCE(msk->pm.addr_signal) & BIT(MPTCP_ADD_ADDR_PORT);
}

static inline bool mptcp_pm_should_rm_signal(struct mptcp_sock *msk)
{
	return READ_ONCE(msk->pm.rm_addr_signal);
	return READ_ONCE(msk->pm.addr_signal) & BIT(MPTCP_RM_ADDR_SIGNAL);
}

static inline unsigned int mptcp_add_addr_len(int family, bool echo)
static inline unsigned int mptcp_add_addr_len(int family, bool echo, bool port)
{
	if (family == AF_INET)
		return echo ? TCPOLEN_MPTCP_ADD_ADDR_BASE
			    : TCPOLEN_MPTCP_ADD_ADDR;
	return echo ? TCPOLEN_MPTCP_ADD_ADDR6_BASE : TCPOLEN_MPTCP_ADD_ADDR6;
	u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE;

	if (family == AF_INET6)
		len = TCPOLEN_MPTCP_ADD_ADDR6_BASE;
	if (!echo)
		len += MPTCPOPT_THMAC_LEN;
	if (port)
		len += TCPOLEN_MPTCP_PORT_LEN;

	return len;
}

bool mptcp_pm_add_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
			      struct mptcp_addr_info *saddr, bool *echo);
			      struct mptcp_addr_info *saddr, bool *echo, bool *port);
bool mptcp_pm_rm_addr_signal(struct mptcp_sock *msk, unsigned int remaining,
			     u8 *rm_id);
int mptcp_pm_get_local_id(struct mptcp_sock *msk, struct sock_common *skc);