1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4. "$(dirname "${0}")/mptcp_lib.sh" 5 6ret=0 7sin="" 8sout="" 9cin="" 10cout="" 11ksft_skip=4 12timeout_poll=30 13timeout_test=$((timeout_poll * 2 + 1)) 14iptables="iptables" 15ip6tables="ip6tables" 16 17sec=$(date +%s) 18rndh=$(printf %x $sec)-$(mktemp -u XXXXXX) 19ns1="ns1-$rndh" 20ns2="ns2-$rndh" 21ns_sbox="ns_sbox-$rndh" 22 23add_mark_rules() 24{ 25 local ns=$1 26 local m=$2 27 28 local t 29 for t in ${iptables} ${ip6tables}; do 30 # just to debug: check we have multiple subflows connection requests 31 ip netns exec $ns $t -A OUTPUT -p tcp --syn -m mark --mark $m -j ACCEPT 32 33 # RST packets might be handled by a internal dummy socket 34 ip netns exec $ns $t -A OUTPUT -p tcp --tcp-flags RST RST -m mark --mark 0 -j ACCEPT 35 36 ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark $m -j ACCEPT 37 ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark 0 -j DROP 38 done 39} 40 41init() 42{ 43 local netns 44 for netns in "$ns1" "$ns2" "$ns_sbox";do 45 ip netns add $netns || exit $ksft_skip 46 ip -net $netns link set lo up 47 ip netns exec $netns sysctl -q net.mptcp.enabled=1 48 ip netns exec $netns sysctl -q net.ipv4.conf.all.rp_filter=0 49 ip netns exec $netns sysctl -q net.ipv4.conf.default.rp_filter=0 50 done 51 52 local i 53 for i in `seq 1 4`; do 54 ip link add ns1eth$i netns "$ns1" type veth peer name ns2eth$i netns "$ns2" 55 ip -net "$ns1" addr add 10.0.$i.1/24 dev ns1eth$i 56 ip -net "$ns1" addr add dead:beef:$i::1/64 dev ns1eth$i nodad 57 ip -net "$ns1" link set ns1eth$i up 58 59 ip -net "$ns2" addr add 10.0.$i.2/24 dev ns2eth$i 60 ip -net "$ns2" addr add dead:beef:$i::2/64 dev ns2eth$i nodad 61 ip -net "$ns2" link set ns2eth$i up 62 63 # let $ns2 reach any $ns1 address from any interface 64 ip -net "$ns2" route add default via 10.0.$i.1 dev ns2eth$i metric 10$i 65 66 ip netns exec $ns1 ./pm_nl_ctl add 10.0.$i.1 flags signal 67 ip netns exec $ns1 ./pm_nl_ctl add dead:beef:$i::1 flags signal 68 69 ip netns exec $ns2 ./pm_nl_ctl add 10.0.$i.2 flags signal 70 ip netns exec $ns2 ./pm_nl_ctl add dead:beef:$i::2 flags signal 71 done 72 73 ip netns exec $ns1 ./pm_nl_ctl limits 8 8 74 ip netns exec $ns2 ./pm_nl_ctl limits 8 8 75 76 add_mark_rules $ns1 1 77 add_mark_rules $ns2 2 78} 79 80cleanup() 81{ 82 local netns 83 for netns in "$ns1" "$ns2" "$ns_sbox"; do 84 ip netns del $netns 85 done 86 rm -f "$cin" "$cout" 87 rm -f "$sin" "$sout" 88} 89 90mptcp_lib_check_mptcp 91mptcp_lib_check_kallsyms 92 93ip -Version > /dev/null 2>&1 94if [ $? -ne 0 ];then 95 echo "SKIP: Could not run test without ip tool" 96 exit $ksft_skip 97fi 98 99# Use the legacy version if available to support old kernel versions 100if iptables-legacy -V &> /dev/null; then 101 iptables="iptables-legacy" 102 ip6tables="ip6tables-legacy" 103elif ! iptables -V &> /dev/null; then 104 echo "SKIP: Could not run all tests without iptables tool" 105 exit $ksft_skip 106elif ! ip6tables -V &> /dev/null; then 107 echo "SKIP: Could not run all tests without ip6tables tool" 108 exit $ksft_skip 109fi 110 111check_mark() 112{ 113 local ns=$1 114 local af=$2 115 116 local tables=${iptables} 117 118 if [ $af -eq 6 ];then 119 tables=${ip6tables} 120 fi 121 122 local counters values 123 counters=$(ip netns exec $ns $tables -v -L OUTPUT | grep DROP) 124 values=${counters%DROP*} 125 126 local v 127 for v in $values; do 128 if [ $v -ne 0 ]; then 129 echo "FAIL: got $tables $values in ns $ns , not 0 - not all expected packets marked" 1>&2 130 ret=1 131 return 1 132 fi 133 done 134 135 return 0 136} 137 138print_file_err() 139{ 140 ls -l "$1" 1>&2 141 echo "Trailing bytes are: " 142 tail -c 27 "$1" 143} 144 145check_transfer() 146{ 147 local in=$1 148 local out=$2 149 local what=$3 150 151 cmp "$in" "$out" > /dev/null 2>&1 152 if [ $? -ne 0 ] ;then 153 echo "[ FAIL ] $what does not match (in, out):" 154 print_file_err "$in" 155 print_file_err "$out" 156 ret=1 157 158 return 1 159 fi 160 161 return 0 162} 163 164# $1: IP address 165is_v6() 166{ 167 [ -z "${1##*:*}" ] 168} 169 170do_transfer() 171{ 172 local listener_ns="$1" 173 local connector_ns="$2" 174 local cl_proto="$3" 175 local srv_proto="$4" 176 local connect_addr="$5" 177 178 local port=12001 179 180 :> "$cout" 181 :> "$sout" 182 183 local mptcp_connect="./mptcp_connect -r 20" 184 185 local local_addr ip 186 if is_v6 "${connect_addr}"; then 187 local_addr="::" 188 ip=ipv6 189 else 190 local_addr="0.0.0.0" 191 ip=ipv4 192 fi 193 194 cmsg="TIMESTAMPNS" 195 if mptcp_lib_kallsyms_has "mptcp_ioctl$"; then 196 cmsg+=",TCPINQ" 197 fi 198 199 timeout ${timeout_test} \ 200 ip netns exec ${listener_ns} \ 201 $mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c "${cmsg}" \ 202 ${local_addr} < "$sin" > "$sout" & 203 local spid=$! 204 205 sleep 1 206 207 timeout ${timeout_test} \ 208 ip netns exec ${connector_ns} \ 209 $mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c "${cmsg}" \ 210 $connect_addr < "$cin" > "$cout" & 211 212 local cpid=$! 213 214 wait $cpid 215 local retc=$? 216 wait $spid 217 local rets=$? 218 219 if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then 220 echo " client exit code $retc, server $rets" 1>&2 221 echo -e "\nnetns ${listener_ns} socket stat for ${port}:" 1>&2 222 ip netns exec ${listener_ns} ss -Menita 1>&2 -o "sport = :$port" 223 224 echo -e "\nnetns ${connector_ns} socket stat for ${port}:" 1>&2 225 ip netns exec ${connector_ns} ss -Menita 1>&2 -o "dport = :$port" 226 227 mptcp_lib_result_fail "transfer ${ip}" 228 229 ret=1 230 return 1 231 fi 232 233 if [ $local_addr = "::" ];then 234 check_mark $listener_ns 6 || retc=1 235 check_mark $connector_ns 6 || retc=1 236 else 237 check_mark $listener_ns 4 || retc=1 238 check_mark $connector_ns 4 || retc=1 239 fi 240 241 check_transfer $cin $sout "file received by server" 242 rets=$? 243 244 mptcp_lib_result_code "${retc}" "mark ${ip}" 245 mptcp_lib_result_code "${rets}" "transfer ${ip}" 246 247 if [ $retc -eq 0 ] && [ $rets -eq 0 ];then 248 return 0 249 fi 250 251 return 1 252} 253 254make_file() 255{ 256 local name=$1 257 local who=$2 258 local size=$3 259 260 dd if=/dev/urandom of="$name" bs=1024 count=$size 2> /dev/null 261 echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" 262 263 echo "Created $name (size $size KB) containing data sent by $who" 264} 265 266do_mptcp_sockopt_tests() 267{ 268 local lret=0 269 270 if ! mptcp_lib_kallsyms_has "mptcp_diag_fill_info$"; then 271 echo "INFO: MPTCP sockopt not supported: SKIP" 272 mptcp_lib_result_skip "sockopt" 273 return 274 fi 275 276 ip netns exec "$ns_sbox" ./mptcp_sockopt 277 lret=$? 278 279 if [ $lret -ne 0 ]; then 280 echo "FAIL: SOL_MPTCP getsockopt" 1>&2 281 mptcp_lib_result_fail "sockopt v4" 282 ret=$lret 283 return 284 fi 285 mptcp_lib_result_pass "sockopt v4" 286 287 ip netns exec "$ns_sbox" ./mptcp_sockopt -6 288 lret=$? 289 290 if [ $lret -ne 0 ]; then 291 echo "FAIL: SOL_MPTCP getsockopt (ipv6)" 1>&2 292 mptcp_lib_result_fail "sockopt v6" 293 ret=$lret 294 return 295 fi 296 mptcp_lib_result_pass "sockopt v6" 297} 298 299run_tests() 300{ 301 local listener_ns="$1" 302 local connector_ns="$2" 303 local connect_addr="$3" 304 local lret=0 305 306 do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} 307 308 lret=$? 309 310 if [ $lret -ne 0 ]; then 311 ret=$lret 312 return 313 fi 314} 315 316do_tcpinq_test() 317{ 318 ip netns exec "$ns_sbox" ./mptcp_inq "$@" 319 local lret=$? 320 if [ $lret -ne 0 ];then 321 ret=$lret 322 echo "FAIL: mptcp_inq $@" 1>&2 323 mptcp_lib_result_fail "TCP_INQ: $*" 324 return $lret 325 fi 326 327 echo "PASS: TCP_INQ cmsg/ioctl $@" 328 mptcp_lib_result_pass "TCP_INQ: $*" 329 return $lret 330} 331 332do_tcpinq_tests() 333{ 334 local lret=0 335 336 if ! mptcp_lib_kallsyms_has "mptcp_ioctl$"; then 337 echo "INFO: TCP_INQ not supported: SKIP" 338 mptcp_lib_result_skip "TCP_INQ" 339 return 340 fi 341 342 local args 343 for args in "-t tcp" "-r tcp"; do 344 do_tcpinq_test $args 345 lret=$? 346 if [ $lret -ne 0 ] ; then 347 return $lret 348 fi 349 do_tcpinq_test -6 $args 350 lret=$? 351 if [ $lret -ne 0 ] ; then 352 return $lret 353 fi 354 done 355 356 do_tcpinq_test -r tcp -t tcp 357 358 return $? 359} 360 361sin=$(mktemp) 362sout=$(mktemp) 363cin=$(mktemp) 364cout=$(mktemp) 365init 366make_file "$cin" "client" 1 367make_file "$sin" "server" 1 368trap cleanup EXIT 369 370run_tests $ns1 $ns2 10.0.1.1 371run_tests $ns1 $ns2 dead:beef:1::1 372 373if [ $ret -eq 0 ];then 374 echo "PASS: all packets had packet mark set" 375fi 376 377do_mptcp_sockopt_tests 378if [ $ret -eq 0 ];then 379 echo "PASS: SOL_MPTCP getsockopt has expected information" 380fi 381 382do_tcpinq_tests 383 384mptcp_lib_result_print_all_tap 385exit $ret 386