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