Commit 8179cc47 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mptcp-mib-counters'



Matthieu Baerts says:

====================
mptcp: add CurrEstab MIB counter

This MIB counter is similar to the one of TCP -- CurrEstab -- available
in /proc/net/snmp. This is useful to quickly list the number of MPTCP
connections without having to iterate over all of them.

Patch 1 prepares its support by adding new helper functions:

 - MPTCP_DEC_STATS(): similar to MPTCP_INC_STATS(), but this time to
   decrement a counter.

 - mptcp_set_state(): similar to tcp_set_state(), to change the state of
   an MPTCP socket, and to inc/decrement the new counter when needed.

Patch 2 uses mptcp_set_state() instead of directly calling
inet_sk_state_store() to change the state of MPTCP sockets.

Patch 3 and 4 validate the new feature in MPTCP "join" and "diag"
selftests.
====================

Signed-off-by: default avatarMatthieu Baerts <matttbe@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 42a7889a 81ab7728
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ static const struct snmp_mib mptcp_snmp_list[] = {
	SNMP_MIB_ITEM("RcvWndShared", MPTCP_MIB_RCVWNDSHARED),
	SNMP_MIB_ITEM("RcvWndConflictUpdate", MPTCP_MIB_RCVWNDCONFLICTUPDATE),
	SNMP_MIB_ITEM("RcvWndConflict", MPTCP_MIB_RCVWNDCONFLICT),
	SNMP_MIB_ITEM("MPCurrEstab", MPTCP_MIB_CURRESTAB),
	SNMP_MIB_SENTINEL
};

+8 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ enum linux_mptcp_mib_field {
					 * conflict with another subflow while updating msk rcv wnd
					 */
	MPTCP_MIB_RCVWNDCONFLICT,	/* Conflict with while updating msk rcv wnd */
	MPTCP_MIB_CURRESTAB,		/* Current established MPTCP connections */
	__MPTCP_MIB_MAX
};

@@ -95,4 +96,11 @@ static inline void __MPTCP_INC_STATS(struct net *net,
		__SNMP_INC_STATS(net->mib.mptcp_statistics, field);
}

static inline void MPTCP_DEC_STATS(struct net *net,
				   enum linux_mptcp_mib_field field)
{
	if (likely(net->mib.mptcp_statistics))
		SNMP_DEC_STATS(net->mib.mptcp_statistics, field);
}

bool mptcp_mib_alloc(struct net *net);
+5 −0
Original line number Diff line number Diff line
@@ -1048,6 +1048,11 @@ static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
	if (err)
		return err;

	/* We don't use mptcp_set_state() here because it needs to be called
	 * under the msk socket lock. For the moment, that will not bring
	 * anything more than only calling inet_sk_state_store(), because the
	 * old status is known (TCP_CLOSE).
	 */
	inet_sk_state_store(newsk, TCP_LISTEN);
	lock_sock(ssk);
	err = __inet_listen_sk(ssk, backlog);
+37 −19
Original line number Diff line number Diff line
@@ -429,11 +429,11 @@ static void mptcp_check_data_fin_ack(struct sock *sk)

		switch (sk->sk_state) {
		case TCP_FIN_WAIT1:
			inet_sk_state_store(sk, TCP_FIN_WAIT2);
			mptcp_set_state(sk, TCP_FIN_WAIT2);
			break;
		case TCP_CLOSING:
		case TCP_LAST_ACK:
			inet_sk_state_store(sk, TCP_CLOSE);
			mptcp_set_state(sk, TCP_CLOSE);
			break;
		}

@@ -594,13 +594,13 @@ static bool mptcp_check_data_fin(struct sock *sk)

		switch (sk->sk_state) {
		case TCP_ESTABLISHED:
			inet_sk_state_store(sk, TCP_CLOSE_WAIT);
			mptcp_set_state(sk, TCP_CLOSE_WAIT);
			break;
		case TCP_FIN_WAIT1:
			inet_sk_state_store(sk, TCP_CLOSING);
			mptcp_set_state(sk, TCP_CLOSING);
			break;
		case TCP_FIN_WAIT2:
			inet_sk_state_store(sk, TCP_CLOSE);
			mptcp_set_state(sk, TCP_CLOSE);
			break;
		default:
			/* Other states not expected */
@@ -775,7 +775,7 @@ static bool __mptcp_subflow_error_report(struct sock *sk, struct sock *ssk)
	 */
	ssk_state = inet_sk_state_load(ssk);
	if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD))
		inet_sk_state_store(sk, ssk_state);
		mptcp_set_state(sk, ssk_state);
	WRITE_ONCE(sk->sk_err, -err);

	/* This barrier is coupled with smp_rmb() in mptcp_poll() */
@@ -2463,7 +2463,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
	    inet_sk_state_load(msk->first) == TCP_CLOSE) {
		if (sk->sk_state != TCP_ESTABLISHED ||
		    msk->in_accept_queue || sock_flag(sk, SOCK_DEAD)) {
			inet_sk_state_store(sk, TCP_CLOSE);
			mptcp_set_state(sk, TCP_CLOSE);
			mptcp_close_wake_up(sk);
		} else {
			mptcp_start_tout_timer(sk);
@@ -2558,7 +2558,7 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk)
		WRITE_ONCE(sk->sk_err, ECONNRESET);
	}

	inet_sk_state_store(sk, TCP_CLOSE);
	mptcp_set_state(sk, TCP_CLOSE);
	WRITE_ONCE(sk->sk_shutdown, SHUTDOWN_MASK);
	smp_mb__before_atomic(); /* SHUTDOWN must be visible first */
	set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags);
