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