| #!/bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| # |
| # Simple tests for ipvtap |
| |
| |
| # |
| # The testing environment looks this way: |
| # |
| # |------HNS-------| |------PHY-------| |
| # | veth<----------------->veth | |
| # |------|--|------| |----------------| |
| # | | |
| # | | |-----TST0-------| |
| # | |------------|----ipvlan | |
| # | |----------------| |
| # | |
| # | |-----TST1-------| |
| # |---------------|----ipvlan | |
| # |----------------| |
| # |
| |
| ALL_TESTS=" |
| test_ip_set |
| " |
| |
| source lib.sh |
| |
| DEBUG=0 |
| |
| VETH_HOST=vethtst.h |
| VETH_PHY=vethtst.p |
| |
| NS_COUNT=32 |
| IP_ITERATIONS=1024 |
| IPSET_TIMEOUT="60s" |
| |
| ns_run() { |
| ns=$1 |
| shift |
| if [[ "$ns" == "global" ]]; then |
| "$@" >/dev/null |
| else |
| ip netns exec "$ns" "$@" >/dev/null |
| fi |
| } |
| |
| test_ip_setup_env() { |
| setup_ns NS_PHY |
| setup_ns HST_NS |
| |
| # setup simulated other-host (phy) and host itself |
| ns_run "$HST_NS" ip link add $VETH_HOST type veth peer name $VETH_PHY \ |
| netns "$NS_PHY" >/dev/null |
| ns_run "$HST_NS" ip link set $VETH_HOST up |
| ns_run "$NS_PHY" ip link set $VETH_PHY up |
| |
| for ((i=0; i<NS_COUNT; i++)); do |
| setup_ns ipvlan_ns_$i |
| ns="ipvlan_ns_$i" |
| if [ "$DEBUG" = "1" ]; then |
| echo "created NS ${!ns}" |
| fi |
| if ! ns_run "$HST_NS" ip link add netns ${!ns} ipvlan0 \ |
| link $VETH_HOST \ |
| type ipvtap mode l2 bridge; then |
| exit_error "FAIL: Failed to configure ipvlan link." |
| fi |
| done |
| } |
| |
| test_ip_cleanup_env() { |
| ns_run "$HST_NS" ip link del $VETH_HOST |
| cleanup_all_ns |
| } |
| |
| exit_error() { |
| echo "$1" |
| exit $ksft_fail |
| } |
| |
| rnd() { |
| echo $(( RANDOM % 32 + 16 )) |
| } |
| |
| test_ip_set_thread() { |
| # Here we are trying to create some IP conflicts between namespaces. |
| # If just add/remove IP, nothing interesting will happen. |
| # But if add random IP and then remove random IP, |
| # eventually conflicts start to apear. |
| ip link set ipvlan0 up |
| for ((i=0; i<IP_ITERATIONS; i++)); do |
| v=$(rnd) |
| ip a a "172.25.0.$v/24" dev ipvlan0 2>/dev/null |
| ip a a "fc00::$v/64" dev ipvlan0 2>/dev/null |
| v=$(rnd) |
| ip a d "172.25.0.$v/24" dev ipvlan0 2>/dev/null |
| ip a d "fc00::$v/64" dev ipvlan0 2>/dev/null |
| done |
| } |
| |
| test_ip_set() { |
| RET=0 |
| |
| trap test_ip_cleanup_env EXIT |
| |
| test_ip_setup_env |
| |
| declare -A ns_pids |
| for ((i=0; i<NS_COUNT; i++)); do |
| ns="ipvlan_ns_$i" |
| ns_run ${!ns} timeout "$IPSET_TIMEOUT" \ |
| bash -c "$0 test_ip_set_thread"& |
| ns_pids[$i]=$! |
| done |
| |
| for ((i=0; i<NS_COUNT; i++)); do |
| wait "${ns_pids[$i]}" |
| done |
| |
| declare -A all_ips |
| for ((i=0; i<NS_COUNT; i++)); do |
| ns="ipvlan_ns_$i" |
| ip_output=$(ip netns exec ${!ns} ip a l dev ipvlan0 | grep inet) |
| while IFS= read -r nsip_out; do |
| if [[ -z $nsip_out ]]; then |
| continue; |
| fi |
| nsip=$(awk '{print $2}' <<< "$nsip_out") |
| if [[ -v all_ips[$nsip] ]]; then |
| RET=$ksft_fail |
| log_test "conflict for $nsip" |
| return "$RET" |
| else |
| all_ips[$nsip]=$i |
| fi |
| done <<< "$ip_output" |
| done |
| |
| if [ "$DEBUG" = "1" ]; then |
| for key in "${!all_ips[@]}"; do |
| echo "$key: ${all_ips[$key]}" |
| done |
| fi |
| |
| trap - EXIT |
| test_ip_cleanup_env |
| |
| log_test "test multithreaded ip set" |
| } |
| |
| if [[ "$1" == "-d" ]]; then |
| DEBUG=1 |
| shift |
| fi |
| |
| if [[ "$1" == "-t" ]]; then |
| shift |
| TESTS="$*" |
| fi |
| |
| if [[ "$1" == "test_ip_set_thread" ]]; then |
| test_ip_set_thread |
| else |
| require_command ip |
| |
| tests_run |
| fi |