# # Test scrip to do basic xdpdump checks # # shellcheck disable=2039 # ALL_TESTS="test_help test_interfaces test_capt_pcap test_capt_pcapng test_capt_term test_exitentry test_snap test_multi_pkt test_perf_wakeup test_promiscuous_selfload test_promiscuous_preload test_none_xdp test_pname_parse test_multi_prog test_xdp_load" XDPDUMP=${XDPDUMP:-./xdpdump} XDP_LOADER=${XDP_LOADER:-../xdp-loader/xdp-loader} RESULT="" print_result() { echo "$RESULT" if [ -n "$1" ]; then echo "ERROR: $1" fi } test_help() { local XDPDUMP_HELP_TEXT XDPDUMP_HELP_TEXT=$(cat <<-END Usage: xdpdump [options] XDPDump tool to dump network traffic Options: --rx-capture Capture point for the rx direction (valid values: entry,exit) -D, --list-interfaces Print the list of available interfaces --load-xdp-mode Mode used for --load-xdp-mode, default native (valid values: native,skb,hw,unspecified) --load-xdp-program Load XDP trace program if no XDP program is loaded -i, --interface Name of interface to capture on --perf-wakeup Wake up xdpdump every packets -p, --program-names Specific program to attach to -P, --promiscuous-mode Open interface in promiscuous mode -s, --snapshot-length Minimum bytes of packet to capture --use-pcap Use legacy pcap format for XDP traces -w, --write Write raw packets to pcap file -x, --hex Print the full packet in hex -v, --verbose Enable verbose logging (-vv: more verbose) --version Display version information -h, --help Show this help END ) $XDPDUMP --help | grep -q "\-\-perf-wakeup" if [ $? -eq 1 ]; then XDPDUMP_HELP_TEXT=$(echo "$XDPDUMP_HELP_TEXT" | sed '/ --perf-wakeup Wake up xdpdump every packets/d') fi RESULT=$($XDPDUMP --help) if [ "$RESULT" != "$XDPDUMP_HELP_TEXT" ]; then print_result "The --help output failed" return 1 fi RESULT=$($XDPDUMP -h) if [ "$RESULT" != "$XDPDUMP_HELP_TEXT" ]; then print_result "The -h output failed" return 1 fi } test_interfaces() { local NO_PROG_REGEX="($NS +)" if is_multiprog_supported; then local PROG_REGEX="($NS[[:space:]]+xdp_dispatcher.+xdp_drop)" else local PROG_REGEX="($NS[[:space:]]+xdp_drop)" fi RESULT=$($XDPDUMP -D) if ! [[ $RESULT =~ $NO_PROG_REGEX ]]; then print_result "Failed showing test interface with no XPD program loaded" return 1 fi RESULT=$($XDPDUMP --list-interfaces) if ! [[ $RESULT =~ $NO_PROG_REGEX ]]; then print_result "Failed showing test interface with no XPD program loaded" return 1 fi $XDP_LOADER load "$NS" "$TEST_PROG_DIR/xdp_drop.o" RESULT=$($XDPDUMP -D) if ! [[ $RESULT =~ $PROG_REGEX ]]; then print_result "Failed showing test interface with XPD program loaded" return 1 fi $XDP_LOADER unload "$NS" --all } test_capt_pcap() { skip_if_missing_kernel_symbol bpf_xdp_output_proto local PASS_PKT="IP6 $INSIDE_IP6 > $OUTSIDE_IP6: ICMP6, echo reply(, id [0-9]+)?, seq 1, length 64" $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" || return 1 PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name --use-pcap -w - 2> /dev/null | tcpdump -r - -n") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 sleep 1 RESULT=$(stop_background "$PID") $XDP_LOADER unload "$NS" --all || return 1 if ! [[ $RESULT =~ $PASS_PKT ]]; then print_result "IPv6 packet not received" return 1 fi } version_greater_or_equal() { printf '%s\n%s\n' "$2" "$1" | sort -V -C } test_capt_pcapng() { skip_if_missing_kernel_symbol bpf_xdp_output_proto local PCAP_FILE="/tmp/${NS}_PID_$$_$RANDOM.pcap" local PASS_PKT="IP6 $INSIDE_IP6 > $OUTSIDE_IP6: ICMP6, echo reply(, id [0-9]+)?, seq 1, length 64" local HW=$(uname -m | sed -e 's/[]\/$*+.^|[]/\\&/g') local OS=$(uname -snrv | sed -e 's/[]\/$+*.^()|[]/\\&/g') local INFOS_REGEX="" local OLD_CAPINFOS=0 local TSHARK_VERSION=$(tshark --version 2> /dev/null | sed -ne 's/^TShark (Wireshark) \([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p') if [[ "$(capinfos --help)" == *"Capinfos (Wireshark) 2."* ]]; then OLD_CAPINFOS=1 fi INFOS_REGEX+="(File type: Wireshark\/\.\.\. - pcapng.*" INFOS_REGEX+="Capture hardware: $HW.*" INFOS_REGEX+="Capture oper-sys: $OS.*" INFOS_REGEX+="Capture application: xdpdump v[0-9]+\.[0-9]+\.[0-9]+.*" INFOS_REGEX+="Capture comment: Capture was taken on interface xdptest, with the following XDP programs loaded: xdp_dispatcher\(\) xdp_test_prog_w.*" INFOS_REGEX+="Interface #0 info:.*" INFOS_REGEX+="Name = ${NS}:xdp_test_prog_with_a_long_name\(\)@fentry.*" if [ $OLD_CAPINFOS -eq 0 ]; then INFOS_REGEX+="Hardware = driver: \"veth\", version: \"1\.0\", fw-version: \"\", rom-version: \"\", bus-info: \"\".*" fi INFOS_REGEX+="Time precision = nanoseconds \(9\).*" INFOS_REGEX+="Interface #1 info:.*" INFOS_REGEX+="Name = ${NS}:xdp_test_prog_with_a_long_name\(\)@fexit.*" if [ $OLD_CAPINFOS -eq 0 ]; then INFOS_REGEX+="Hardware = driver: \"veth\", version: \"1\.0\", fw-version: \"\", rom-version: \"\", bus-info: \"\".*" fi INFOS_REGEX+="Time precision = nanoseconds \(9\))" $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" || return 1 PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name -w - 2> /dev/null | tcpdump -r - -n") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_PKT ]]; then print_result "IPv6 packet not received" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name -w $PCAP_FILE --rx-capture=entry,exit") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") || (print_result "xdpdump failed"; return 1) RESULT=$(capinfos "$PCAP_FILE") || (print_result "capinfos failed"; return 1) if ! [[ $RESULT =~ $INFOS_REGEX ]]; then echo "REGEX: $INFOS_REGEX" print_result "Failed capinfos content" return 1 fi if version_greater_or_equal "$TSHARK_VERSION" 3.4.0; then local ATTRIB_REGEX="^xdptest:xdp_test_prog_with_a_long_name\(\)@fentry 0 1 $.*^xdptest:xdp_test_prog_with_a_long_name\(\)@fexit 0 1 2$.*" RESULT=$(tshark -r "$PCAP_FILE" -T fields \ -e frame.interface_name \ -e frame.interface_queue \ -e frame.packet_id \ -e frame.verdict.ebpf_xdp) if ! [[ $RESULT =~ $ATTRIB_REGEX ]]; then print_result "Failed attributes content" return 1 fi fi rm "$PCAP_FILE" >& /dev/null $XDP_LOADER unload "$NS" --all || return 1 } test_capt_term() { skip_if_missing_kernel_symbol bpf_xdp_output_proto local PASS_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local PASS_X_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes, captured 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local PASS_X_OPT="0x0020: 00 00 00 00 00 02 fc 42 de ad ca fe 00 01 00 00" $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" || return 1 PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_REGEX ]]; then print_result "IPv6 packet not received" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name -x") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_X_REGEX ]]; then print_result "IPv6 packet not received[2]" return 1 fi # If the IP6 addresses remain the same this simple string compare can be # used to verify the -x output is present. if [[ "$RESULT" != *"$PASS_X_OPT"* ]]; then print_result "IPv6 HEX packet not received" return 1 fi $XDP_LOADER unload "$NS" --all || return 1 } test_exitentry() { skip_if_missing_kernel_symbol bpf_xdp_output_proto local PASS_ENTRY_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local PASS_EXIT_REGEX="(xdp_test_prog_with_a_long_name\(\)@exit\[PASS\]: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local PASS_ENTRY_D_REGEX="(xdp_drop\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local PASS_EXIT_D_REGEX="(xdp_drop\(\)@exit\[DROP\]: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local ID_ENTRY_REGEX="xdp_drop\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id ([0-9]+)" local ID_EXIT_REGEX="xdp_drop\(\)@exit\[DROP\]: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id ([0-9]+)" $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" || return 1 PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name --rx-capture=entry") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_ENTRY_REGEX ]]; then print_result "IPv6 entry packet not received" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name --rx-capture=exit") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_EXIT_REGEX ]]; then print_result "IPv6 exit packet not received" return 1 fi $XDP_LOADER unload "$NS" --all || return 1 $XDP_LOADER load "$NS" "$TEST_PROG_DIR/xdp_drop.o" || return 1 PID=$(start_background "$XDPDUMP -i $NS --rx-capture=exit") $PING6 -W 1 -c 1 "$INSIDE_IP6" # Note that this ping will fail!! RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_EXIT_D_REGEX ]]; then print_result "IPv6 drop exit packet not received" return 1 fi PID=$(start_background "$XDPDUMP -i $NS --rx-capture=exit,entry") $PING6 -W 1 -c 1 "$INSIDE_IP6" # Note that this ping will fail!! RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_EXIT_D_REGEX && $RESULT =~ $PASS_ENTRY_D_REGEX ]]; then print_result "IPv6 drop entry/exit packet not received" return 1 fi [[ $RESULT =~ $ID_ENTRY_REGEX ]] ENTRY_ID=${BASH_REMATCH[1]} [[ $RESULT =~ $ID_EXIT_REGEX ]] EXIT_ID=${BASH_REMATCH[1]} if [[ "$EXIT_ID" != "$ENTRY_ID" ]]; then print_result "Failed matching IDs" return 1 fi $XDP_LOADER unload "$NS" --all || return 1 } test_snap() { skip_if_missing_kernel_symbol bpf_xdp_output_proto local PASS_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes, captured 16 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local PASS_II_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes, captured 21 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" || return 1 PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name -x --snapshot-length=16") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_REGEX ]]; then print_result "IPv6 packet fragment not received" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name -x -s 21") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_II_REGEX ]]; then print_result "IPv6 packet fragment not received[2]" return 1 fi $XDP_LOADER unload "$NS" --all || return 1 } test_multi_pkt() { skip_if_missing_kernel_symbol bpf_xdp_output_proto local PASS_ENTRY_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size [0-9]+ bytes on if_index [0-9]+, rx queue [0-9]+, id 20000)" local PASS_EXIT_REGEX="(xdp_test_prog_with_a_long_name\(\)@exit\[PASS\]: packet size [0-9]+ bytes on if_index [0-9]+, rx queue [0-9]+, id 20000)" local PKT_SIZES=(56 512 1500) $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" || return 1 for PKT_SIZE in "${PKT_SIZES[@]}" ; do PID=$(start_background_no_stderr "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name --rx-capture=entry,exit") timeout 4 $PING6 -W 2 -s "$PKT_SIZE" -c 20000 -f "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_ENTRY_REGEX ]]; then print_result "IPv6 entry packet not received, $PKT_SIZE" return 1 fi if ! [[ $RESULT =~ $PASS_EXIT_REGEX ]]; then print_result "IPv6 exit packet not received, $PKT_SIZE" return 1 fi done $XDP_LOADER unload "$NS" --all || return 1 } test_perf_wakeup() { skip_if_missing_kernel_symbol bpf_xdp_output_proto $XDPDUMP --help | grep -q "\-\-perf-wakeup" if [ $? -eq 1 ]; then # No support for perf_wakeup, so return SKIP return "$SKIPPED_TEST" fi local PASS_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+)" local PASS_10K_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id 10000)" local WAKEUPS=(0 1 32 128) $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" || return 1 for WAKEUP in "${WAKEUPS[@]}" ; do # We send a single packet to make sure flushing of the buffer works! PID=$(start_background_no_stderr "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name --perf-wakeup=$WAKEUP") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_REGEX ]]; then print_result "IPv6 packet not received for wakeup $WAKEUP" return 1 fi # We sent 10k packets and see if the all arrive PID=$(start_background_no_stderr "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name --perf-wakeup=$WAKEUP") timeout 2 "$PING6" -W 2 -c 10000 -f "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_10K_REGEX ]]; then print_result "IPv6 10k packet not received for wakeup $WAKEUP" return 1 fi done $XDP_LOADER unload "$NS" --all || return 1 } test_none_xdp() { local PASS_PKT="packet size 118 bytes on if_name \"$NS\"" local WARN_MSG="WARNING: Specified interface does not have an XDP program loaded," $XDP_LOADER unload "$NS" --all PID=$(start_background "$XDPDUMP -i $NS") $PING6 -W 2 -c 4 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if [[ "$RESULT" != *"$PASS_PKT"* ]]; then print_result "IPv6 packet not received" return 1 fi if [[ "$RESULT" != *"$WARN_MSG"* ]]; then print_result "Missing warning message" return 1 fi } test_promiscuous_selfload() { local PASS_PKT="packet size 118 bytes on if_name \"$NS\"" local PASS_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes, captured 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" $XDP_LOADER unload "$NS" --all dmesg -C PID=$(start_background "$XDPDUMP -i $NS -P") $PING6 -W 2 -c 4 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if [[ "$RESULT" != *"$PASS_PKT"* ]]; then print_result "IPv6 packet not received [legacy mode]" return 1 fi RESULT=$(dmesg) if [[ "$RESULT" != *"device $NS entered promiscuous mode"* ]]; then print_result "Failed enabling promiscuous mode on legacy interface" return 1 fi if [[ "$RESULT" != *"device $NS left promiscuous mode"* ]]; then print_result "Failed disabling promiscuous mode on legacy interface" return 1 fi } test_promiscuous_preload() { skip_if_missing_kernel_symbol bpf_xdp_output local PASS_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes, captured 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" || return 1 dmesg -C PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name -x --promiscuous-mode") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_REGEX ]]; then print_result "IPv6 packet not received" return 1 fi RESULT=$(dmesg) if [[ "$RESULT" != *"device $NS entered promiscuous mode"* ]]; then print_result "Failed enabling promiscuous mode on interface" return 1 fi if [[ "$RESULT" != *"device $NS left promiscuous mode"* ]]; then print_result "Failed disabling promiscuous mode on interface" return 1 fi } test_pname_parse() { skip_if_legacy_fallback local PIN_DIR="/sys/fs/bpf/${NS}_PID_$$_$RANDOM" local PASS_REGEX="(xdp_test_prog_with_a_long_name\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local PROG_ID_1=0 local PROG_ID_2=0 local PROG_ID_3=0 local PROG_ID_4=0 $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 # Here we load the programs without the xdp-tools loader to make sure # they are not loaded as a multi-program. bpftool prog loadall "$TEST_PROG_DIR/test_long_func_name.o" "$PIN_DIR" bpftool net attach xdpgeneric pinned "$PIN_DIR/xdp_test_prog_long" dev "$NS" # We need to specify the function name or else it should fail PID=$(start_background "$XDPDUMP -i $NS") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Can't identify the full XDP main function!"* ]]; then print_result "xdpdump should fail with duplicate function!" rm -rf "$PIN_DIR" return 1 fi # Here we specify the correct function name so we should get the packet PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $PASS_REGEX ]]; then print_result "IPv6 packet not received" rm -rf "$PIN_DIR" return 1 fi # Here we specify the wrong correct function name so we should not get the packet PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name_too") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Can't load eBPF object: Kernel verifier blocks program loading"* ]]; then print_result "xdpdump should fail being unable to attach!" rm -rf "$PIN_DIR" return 1 fi # Here we specify an non-existing function PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_non_existing_name") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Can't find function 'xdp_test_prog_with_a_long_non_existing_name' on interface!"* ]]; then print_result "xdpdump should fail with unknown function!" rm -rf "$PIN_DIR" return 1 fi # Verify invalid program indexes PID=$(start_background "$XDPDUMP -i $NS -p hallo@3e") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Can't extract valid program id from \"hallo@3e\"!"* ]]; then print_result "xdpdump should fail with id value error!" rm -rf "$PIN_DIR" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p hallo@128") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Invalid program id supplied, \"hallo@128\"!"* ]]; then print_result "xdpdump should fail with invalid id!" rm -rf "$PIN_DIR" return 1 fi # Remove pinned programs rm -rf "$PIN_DIR" ip link set dev "$NS" xdpgeneric off # Now test actual multi-program parsing (negative test cases) $XDP_LOADER unload "$NS" --all $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" "$TEST_PROG_DIR/xdp_pass.o" "$TEST_PROG_DIR/xdp_drop.o" PID=$(start_background "$XDPDUMP -D") RESULT=$(stop_background "$PID") PROG_ID_1=$(echo "$RESULT" | grep "$NS" -A4 | cut -c51-55 | sed -n 1p | tr -d ' ') PROG_ID_2=$(echo "$RESULT" | grep "$NS" -A4 | cut -c51-55 | sed -n 2p | tr -d ' ') PROG_ID_3=$(echo "$RESULT" | grep "$NS" -A4 | cut -c51-55 | sed -n 3p | tr -d ' ') PROG_ID_4=$(echo "$RESULT" | grep "$NS" -A4 | cut -c51-55 | sed -n 4p | tr -d ' ') PID=$(start_background "$XDPDUMP -i $NS -p all") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Can't identify the full XDP 'xdp_test_prog_w' function in program $PROG_ID_2!"* || $RESULT != *"xdp_test_prog_with_a_long_name@$PROG_ID_2"* || $RESULT != *"xdp_test_prog_with_a_long_name_too@$PROG_ID_2"* || $RESULT != *"Command line to replace 'all':"* || $RESULT != *"xdp_dispatcher@$PROG_ID_1,@$PROG_ID_2,xdp_pass@$PROG_ID_3,xdp_drop@$PROG_ID_4"* ]]; then print_result "xdpdump should fail with all list!" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p hallo@$PROG_ID_1") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Can't find function 'hallo' in interface program $PROG_ID_1!"* ]]; then print_result "xdpdump should fail with hallo not found on program $PROG_ID_1!" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p hallo") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Can't find function 'hallo' on interface"* ]]; then print_result "xdpdump should fail hallo not found!" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_w") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Can't identify the full XDP 'xdp_test_prog_w' function!"* || $RESULT != *"xdp_test_prog_with_a_long_name_too"* ]]; then print_result "xdpdump should fail can't id xdp_test_prog_w!" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_w@$PROG_ID_2") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: Can't identify the full XDP 'xdp_test_prog_w' function in program $PROG_ID_2!"* || $RESULT != *"xdp_test_prog_with_a_long_name_too@$PROG_ID_2"* ]]; then print_result "xdpdump should fail can't id xdp_test_prog_w@$PROG_ID_2!" return 1 fi # Now load XDP programs with duplicate functions $XDP_LOADER unload "$NS" --all $XDP_LOADER load "$NS" "$TEST_PROG_DIR/test_long_func_name.o" "$TEST_PROG_DIR/test_long_func_name.o" "$TEST_PROG_DIR/xdp_pass.o" "$TEST_PROG_DIR/xdp_drop.o" PID=$(start_background "$XDPDUMP -D") RESULT=$(stop_background "$PID") PROG_ID_1=$(echo "$RESULT" | grep "$NS" -A2 | cut -c51-55 | sed -n 1p | tr -d ' ') PROG_ID_2=$(echo "$RESULT" | grep "$NS" -A2 | cut -c51-55 | sed -n 2p | tr -d ' ') PROG_ID_3=$(echo "$RESULT" | grep "$NS" -A2 | cut -c51-55 | sed -n 2p | tr -d ' ') PID=$(start_background "$XDPDUMP -i $NS -p xdp_test_prog_with_a_long_name") RESULT=$(stop_background "$PID") if [[ $RESULT != *"ERROR: The function 'xdp_test_prog_with_a_long_name' exists in multiple programs!"* || $RESULT != *"xdp_test_prog_with_a_long_name@$PROG_ID_2"* || $RESULT != *"xdp_test_prog_with_a_long_name@$PROG_ID_3"* ]]; then print_result "xdpdump should fail with duplicate function!" return 1 fi $XDP_LOADER unload "$NS" --all return 0 } test_multi_prog() { skip_if_legacy_fallback local ENTRY_REGEX="(xdp_dispatcher\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+).*(xdp_pass\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local EXIT_REGEX="(xdp_pass\(\)@exit\[PASS\]: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+).*(xdp_dispatcher\(\)@exit\[PASS\]: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local PROG_ID_1=0 local PROG_ID_4=0 $XDP_LOADER load "$NS" "$TEST_PROG_DIR/xdp_pass.o" "$TEST_PROG_DIR/test_long_func_name.o" "$TEST_PROG_DIR/xdp_pass.o" PID=$(start_background "$XDPDUMP -D") RESULT=$(stop_background "$PID") PROG_ID_1=$(echo "$RESULT" | grep "$NS" -A4 | cut -c51-55 | sed -n 1p | tr -d ' ') PROG_ID_4=$(echo "$RESULT" | grep "$NS" -A4 | cut -c51-55 | sed -n 4p | tr -d ' ') PID=$(start_background "$XDPDUMP -i $NS -p xdp_dispatcher,xdp_pass@$PROG_ID_4 -vv") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if [[ $RESULT == *"Unrecognized arg#0 type PTR"* ]]; then $XDP_LOADER unload "$NS" --all return $SKIPPED_TEST fi if ! [[ $RESULT =~ $ENTRY_REGEX ]]; then print_result "Not received all fentry packets" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p xdp_dispatcher,xdp_pass@$PROG_ID_4 --rx-capture=exit") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $EXIT_REGEX ]]; then print_result "Not received all fexit packets" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p xdp_dispatcher,xdp_pass@$PROG_ID_4 --rx-capture=exit,entry") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $ENTRY_REGEX ]]; then print_result "Not received all fentry packets on entry/exit test" return 1 fi if ! [[ $RESULT =~ $EXIT_REGEX ]]; then print_result "Not received all fexit packets on entry/exit test" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p $PROG_ID_1,$PROG_ID_4 --rx-capture=exit,entry") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $ENTRY_REGEX ]]; then print_result "[IDs]Not received all fentry packets on entry/exit test" return 1 fi if ! [[ $RESULT =~ $EXIT_REGEX ]]; then print_result "[IDs]Not received all fexit packets on entry/exit test" return 1 fi PID=$(start_background "$XDPDUMP -i $NS -p xdp_dispatcher,$PROG_ID_4 --rx-capture=exit,entry") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if ! [[ $RESULT =~ $ENTRY_REGEX ]]; then print_result "[Mix]Not received all fentry packets on entry/exit test" return 1 fi if ! [[ $RESULT =~ $EXIT_REGEX ]]; then print_result "[Mix]Not received all fexit packets on entry/exit test" return 1 fi $XDP_LOADER unload "$NS" --all return 0 } test_xdp_load() { local PASS_REGEX="(xdpdump\(\)@entry: packet size 118 bytes on if_index [0-9]+, rx queue [0-9]+, id [0-9]+)" local WARN_MSG="Will load a capture only XDP program!" PID=$(start_background "$XDPDUMP -i $NS --load-xdp-program") $PING6 -W 2 -c 1 "$INSIDE_IP6" || return 1 RESULT=$(stop_background "$PID") if [[ "$RESULT" != *"$WARN_MSG"* ]]; then print_result "Missing warning message" return 1 fi if ! [[ $RESULT =~ $PASS_REGEX ]]; then print_result "IPv6 packet not received" return 1 fi } cleanup_tests() { $XDP_LOADER unload "$NS" --all >/dev/null 2>&1 }