Commit 90141edc authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mptcp-fixes'



Mat Martineau says:

====================
mptcp: Fix address advertisement races and stabilize tests

Patches 1, 2, and 7 modify two self tests to give consistent, accurate
results by fixing timing issues and accounting for syncookie behavior.

Paches 3-6 fix two races in overlapping address advertisement send and
receive. Associated self tests are updated, including addition of two
MIBs to enable testing and tracking dropped address events.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3a14d088 e35f885b
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -35,12 +35,14 @@ static const struct snmp_mib mptcp_snmp_list[] = {
	SNMP_MIB_ITEM("AddAddr", MPTCP_MIB_ADDADDR),
	SNMP_MIB_ITEM("AddAddr", MPTCP_MIB_ADDADDR),
	SNMP_MIB_ITEM("EchoAdd", MPTCP_MIB_ECHOADD),
	SNMP_MIB_ITEM("EchoAdd", MPTCP_MIB_ECHOADD),
	SNMP_MIB_ITEM("PortAdd", MPTCP_MIB_PORTADD),
	SNMP_MIB_ITEM("PortAdd", MPTCP_MIB_PORTADD),
	SNMP_MIB_ITEM("AddAddrDrop", MPTCP_MIB_ADDADDRDROP),
	SNMP_MIB_ITEM("MPJoinPortSynRx", MPTCP_MIB_JOINPORTSYNRX),
	SNMP_MIB_ITEM("MPJoinPortSynRx", MPTCP_MIB_JOINPORTSYNRX),
	SNMP_MIB_ITEM("MPJoinPortSynAckRx", MPTCP_MIB_JOINPORTSYNACKRX),
	SNMP_MIB_ITEM("MPJoinPortSynAckRx", MPTCP_MIB_JOINPORTSYNACKRX),
	SNMP_MIB_ITEM("MPJoinPortAckRx", MPTCP_MIB_JOINPORTACKRX),
	SNMP_MIB_ITEM("MPJoinPortAckRx", MPTCP_MIB_JOINPORTACKRX),
	SNMP_MIB_ITEM("MismatchPortSynRx", MPTCP_MIB_MISMATCHPORTSYNRX),
	SNMP_MIB_ITEM("MismatchPortSynRx", MPTCP_MIB_MISMATCHPORTSYNRX),
	SNMP_MIB_ITEM("MismatchPortAckRx", MPTCP_MIB_MISMATCHPORTACKRX),
	SNMP_MIB_ITEM("MismatchPortAckRx", MPTCP_MIB_MISMATCHPORTACKRX),
	SNMP_MIB_ITEM("RmAddr", MPTCP_MIB_RMADDR),
	SNMP_MIB_ITEM("RmAddr", MPTCP_MIB_RMADDR),
	SNMP_MIB_ITEM("RmAddrDrop", MPTCP_MIB_RMADDRDROP),
	SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW),
	SNMP_MIB_ITEM("RmSubflow", MPTCP_MIB_RMSUBFLOW),
	SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX),
	SNMP_MIB_ITEM("MPPrioTx", MPTCP_MIB_MPPRIOTX),
	SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX),
	SNMP_MIB_ITEM("MPPrioRx", MPTCP_MIB_MPPRIORX),
