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="" 15do_all_tests=1 16iptables="iptables" 17ip6tables="ip6tables" 18 19add_mark_rules() 20{ 21 local ns=$1 22 local m=$2 23 24 for t in ${iptables} ${ip6tables}; do 25 # just to debug: check we have multiple subflows connection requests 26 ip netns exec $ns $t -A OUTPUT -p tcp --syn -m mark --mark $m -j ACCEPT 27 28 # RST packets might be handled by a internal dummy socket 29 ip netns exec $ns $t -A OUTPUT -p tcp --tcp-flags RST RST -m mark --mark 0 -j ACCEPT 30 31 ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark $m -j ACCEPT 32 ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark 0 -j DROP 33 done 34} 35 36init() 37{ 38 rndh=$(printf %x $sec)-$(mktemp -u XXXXXX) 39 40 ns1="ns1-$rndh" 41 ns2="ns2-$rndh" 42 ns_sbox="ns_sbox-$rndh" 43 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 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 for netns in "$ns1" "$ns2" "$ns_sbox"; do 82 ip netns del $netns 83 done 84 rm -f "$cin" "$cout" 85 rm -f "$sin" "$sout" 86} 87 88mptcp_lib_check_mptcp 89mptcp_lib_check_kallsyms 90 91ip -Version > /dev/null 2>&1 92if [ $? -ne 0 ];then 93 echo "SKIP: Could not run test without ip tool" 94 exit $ksft_skip 95fi 96 97# Use the legacy version if available to support old kernel versions 98if iptables-legacy -V &> /dev/null; then 99 iptables="iptables-legacy" 100 ip6tables="ip6tables-legacy" 101elif ! iptables -V &> /dev/null; then 102 echo "SKIP: Could not run all tests without iptables tool" 103 exit $ksft_skip 104elif ! ip6tables -V &> /dev/null; then 105 echo "SKIP: Could not run all tests without ip6tables tool" 106 exit $ksft_skip 107fi 108 109check_mark() 110{ 111 local ns=$1 112 local af=$2 113 114 tables=${iptables} 115 116 if [ $af -eq 6 ];then 117 tables=${ip6tables} 118 fi 119 120 counters=$(ip netns exec $ns $tables -v -L OUTPUT | grep DROP) 121 values=${counters%DROP*} 122 123 for v in $values; do 124 if [ $v -ne 0 ]; then 125 echo "FAIL: got $tables $values in ns $ns , not 0 - not all expected packets marked" 1>&2 126 ret=1 127 return 1 128 fi 129 done 130 131 return 0 132} 133 134print_file_err() 135{ 136 ls -l "$1" 1>&2 137 echo "Trailing bytes are: " 138 tail -c 27 "$1" 139} 140 141check_transfer() 142{ 143 in=$1 144 out=$2 145 what=$3 146 147 cmp "$in" "$out" > /dev/null 2>&1 148 if [ $? -ne 0 ] ;then 149 echo "[ FAIL ] $what does not match (in, out):" 150 print_file_err "$in" 151 print_file_err "$out" 152 ret=1 153 154 return 1 155 fi 156 157 return 0 158} 159 160# $1: IP address 161is_v6() 162{ 163 [ -z "${1##*:*}" ] 164} 165 166do_transfer() 167{ 168 listener_ns="$1" 169 connector_ns="$2" 170 cl_proto="$3" 171 srv_proto="$4" 172 connect_addr="$5" 173 174 port=12001 175 176 :> "$cout" 177 :> "$sout" 178 179 mptcp_connect="./mptcp_connect -r 20" 180 181 local local_addr 182 if is_v6 "${connect_addr}"; then 183 local_addr="::" 184 else 185 local_addr="0.0.0.0" 186 fi 187 188 cmsg="TIMESTAMPNS" 189 if mptcp_lib_kallsyms_has "mptcp_ioctl$"; then 190 cmsg+=",TCPINQ" 191 fi 192 193 timeout ${timeout_test} \ 194 ip netns exec ${listener_ns} \ 195 $mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c "${cmsg}" \ 196 ${local_addr} < "$sin" > "$sout" & 197 spid=$! 198 199 sleep 1 200 201 timeout ${timeout_test} \ 202 ip netns exec ${connector_ns} \ 203 $mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c "${cmsg}" \ 204 $connect_addr < "$cin" > "$cout" & 205 206 cpid=$! 207 208 wait $cpid 209 retc=$? 210 wait $spid 211 rets=$? 212 213 if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then 214 echo " client exit code $retc, server $rets" 1>&2 215 echo -e "\nnetns ${listener_ns} socket stat for ${port}:" 1>&2 216 ip netns exec ${listener_ns} ss -Menita 1>&2 -o "sport = :$port" 217 218 echo -e "\nnetns ${connector_ns} socket stat for ${port}:" 1>&2 219 ip netns exec ${connector_ns} ss -Menita 1>&2 -o "dport = :$port" 220 221 ret=1 222 return 1 223 fi 224 225 if [ $local_addr = "::" ];then 226 check_mark $listener_ns 6 || retc=1 227 check_mark $connector_ns 6 || retc=1 228 else 229 check_mark $listener_ns 4 || retc=1 230 check_mark $connector_ns 4 || retc=1 231 fi 232 233 check_transfer $cin $sout "file received by server" 234 235 rets=$? 236 237 if [ $retc -eq 0 ] && [ $rets -eq 0 ];then 238 return 0 239 fi 240 241 return 1 242} 243 244make_file() 245{ 246 name=$1 247 who=$2 248 size=$3 249 250 dd if=/dev/urandom of="$name" bs=1024 count=$size 2> /dev/null 251 echo -e "\nMPTCP_TEST_FILE_END_MARKER" >> "$name" 252 253 echo "Created $name (size $size KB) containing data sent by $who" 254} 255 256do_mptcp_sockopt_tests() 257{ 258 local lret=0 259 260 if ! mptcp_lib_kallsyms_has "mptcp_diag_fill_info$"; then 261 echo "INFO: MPTCP sockopt not supported: SKIP" 262 return 263 fi 264 265 ip netns exec "$ns_sbox" ./mptcp_sockopt 266 lret=$? 267 268 if [ $lret -ne 0 ]; then 269 echo "FAIL: SOL_MPTCP getsockopt" 1>&2 270 ret=$lret 271 return 272 fi 273 274 ip netns exec "$ns_sbox" ./mptcp_sockopt -6 275 lret=$? 276 277 if [ $lret -ne 0 ]; then 278 echo "FAIL: SOL_MPTCP getsockopt (ipv6)" 1>&2 279 ret=$lret 280 return 281 fi 282} 283 284run_tests() 285{ 286 listener_ns="$1" 287 connector_ns="$2" 288 connect_addr="$3" 289 local lret=0 290 291 do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} 292 293 lret=$? 294 295 if [ $lret -ne 0 ]; then 296 ret=$lret 297 return 298 fi 299} 300 301do_tcpinq_test() 302{ 303 ip netns exec "$ns1" ./mptcp_inq "$@" 304 lret=$? 305 if [ $lret -ne 0 ];then 306 ret=$lret 307 echo "FAIL: mptcp_inq $@" 1>&2 308 return $lret 309 fi 310 311 echo "PASS: TCP_INQ cmsg/ioctl $@" 312 return $lret 313} 314 315do_tcpinq_tests() 316{ 317 local lret=0 318 319 ip netns exec "$ns1" ${iptables} -F 320 ip netns exec "$ns1" ${ip6tables} -F 321 322 if ! mptcp_lib_kallsyms_has "mptcp_ioctl$"; then 323 echo "INFO: TCP_INQ not supported: SKIP" 324 return 325 fi 326 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