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