userspace_pm.sh 30.1 KB
Newer Older
1 2 3
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0

4 5 6
. "$(dirname "${0}")/mptcp_lib.sh"

mptcp_lib_check_mptcp
7
mptcp_lib_check_kallsyms
8

9 10 11 12 13
if ! mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
	echo "userspace pm tests are not supported by the kernel: SKIP"
	exit ${KSFT_SKIP}
fi

14 15 16
ip -Version > /dev/null 2>&1
if [ $? -ne 0 ];then
	echo "SKIP: Cannot not run test without ip tool"
17
	exit ${KSFT_SKIP}
18 19 20 21 22 23
fi

ANNOUNCED=6        # MPTCP_EVENT_ANNOUNCED
REMOVED=7          # MPTCP_EVENT_REMOVED
SUB_ESTABLISHED=10 # MPTCP_EVENT_SUB_ESTABLISHED
SUB_CLOSED=11      # MPTCP_EVENT_SUB_CLOSED
24 25
LISTENER_CREATED=15 #MPTCP_EVENT_LISTENER_CREATED
LISTENER_CLOSED=16  #MPTCP_EVENT_LISTENER_CLOSED
26 27 28 29

AF_INET=2
AF_INET6=10

30 31 32 33 34
file=""
server_evts=""
client_evts=""
server_evts_pid=0
client_evts_pid=0
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
client4_pid=0
server4_pid=0
client6_pid=0
server6_pid=0
client4_token=""
server4_token=""
client6_token=""
server6_token=""
client4_port=0;
client6_port=0;
app4_port=50002
new4_port=50003
app6_port=50004
client_addr_id=${RANDOM:0:2}
server_addr_id=${RANDOM:0:2}

sec=$(date +%s)
52
rndh=$(printf %x "$sec")-$(mktemp -u XXXXXX)
53 54 55
ns1="ns1-$rndh"
ns2="ns2-$rndh"

56 57 58 59 60
print_title()
{
	stdbuf -o0 -e0 printf "INFO: %s\n" "${1}"
}

61 62
kill_wait()
{
63 64 65
	[ $1 -eq 0 ] && return 0

	kill -SIGUSR1 $1 > /dev/null 2>&1
66 67 68 69
	kill $1 > /dev/null 2>&1
	wait $1 2>/dev/null
}

70 71
cleanup()
{
72
	print_title "Cleanup"
73 74

	# Terminate the MPTCP connection and related processes
75 76 77 78 79 80 81
	local pid
	for pid in $client4_pid $server4_pid $client6_pid $server6_pid\
		   $server_evts_pid $client_evts_pid
	do
		kill_wait $pid
	done

82 83 84 85
	local netns
	for netns in "$ns1" "$ns2" ;do
		ip netns del "$netns"
	done
86

87 88
	rm -rf $file $client_evts $server_evts

89
	stdbuf -o0 -e0 printf "Done\n"
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
}

trap cleanup EXIT

# Create and configure network namespaces for testing
for i in "$ns1" "$ns2" ;do
	ip netns add "$i" || exit 1
	ip -net "$i" link set lo up
	ip netns exec "$i" sysctl -q net.mptcp.enabled=1
	ip netns exec "$i" sysctl -q net.mptcp.pm_type=1
done

#  "$ns1"              ns2
#     ns1eth2    ns2eth1

ip link add ns1eth2 netns "$ns1" type veth peer name ns2eth1 netns "$ns2"

# Add IPv4/v6 addresses to the namespaces
ip -net "$ns1" addr add 10.0.1.1/24 dev ns1eth2
ip -net "$ns1" addr add 10.0.2.1/24 dev ns1eth2
ip -net "$ns1" addr add dead:beef:1::1/64 dev ns1eth2 nodad
ip -net "$ns1" addr add dead:beef:2::1/64 dev ns1eth2 nodad
ip -net "$ns1" link set ns1eth2 up

ip -net "$ns2" addr add 10.0.1.2/24 dev ns2eth1
ip -net "$ns2" addr add 10.0.2.2/24 dev ns2eth1
ip -net "$ns2" addr add dead:beef:1::2/64 dev ns2eth1 nodad
ip -net "$ns2" addr add dead:beef:2::2/64 dev ns2eth1 nodad
ip -net "$ns2" link set ns2eth1 up

120
print_title "Init"
121 122 123 124 125 126 127 128 129 130 131 132 133 134
stdbuf -o0 -e0 printf "Created network namespaces ns1, ns2         \t\t\t[OK]\n"

make_file()
{
	# Store a chunk of data in a file to transmit over an MPTCP connection
	local name=$1
	local ksize=1

	dd if=/dev/urandom of="$name" bs=2 count=$ksize 2> /dev/null
	echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name"
}

