1*e64e03b4SCosmin Ratiu#!/usr/bin/env python3 2*e64e03b4SCosmin Ratiu# SPDX-License-Identifier: GPL-2.0 3*e64e03b4SCosmin Ratiu"""Traffic test for VXLAN + IPsec crypto-offload.""" 4*e64e03b4SCosmin Ratiu 5*e64e03b4SCosmin Ratiuimport os 6*e64e03b4SCosmin Ratiu 7*e64e03b4SCosmin Ratiufrom lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge 8*e64e03b4SCosmin Ratiufrom lib.py import ksft_variants, KsftNamedVariant, KsftSkipEx 9*e64e03b4SCosmin Ratiufrom lib.py import CmdExitFailure, NetDrvEpEnv, cmd, defer, ethtool, ip 10*e64e03b4SCosmin Ratiufrom lib.py import Iperf3Runner 11*e64e03b4SCosmin Ratiu 12*e64e03b4SCosmin Ratiu# Inner tunnel addresses - TEST-NET-2 (RFC 5737) / doc prefix (RFC 3849) 13*e64e03b4SCosmin RatiuINNER_V4_LOCAL = "198.51.100.1" 14*e64e03b4SCosmin RatiuINNER_V4_REMOTE = "198.51.100.2" 15*e64e03b4SCosmin RatiuINNER_V6_LOCAL = "2001:db8:100::1" 16*e64e03b4SCosmin RatiuINNER_V6_REMOTE = "2001:db8:100::2" 17*e64e03b4SCosmin Ratiu 18*e64e03b4SCosmin Ratiu# ESP parameters 19*e64e03b4SCosmin RatiuSPI_OUT = "0x1000" 20*e64e03b4SCosmin RatiuSPI_IN = "0x1001" 21*e64e03b4SCosmin Ratiu# 128-bit key + 32-bit salt = 20 bytes hex, 128-bit ICV 22*e64e03b4SCosmin RatiuESP_AEAD = "aead 'rfc4106(gcm(aes))' 0x" + "01" * 20 + " 128" 23*e64e03b4SCosmin Ratiu 24*e64e03b4SCosmin Ratiu 25*e64e03b4SCosmin Ratiudef xfrm(args, host=None): 26*e64e03b4SCosmin Ratiu """Runs 'ip xfrm' via shell to preserve parentheses in algo names.""" 27*e64e03b4SCosmin Ratiu cmd(f"ip xfrm {args}", shell=True, host=host) 28*e64e03b4SCosmin Ratiu 29*e64e03b4SCosmin Ratiu 30*e64e03b4SCosmin Ratiudef check_xfrm_offload_support(): 31*e64e03b4SCosmin Ratiu """Skips if iproute2 lacks xfrm offload support.""" 32*e64e03b4SCosmin Ratiu out = cmd("ip xfrm state help", fail=False) 33*e64e03b4SCosmin Ratiu if "offload" not in out.stdout + out.stderr: 34*e64e03b4SCosmin Ratiu raise KsftSkipEx("iproute2 too old, missing xfrm offload") 35*e64e03b4SCosmin Ratiu 36*e64e03b4SCosmin Ratiu 37*e64e03b4SCosmin Ratiudef check_esp_hw_offload(cfg): 38*e64e03b4SCosmin Ratiu """Skips if device lacks esp-hw-offload support.""" 39*e64e03b4SCosmin Ratiu check_xfrm_offload_support() 40*e64e03b4SCosmin Ratiu try: 41*e64e03b4SCosmin Ratiu feat = ethtool(f"-k {cfg.ifname}", json=True)[0] 42*e64e03b4SCosmin Ratiu except (CmdExitFailure, IndexError) as e: 43*e64e03b4SCosmin Ratiu raise KsftSkipEx(f"can't query features: {e}") from e 44*e64e03b4SCosmin Ratiu if not feat.get("esp-hw-offload", {}).get("active"): 45*e64e03b4SCosmin Ratiu raise KsftSkipEx("Device does not support esp-hw-offload") 46*e64e03b4SCosmin Ratiu 47*e64e03b4SCosmin Ratiu 48*e64e03b4SCosmin Ratiudef get_tx_drops(cfg): 49*e64e03b4SCosmin Ratiu """Returns TX dropped counter from the physical device.""" 50*e64e03b4SCosmin Ratiu stats = ip("-s -s link show dev " + cfg.ifname, json=True)[0] 51*e64e03b4SCosmin Ratiu return stats["stats64"]["tx"]["dropped"] 52*e64e03b4SCosmin Ratiu 53*e64e03b4SCosmin Ratiu 54*e64e03b4SCosmin Ratiudef setup_vxlan_ipsec(cfg, outer_ipver, inner_ipver): 55*e64e03b4SCosmin Ratiu """Sets up VXLAN tunnel with IPsec transport-mode crypto-offload.""" 56*e64e03b4SCosmin Ratiu vxlan_name = f"vx{os.getpid()}" 57*e64e03b4SCosmin Ratiu local_addr = cfg.addr_v[outer_ipver] 58*e64e03b4SCosmin Ratiu remote_addr = cfg.remote_addr_v[outer_ipver] 59*e64e03b4SCosmin Ratiu 60*e64e03b4SCosmin Ratiu if inner_ipver == "4": 61*e64e03b4SCosmin Ratiu inner_local = f"{INNER_V4_LOCAL}/24" 62*e64e03b4SCosmin Ratiu inner_remote = f"{INNER_V4_REMOTE}/24" 63*e64e03b4SCosmin Ratiu addr_extra = "" 64*e64e03b4SCosmin Ratiu else: 65*e64e03b4SCosmin Ratiu inner_local = f"{INNER_V6_LOCAL}/64" 66*e64e03b4SCosmin Ratiu inner_remote = f"{INNER_V6_REMOTE}/64" 67*e64e03b4SCosmin Ratiu addr_extra = " nodad" 68*e64e03b4SCosmin Ratiu 69*e64e03b4SCosmin Ratiu if outer_ipver == "6": 70*e64e03b4SCosmin Ratiu vxlan_opts = "udp6zerocsumtx udp6zerocsumrx" 71*e64e03b4SCosmin Ratiu else: 72*e64e03b4SCosmin Ratiu vxlan_opts = "noudpcsum" 73*e64e03b4SCosmin Ratiu 74*e64e03b4SCosmin Ratiu # VXLAN tunnel - local side 75*e64e03b4SCosmin Ratiu ip(f"link add {vxlan_name} type vxlan id 100 dstport 4789 {vxlan_opts} " 76*e64e03b4SCosmin Ratiu f"local {local_addr} remote {remote_addr} dev {cfg.ifname}") 77*e64e03b4SCosmin Ratiu defer(ip, f"link del {vxlan_name}") 78*e64e03b4SCosmin Ratiu ip(f"addr add {inner_local} dev {vxlan_name}{addr_extra}") 79*e64e03b4SCosmin Ratiu ip(f"link set {vxlan_name} up") 80*e64e03b4SCosmin Ratiu 81*e64e03b4SCosmin Ratiu # VXLAN tunnel - remote side 82*e64e03b4SCosmin Ratiu ip(f"link add {vxlan_name} type vxlan id 100 dstport 4789 {vxlan_opts} " 83*e64e03b4SCosmin Ratiu f"local {remote_addr} remote {local_addr} dev {cfg.remote_ifname}", 84*e64e03b4SCosmin Ratiu host=cfg.remote) 85*e64e03b4SCosmin Ratiu defer(ip, f"link del {vxlan_name}", host=cfg.remote) 86*e64e03b4SCosmin Ratiu ip(f"addr add {inner_remote} dev {vxlan_name}{addr_extra}", 87*e64e03b4SCosmin Ratiu host=cfg.remote) 88*e64e03b4SCosmin Ratiu ip(f"link set {vxlan_name} up", host=cfg.remote) 89*e64e03b4SCosmin Ratiu 90*e64e03b4SCosmin Ratiu # xfrm state - local outbound SA 91*e64e03b4SCosmin Ratiu xfrm(f"state add src {local_addr} dst {remote_addr} " 92*e64e03b4SCosmin Ratiu f"proto esp spi {SPI_OUT} " 93*e64e03b4SCosmin Ratiu f"{ESP_AEAD} " 94*e64e03b4SCosmin Ratiu f"mode transport offload crypto dev {cfg.ifname} dir out") 95*e64e03b4SCosmin Ratiu defer(xfrm, f"state del src {local_addr} dst {remote_addr} " 96*e64e03b4SCosmin Ratiu f"proto esp spi {SPI_OUT}") 97*e64e03b4SCosmin Ratiu 98*e64e03b4SCosmin Ratiu # xfrm state - local inbound SA 99*e64e03b4SCosmin Ratiu xfrm(f"state add src {remote_addr} dst {local_addr} " 100*e64e03b4SCosmin Ratiu f"proto esp spi {SPI_IN} " 101*e64e03b4SCosmin Ratiu f"{ESP_AEAD} " 102*e64e03b4SCosmin Ratiu f"mode transport offload crypto dev {cfg.ifname} dir in") 103*e64e03b4SCosmin Ratiu defer(xfrm, f"state del src {remote_addr} dst {local_addr} " 104*e64e03b4SCosmin Ratiu f"proto esp spi {SPI_IN}") 105*e64e03b4SCosmin Ratiu 106*e64e03b4SCosmin Ratiu # xfrm state - remote outbound SA (mirror, software crypto) 107*e64e03b4SCosmin Ratiu xfrm(f"state add src {remote_addr} dst {local_addr} " 108*e64e03b4SCosmin Ratiu f"proto esp spi {SPI_IN} " 109*e64e03b4SCosmin Ratiu f"{ESP_AEAD} " 110*e64e03b4SCosmin Ratiu f"mode transport", 111*e64e03b4SCosmin Ratiu host=cfg.remote) 112*e64e03b4SCosmin Ratiu defer(xfrm, f"state del src {remote_addr} dst {local_addr} " 113*e64e03b4SCosmin Ratiu f"proto esp spi {SPI_IN}", host=cfg.remote) 114*e64e03b4SCosmin Ratiu 115*e64e03b4SCosmin Ratiu # xfrm state - remote inbound SA (mirror, software crypto) 116*e64e03b4SCosmin Ratiu xfrm(f"state add src {local_addr} dst {remote_addr} " 117*e64e03b4SCosmin Ratiu f"proto esp spi {SPI_OUT} " 118*e64e03b4SCosmin Ratiu f"{ESP_AEAD} " 119*e64e03b4SCosmin Ratiu f"mode transport", 120*e64e03b4SCosmin Ratiu host=cfg.remote) 121*e64e03b4SCosmin Ratiu defer(xfrm, f"state del src {local_addr} dst {remote_addr} " 122*e64e03b4SCosmin Ratiu f"proto esp spi {SPI_OUT}", host=cfg.remote) 123*e64e03b4SCosmin Ratiu 124*e64e03b4SCosmin Ratiu # xfrm policy - local out 125*e64e03b4SCosmin Ratiu xfrm(f"policy add src {local_addr} dst {remote_addr} " 126*e64e03b4SCosmin Ratiu f"proto udp dport 4789 dir out " 127*e64e03b4SCosmin Ratiu f"tmpl src {local_addr} dst {remote_addr} proto esp mode transport") 128*e64e03b4SCosmin Ratiu defer(xfrm, f"policy del src {local_addr} dst {remote_addr} " 129*e64e03b4SCosmin Ratiu f"proto udp dport 4789 dir out") 130*e64e03b4SCosmin Ratiu 131*e64e03b4SCosmin Ratiu # xfrm policy - local in 132*e64e03b4SCosmin Ratiu xfrm(f"policy add src {remote_addr} dst {local_addr} " 133*e64e03b4SCosmin Ratiu f"proto udp dport 4789 dir in " 134*e64e03b4SCosmin Ratiu f"tmpl src {remote_addr} dst {local_addr} proto esp mode transport") 135*e64e03b4SCosmin Ratiu defer(xfrm, f"policy del src {remote_addr} dst {local_addr} " 136*e64e03b4SCosmin Ratiu f"proto udp dport 4789 dir in") 137*e64e03b4SCosmin Ratiu 138*e64e03b4SCosmin Ratiu # xfrm policy - remote out 139*e64e03b4SCosmin Ratiu xfrm(f"policy add src {remote_addr} dst {local_addr} " 140*e64e03b4SCosmin Ratiu f"proto udp dport 4789 dir out " 141*e64e03b4SCosmin Ratiu f"tmpl src {remote_addr} dst {local_addr} proto esp mode transport", 142*e64e03b4SCosmin Ratiu host=cfg.remote) 143*e64e03b4SCosmin Ratiu defer(xfrm, f"policy del src {remote_addr} dst {local_addr} " 144*e64e03b4SCosmin Ratiu f"proto udp dport 4789 dir out", host=cfg.remote) 145*e64e03b4SCosmin Ratiu 146*e64e03b4SCosmin Ratiu # xfrm policy - remote in 147*e64e03b4SCosmin Ratiu xfrm(f"policy add src {local_addr} dst {remote_addr} " 148*e64e03b4SCosmin Ratiu f"proto udp dport 4789 dir in " 149*e64e03b4SCosmin Ratiu f"tmpl src {local_addr} dst {remote_addr} proto esp mode transport", 150*e64e03b4SCosmin Ratiu host=cfg.remote) 151*e64e03b4SCosmin Ratiu defer(xfrm, f"policy del src {local_addr} dst {remote_addr} " 152*e64e03b4SCosmin Ratiu f"proto udp dport 4789 dir in", host=cfg.remote) 153*e64e03b4SCosmin Ratiu 154*e64e03b4SCosmin Ratiu 155*e64e03b4SCosmin Ratiudef _vxlan_ipsec_variants(): 156*e64e03b4SCosmin Ratiu """Generates outer/inner IP version variants.""" 157*e64e03b4SCosmin Ratiu for outer in ["4", "6"]: 158*e64e03b4SCosmin Ratiu for inner in ["4", "6"]: 159*e64e03b4SCosmin Ratiu yield KsftNamedVariant(f"outer_v{outer}_inner_v{inner}", outer, inner) 160*e64e03b4SCosmin Ratiu 161*e64e03b4SCosmin Ratiu 162*e64e03b4SCosmin Ratiu@ksft_variants(_vxlan_ipsec_variants()) 163*e64e03b4SCosmin Ratiudef test_vxlan_ipsec_crypto_offload(cfg, outer_ipver, inner_ipver): 164*e64e03b4SCosmin Ratiu """Tests VXLAN+IPsec crypto-offload has no TX drops.""" 165*e64e03b4SCosmin Ratiu cfg.require_ipver(outer_ipver) 166*e64e03b4SCosmin Ratiu check_esp_hw_offload(cfg) 167*e64e03b4SCosmin Ratiu 168*e64e03b4SCosmin Ratiu setup_vxlan_ipsec(cfg, outer_ipver, inner_ipver) 169*e64e03b4SCosmin Ratiu 170*e64e03b4SCosmin Ratiu if inner_ipver == "4": 171*e64e03b4SCosmin Ratiu inner_local = INNER_V4_LOCAL 172*e64e03b4SCosmin Ratiu inner_remote = INNER_V4_REMOTE 173*e64e03b4SCosmin Ratiu ping = "ping" 174*e64e03b4SCosmin Ratiu else: 175*e64e03b4SCosmin Ratiu inner_local = INNER_V6_LOCAL 176*e64e03b4SCosmin Ratiu inner_remote = INNER_V6_REMOTE 177*e64e03b4SCosmin Ratiu ping = "ping -6" 178*e64e03b4SCosmin Ratiu 179*e64e03b4SCosmin Ratiu cmd(f"{ping} -c 1 -W 2 {inner_remote}") 180*e64e03b4SCosmin Ratiu 181*e64e03b4SCosmin Ratiu drops_before = get_tx_drops(cfg) 182*e64e03b4SCosmin Ratiu 183*e64e03b4SCosmin Ratiu runner = Iperf3Runner(cfg, server_ip=inner_local, 184*e64e03b4SCosmin Ratiu client_ip=inner_remote) 185*e64e03b4SCosmin Ratiu bw_gbps = runner.measure_bandwidth(reverse=True) 186*e64e03b4SCosmin Ratiu 187*e64e03b4SCosmin Ratiu cfg.wait_hw_stats_settle() 188*e64e03b4SCosmin Ratiu drops_after = get_tx_drops(cfg) 189*e64e03b4SCosmin Ratiu 190*e64e03b4SCosmin Ratiu ksft_eq(drops_after - drops_before, 0, 191*e64e03b4SCosmin Ratiu comment="TX drops during VXLAN+IPsec") 192*e64e03b4SCosmin Ratiu ksft_ge(bw_gbps, 0.1, 193*e64e03b4SCosmin Ratiu comment="Minimum 100Mbps over VXLAN+IPsec") 194*e64e03b4SCosmin Ratiu 195*e64e03b4SCosmin Ratiu 196*e64e03b4SCosmin Ratiudef main(): 197*e64e03b4SCosmin Ratiu """Runs VXLAN+IPsec crypto-offload GSO selftest.""" 198*e64e03b4SCosmin Ratiu with NetDrvEpEnv(__file__, nsim_test=False) as cfg: 199*e64e03b4SCosmin Ratiu ksft_run([test_vxlan_ipsec_crypto_offload], args=(cfg,)) 200*e64e03b4SCosmin Ratiu ksft_exit() 201*e64e03b4SCosmin Ratiu 202*e64e03b4SCosmin Ratiu 203*e64e03b4SCosmin Ratiuif __name__ == "__main__": 204*e64e03b4SCosmin Ratiu main() 205