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