diff options
| author | Davide Caratti <dcaratti@redhat.com> | 2020-03-27 14:48:49 -0700 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2020-03-29 22:14:48 -0700 | 
| commit | 5147dfb5083204d6f5468d6d6d2d04b2cdc0cf2b (patch) | |
| tree | 69230ab7f4b1f6df999b78c6b82a5aa353bcbfc4 /net/mptcp | |
| parent | 3b1d6210a9577369103330b0d802b0bf74b65e7f (diff) | |
| download | linux-5147dfb5083204d6f5468d6d6d2d04b2cdc0cf2b.tar.bz2 | |
mptcp: allow dumping subflow context to userspace
add ulp-specific diagnostic functions, so that subflow information can be
dumped to userspace programs like 'ss'.
v2 -> v3:
- uapi: use bit macros appropriate for userspace
Co-developed-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Co-developed-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mptcp')
| -rw-r--r-- | net/mptcp/Makefile | 2 | ||||
| -rw-r--r-- | net/mptcp/diag.c | 104 | ||||
| -rw-r--r-- | net/mptcp/protocol.h | 2 | ||||
| -rw-r--r-- | net/mptcp/subflow.c | 2 | 
4 files changed, 109 insertions, 1 deletions
diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile index 2848d723c252..54494cf5bec0 100644 --- a/net/mptcp/Makefile +++ b/net/mptcp/Makefile @@ -1,4 +1,4 @@  # SPDX-License-Identifier: GPL-2.0  obj-$(CONFIG_MPTCP) += mptcp.o -mptcp-y := protocol.o subflow.o options.o token.o crypto.o ctrl.o pm.o +mptcp-y := protocol.o subflow.o options.o token.o crypto.o ctrl.o pm.o diag.o diff --git a/net/mptcp/diag.c b/net/mptcp/diag.c new file mode 100644 index 000000000000..a536586742f2 --- /dev/null +++ b/net/mptcp/diag.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +/* MPTCP socket monitoring support + * + * Copyright (c) 2019 Red Hat + * + * Author: Davide Caratti <dcaratti@redhat.com> + */ + +#include <linux/kernel.h> +#include <linux/net.h> +#include <linux/inet_diag.h> +#include <net/netlink.h> +#include <uapi/linux/mptcp.h> +#include "protocol.h" + +static int subflow_get_info(const struct sock *sk, struct sk_buff *skb) +{ +	struct mptcp_subflow_context *sf; +	struct nlattr *start; +	u32 flags = 0; +	int err; + +	start = nla_nest_start_noflag(skb, INET_ULP_INFO_MPTCP); +	if (!start) +		return -EMSGSIZE; + +	rcu_read_lock(); +	sf = rcu_dereference(inet_csk(sk)->icsk_ulp_data); +	if (!sf) { +		err = 0; +		goto nla_failure; +	} + +	if (sf->mp_capable) +		flags |= MPTCP_SUBFLOW_FLAG_MCAP_REM; +	if (sf->request_mptcp) +		flags |= MPTCP_SUBFLOW_FLAG_MCAP_LOC; +	if (sf->mp_join) +		flags |= MPTCP_SUBFLOW_FLAG_JOIN_REM; +	if (sf->request_join) +		flags |= MPTCP_SUBFLOW_FLAG_JOIN_LOC; +	if (sf->backup) +		flags |= MPTCP_SUBFLOW_FLAG_BKUP_REM; +	if (sf->request_bkup) +		flags |= MPTCP_SUBFLOW_FLAG_BKUP_LOC; +	if (sf->fully_established) +		flags |= MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED; +	if (sf->conn_finished) +		flags |= MPTCP_SUBFLOW_FLAG_CONNECTED; +	if (sf->map_valid) +		flags |= MPTCP_SUBFLOW_FLAG_MAPVALID; + +	if (nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_TOKEN_REM, sf->remote_token) || +	    nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_TOKEN_LOC, sf->token) || +	    nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ, +			sf->rel_write_seq) || +	    nla_put_u64_64bit(skb, MPTCP_SUBFLOW_ATTR_MAP_SEQ, sf->map_seq, +			      MPTCP_SUBFLOW_ATTR_PAD) || +	    nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_MAP_SFSEQ, +			sf->map_subflow_seq) || +	    nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_SSN_OFFSET, sf->ssn_offset) || +	    nla_put_u16(skb, MPTCP_SUBFLOW_ATTR_MAP_DATALEN, +			sf->map_data_len) || +	    nla_put_u32(skb, MPTCP_SUBFLOW_ATTR_FLAGS, flags) || +	    nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_REM, sf->remote_id) || +	    nla_put_u8(skb, MPTCP_SUBFLOW_ATTR_ID_LOC, sf->local_id)) { +		err = -EMSGSIZE; +		goto nla_failure; +	} + +	rcu_read_unlock(); +	nla_nest_end(skb, start); +	return 0; + +nla_failure: +	rcu_read_unlock(); +	nla_nest_cancel(skb, start); +	return err; +} + +static size_t subflow_get_info_size(const struct sock *sk) +{ +	size_t size = 0; + +	size += nla_total_size(0) +	/* INET_ULP_INFO_MPTCP */ +		nla_total_size(4) +	/* MPTCP_SUBFLOW_ATTR_TOKEN_REM */ +		nla_total_size(4) +	/* MPTCP_SUBFLOW_ATTR_TOKEN_LOC */ +		nla_total_size(4) +	/* MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ */ +		nla_total_size_64bit(8) +	/* MPTCP_SUBFLOW_ATTR_MAP_SEQ */ +		nla_total_size(4) +	/* MPTCP_SUBFLOW_ATTR_MAP_SFSEQ */ +		nla_total_size(2) +	/* MPTCP_SUBFLOW_ATTR_SSN_OFFSET */ +		nla_total_size(2) +	/* MPTCP_SUBFLOW_ATTR_MAP_DATALEN */ +		nla_total_size(4) +	/* MPTCP_SUBFLOW_ATTR_FLAGS */ +		nla_total_size(1) +	/* MPTCP_SUBFLOW_ATTR_ID_REM */ +		nla_total_size(1) +	/* MPTCP_SUBFLOW_ATTR_ID_LOC */ +		0; +	return size; +} + +void mptcp_diag_subflow_init(struct tcp_ulp_ops *ops) +{ +	ops->get_info = subflow_get_info; +	ops->get_info_size = subflow_get_info_size; +} diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index e9d4a852c7f1..0999f74df027 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -408,4 +408,6 @@ static inline bool before64(__u64 seq1, __u64 seq2)  #define after64(seq2, seq1)	before64(seq1, seq2) +void mptcp_diag_subflow_init(struct tcp_ulp_ops *ops); +  #endif /* __MPTCP_PROTOCOL_H */ diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index ba636cd84a3c..c051db074708 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -1148,6 +1148,8 @@ void mptcp_subflow_init(void)  	subflow_v6m_specific.net_frag_header_len = 0;  #endif +	mptcp_diag_subflow_init(&subflow_ulp_ops); +  	if (tcp_register_ulp(&subflow_ulp_ops) != 0)  		panic("MPTCP: failed to register subflows to ULP\n");  }  |