#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # # Test the protodown mechanism. Verify basic protodown toggling, protodown # reasons, operational state when the lower device carrier changes, and correct # operational state when the lower device has no carrier. # shellcheck disable=SC1091,SC2034,SC2154,SC2317 source lib.sh require_command jq ALL_TESTS=" protodown_basic_macvlan protodown_basic_vxlan protodown_reasons protodown_lower_toggle protodown_lower_down " operstate_get() { local ns=$1; shift local dev=$1; shift ip -n "$ns" -j link show dev "$dev" | jq -r '.[].operstate' } operstate_check() { local ns=$1; shift local dev=$1; shift local expected=$1; shift local current current=$(operstate_get "$ns" "$dev") [ "$current" = "$expected" ] } setup_prepare() { setup_ns NS defer cleanup_all_ns ip -n "$NS" link add name dummy0 up type dummy ip -n "$NS" link add name macvlan0 link dummy0 up type macvlan mode bridge ip -n "$NS" link add name vxlan0 up type vxlan id 10010 dstport 4789 } protodown_basic() { local dev=$1; shift ip -n "$NS" link set dev "$dev" protodown on check_err $? "Failed to set protodown on" busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" "$dev" DOWN check_err $? "Operational state is not DOWN after setting protodown" ip -n "$NS" link set dev "$dev" protodown off check_err $? "Failed to set protodown off" busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" "$dev" UP check_err $? "Operational state is not UP after clearing protodown" } protodown_basic_macvlan() { RET=0 protodown_basic macvlan0 log_test "Basic protodown on/off with macvlan" } protodown_basic_vxlan() { RET=0 protodown_basic vxlan0 log_test "Basic protodown on/off with vxlan" } protodown_reasons() { RET=0 ip -n "$NS" link set dev macvlan0 protodown on ip -n "$NS" link set dev macvlan0 protodown_reason 0 on check_err $? "Failed to set protodown reason bit 0" # Cannot clear protodown while reasons are active. ip -n "$NS" link set dev macvlan0 protodown off 2>/dev/null check_fail $? "Clearing protodown succeeded with active reasons" ip -n "$NS" link set dev macvlan0 protodown_reason 0 off check_err $? "Failed to clear protodown reason bit 0" # Can clear protodown when no reasons are active. ip -n "$NS" link set dev macvlan0 protodown off check_err $? "Failed to clear protodown with no active reasons" busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" macvlan0 UP check_err $? "Operational state is not UP after clearing protodown" log_test "Protodown reasons" } protodown_lower_toggle() { RET=0 ip -n "$NS" link set dev macvlan0 protodown on busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" macvlan0 DOWN check_err $? "Operational state is not DOWN after setting protodown" # Toggle carrier on the lower device. The macvlan should stay DOWN # because protodown is on. ip -n "$NS" link set dev dummy0 carrier off ip -n "$NS" link set dev dummy0 carrier on busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" dummy0 UP check_err $? "Lower device is not UP after carrier on" busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" macvlan0 DOWN check_err $? "Macvlan operational state is not DOWN despite protodown" # Clear protodown and verify the macvlan comes back up. ip -n "$NS" link set dev macvlan0 protodown off busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" macvlan0 UP check_err $? "Operational state is not UP after clearing protodown" log_test "Protodown with lower device toggled" } protodown_lower_down() { RET=0 # Bring the lower device carrier down first. ip -n "$NS" link set dev dummy0 carrier off busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" macvlan0 LOWERLAYERDOWN check_err $? "Macvlan is not LOWERLAYERDOWN with lower carrier off" # Toggle protodown on and off while lower has no carrier. The macvlan # should not transition to UP. ip -n "$NS" link set dev macvlan0 protodown on busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" macvlan0 LOWERLAYERDOWN check_err $? "Macvlan is not LOWERLAYERDOWN after setting protodown" ip -n "$NS" link set dev macvlan0 protodown off busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" macvlan0 LOWERLAYERDOWN check_err $? "Macvlan is not LOWERLAYERDOWN after clearing protodown" # Bring the lower device carrier up. The macvlan should transition to # UP. ip -n "$NS" link set dev dummy0 carrier on busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" dummy0 UP check_err $? "Lower device is not UP after carrier on" busywait "$BUSYWAIT_TIMEOUT" operstate_check "$NS" macvlan0 UP check_err $? "Macvlan is not UP after lower device is UP" log_test "Protodown with lower device down" } trap defer_scopes_cleanup EXIT setup_prepare tests_run exit "$EXIT_STATUS"