+2 −0
Original line number Original line Diff line number Diff line
@@ -28,12 +28,14 @@ enum linux_mptcp_mib_field {
	MPTCP_MIB_ADDADDR,		/* Received ADD_ADDR with echo-flag=0 */
	MPTCP_MIB_ADDADDR,		/* Received ADD_ADDR with echo-flag=0 */
	MPTCP_MIB_ECHOADD,		/* Received ADD_ADDR with echo-flag=1 */
	MPTCP_MIB_ECHOADD,		/* Received ADD_ADDR with echo-flag=1 */
	MPTCP_MIB_PORTADD,		/* Received ADD_ADDR with a port-number */
	MPTCP_MIB_PORTADD,		/* Received ADD_ADDR with a port-number */
	MPTCP_MIB_ADDADDRDROP,		/* Dropped incoming ADD_ADDR */
	MPTCP_MIB_JOINPORTSYNRX,	/* Received a SYN MP_JOIN with a different port-number */
	MPTCP_MIB_JOINPORTSYNRX,	/* Received a SYN MP_JOIN with a different port-number */
	MPTCP_MIB_JOINPORTSYNACKRX,	/* Received a SYNACK MP_JOIN with a different port-number */
	MPTCP_MIB_JOINPORTSYNACKRX,	/* Received a SYNACK MP_JOIN with a different port-number */
	MPTCP_MIB_JOINPORTACKRX,	/* Received an ACK MP_JOIN with a different port-number */
	MPTCP_MIB_JOINPORTACKRX,	/* Received an ACK MP_JOIN with a different port-number */
	MPTCP_MIB_MISMATCHPORTSYNRX,	/* Received a SYN MP_JOIN with a mismatched port-number */
	MPTCP_MIB_MISMATCHPORTSYNRX,	/* Received a SYN MP_JOIN with a mismatched port-number */
	MPTCP_MIB_MISMATCHPORTACKRX,	/* Received an ACK MP_JOIN with a mismatched port-number */
	MPTCP_MIB_MISMATCHPORTACKRX,	/* Received an ACK MP_JOIN with a mismatched port-number */
	MPTCP_MIB_RMADDR,		/* Received RM_ADDR */
	MPTCP_MIB_RMADDR,		/* Received RM_ADDR */
	MPTCP_MIB_RMADDRDROP,		/* Dropped incoming RM_ADDR */
	MPTCP_MIB_RMSUBFLOW,		/* Remove a subflow */
	MPTCP_MIB_RMSUBFLOW,		/* Remove a subflow */
	MPTCP_MIB_MPPRIOTX,		/* Transmit a MP_PRIO */
	MPTCP_MIB_MPPRIOTX,		/* Transmit a MP_PRIO */
	MPTCP_MIB_MPPRIORX,		/* Received a MP_PRIO */
	MPTCP_MIB_MPPRIORX,		/* Received a MP_PRIO */
+6 −2
Original line number Original line Diff line number Diff line
@@ -213,6 +213,8 @@ void mptcp_pm_add_addr_received(struct mptcp_sock *msk,
		mptcp_pm_add_addr_send_ack(msk);
		mptcp_pm_add_addr_send_ack(msk);
	} else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED)) {
	} else if (mptcp_pm_schedule_work(msk, MPTCP_PM_ADD_ADDR_RECEIVED)) {
		pm->remote = *addr;
		pm->remote = *addr;
	} else {
		__MPTCP_INC_STATS(sock_net((struct sock *)msk), MPTCP_MIB_ADDADDRDROP);
	}
	}


	spin_unlock_bh(&pm->lock);
	spin_unlock_bh(&pm->lock);
@@ -253,8 +255,10 @@ void mptcp_pm_rm_addr_received(struct mptcp_sock *msk,
		mptcp_event_addr_removed(msk, rm_list->ids[i]);
		mptcp_event_addr_removed(msk, rm_list->ids[i]);


	spin_lock_bh(&pm->lock);
	spin_lock_bh(&pm->lock);
	mptcp_pm_schedule_work(msk, MPTCP_PM_RM_ADDR_RECEIVED);
	if (mptcp_pm_schedule_work(msk, MPTCP_PM_RM_ADDR_RECEIVED))
		pm->rm_list_rx = *rm_list;
		pm->rm_list_rx = *rm_list;
	else
		__MPTCP_INC_STATS(sock_net((struct sock *)msk), MPTCP_MIB_RMADDRDROP);
	spin_unlock_bh(&pm->lock);
	spin_unlock_bh(&pm->lock);
}
}


+24 −5
Original line number Original line Diff line number Diff line
@@ -546,6 +546,16 @@ static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
	if (msk->pm.add_addr_signaled < add_addr_signal_max) {
	if (msk->pm.add_addr_signaled < add_addr_signal_max) {
		local = select_signal_address(pernet, msk);
		local = select_signal_address(pernet, msk);


		/* due to racing events on both ends we can reach here while
		 * previous add address is still running: if we invoke now
		 * mptcp_pm_announce_addr(), that will fail and the
		 * corresponding id will be marked as used.
		 * Instead let the PM machinery reschedule us when the
		 * current address announce will be completed.
		 */
		if (msk->pm.addr_signal & BIT(MPTCP_ADD_ADDR_SIGNAL))
			return;

		if (local) {
		if (local) {
			if (mptcp_pm_alloc_anno_list(msk, local)) {
			if (mptcp_pm_alloc_anno_list(msk, local)) {
				__clear_bit(local->addr.id, msk->pm.id_avail_bitmap);
				__clear_bit(local->addr.id, msk->pm.id_avail_bitmap);
@@ -650,6 +660,7 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
	unsigned int add_addr_accept_max;
	unsigned int add_addr_accept_max;
	struct mptcp_addr_info remote;
	struct mptcp_addr_info remote;
	unsigned int subflows_max;
	unsigned int subflows_max;
	bool reset_port = false;
	int i, nr;
	int i, nr;


	add_addr_accept_max = mptcp_pm_get_add_addr_accept_max(msk);
	add_addr_accept_max = mptcp_pm_get_add_addr_accept_max(msk);
@@ -659,15 +670,19 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
		 msk->pm.add_addr_accepted, add_addr_accept_max,
		 msk->pm.add_addr_accepted, add_addr_accept_max,
		 msk->pm.remote.family);
		 msk->pm.remote.family);


	if (lookup_subflow_by_daddr(&msk->conn_list, &msk->pm.remote))
	remote = msk->pm.remote;
	if (lookup_subflow_by_daddr(&msk->conn_list, &remote))
		goto add_addr_echo;
		goto add_addr_echo;


	/* pick id 0 port, if none is provided the remote address */
	if (!remote.port) {
		reset_port = true;
		remote.port = sk->sk_dport;
	}

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


	msk->pm.add_addr_accepted++;
	msk->pm.add_addr_accepted++;
@@ -680,8 +695,12 @@ static void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
		__mptcp_subflow_connect(sk, &addrs[i], &remote);
		__mptcp_subflow_connect(sk, &addrs[i], &remote);
	spin_lock_bh(&msk->pm.lock);
	spin_lock_bh(&msk->pm.lock);


	/* be sure to echo exactly the received address */
	if (reset_port)
		remote.port = 0;

add_addr_echo:
add_addr_echo:
	mptcp_pm_announce_addr(msk, &msk->pm.remote, true);
	mptcp_pm_announce_addr(msk, &remote, true);
	mptcp_pm_nl_addr_send_ack(msk);
	mptcp_pm_nl_addr_send_ack(msk);
}
}


+37 −7
Original line number Original line Diff line number Diff line
@@ -71,6 +71,36 @@ chk_msk_remote_key_nr()
		__chk_nr "grep -c remote_key" $*
		__chk_nr "grep -c remote_key" $*
}
}


