1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4# Double quotes to prevent globbing and word splitting is recommended in new 5# code but we accept it, especially because there were too many before having 6# address all other issues detected by shellcheck. 7#shellcheck disable=SC2086 8 9. "$(dirname "${0}")/mptcp_lib.sh" 10 11ret=0 12sin="" 13sout="" 14cin="" 15cout="" 16timeout_poll=30 17timeout_test=$((timeout_poll * 2 + 1)) 18iptables="iptables" 19ip6tables="ip6tables" 20 21ns1="" 22ns2="" 23ns_sbox="" 24 25add_mark_rules() 26{ 27 local ns=$1 28 local m=$2 29 30 local t 31 for t in ${iptables} ${ip6tables}; do 32 # just to debug: check we have multiple subflows connection requests 33 ip netns exec $ns $t -A OUTPUT -p tcp --syn -m mark --mark $m -j ACCEPT 34 35 # RST packets might be handled by a internal dummy socket 36 ip netns exec $ns $t -A OUTPUT -p tcp --tcp-flags RST RST -m mark --mark 0 -j ACCEPT 37 38 ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark $m -j ACCEPT 39 ip netns exec $ns $t -A OUTPUT -p tcp -m mark --mark 0 -j DROP 40 done 41} 42 43init() 44{ 45 mptcp_lib_ns_init ns1 ns2 ns_sbox 46 47 local i 48 for i in $(seq 1 4); do 49 ip link add ns1eth$i netns "$ns1" type veth peer name ns2eth$i netns "$ns2" 50 ip -net "$ns1" addr add 10.0.$i.1/24 dev ns1eth$i 51 ip -net "$ns1" addr add dead:beef:$i::1/64 dev ns1eth$i nodad 52 ip -net "$ns1" link set ns1eth$i up 53 54 ip -net "$ns2" addr add 10.0.$i.2/24 dev ns2eth$i 55 ip -net "$ns2" addr add dead:beef:$i::2/64 dev ns2eth$i nodad 56 ip -net "$ns2" link set ns2eth$i up 57 58 # let $ns2 reach any $ns1 address from any interface 59 ip -net "$ns2" route add default via 10.0.$i.1 dev ns2eth$i metric 10$i 60 61 ip netns exec $ns1 ./pm_nl_ctl add 10.0.$i.1 flags signal 62 ip netns exec $ns1 ./pm_nl_ctl add dead:beef:$i::1 flags signal 63 64 ip netns exec $ns2 ./pm_nl_ctl add 10.0.$i.2 flags signal 65 ip netns exec $ns2 ./pm_nl_ctl add dead:beef:$i::2 flags signal 66 done 67 68 ip netns exec $ns1 ./pm_nl_ctl limits 8 8 69 ip netns exec $ns2 ./pm_nl_ctl limits 8 8 70 71 add_mark_rules $ns1 1 72 add_mark_rules $ns2 2 73} 74 75# This function is used in the cleanup trap 76#shellcheck disable=SC2317 77cleanup() 78{ 79 mptcp_lib_ns_exit "${ns1}" "${ns2}" "${ns_sbox}" 80 rm -f "$cin" "$cout" 81 rm -f "$sin" "$sout" 82} 83 84mptcp_lib_check_mptcp 85mptcp_lib_check_kallsyms 86mptcp_lib_check_tools ip "${iptables}" "${ip6tables}" 87 88check_mark() 89{ 90 local ns=$1 91 local af=$2 92 93 local tables=${iptables} 94 95 if [ $af -eq 6 ];then 96 tables=${ip6tables} 97 fi 98 99 local counters values 100 counters=$(ip netns exec $ns $tables -v -L OUTPUT | grep DROP) 101 values=${counters%DROP*} 102 103 local v 104 for v in $values; do 105 if [ $v -ne 0 ]; then 106 mptcp_lib_pr_fail "got $tables $values in ns $ns," \ 107 "not 0 - not all expected packets marked" 108 ret=${KSFT_FAIL} 109 return 1 110 fi 111 done 112 113 return 0 114} 115 116print_title() 117{ 118 mptcp_lib_print_title "${@}" 119} 120 121do_transfer() 122{ 123 local listener_ns="$1" 124 local connector_ns="$2" 125 local cl_proto="$3" 126 local srv_proto="$4" 127 local connect_addr="$5" 128 129 local port=12001 130 131 :> "$cout" 132 :> "$sout" 133 134 local mptcp_connect="./mptcp_connect -r 20" 135 136 local local_addr ip 137 if mptcp_lib_is_v6 "${connect_addr}"; then 138 local_addr="::" 139 ip=ipv6 140 else 141 local_addr="0.0.0.0" 142 ip=ipv4 143 fi 144 145 cmsg="TIMESTAMPNS" 146 if mptcp_lib_kallsyms_has "mptcp_ioctl$"; then 147 cmsg+=",TCPINQ" 148 fi 149 150 timeout ${timeout_test} \ 151 ip netns exec ${listener_ns} \ 152 $mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c "${cmsg}" \ 153 ${local_addr} < "$sin" > "$sout" & 154 local spid=$! 155 156 sleep 1 157 158 timeout ${timeout_test} \ 159 ip netns exec ${connector_ns} \ 160 $mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c "${cmsg}" \ 161 $connect_addr < "$cin" > "$cout" & 162 163 local cpid=$! 164 165 wait $cpid 166 local retc=$? 167 wait $spid 168 local rets=$? 169 170 print_title "Transfer ${ip:2}" 171 if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then 172 mptcp_lib_pr_fail "client exit code $retc, server $rets" 173 echo -e "\nnetns ${listener_ns} socket stat for ${port}:" 1>&2 174 ip netns exec ${listener_ns} ss -Menita 1>&2 -o "sport = :$port" 175 176 echo -e "\nnetns ${connector_ns} socket stat for ${port}:" 1>&2 177 ip netns exec ${connector_ns} ss -Menita 1>&2 -o "dport = :$port" 178 179 mptcp_lib_result_fail "transfer ${ip}" 180 181 ret=${KSFT_FAIL} 182 return 1 183 fi 184 if ! mptcp_lib_check_transfer $cin $sout "file received by server"; then 185 rets=1 186 else 187 mptcp_lib_pr_ok 188 fi 189 mptcp_lib_result_code "${rets}" "transfer ${ip}" 190 191 print_title "Mark ${ip:2}" 192 if [ $local_addr = "::" ];then 193 check_mark $listener_ns 6 || retc=1 194 check_mark $connector_ns 6 || retc=1 195 else 196 check_mark $listener_ns 4 || retc=1 197 check_mark $connector_ns 4 || retc=1 198 fi 199 200 mptcp_lib_result_code "${retc}" "mark ${ip}" 201 202 if [ $retc -eq 0 ] && [ $rets -eq 0 ];then 203 mptcp_lib_pr_ok 204 return 0 205 fi 206 mptcp_lib_pr_fail 207 208 return 1 209} 210 211make_file() 212{ 213 local name=$1 214 local who=$2 215 local size=$3 216 217 mptcp_lib_make_file $name 1024 $size 218 219 echo "Created $name (size $size KB) containing data sent by $who" 220} 221 222do_mptcp_sockopt_tests() 223{ 224 local lret=0 225 226 if ! mptcp_lib_kallsyms_has "mptcp_diag_fill_info$"; then 227 mptcp_lib_pr_skip "MPTCP sockopt not supported" 228 mptcp_lib_result_skip "sockopt" 229 return 230 fi 231 232 ip netns exec "$ns_sbox" ./mptcp_sockopt 233 lret=$? 234 235 print_title "SOL_MPTCP sockopt v4" 236 if [ $lret -ne 0 ]; then 237 mptcp_lib_pr_fail 238 mptcp_lib_result_fail "sockopt v4" 239 ret=$lret 240 return 241 fi 242 mptcp_lib_pr_ok 243 mptcp_lib_result_pass "sockopt v4" 244 245 ip netns exec "$ns_sbox" ./mptcp_sockopt -6 246 lret=$? 247 248 print_title "SOL_MPTCP sockopt v6" 249 if [ $lret -ne 0 ]; then 250 mptcp_lib_pr_fail 251 mptcp_lib_result_fail "sockopt v6" 252 ret=$lret 253 return 254 fi 255 mptcp_lib_pr_ok 256 mptcp_lib_result_pass "sockopt v6" 257} 258 259run_tests() 260{ 261 local listener_ns="$1" 262 local connector_ns="$2" 263 local connect_addr="$3" 264 local lret=0 265 266 do_transfer ${listener_ns} ${connector_ns} MPTCP MPTCP ${connect_addr} 267 268 lret=$? 269 270 if [ $lret -ne 0 ]; then 271 ret=$lret 272 return 273 fi 274} 275 276do_tcpinq_test() 277{ 278 print_title "TCP_INQ cmsg/ioctl $*" 279 ip netns exec "$ns_sbox" ./mptcp_inq "$@" 280 local lret=$? 281 if [ $lret -ne 0 ];then 282 ret=$lret 283 mptcp_lib_pr_fail 284 mptcp_lib_result_fail "TCP_INQ: $*" 285 return $lret 286 fi 287 288 mptcp_lib_pr_ok 289 mptcp_lib_result_pass "TCP_INQ: $*" 290 return $lret 291} 292 293do_tcpinq_tests() 294{ 295 local lret=0 296 297 if ! mptcp_lib_kallsyms_has "mptcp_ioctl$"; then 298 mptcp_lib_pr_skip "TCP_INQ not supported" 299 mptcp_lib_result_skip "TCP_INQ" 300 return 301 fi 302 303 local args 304 for args in "-t tcp" "-r tcp"; do 305 do_tcpinq_test $args 306 lret=$? 307 if [ $lret -ne 0 ] ; then 308 return $lret 309 fi 310 do_tcpinq_test -6 $args 311 lret=$? 312 if [ $lret -ne 0 ] ; then 313 return $lret 314 fi 315 done 316 317 do_tcpinq_test -r tcp -t tcp 318 319 return $? 320} 321 322sin=$(mktemp) 323sout=$(mktemp) 324cin=$(mktemp) 325cout=$(mktemp) 326init 327make_file "$cin" "client" 1 328make_file "$sin" "server" 1 329trap cleanup EXIT 330 331run_tests $ns1 $ns2 10.0.1.1 332run_tests $ns1 $ns2 dead:beef:1::1 333 334do_mptcp_sockopt_tests 335do_tcpinq_tests 336 337mptcp_lib_result_print_all_tap 338exit $ret 339