make_connection()
{
135 136 137
	if [ -z "$file" ]; then
		file=$(mktemp)
	fi
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
	make_file "$file" "client"

	local is_v6=$1
	local app_port=$app4_port
	local connect_addr="10.0.1.1"
	local listen_addr="0.0.0.0"
	if [ "$is_v6" = "v6" ]
	then
		connect_addr="dead:beef:1::1"
		listen_addr="::"
		app_port=$app6_port
	else
		is_v6="v4"
	fi

	# Capture netlink events over the two network namespaces running
	# the MPTCP client and server
155 156 157
	if [ -z "$client_evts" ]; then
		client_evts=$(mktemp)
	fi
158
	:>"$client_evts"
159 160 161
	if [ $client_evts_pid -ne 0 ]; then
		kill_wait $client_evts_pid
	fi
162
	ip netns exec "$ns2" ./pm_nl_ctl events >> "$client_evts" 2>&1 &
163 164 165 166
	client_evts_pid=$!
	if [ -z "$server_evts" ]; then
		server_evts=$(mktemp)
	fi
167
	:>"$server_evts"
168 169 170
	if [ $server_evts_pid -ne 0 ]; then
		kill_wait $server_evts_pid
	fi
171
	ip netns exec "$ns1" ./pm_nl_ctl events >> "$server_evts" 2>&1 &
172
	server_evts_pid=$!
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	sleep 0.5

	# Run the server
	ip netns exec "$ns1" \
	   ./mptcp_connect -s MPTCP -w 300 -p $app_port -l $listen_addr > /dev/null 2>&1 &
	local server_pid=$!
	sleep 0.5

	# Run the client, transfer $file and stay connected to the server
	# to conduct tests
	ip netns exec "$ns2" \
	   ./mptcp_connect -s MPTCP -w 300 -m sendfile -p $app_port $connect_addr\
	   2>&1 > /dev/null < "$file" &
	local client_pid=$!
	sleep 1

	# Capture client/server attributes from MPTCP connection netlink events

	local client_token
	local client_port
	local client_serverside
	local server_token
	local server_serverside

	client_token=$(sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts")
	client_port=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts")
	client_serverside=$(sed --unbuffered -n 's/.*\(server_side:\)\([[:digit:]]*\).*$/\2/p;q'\
				      "$client_evts")
201 202 203 204
	server_token=$(grep "type:1," "$server_evts" |
		       sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q')
	server_serverside=$(grep "type:1," "$server_evts" |
			    sed --unbuffered -n 's/.*\(server_side:\)\([[:digit:]]*\).*$/\2/p;q')
205

206
	stdbuf -o0 -e0 printf "Established IP%s MPTCP Connection ns2 => ns1    \t\t" $is_v6
207 208 209
	if [ "$client_token" != "" ] && [ "$server_token" != "" ] && [ "$client_serverside" = 0 ] &&
		   [ "$server_serverside" = 1 ]
	then
210
		stdbuf -o0 -e0 printf "[OK]\n"
211
	else
212 213 214 215
		stdbuf -o0 -e0 printf "[FAIL]\n"
		stdbuf -o0 -e0 printf "\tExpected tokens (c:%s - s:%s) and server (c:%d - s:%d)\n" \
			"${client_token}" "${server_token}" \
			"${client_serverside}" "${server_serverside}"
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
		exit 1
	fi

	if [ "$is_v6" = "v6" ]
	then
		client6_token=$client_token
		server6_token=$server_token
		client6_port=$client_port
		client6_pid=$client_pid
		server6_pid=$server_pid
	else
		client4_token=$client_token
		server4_token=$server_token
		client4_port=$client_port
		client4_pid=$client_pid
		server4_pid=$server_pid
	fi
}

235
# $1: var name ; $2: prev ret
236 237 238 239
check_expected_one()
{
	local var="${1}"
	local exp="e_${var}"
240
	local prev_ret="${2}"
241

242 243 244 245 246 247 248 249 250 251 252
	if [ "${!var}" = "${!exp}" ]
	then
		return 0
	fi

	if [ "${prev_ret}" = "0" ]
	then
		stdbuf -o0 -e0 printf "[FAIL]\n"
	fi

	stdbuf -o0 -e0 printf "\tExpected value for '%s': '%s', got '%s'.\n" \
253
		"${var}" "${!exp}" "${!var}"
254
	return 1
255 256 257 258 259 260 261 262 263 264
}

# $@: all var names to check
check_expected()
{
	local ret=0
	local var

	for var in "${@}"
	do
265
		check_expected_one "${var}" "${ret}" || ret=1
266 267 268 269 270 271 272 273 274 275 276
	done

	if [ ${ret} -eq 0 ]
	then
		stdbuf -o0 -e0 printf "[OK]\n"
		return 0
	fi

	exit 1
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
verify_announce_event()
{
	local evt=$1
	local e_type=$2
	local e_token=$3
	local e_addr=$4
	local e_id=$5
	local e_dport=$6
	local e_af=$7
	local type
	local token
	local addr
	local dport
	local id

	type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	token=$(sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	if [ "$e_af" = "v6" ]
	then
		addr=$(sed --unbuffered -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q' "$evt")
	else
		addr=$(sed --unbuffered -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evt")
	fi
	dport=$(sed --unbuffered -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	id=$(sed --unbuffered -n 's/.*\(rem_id:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
302 303

	check_expected "type" "token" "addr" "dport" "id"
304 305 306 307
}

test_announce()
{
308 309
	print_title "Announce tests"

310
	# Capture events on the network namespace running the server
311
	:>"$server_evts"
312 313 314 315 316 317 318

	# ADD_ADDR using an invalid token should result in no action
	local invalid_token=$(( client4_token - 1))
	ip netns exec "$ns2" ./pm_nl_ctl ann 10.0.2.2 token $invalid_token id\
	   $client_addr_id dev ns2eth1 > /dev/null 2>&1

	local type
319
	type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts")
320 321 322 323 324
	stdbuf -o0 -e0 printf "ADD_ADDR 10.0.2.2 (ns2) => ns1, invalid token    \t\t"
	if [ "$type" = "" ]
	then
		stdbuf -o0 -e0 printf "[OK]\n"
	else
325
		stdbuf -o0 -e0 printf "[FAIL]\n\ttype defined: %s\n" "${type}"
326 327 328 329
		exit 1
	fi

	# ADD_ADDR from the client to server machine reusing the subflow port
330
	:>"$server_evts"
331 332 333 334 335
	ip netns exec "$ns2"\
	   ./pm_nl_ctl ann 10.0.2.2 token "$client4_token" id $client_addr_id dev\
	   ns2eth1 > /dev/null 2>&1
	stdbuf -o0 -e0 printf "ADD_ADDR id:%d 10.0.2.2 (ns2) => ns1, reuse port \t\t" $client_addr_id
	sleep 0.5
336
	verify_announce_event $server_evts $ANNOUNCED $server4_token "10.0.2.2" $client_addr_id \
337 338 339
			      "$client4_port"

	# ADD_ADDR6 from the client to server machine reusing the subflow port
340
	:>"$server_evts"
341 342 343 344
	ip netns exec "$ns2" ./pm_nl_ctl ann\
	   dead:beef:2::2 token "$client6_token" id $client_addr_id dev ns2eth1 > /dev/null 2>&1
	stdbuf -o0 -e0 printf "ADD_ADDR6 id:%d dead:beef:2::2 (ns2) => ns1, reuse port\t\t" $client_addr_id
	sleep 0.5
345
	verify_announce_event "$server_evts" "$ANNOUNCED" "$server6_token" "dead:beef:2::2"\
346 347 348
			      "$client_addr_id" "$client6_port" "v6"

	# ADD_ADDR from the client to server machine using a new port
349
	:>"$server_evts"
350 351 352 353 354
	client_addr_id=$((client_addr_id+1))
	ip netns exec "$ns2" ./pm_nl_ctl ann 10.0.2.2 token "$client4_token" id\
	   $client_addr_id dev ns2eth1 port $new4_port > /dev/null 2>&1
	stdbuf -o0 -e0 printf "ADD_ADDR id:%d 10.0.2.2 (ns2) => ns1, new port \t\t\t" $client_addr_id
	sleep 0.5
355
	verify_announce_event "$server_evts" "$ANNOUNCED" "$server4_token" "10.0.2.2"\
356 357 358
			      "$client_addr_id" "$new4_port"

	# Capture events on the network namespace running the client
359
	:>"$client_evts"
360 361 362 363 364 365

	# ADD_ADDR from the server to client machine reusing the subflow port
	ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server4_token" id\
	   $server_addr_id dev ns1eth2 > /dev/null 2>&1
	stdbuf -o0 -e0 printf "ADD_ADDR id:%d 10.0.2.1 (ns1) => ns2, reuse port \t\t" $server_addr_id
	sleep 0.5
366
	verify_announce_event "$client_evts" "$ANNOUNCED" "$client4_token" "10.0.2.1"\
367 368 369
			      "$server_addr_id" "$app4_port"

	# ADD_ADDR6 from the server to client machine reusing the subflow port
370
	:>"$client_evts"
371 372 373 374
	ip netns exec "$ns1" ./pm_nl_ctl ann dead:beef:2::1 token "$server6_token" id\
	   $server_addr_id dev ns1eth2 > /dev/null 2>&1
	stdbuf -o0 -e0 printf "ADD_ADDR6 id:%d dead:beef:2::1 (ns1) => ns2, reuse port\t\t" $server_addr_id
	sleep 0.5
375
	verify_announce_event "$client_evts" "$ANNOUNCED" "$client6_token" "dead:beef:2::1"\
376 377 378
			      "$server_addr_id" "$app6_port" "v6"

	# ADD_ADDR from the server to client machine using a new port
379
	:>"$client_evts"
380 381 382 383 384
	server_addr_id=$((server_addr_id+1))
	ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server4_token" id\
	   $server_addr_id dev ns1eth2 port $new4_port > /dev/null 2>&1
	stdbuf -o0 -e0 printf "ADD_ADDR id:%d 10.0.2.1 (ns1) => ns2, new port \t\t\t" $server_addr_id
	sleep 0.5
385
	verify_announce_event "$client_evts" "$ANNOUNCED" "$client4_token" "10.0.2.1"\
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
			      "$server_addr_id" "$new4_port"
}

verify_remove_event()
{
	local evt=$1
	local e_type=$2
	local e_token=$3
	local e_id=$4
	local type
	local token
	local id

	type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	token=$(sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	id=$(sed --unbuffered -n 's/.*\(rem_id:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
402 403

	check_expected "type" "token" "id"
404 405 406 407
}

test_remove()
{
408 409
	print_title "Remove tests"

410
	# Capture events on the network namespace running the server
411
	:>"$server_evts"
412 413 414 415 416 417 418 419

	# RM_ADDR using an invalid token should result in no action
	local invalid_token=$(( client4_token - 1 ))
	ip netns exec "$ns2" ./pm_nl_ctl rem token $invalid_token id\
	   $client_addr_id > /dev/null 2>&1
	stdbuf -o0 -e0 printf "RM_ADDR id:%d ns2 => ns1, invalid token                    \t"\
	       $client_addr_id
	local type
420
	type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts")
421 422 423 424 425 426 427 428 429 430 431 432 433
	if [ "$type" = "" ]
	then
		stdbuf -o0 -e0 printf "[OK]\n"
	else
		stdbuf -o0 -e0 printf "[FAIL]\n"
	fi

	# RM_ADDR using an invalid addr id should result in no action
	local invalid_id=$(( client_addr_id + 1 ))
	ip netns exec "$ns2" ./pm_nl_ctl rem token "$client4_token" id\
	   $invalid_id > /dev/null 2>&1
	stdbuf -o0 -e0 printf "RM_ADDR id:%d ns2 => ns1, invalid id                    \t"\
	       $invalid_id
434
	type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts")
435 436 437 438 439 440 441 442
	if [ "$type" = "" ]
	then
		stdbuf -o0 -e0 printf "[OK]\n"
	else
		stdbuf -o0 -e0 printf "[FAIL]\n"
	fi

	# RM_ADDR from the client to server machine
443
	:>"$server_evts"
444 445 446 447 448
	ip netns exec "$ns2" ./pm_nl_ctl rem token "$client4_token" id\
	   $client_addr_id > /dev/null 2>&1
	stdbuf -o0 -e0 printf "RM_ADDR id:%d ns2 => ns1                                \t"\
	       $client_addr_id
	sleep 0.5
449
	verify_remove_event "$server_evts" "$REMOVED" "$server4_token" "$client_addr_id"
450 451

	# RM_ADDR from the client to server machine
452
	:>"$server_evts"
453 454 455 456 457 458
	client_addr_id=$(( client_addr_id - 1 ))
	ip netns exec "$ns2" ./pm_nl_ctl rem token "$client4_token" id\
	   $client_addr_id > /dev/null 2>&1
	stdbuf -o0 -e0 printf "RM_ADDR id:%d ns2 => ns1                                \t"\
	       $client_addr_id
	sleep 0.5
459
	verify_remove_event "$server_evts" "$REMOVED" "$server4_token" "$client_addr_id"
460 461

	# RM_ADDR6 from the client to server machine
462
	:>"$server_evts"
463 464 465 466 467
	ip netns exec "$ns2" ./pm_nl_ctl rem token "$client6_token" id\
	   $client_addr_id > /dev/null 2>&1
	stdbuf -o0 -e0 printf "RM_ADDR6 id:%d ns2 => ns1                               \t"\
	       $client_addr_id
	sleep 0.5
468
	verify_remove_event "$server_evts" "$REMOVED" "$server6_token" "$client_addr_id"
469 470

	# Capture events on the network namespace running the client
471
	:>"$client_evts"
472 473 474 475 476 477 478

	# RM_ADDR from the server to client machine
	ip netns exec "$ns1" ./pm_nl_ctl rem token "$server4_token" id\
	   $server_addr_id > /dev/null 2>&1
	stdbuf -o0 -e0 printf "RM_ADDR id:%d ns1 => ns2                                \t"\
	       $server_addr_id
	sleep 0.5
479
	verify_remove_event "$client_evts" "$REMOVED" "$client4_token" "$server_addr_id"
480 481

	# RM_ADDR from the server to client machine
482
	:>"$client_evts"
483 484 485 486 487
	server_addr_id=$(( server_addr_id - 1 ))
	ip netns exec "$ns1" ./pm_nl_ctl rem token "$server4_token" id\
	   $server_addr_id > /dev/null 2>&1
	stdbuf -o0 -e0 printf "RM_ADDR id:%d ns1 => ns2                                \t" $server_addr_id
	sleep 0.5
488
	verify_remove_event "$client_evts" "$REMOVED" "$client4_token" "$server_addr_id"
489 490

	# RM_ADDR6 from the server to client machine
491
	:>"$client_evts"
492 493 494 495
	ip netns exec "$ns1" ./pm_nl_ctl rem token "$server6_token" id\
	   $server_addr_id > /dev/null 2>&1
	stdbuf -o0 -e0 printf "RM_ADDR6 id:%d ns1 => ns2                               \t" $server_addr_id
	sleep 0.5
496
	verify_remove_event "$client_evts" "$REMOVED" "$client6_token" "$server_addr_id"
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
}

verify_subflow_events()
{
	local evt=$1
	local e_type=$2
	local e_token=$3
	local e_family=$4
	local e_saddr=$5
	local e_daddr=$6
	local e_dport=$7
	local e_locid=$8
	local e_remid=$9
	shift 2
	local e_from=$8
	local e_to=$9
	local type
	local token
	local family
	local saddr
	local daddr
	local dport
	local locid
	local remid

	if [ "$e_type" = "$SUB_ESTABLISHED" ]
	then
		if [ "$e_family" = "$AF_INET6" ]
		then
			stdbuf -o0 -e0 printf "CREATE_SUBFLOW6 %s (%s) => %s (%s)    "\
			       "$e_saddr" "$e_from" "$e_daddr" "$e_to"
		else
			stdbuf -o0 -e0 printf "CREATE_SUBFLOW %s (%s) => %s (%s)         \t"\
			       "$e_saddr" "$e_from" "$e_daddr" "$e_to"
		fi
	else
		if [ "$e_family" = "$AF_INET6" ]
		then
			stdbuf -o0 -e0 printf "DESTROY_SUBFLOW6 %s (%s) => %s (%s)   "\
			       "$e_saddr" "$e_from" "$e_daddr" "$e_to"
		else
			stdbuf -o0 -e0 printf "DESTROY_SUBFLOW %s (%s) => %s (%s)         \t"\
			       "$e_saddr" "$e_from" "$e_daddr" "$e_to"
		fi
	fi

	type=$(sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	token=$(sed --unbuffered -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	family=$(sed --unbuffered -n 's/.*\(family:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	dport=$(sed --unbuffered -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	locid=$(sed --unbuffered -n 's/.*\(loc_id:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	remid=$(sed --unbuffered -n 's/.*\(rem_id:\)\([[:digit:]]*\).*$/\2/p;q' "$evt")
	if [ "$family" = "$AF_INET6" ]
	then
		saddr=$(sed --unbuffered -n 's/.*\(saddr6:\)\([0-9a-f:.]*\).*$/\2/p;q' "$evt")
		daddr=$(sed --unbuffered -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q' "$evt")
	else
		saddr=$(sed --unbuffered -n 's/.*\(saddr4:\)\([0-9.]*\).*$/\2/p;q' "$evt")
		daddr=$(sed --unbuffered -n 's/.*\(daddr4:\)\([0-9.]*\).*$/\2/p;q' "$evt")
	fi

558
	check_expected "type" "token" "daddr" "dport" "family" "saddr" "locid" "remid"
559 560 561 562
}

test_subflows()
{
563 564
	print_title "Subflows v4 or v6 only tests"

565
	# Capture events on the network namespace running the server
566
	:>"$server_evts"
567 568 569 570 571 572 573 574 575 576 577 578

	# Attempt to add a listener at 10.0.2.2:<subflow-port>
	ip netns exec "$ns2" ./pm_nl_ctl listen 10.0.2.2\
	   "$client4_port" > /dev/null 2>&1 &
	local listener_pid=$!

	# ADD_ADDR from client to server machine reusing the subflow port
	ip netns exec "$ns2" ./pm_nl_ctl ann 10.0.2.2 token "$client4_token" id\
	   $client_addr_id > /dev/null 2>&1
	sleep 0.5

	# CREATE_SUBFLOW from server to client machine
579
	:>"$server_evts"
580 581 582
	ip netns exec "$ns1" ./pm_nl_ctl csf lip 10.0.2.1 lid 23 rip 10.0.2.2\
	   rport "$client4_port" token "$server4_token" > /dev/null 2>&1
	sleep 0.5
583
	verify_subflow_events $server_evts $SUB_ESTABLISHED $server4_token $AF_INET "10.0.2.1" \
584 585 586
			      "10.0.2.2" "$client4_port" "23" "$client_addr_id" "ns1" "ns2"

	# Delete the listener from the client ns, if one was created
587
	kill_wait $listener_pid
588 589

	local sport
590
	sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts")
591 592

	# DESTROY_SUBFLOW from server to client machine
593
	:>"$server_evts"
594 595 596
	ip netns exec "$ns1" ./pm_nl_ctl dsf lip 10.0.2.1 lport "$sport" rip 10.0.2.2 rport\
	   "$client4_port" token "$server4_token" > /dev/null 2>&1
	sleep 0.5
597
	verify_subflow_events "$server_evts" "$SUB_CLOSED" "$server4_token" "$AF_INET" "10.0.2.1"\
598 599 600 601 602 603 604 605 606 607 608 609 610
			      "10.0.2.2" "$client4_port" "23" "$client_addr_id" "ns1" "ns2"

	# RM_ADDR from client to server machine
	ip netns exec "$ns2" ./pm_nl_ctl rem id $client_addr_id token\
	   "$client4_token" > /dev/null 2>&1
	sleep 0.5

	# Attempt to add a listener at dead:beef:2::2:<subflow-port>
	ip netns exec "$ns2" ./pm_nl_ctl listen dead:beef:2::2\
	   "$client6_port" > /dev/null 2>&1 &
	listener_pid=$!

	# ADD_ADDR6 from client to server machine reusing the subflow port
611
	:>"$server_evts"
612 613 614 615 616
	ip netns exec "$ns2" ./pm_nl_ctl ann dead:beef:2::2 token "$client6_token" id\
	   $client_addr_id > /dev/null 2>&1
	sleep 0.5

	# CREATE_SUBFLOW6 from server to client machine
617
	:>"$server_evts"
618 619 620
	ip netns exec "$ns1" ./pm_nl_ctl csf lip dead:beef:2::1 lid 23 rip\
	   dead:beef:2::2 rport "$client6_port" token "$server6_token" > /dev/null 2>&1
	sleep 0.5
621
	verify_subflow_events "$server_evts" "$SUB_ESTABLISHED" "$server6_token" "$AF_INET6"\
622 623 624 625
			      "dead:beef:2::1" "dead:beef:2::2" "$client6_port" "23"\
			      "$client_addr_id" "ns1" "ns2"

	# Delete the listener from the client ns, if one was created
626
	kill_wait $listener_pid
627

628
	sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts")
629 630

	# DESTROY_SUBFLOW6 from server to client machine
631
	:>"$server_evts"
632 633 634
	ip netns exec "$ns1" ./pm_nl_ctl dsf lip dead:beef:2::1 lport "$sport" rip\
	   dead:beef:2::2 rport "$client6_port" token "$server6_token" > /dev/null 2>&1
	sleep 0.5
635
	verify_subflow_events "$server_evts" "$SUB_CLOSED" "$server6_token" "$AF_INET6"\
636 637 638 639 640 641 642 643 644 645 646 647 648 649
			      "dead:beef:2::1" "dead:beef:2::2" "$client6_port" "23"\
			      "$client_addr_id" "ns1" "ns2"

	# RM_ADDR from client to server machine
	ip netns exec "$ns2" ./pm_nl_ctl rem id $client_addr_id token\
	   "$client6_token" > /dev/null 2>&1
	sleep 0.5

	# Attempt to add a listener at 10.0.2.2:<new-port>
	ip netns exec "$ns2" ./pm_nl_ctl listen 10.0.2.2\
	   $new4_port > /dev/null 2>&1 &
	listener_pid=$!

	# ADD_ADDR from client to server machine using a new port
650
	:>"$server_evts"
651 652 653 654 655
	ip netns exec "$ns2" ./pm_nl_ctl ann 10.0.2.2 token "$client4_token" id\
	   $client_addr_id port $new4_port > /dev/null 2>&1
	sleep 0.5

	# CREATE_SUBFLOW from server to client machine
656
	:>"$server_evts"
657 658 659
	ip netns exec "$ns1" ./pm_nl_ctl csf lip 10.0.2.1 lid 23 rip 10.0.2.2 rport\
	   $new4_port token "$server4_token" > /dev/null 2>&1
	sleep 0.5
660
	verify_subflow_events "$server_evts" "$SUB_ESTABLISHED" "$server4_token" "$AF_INET"\
661 662 663 664
			      "10.0.2.1" "10.0.2.2" "$new4_port" "23"\
			      "$client_addr_id" "ns1" "ns2"

	# Delete the listener from the client ns, if one was created
665
	kill_wait $listener_pid
666

667
	sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$server_evts")
668 669

	# DESTROY_SUBFLOW from server to client machine
670
	:>"$server_evts"
671 672 673
	ip netns exec "$ns1" ./pm_nl_ctl dsf lip 10.0.2.1 lport "$sport" rip 10.0.2.2 rport\
	   $new4_port token "$server4_token" > /dev/null 2>&1
	sleep 0.5
674
	verify_subflow_events "$server_evts" "$SUB_CLOSED" "$server4_token" "$AF_INET" "10.0.2.1"\
675 676 677 678 679 680 681
			      "10.0.2.2" "$new4_port" "23" "$client_addr_id" "ns1" "ns2"

	# RM_ADDR from client to server machine
	ip netns exec "$ns2" ./pm_nl_ctl rem id $client_addr_id token\
	   "$client4_token" > /dev/null 2>&1

	# Capture events on the network namespace running the client
682
	:>"$client_evts"
683 684 685 686 687 688 689 690 691 692 693 694

	# Attempt to add a listener at 10.0.2.1:<subflow-port>
	ip netns exec "$ns1" ./pm_nl_ctl listen 10.0.2.1\
	   $app4_port > /dev/null 2>&1 &
	listener_pid=$!

	# ADD_ADDR from server to client machine reusing the subflow port
	ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server4_token" id\
	   $server_addr_id > /dev/null 2>&1
	sleep 0.5

	# CREATE_SUBFLOW from client to server machine
695
	:>"$client_evts"
696 697 698
	ip netns exec "$ns2" ./pm_nl_ctl csf lip 10.0.2.2 lid 23 rip 10.0.2.1 rport\
	   $app4_port token "$client4_token" > /dev/null 2>&1
	sleep 0.5
699
	verify_subflow_events $client_evts $SUB_ESTABLISHED $client4_token $AF_INET "10.0.2.2"\
700 701 702
			      "10.0.2.1" "$app4_port" "23" "$server_addr_id" "ns2" "ns1"

	# Delete the listener from the server ns, if one was created
703
	kill_wait $listener_pid
704

705
	sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts")
706 707

	# DESTROY_SUBFLOW from client to server machine
708
	:>"$client_evts"
709 710 711
	ip netns exec "$ns2" ./pm_nl_ctl dsf lip 10.0.2.2 lport "$sport" rip 10.0.2.1 rport\
	   $app4_port token "$client4_token" > /dev/null 2>&1
	sleep 0.5
712
	verify_subflow_events "$client_evts" "$SUB_CLOSED" "$client4_token" "$AF_INET" "10.0.2.2"\
713 714 715 716 717 718 719 720 721 722 723 724 725
			      "10.0.2.1" "$app4_port" "23" "$server_addr_id" "ns2" "ns1"

	# RM_ADDR from server to client machine
	ip netns exec "$ns1" ./pm_nl_ctl rem id $server_addr_id token\
	   "$server4_token" > /dev/null 2>&1
	sleep 0.5

	# Attempt to add a listener at dead:beef:2::1:<subflow-port>
	ip netns exec "$ns1" ./pm_nl_ctl listen dead:beef:2::1\
	   $app6_port > /dev/null 2>&1 &
	listener_pid=$!

	# ADD_ADDR6 from server to client machine reusing the subflow port
726
	:>"$client_evts"
727 728 729 730 731
	ip netns exec "$ns1" ./pm_nl_ctl ann dead:beef:2::1 token "$server6_token" id\
	   $server_addr_id > /dev/null 2>&1
	sleep 0.5

	# CREATE_SUBFLOW6 from client to server machine
732
	:>"$client_evts"
733 734 735
	ip netns exec "$ns2" ./pm_nl_ctl csf lip dead:beef:2::2 lid 23 rip\
	   dead:beef:2::1 rport $app6_port token "$client6_token" > /dev/null 2>&1
	sleep 0.5
736
	verify_subflow_events "$client_evts" "$SUB_ESTABLISHED" "$client6_token"\
737 738 739 740 741
			      "$AF_INET6" "dead:beef:2::2"\
			      "dead:beef:2::1" "$app6_port" "23"\
			      "$server_addr_id" "ns2" "ns1"

	# Delete the listener from the server ns, if one was created
742
	kill_wait $listener_pid
743

744
	sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts")
745 746

	# DESTROY_SUBFLOW6 from client to server machine
747
	:>"$client_evts"
748 749 750
	ip netns exec "$ns2" ./pm_nl_ctl dsf lip dead:beef:2::2 lport "$sport" rip\
	   dead:beef:2::1 rport $app6_port token "$client6_token" > /dev/null 2>&1
	sleep 0.5
751
	verify_subflow_events $client_evts $SUB_CLOSED $client6_token $AF_INET6 "dead:beef:2::2"\
752 753 754 755 756 757 758 759 760 761 762 763 764
			      "dead:beef:2::1" "$app6_port" "23" "$server_addr_id" "ns2" "ns1"

	# RM_ADDR6 from server to client machine
	ip netns exec "$ns1" ./pm_nl_ctl rem id $server_addr_id token\
	   "$server6_token" > /dev/null 2>&1
	sleep 0.5

	# Attempt to add a listener at 10.0.2.1:<new-port>
	ip netns exec "$ns1" ./pm_nl_ctl listen 10.0.2.1\
	   $new4_port > /dev/null 2>&1 &
	listener_pid=$!

	# ADD_ADDR from server to client machine using a new port
765
	:>"$client_evts"
766 767 768 769 770
	ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server4_token" id\
	   $server_addr_id port $new4_port > /dev/null 2>&1
	sleep 0.5

	# CREATE_SUBFLOW from client to server machine
771
	:>"$client_evts"
772 773 774
	ip netns exec "$ns2" ./pm_nl_ctl csf lip 10.0.2.2 lid 23 rip 10.0.2.1 rport\
	   $new4_port token "$client4_token" > /dev/null 2>&1
	sleep 0.5
775
	verify_subflow_events "$client_evts" "$SUB_ESTABLISHED" "$client4_token" "$AF_INET"\
776 777 778
			      "10.0.2.2" "10.0.2.1" "$new4_port" "23" "$server_addr_id" "ns2" "ns1"

	# Delete the listener from the server ns, if one was created
779
	kill_wait $listener_pid
780

781
	sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts")
782 783

	# DESTROY_SUBFLOW from client to server machine
784
	:>"$client_evts"
785 786 787
	ip netns exec "$ns2" ./pm_nl_ctl dsf lip 10.0.2.2 lport "$sport" rip 10.0.2.1 rport\
	   $new4_port token "$client4_token" > /dev/null 2>&1
	sleep 0.5
788
	verify_subflow_events "$client_evts" "$SUB_CLOSED" "$client4_token" "$AF_INET" "10.0.2.2"\
789 790 791 792 793 794 795
			      "10.0.2.1" "$new4_port" "23" "$server_addr_id" "ns2" "ns1"

	# RM_ADDR from server to client machine
	ip netns exec "$ns1" ./pm_nl_ctl rem id $server_addr_id token\
	   "$server4_token" > /dev/null 2>&1
}

796 797
test_subflows_v4_v6_mix()
{
798 799
	print_title "Subflows v4 and v6 mix tests"

800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
	# Attempt to add a listener at 10.0.2.1:<subflow-port>
	ip netns exec "$ns1" ./pm_nl_ctl listen 10.0.2.1\
	   $app6_port > /dev/null 2>&1 &
	local listener_pid=$!

	# ADD_ADDR4 from server to client machine reusing the subflow port on
	# the established v6 connection
	:>"$client_evts"
	ip netns exec "$ns1" ./pm_nl_ctl ann 10.0.2.1 token "$server6_token" id\
	   $server_addr_id dev ns1eth2 > /dev/null 2>&1
	stdbuf -o0 -e0 printf "ADD_ADDR4 id:%d 10.0.2.1 (ns1) => ns2, reuse port\t\t" $server_addr_id
	sleep 0.5
	verify_announce_event "$client_evts" "$ANNOUNCED" "$client6_token" "10.0.2.1"\
			      "$server_addr_id" "$app6_port"

	# CREATE_SUBFLOW from client to server machine
	:>"$client_evts"
	ip netns exec "$ns2" ./pm_nl_ctl csf lip 10.0.2.2 lid 23 rip 10.0.2.1 rport\
	   $app6_port token "$client6_token" > /dev/null 2>&1
	sleep 0.5
	verify_subflow_events "$client_evts" "$SUB_ESTABLISHED" "$client6_token"\
			      "$AF_INET" "10.0.2.2" "10.0.2.1" "$app6_port" "23"\
			      "$server_addr_id" "ns2" "ns1"

	# Delete the listener from the server ns, if one was created
	kill_wait $listener_pid

	sport=$(sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q' "$client_evts")

	# DESTROY_SUBFLOW from client to server machine
	:>"$client_evts"
	ip netns exec "$ns2" ./pm_nl_ctl dsf lip 10.0.2.2 lport "$sport" rip 10.0.2.1 rport\
	   $app6_port token "$client6_token" > /dev/null 2>&1
	sleep 0.5
	verify_subflow_events "$client_evts" "$SUB_CLOSED" "$client6_token" \
			      "$AF_INET" "10.0.2.2" "10.0.2.1" "$app6_port" "23"\
			      "$server_addr_id" "ns2" "ns1"

	# RM_ADDR from server to client machine
	ip netns exec "$ns1" ./pm_nl_ctl rem id $server_addr_id token\
	   "$server6_token" > /dev/null 2>&1
	sleep 0.5
}

844 845
test_prio()
{
846 847
	print_title "Prio tests"

848 849 850
	local count

	# Send MP_PRIO signal from client to server machine
851
	ip netns exec "$ns2" ./pm_nl_ctl set 10.0.1.2 port "$client4_port" flags backup token "$client4_token" rip 10.0.1.1 rport "$app4_port"
852 853 854 855 856 857 858
	sleep 0.5

	# Check TX
	stdbuf -o0 -e0 printf "MP_PRIO TX                                                 \t"
	count=$(ip netns exec "$ns2" nstat -as | grep MPTcpExtMPPrioTx | awk '{print $2}')
	[ -z "$count" ] && count=0
	if [ $count != 1 ]; then
859
		stdbuf -o0 -e0 printf "[FAIL]\n\tCount != 1: %d\n" "${count}"
860 861 862 863 864 865 866 867 868 869
		exit 1
	else
		stdbuf -o0 -e0 printf "[OK]\n"
	fi

	# Check RX
	stdbuf -o0 -e0 printf "MP_PRIO RX                                                 \t"
	count=$(ip netns exec "$ns1" nstat -as | grep MPTcpExtMPPrioRx | awk '{print $2}')
	[ -z "$count" ] && count=0
	if [ $count != 1 ]; then
870
		stdbuf -o0 -e0 printf "[FAIL]\n\tCount != 1: %d\n" "${count}"
871 872 873 874 875 876
		exit 1
	else
		stdbuf -o0 -e0 printf "[OK]\n"
	fi
}

877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910
verify_listener_events()
{
	local evt=$1
	local e_type=$2
	local e_family=$3
	local e_saddr=$4
	local e_sport=$5
	local type
	local family
	local saddr
	local sport

	if [ $e_type = $LISTENER_CREATED ]; then
		stdbuf -o0 -e0 printf "CREATE_LISTENER %s:%s\t\t\t\t\t"\
			$e_saddr $e_sport
	elif [ $e_type = $LISTENER_CLOSED ]; then
		stdbuf -o0 -e0 printf "CLOSE_LISTENER %s:%s\t\t\t\t\t"\
			$e_saddr $e_sport
	fi

	type=$(grep "type:$e_type," $evt |
	       sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q')
	family=$(grep "type:$e_type," $evt |
		 sed --unbuffered -n 's/.*\(family:\)\([[:digit:]]*\).*$/\2/p;q')
	sport=$(grep "type:$e_type," $evt |
		sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q')
	if [ $family ] && [ $family = $AF_INET6 ]; then
		saddr=$(grep "type:$e_type," $evt |
			sed --unbuffered -n 's/.*\(saddr6:\)\([0-9a-f:.]*\).*$/\2/p;q')
	else
		saddr=$(grep "type:$e_type," $evt |
			sed --unbuffered -n 's/.*\(saddr4:\)\([0-9.]*\).*$/\2/p;q')
	fi

911
	check_expected "type" "family" "saddr" "sport"
912 913 914 915
}

test_listener()
{
916 917
	print_title "Listener tests"

918 919 920 921 922
	if ! mptcp_lib_kallsyms_has "mptcp_event_pm_listener$"; then
		stdbuf -o0 -e0 printf "LISTENER events                                            \t[SKIP] Not supported\n"
		return
	fi

923 924 925 926 927 928 929 930
	# Capture events on the network namespace running the client
	:>$client_evts

	# Attempt to add a listener at 10.0.2.2:<subflow-port>
	ip netns exec $ns2 ./pm_nl_ctl listen 10.0.2.2\
		$client4_port > /dev/null 2>&1 &
	local listener_pid=$!

931
	sleep 0.5
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
	verify_listener_events $client_evts $LISTENER_CREATED $AF_INET 10.0.2.2 $client4_port

	# ADD_ADDR from client to server machine reusing the subflow port
	ip netns exec $ns2 ./pm_nl_ctl ann 10.0.2.2 token $client4_token id\
		$client_addr_id > /dev/null 2>&1
	sleep 0.5

	# CREATE_SUBFLOW from server to client machine
	ip netns exec $ns1 ./pm_nl_ctl csf lip 10.0.2.1 lid 23 rip 10.0.2.2\
		rport $client4_port token $server4_token > /dev/null 2>&1
	sleep 0.5

	# Delete the listener from the client ns, if one was created
	kill_wait $listener_pid

947
	sleep 0.5
948 949 950
	verify_listener_events $client_evts $LISTENER_CLOSED $AF_INET 10.0.2.2 $client4_port
}

951
print_title "Make connections"
952 953
make_connection
make_connection "v6"
954

955 956 957
test_announce
test_remove
test_subflows
958
test_subflows_v4_v6_mix
959
test_prio
960
test_listener
961 962

exit 0