# $1: ns, $2: port
wait_local_port_listen()
{
	local listener_ns="${1}"
	local port="${2}"

	local port_hex i

	port_hex="$(printf "%04X" "${port}")"
	for i in $(seq 10); do
		ip netns exec "${listener_ns}" cat /proc/net/tcp | \
			awk "BEGIN {rc=1} {if (\$2 ~ /:${port_hex}\$/ && \$4 ~ /0A/) {rc=0; exit}} END {exit rc}" &&
			break
		sleep 0.1
	done
}

wait_connected()
{
	local listener_ns="${1}"
	local port="${2}"

	local port_hex i

	port_hex="$(printf "%04X" "${port}")"
	for i in $(seq 10); do
		ip netns exec ${listener_ns} grep -q " 0100007F:${port_hex} " /proc/net/tcp && break
		sleep 0.1
	done
}


trap cleanup EXIT
trap cleanup EXIT
ip netns add $ns
ip netns add $ns
@@ -81,15 +111,15 @@ echo "a" | \
		ip netns exec $ns \
		ip netns exec $ns \
			./mptcp_connect -p 10000 -l -t ${timeout_poll} \
			./mptcp_connect -p 10000 -l -t ${timeout_poll} \
				0.0.0.0 >/dev/null &
				0.0.0.0 >/dev/null &
sleep 0.1
wait_local_port_listen $ns 10000
chk_msk_nr 0 "no msk on netns creation"
chk_msk_nr 0 "no msk on netns creation"


echo "b" | \
echo "b" | \
	timeout ${timeout_test} \
	timeout ${timeout_test} \
		ip netns exec $ns \
		ip netns exec $ns \
			./mptcp_connect -p 10000 -j -t ${timeout_poll} \
			./mptcp_connect -p 10000 -r 0 -t ${timeout_poll} \
				127.0.0.1 >/dev/null &
				127.0.0.1 >/dev/null &
sleep 0.1
wait_connected $ns 10000
chk_msk_nr 2 "after MPC handshake "
chk_msk_nr 2 "after MPC handshake "
chk_msk_remote_key_nr 2 "....chk remote_key"
chk_msk_remote_key_nr 2 "....chk remote_key"
chk_msk_fallback_nr 0 "....chk no fallback"
chk_msk_fallback_nr 0 "....chk no fallback"
@@ -101,13 +131,13 @@ echo "a" | \
		ip netns exec $ns \
		ip netns exec $ns \
			./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} \
			./mptcp_connect -p 10001 -l -s TCP -t ${timeout_poll} \
				0.0.0.0 >/dev/null &
				0.0.0.0 >/dev/null &
sleep 0.1
wait_local_port_listen $ns 10001
echo "b" | \
echo "b" | \
	timeout ${timeout_test} \
	timeout ${timeout_test} \
		ip netns exec $ns \
		ip netns exec $ns \
			./mptcp_connect -p 10001 -j -t ${timeout_poll} \
			./mptcp_connect -p 10001 -r 0 -t ${timeout_poll} \
				127.0.0.1 >/dev/null &
				127.0.0.1 >/dev/null &
sleep 0.1
wait_connected $ns 10001
chk_msk_fallback_nr 1 "check fallback"
chk_msk_fallback_nr 1 "check fallback"
flush_pids
flush_pids


@@ -119,7 +149,7 @@ for I in `seq 1 $NR_CLIENTS`; do
				./mptcp_connect -p $((I+10001)) -l -w 10 \
				./mptcp_connect -p $((I+10001)) -l -w 10 \
					-t ${timeout_poll} 0.0.0.0 >/dev/null &
					-t ${timeout_poll} 0.0.0.0 >/dev/null &
done
done
sleep 0.1
wait_local_port_listen $ns $((NR_CLIENTS + 10001))


for I in `seq 1 $NR_CLIENTS`; do
for I in `seq 1 $NR_CLIENTS`; do
	echo "b" | \
	echo "b" | \
Loading