@@ -2693,7 +2693,7 @@ static void mptcp_do_fastclose(struct sock *sk)
	struct mptcp_subflow_context *subflow, *tmp;
	struct mptcp_sock *msk = mptcp_sk(sk);

	inet_sk_state_store(sk, TCP_CLOSE);
	mptcp_set_state(sk, TCP_CLOSE);
	mptcp_for_each_subflow_safe(msk, subflow, tmp)
		__mptcp_close_ssk(sk, mptcp_subflow_tcp_sock(subflow),
				  subflow, MPTCP_CF_FASTCLOSE);
@@ -2871,6 +2871,24 @@ void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how)
	release_sock(ssk);
}

void mptcp_set_state(struct sock *sk, int state)
{
	int oldstate = sk->sk_state;

	switch (state) {
	case TCP_ESTABLISHED:
		if (oldstate != TCP_ESTABLISHED)
			MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_CURRESTAB);
		break;

	default:
		if (oldstate == TCP_ESTABLISHED)
			MPTCP_DEC_STATS(sock_net(sk), MPTCP_MIB_CURRESTAB);
	}

	inet_sk_state_store(sk, state);
}

static const unsigned char new_state[16] = {
	/* current state:     new state:      action:	*/
	[0 /* (Invalid) */] = TCP_CLOSE,
@@ -2893,7 +2911,7 @@ static int mptcp_close_state(struct sock *sk)
	int next = (int)new_state[sk->sk_state];
	int ns = next & TCP_STATE_MASK;

	inet_sk_state_store(sk, ns);
	mptcp_set_state(sk, ns);

	return next & TCP_ACTION_FIN;
}
@@ -3004,7 +3022,7 @@ bool __mptcp_close(struct sock *sk, long timeout)

	if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) {
		mptcp_check_listen_stop(sk);
		inet_sk_state_store(sk, TCP_CLOSE);
		mptcp_set_state(sk, TCP_CLOSE);
		goto cleanup;
	}

@@ -3047,7 +3065,7 @@ bool __mptcp_close(struct sock *sk, long timeout)
	 * state, let's not keep resources busy for no reasons
	 */
	if (subflows_alive == 0)
		inet_sk_state_store(sk, TCP_CLOSE);
		mptcp_set_state(sk, TCP_CLOSE);

	sock_hold(sk);
	pr_debug("msk=%p state=%d", sk, sk->sk_state);
@@ -3113,7 +3131,7 @@ static int mptcp_disconnect(struct sock *sk, int flags)
		return -EBUSY;

	mptcp_check_listen_stop(sk);
	inet_sk_state_store(sk, TCP_CLOSE);
	mptcp_set_state(sk, TCP_CLOSE);

	mptcp_stop_rtx_timer(sk);
	mptcp_stop_tout_timer(sk);
@@ -3201,7 +3219,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
	/* this can't race with mptcp_close(), as the msk is
	 * not yet exposted to user-space
	 */
	inet_sk_state_store(nsk, TCP_ESTABLISHED);
	mptcp_set_state(nsk, TCP_ESTABLISHED);

	/* The msk maintain a ref to each subflow in the connections list */
	WRITE_ONCE(msk->first, ssk);
@@ -3622,7 +3640,7 @@ static int mptcp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
	if (IS_ERR(ssk))
		return PTR_ERR(ssk);

	inet_sk_state_store(sk, TCP_SYN_SENT);
	mptcp_set_state(sk, TCP_SYN_SENT);
	subflow = mptcp_subflow_ctx(ssk);
#ifdef CONFIG_TCP_MD5SIG
	/* no MPTCP if MD5SIG is enabled on this socket or we may run out of
@@ -3672,7 +3690,7 @@ static int mptcp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
	if (unlikely(err)) {
		/* avoid leaving a dangling token in an unconnected socket */
		mptcp_token_destroy(msk);
		inet_sk_state_store(sk, TCP_CLOSE);
		mptcp_set_state(sk, TCP_CLOSE);
		return err;
	}

@@ -3761,13 +3779,13 @@ static int mptcp_listen(struct socket *sock, int backlog)
		goto unlock;
	}

	inet_sk_state_store(sk, TCP_LISTEN);
	mptcp_set_state(sk, TCP_LISTEN);
	sock_set_flag(sk, SOCK_RCU_FREE);

	lock_sock(ssk);
	err = __inet_listen_sk(ssk, backlog);
	release_sock(ssk);
	inet_sk_state_store(sk, inet_sk_state_load(ssk));
	mptcp_set_state(sk, inet_sk_state_load(ssk));

	if (!err) {
		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
@@ -3845,7 +3863,7 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock,
			__mptcp_close_ssk(newsk, msk->first,
					  mptcp_subflow_ctx(msk->first), 0);
			if (unlikely(list_is_singular(&msk->conn_list)))
				inet_sk_state_store(newsk, TCP_CLOSE);
				mptcp_set_state(newsk, TCP_CLOSE);
		}
	} else {
		MPTCP_INC_STATS(sock_net(ssk),
+1 −0
Original line number Diff line number Diff line
@@ -641,6 +641,7 @@ bool __mptcp_close(struct sock *sk, long timeout);
void mptcp_cancel_work(struct sock *sk);
void __mptcp_unaccepted_force_close(struct sock *sk);
void mptcp_set_owner_r(struct sk_buff *skb, struct sock *sk);
void mptcp_set_state(struct sock *sk, int state);

bool mptcp_addresses_equal(const struct mptcp_addr_info *a,
			   const struct mptcp_addr_info *b, bool use_port);
Loading