| #!/bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| |
| # +--------------------+ |
| # | H1 (vrf) | |
| # | + $h1 | |
| # | | 192.0.2.1/28 | |
| # +----|---------------+ |
| # | |
| # +----|--------------------------------+ |
| # | SW | | |
| # | +--|------------------------------+ | |
| # | | + $swp1 BR1 (802.1d) | | |
| # | | | | |
| # | | + vx1 (vxlan) | | |
| # | | local 192.0.2.17 | | |
| # | | id 1000 dstport $VXPORT | | |
| # | +---------------------------------+ | |
| # | | |
| # | 192.0.2.32/28 via 192.0.2.18 | |
| # | | |
| # | + $rp1 | |
| # | | 192.0.2.17/28 | |
| # +--|----------------------------------+ |
| # | |
| # +--|----------------------------------+ |
| # | | | |
| # | + $rp2 | |
| # | 192.0.2.18/28 | |
| # | | |
| # | VRP2 (vrf) | |
| # +-------------------------------------+ |
| |
| : ${VXPORT:=4789} |
| : ${ALL_TESTS:=" |
| default_test |
| plain_test |
| reserved_0_test |
| reserved_10_test |
| reserved_31_test |
| reserved_56_test |
| reserved_63_test |
| "} |
| |
| NUM_NETIFS=4 |
| source lib.sh |
| |
| h1_create() |
| { |
| simple_if_init $h1 192.0.2.1/28 |
| defer simple_if_fini $h1 192.0.2.1/28 |
| |
| tc qdisc add dev $h1 clsact |
| defer tc qdisc del dev $h1 clsact |
| |
| tc filter add dev $h1 ingress pref 77 \ |
| prot ip flower skip_hw ip_proto icmp action drop |
| defer tc filter del dev $h1 ingress pref 77 |
| } |
| |
| switch_create() |
| { |
| ip_link_add br1 type bridge vlan_filtering 0 mcast_snooping 0 |
| # Make sure the bridge uses the MAC address of the local port and not |
| # that of the VxLAN's device. |
| ip_link_set_addr br1 $(mac_get $swp1) |
| ip_link_set_up br1 |
| |
| ip_link_set_up $rp1 |
| ip_addr_add $rp1 192.0.2.17/28 |
| ip_route_add 192.0.2.32/28 nexthop via 192.0.2.18 |
| |
| ip_link_set_master $swp1 br1 |
| ip_link_set_up $swp1 |
| } |
| |
| vrp2_create() |
| { |
| simple_if_init $rp2 192.0.2.18/28 |
| defer simple_if_fini $rp2 192.0.2.18/28 |
| } |
| |
| setup_prepare() |
| { |
| h1=${NETIFS[p1]} |
| swp1=${NETIFS[p2]} |
| |
| rp1=${NETIFS[p3]} |
| rp2=${NETIFS[p4]} |
| |
| vrf_prepare |
| defer vrf_cleanup |
| |
| forwarding_enable |
| defer forwarding_restore |
| |
| h1_create |
| switch_create |
| |
| vrp2_create |
| } |
| |
| vxlan_header_bytes() |
| { |
| local vni=$1; shift |
| local -a extra_bits=("$@") |
| local -a bits |
| local i |
| |
| for ((i=0; i < 64; i++)); do |
| bits[i]=0 |
| done |
| |
| # Bit 4 is the I flag and is always on. |
| bits[4]=1 |
| |
| for i in ${extra_bits[@]}; do |
| bits[i]=1 |
| done |
| |
| # Bits 32..55 carry the VNI |
| local mask=0x800000 |
| for ((i=0; i < 24; i++)); do |
| bits[$((i + 32))]=$(((vni & mask) != 0)) |
| ((mask >>= 1)) |
| done |
| |
| local bytes |
| for ((i=0; i < 8; i++)); do |
| local byte=0 |
| local j |
| for ((j=0; j < 8; j++)); do |
| local bit=${bits[8 * i + j]} |
| ((byte += bit << (7 - j))) |
| done |
| bytes+=$(printf %02x $byte): |
| done |
| |
| echo ${bytes%:} |
| } |
| |
| neg_bytes() |
| { |
| local bytes=$1; shift |
| |
| local -A neg=([0]=f [1]=e [2]=d [3]=c [4]=b [5]=a [6]=9 [7]=8 |
| [8]=7 [9]=6 [a]=5 [b]=4 [c]=3 [d]=2 [e]=1 [f]=0 [:]=:) |
| local out |
| local i |
| |
| for ((i=0; i < ${#bytes}; i++)); do |
| local c=${bytes:$i:1} |
| out+=${neg[$c]} |
| done |
| echo $out |
| } |
| |
| vxlan_ping_do() |
| { |
| local count=$1; shift |
| local dev=$1; shift |
| local next_hop_mac=$1; shift |
| local dest_ip=$1; shift |
| local dest_mac=$1; shift |
| local vni=$1; shift |
| local reserved_bits=$1; shift |
| |
| local vxlan_header=$(vxlan_header_bytes $vni $reserved_bits) |
| |
| $MZ $dev -c $count -d 100msec -q \ |
| -b $next_hop_mac -B $dest_ip \ |
| -t udp sp=23456,dp=$VXPORT,p=$(: |
| )"$vxlan_header:"$( : VXLAN |
| )"$dest_mac:"$( : ETH daddr |
| )"00:11:22:33:44:55:"$( : ETH saddr |
| )"08:00:"$( : ETH type |
| )"45:"$( : IP version + IHL |
| )"00:"$( : IP TOS |
| )"00:54:"$( : IP total length |
| )"99:83:"$( : IP identification |
| )"40:00:"$( : IP flags + frag off |
| )"40:"$( : IP TTL |
| )"01:"$( : IP proto |
| )"00:00:"$( : IP header csum |
| )"$(ipv4_to_bytes 192.0.2.3):"$( : IP saddr |
| )"$(ipv4_to_bytes 192.0.2.1):"$( : IP daddr |
| )"08:"$( : ICMP type |
| )"00:"$( : ICMP code |
| )"8b:f2:"$( : ICMP csum |
| )"1f:6a:"$( : ICMP request identifier |
| )"00:01:"$( : ICMP request seq. number |
| )"4f:ff:c5:5b:00:00:00:00:"$( : ICMP payload |
| )"6d:74:0b:00:00:00:00:00:"$( : |
| )"10:11:12:13:14:15:16:17:"$( : |
| )"18:19:1a:1b:1c:1d:1e:1f:"$( : |
| )"20:21:22:23:24:25:26:27:"$( : |
| )"28:29:2a:2b:2c:2d:2e:2f:"$( : |
| )"30:31:32:33:34:35:36:37" |
| } |
| |
| vxlan_device_add() |
| { |
| ip_link_add vx1 up type vxlan id 1000 \ |
| local 192.0.2.17 dstport "$VXPORT" \ |
| nolearning noudpcsum tos inherit ttl 100 "$@" |
| ip_link_set_master vx1 br1 |
| } |
| |
| vxlan_all_reserved_bits() |
| { |
| local i |
| |
| for ((i=0; i < 64; i++)); do |
| if ((i == 4 || i >= 32 && i < 56)); then |
| continue |
| fi |
| echo $i |
| done |
| } |
| |
| vxlan_ping_vanilla() |
| { |
| vxlan_ping_do 10 $rp2 $(mac_get $rp1) 192.0.2.17 $(mac_get $h1) 1000 |
| } |
| |
| vxlan_ping_reserved() |
| { |
| for bit in $(vxlan_all_reserved_bits); do |
| vxlan_ping_do 1 $rp2 $(mac_get $rp1) \ |
| 192.0.2.17 $(mac_get $h1) 1000 "$bit" |
| ((n++)) |
| done |
| } |
| |
| vxlan_ping_test() |
| { |
| local what=$1; shift |
| local get_stat=$1; shift |
| local expect=$1; shift |
| |
| RET=0 |
| |
| local t0=$($get_stat) |
| |
| "$@" |
| check_err $? "Failure when running $@" |
| |
| local t1=$($get_stat) |
| local delta=$((t1 - t0)) |
| |
| ((expect == delta)) |
| check_err $? "Expected to capture $expect packets, got $delta." |
| |
| log_test "$what" |
| } |
| |
| __default_test_do() |
| { |
| local n_allowed_bits=$1; shift |
| local what=$1; shift |
| |
| vxlan_ping_test "$what: clean packets" \ |
| "tc_rule_stats_get $h1 77 ingress" \ |
| 10 vxlan_ping_vanilla |
| |
| local t0=$(link_stats_get vx1 rx errors) |
| vxlan_ping_test "$what: mangled packets" \ |
| "tc_rule_stats_get $h1 77 ingress" \ |
| $n_allowed_bits vxlan_ping_reserved |
| local t1=$(link_stats_get vx1 rx errors) |
| |
| RET=0 |
| local expect=$((39 - n_allowed_bits)) |
| local delta=$((t1 - t0)) |
| ((expect == delta)) |
| check_err $? "Expected $expect error packets, got $delta." |
| log_test "$what: drops reported" |
| } |
| |
| default_test_do() |
| { |
| vxlan_device_add |
| __default_test_do 0 "Default" |
| } |
| |
| default_test() |
| { |
| in_defer_scope \ |
| default_test_do |
| } |
| |
| plain_test_do() |
| { |
| vxlan_device_add reserved_bits 0xf7ffffff000000ff |
| __default_test_do 0 "reserved_bits 0xf7ffffff000000ff" |
| } |
| |
| plain_test() |
| { |
| in_defer_scope \ |
| plain_test_do |
| } |
| |
| reserved_test() |
| { |
| local bit=$1; shift |
| |
| local allowed_bytes=$(vxlan_header_bytes 0xffffff $bit) |
| local reserved_bytes=$(neg_bytes $allowed_bytes) |
| local reserved_bits=${reserved_bytes//:/} |
| |
| vxlan_device_add reserved_bits 0x$reserved_bits |
| __default_test_do 1 "reserved_bits 0x$reserved_bits" |
| } |
| |
| reserved_0_test() |
| { |
| in_defer_scope \ |
| reserved_test 0 |
| } |
| |
| reserved_10_test() |
| { |
| in_defer_scope \ |
| reserved_test 10 |
| } |
| |
| reserved_31_test() |
| { |
| in_defer_scope \ |
| reserved_test 31 |
| } |
| |
| reserved_56_test() |
| { |
| in_defer_scope \ |
| reserved_test 56 |
| } |
| |
| reserved_63_test() |
| { |
| in_defer_scope \ |
| reserved_test 63 |
| } |
| |
| trap cleanup EXIT |
| |
| setup_prepare |
| setup_wait |
| tests_run |
| |
| exit $EXIT_STATUS |