xref: /linux/tools/testing/selftests/drivers/net/hw/ipsec_vxlan.py (revision fcee7d82f27d6a8b1ddc5bbefda59b4e441e9bc0)
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