1 /****************************************************************************
2 * Test cases for ethtool features
3 * Copyright 2012 Solarflare Communications Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published
7 * by the Free Software Foundation, incorporated herein by reference.
8 */
9
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #define TEST_NO_WRAPPERS
15 #include "internal.h"
16
17 static const struct {
18 struct ethtool_sset_info cmd;
19 u32 data[1];
20 }
21 cmd_gssetinfo = { { ETHTOOL_GSSET_INFO, 0, 1ULL << ETH_SS_FEATURES }, { 34 } };
22
23 static const struct ethtool_value
24 cmd_grxcsum_off = { ETHTOOL_GRXCSUM, 0 },
25 cmd_grxcsum_on = { ETHTOOL_GRXCSUM, 1 },
26 cmd_srxcsum_off = { ETHTOOL_SRXCSUM, 0 },
27 cmd_srxcsum_on = { ETHTOOL_SRXCSUM, 1 },
28 cmd_gtxcsum_off = { ETHTOOL_GTXCSUM, 0 },
29 cmd_gtxcsum_on = { ETHTOOL_GTXCSUM, 1 },
30 cmd_stxcsum_off = { ETHTOOL_STXCSUM, 0 },
31 cmd_stxcsum_on = { ETHTOOL_STXCSUM, 1 },
32 cmd_gsg_off = { ETHTOOL_GSG, 0 },
33 cmd_gsg_on = { ETHTOOL_GSG, 1 },
34 cmd_ssg_off = { ETHTOOL_SSG, 0 },
35 cmd_ssg_on = { ETHTOOL_SSG, 1 },
36 cmd_gtso_off = { ETHTOOL_GTSO, 0 },
37 cmd_gtso_on = { ETHTOOL_GTSO, 1 },
38 cmd_stso_off = { ETHTOOL_STSO, 0 },
39 cmd_stso_on = { ETHTOOL_STSO, 1 },
40 cmd_gufo_off = { ETHTOOL_GUFO, 0 },
41 cmd_gufo_on = { ETHTOOL_GUFO, 1 },
42 cmd_sufo_off = { ETHTOOL_SUFO, 0 },
43 cmd_sufo_on = { ETHTOOL_SUFO, 1 },
44 cmd_ggso_off = { ETHTOOL_GGSO, 0 },
45 cmd_ggso_on = { ETHTOOL_GGSO, 1 },
46 cmd_sgso_off = { ETHTOOL_SGSO, 0 },
47 cmd_sgso_on = { ETHTOOL_SGSO, 1 },
48 cmd_ggro_off = { ETHTOOL_GGRO, 0 },
49 cmd_ggro_on = { ETHTOOL_GGRO, 1 },
50 cmd_sgro_off = { ETHTOOL_SGRO, 0 },
51 cmd_sgro_on = { ETHTOOL_SGRO, 1 },
52 cmd_gflags_off = { ETHTOOL_GFLAGS, 0 },
53 cmd_gflags_on = { ETHTOOL_GFLAGS,
54 ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
55 ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH },
56 cmd_sflags_off = { ETHTOOL_SFLAGS, 0 },
57 cmd_sflags_ntuple = { ETHTOOL_GFLAGS, ETH_FLAG_NTUPLE },
58 cmd_sflags_on = { ETHTOOL_SFLAGS,
59 ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
60 ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH },
61 cmd_sflags_not_rxhash = { ETHTOOL_SFLAGS,
62 ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
63 ETH_FLAG_NTUPLE };
64
65 static const struct cmd_expect cmd_expect_get_strings_old[] = {
66 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
67 { 0, 0, 0, 0, 0 }
68 };
69
70 static const struct cmd_expect cmd_expect_get_features_off_old[] = {
71 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
72 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
73 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
74 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
75 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
76 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
77 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
78 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
79 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
80 { 0, 0, 0, 0, 0 }
81 };
82
83 static const struct cmd_expect cmd_expect_get_features_off_old_some_unsup[] = {
84 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
85 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
86 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
87 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
88 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
89 { &cmd_gufo_off, 4, -EOPNOTSUPP },
90 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
91 { &cmd_ggro_off, 4, -EOPNOTSUPP },
92 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
93 { 0, 0, 0, 0, 0 }
94 };
95
96 static const struct cmd_expect cmd_expect_get_features_off_old_some_priv[] = {
97 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EPERM },
98 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
99 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
100 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
101 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
102 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
103 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
104 { &cmd_ggro_off, 4, -EPERM },
105 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
106 { 0, 0, 0, 0, 0 }
107 };
108
109 static const struct cmd_expect cmd_expect_set_features_off_old[] = {
110 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
111 { &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
112 { &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
113 { &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
114 { &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
115 { &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
116 { &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
117 { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
118 { &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
119 { &cmd_srxcsum_off, sizeof(cmd_srxcsum_off), 0, 0, 0 },
120 { &cmd_stxcsum_off, sizeof(cmd_stxcsum_off), 0, 0, 0 },
121 { &cmd_ssg_off, sizeof(cmd_ssg_off), 0, 0, 0 },
122 { &cmd_stso_off, sizeof(cmd_stso_off), 0, 0, 0 },
123 { &cmd_sufo_off, sizeof(cmd_sufo_off), 0, 0, 0 },
124 { &cmd_sgso_off, sizeof(cmd_sgso_off), 0, 0, 0 },
125 { &cmd_sgro_off, sizeof(cmd_sgro_off), 0, 0, 0 },
126 { &cmd_sflags_off, sizeof(cmd_sflags_off), 0, 0, 0 },
127 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
128 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
129 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
130 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
131 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
132 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
133 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
134 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_sflags_off) },
135 { 0, 0, 0, 0, 0 }
136 };
137
138 static const struct cmd_expect cmd_expect_set_features_on_old[] = {
139 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
140 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
141 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
142 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
143 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
144 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
145 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
146 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
147 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
148 { &cmd_srxcsum_on, sizeof(cmd_srxcsum_on), 0, 0, 0 },
149 { &cmd_stxcsum_on, sizeof(cmd_stxcsum_on), 0, 0, 0 },
150 { &cmd_ssg_on, sizeof(cmd_ssg_on), 0, 0, 0 },
151 { &cmd_stso_on, sizeof(cmd_stso_on), 0, 0, 0 },
152 { &cmd_sufo_on, sizeof(cmd_sufo_on), 0, 0, 0 },
153 { &cmd_sgso_on, sizeof(cmd_sgso_on), 0, 0, 0 },
154 { &cmd_sgro_on, sizeof(cmd_sgro_on), 0, 0, 0 },
155 { &cmd_sflags_on, sizeof(cmd_sflags_on), 0, 0, 0 },
156 { &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
157 { &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
158 { &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
159 { &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
160 { &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
161 { &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
162 { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
163 { &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
164 { 0, 0, 0, 0, 0 }
165 };
166
167 static const struct cmd_expect cmd_expect_set_features_unsup_on_old[] = {
168 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
169 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
170 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
171 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
172 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
173 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
174 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
175 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
176 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
177 { &cmd_stxcsum_on, sizeof(cmd_stxcsum_on), -EOPNOTSUPP },
178 { 0, 0, 0, 0, 0 }
179 };
180
181 static const struct {
182 struct ethtool_gstrings cmd;
183 u8 data[34][ETH_GSTRING_LEN];
184 }
185 cmd_gstrings = {
186 { ETHTOOL_GSTRINGS, ETH_SS_FEATURES, 34 },
187 {
188 "tx-scatter-gather",
189 "tx-checksum-ipv4",
190 "",
191 "tx-checksum-ip-generic",
192 "tx-checksum-ipv6",
193 "highdma",
194 "tx-scatter-gather-fraglist",
195 "tx-vlan-hw-insert",
196 "rx-vlan-hw-parse",
197 "rx-vlan-filter",
198 "vlan-challenged",
199 "tx-generic-segmentation",
200 "tx-lockless",
201 "netns-local",
202 "rx-gro",
203 "rx-lro",
204 "tx-tcp-segmentation",
205 "tx-udp-fragmentation",
206 "tx-gso-robust",
207 "tx-tcp-ecn-segmentation",
208 "tx-tcp6-segmentation",
209 "tx-fcoe-segmentation",
210 "",
211 "",
212 "tx-checksum-fcoe-crc",
213 "tx-checksum-sctp",
214 "fcoe-mtu",
215 "rx-ntuple-filter",
216 "rx-hashing",
217 "rx-checksum",
218 "tx-nocache-copy",
219 "loopback",
220 "rx-fcs",
221 "rx-all",
222 }
223 };
224
225 static const struct {
226 struct ethtool_gfeatures cmd;
227 struct ethtool_get_features_block data[2];
228 }
229 /* available requested active never_changed */
230 /* minimal: only GRO and GSO are available (and GSO won't work) */
231 cmd_gfeatures_min_off = { { ETHTOOL_GFEATURES, 2 },
232 {{ 0x00004800, 0x00000000, 0x00000000, 0x00003400},
233 { 0x00000000, 0x00000000, 0x00000000, 0x00000000}}
234 },
235 cmd_gfeatures_min_on = { { ETHTOOL_GFEATURES, 2 },
236 {{ 0x00004800, 0x00004800, 0x00004000, 0x00003400},
237 { 0x00000000, 0x00000000, 0x00000000, 0x00000000}}
238 },
239 /* maximal: everything that isn't never-changed is available */
240 cmd_gfeatures_max_off = { { ETHTOOL_GFEATURES, 2 },
241 {{ 0xffffcbff, 0x00000000, 0x00000000, 0x00003400 },
242 { 0x00000003, 0x00000000, 0x00000000, 0x00000000 }}
243 },
244 cmd_gfeatures_max_on = { { ETHTOOL_GFEATURES, 2 },
245 {{ 0xffffcbff, 0xffffcbff, 0xffffcbff, 0x00003400 },
246 { 0x00000003, 0x00000003, 0x00000003, 0x00000000 }}
247 },
248 /* IPv4: GRO, GSO, SG and some IPv4-specific offloads are available */
249 cmd_gfeatures_ipv4_off = { { ETHTOOL_GFEATURES, 2 },
250 {{ 0x00014803, 0x00000000, 0x00000000, 0x00003400 },
251 { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }}
252 },
253 cmd_gfeatures_ipv4_on = { { ETHTOOL_GFEATURES, 2 },
254 {{ 0x00014803, 0x00014803, 0x00014803, 0x00003400 },
255 { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }}
256 };
257
258 static const struct {
259 struct ethtool_sfeatures cmd;
260 struct ethtool_set_features_block data[2];
261 }
262 /* valid requested */
263 cmd_sfeatures_min_on = { { ETHTOOL_SFEATURES, 2 },
264 {{ 0x00004800, 0x00004800 },
265 { 0x00000000, 0x00000000 }} },
266 cmd_sfeatures_min_off = { { ETHTOOL_SFEATURES, 2 },
267 {{ 0x00004800, 0x00000000 },
268 { 0x00000000, 0x00000000 }} },
269 cmd_sfeatures_noop = { { ETHTOOL_SFEATURES, 2 },
270 {{ 0x00000000, 0x00000000 },
271 { 0x00000000, 0x00000000 }} },
272 cmd_sfeatures_ipv4_on = { { ETHTOOL_SFEATURES, 2 },
273 {{ 0x00014803, 0x00014803 },
274 { 0x00000000, 0x00000000 }} };
275
276 static const struct cmd_expect cmd_expect_get_strings[] = {
277 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
278 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
279 { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
280 0, &cmd_gstrings, sizeof(cmd_gstrings) },
281 { 0, 0, 0, 0, 0 }
282 };
283
284 static const struct cmd_expect cmd_expect_get_features_min_off[] = {
285 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
286 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
287 { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
288 0, &cmd_gstrings, sizeof(cmd_gstrings) },
289 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
290 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
291 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
292 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
293 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
294 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
295 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
296 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
297 { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
298 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
299 { 0, 0, 0, 0, 0 }
300 };
301
302 static const struct cmd_expect cmd_expect_get_features_max_on[] = {
303 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
304 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
305 { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
306 0, &cmd_gstrings, sizeof(cmd_gstrings) },
307 { &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
308 { &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
309 { &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
310 { &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
311 { &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
312 { &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
313 { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
314 { &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
315 { &cmd_gfeatures_max_on, sizeof(cmd_gfeatures_max_on.cmd),
316 0, &cmd_gfeatures_max_on, sizeof(cmd_gfeatures_max_on) },
317 { 0, 0, 0, 0, 0 }
318 };
319
320 static const struct cmd_expect cmd_expect_set_features_min_off_min_on[] = {
321 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
322 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
323 { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
324 0, &cmd_gstrings, sizeof(cmd_gstrings) },
325 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
326 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
327 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
328 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
329 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
330 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
331 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
332 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
333 { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
334 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
335 { &cmd_sfeatures_min_on, sizeof(cmd_sfeatures_min_on),
336 ETHTOOL_F_WISH, 0, 0 },
337 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
338 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
339 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
340 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
341 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
342 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
343 { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
344 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
345 { &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on.cmd),
346 0, &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on) },
347 { 0, 0, 0, 0, 0 }
348 };
349
350 static const struct cmd_expect cmd_expect_set_features_min_off_min_off[] = {
351 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
352 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
353 { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
354 0, &cmd_gstrings, sizeof(cmd_gstrings) },
355 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
356 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
357 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
358 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
359 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
360 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
361 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
362 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
363 { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
364 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
365 { &cmd_sfeatures_min_off, sizeof(cmd_sfeatures_min_off), 0, 0, 0 },
366 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
367 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
368 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
369 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
370 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
371 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
372 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
373 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
374 { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
375 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
376 { 0, 0, 0, 0, 0 }
377 };
378
379 static const struct cmd_expect cmd_expect_set_features_min_on_min_off[] = {
380 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
381 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
382 { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
383 0, &cmd_gstrings, sizeof(cmd_gstrings) },
384 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
385 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
386 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
387 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
388 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
389 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
390 { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
391 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
392 { &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on.cmd),
393 0, &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on) },
394 { &cmd_sfeatures_min_off, sizeof(cmd_sfeatures_min_off), 0, 0, 0 },
395 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
396 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
397 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
398 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
399 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
400 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
401 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
402 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
403 { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
404 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
405 { 0, 0, 0, 0, 0 }
406 };
407
408 static const struct cmd_expect cmd_expect_set_features_min_off_unsup_on[] = {
409 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
410 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
411 { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
412 0, &cmd_gstrings, sizeof(cmd_gstrings) },
413 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
414 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
415 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
416 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
417 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
418 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
419 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
420 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
421 { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
422 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
423 { &cmd_sfeatures_noop, sizeof(cmd_sfeatures_noop), 0, 0, 0 },
424 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
425 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
426 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
427 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
428 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
429 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
430 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
431 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
432 { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
433 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
434 { 0, 0, 0, 0, 0 }
435 };
436
437 static const struct cmd_expect cmd_expect_set_features_ipv4_off_many_on[] = {
438 { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
439 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
440 { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
441 0, &cmd_gstrings, sizeof(cmd_gstrings) },
442 { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
443 { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
444 { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
445 { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
446 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
447 { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
448 { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
449 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
450 { &cmd_gfeatures_ipv4_off, sizeof(cmd_gfeatures_ipv4_off.cmd),
451 0, &cmd_gfeatures_ipv4_off, sizeof(cmd_gfeatures_ipv4_off) },
452 { &cmd_sfeatures_ipv4_on, sizeof(cmd_sfeatures_ipv4_on), 0, 0, 0 },
453 { &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
454 { &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
455 { &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
456 { &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
457 { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
458 { &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
459 { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
460 { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
461 { &cmd_gfeatures_ipv4_on, sizeof(cmd_gfeatures_ipv4_on.cmd),
462 0, &cmd_gfeatures_ipv4_on, sizeof(cmd_gfeatures_ipv4_on) },
463 { 0, 0, 0, 0, 0 }
464 };
465
466 static struct test_case {
467 int rc;
468 const char *args;
469 const struct cmd_expect *expect;
470 } const test_cases[] = {
471 { 0, "-k devname", cmd_expect_get_features_off_old },
472 { 0, "-k dev_unsup", cmd_expect_get_features_off_old_some_unsup },
473 { 0, "-k dev_priv", cmd_expect_get_features_off_old_some_priv },
474 { 0, "-K devname rx off tx off sg off tso off ufo off gso off lro off rxvlan off txvlan off ntuple off rxhash off gro off",
475 cmd_expect_set_features_off_old },
476 { 0, "-K devname rx on tx on sg on tso on ufo on gso on lro on rxvlan on txvlan on ntuple on rxhash on gro on",
477 cmd_expect_set_features_on_old },
478 { 1, "-K devname tx on sg on", cmd_expect_set_features_unsup_on_old },
479 { 0, "--show-offload devname", cmd_expect_get_features_min_off },
480 { 0, "--show-features devname", cmd_expect_get_features_max_on },
481 { 0, "-K devname rx on tx on sg on tso on ufo on gso on gro on",
482 cmd_expect_set_features_min_off_min_on },
483 { 0, "-K devname rx off tx off sg off tso off ufo off gso off gro off",
484 cmd_expect_set_features_min_off_min_off },
485 { 0, "-K devname rx off tx off sg off tso off ufo off gso off gro off",
486 cmd_expect_set_features_min_on_min_off },
487 { 1, "-K devname tx on sg on",
488 cmd_expect_set_features_min_off_unsup_on },
489 { 0, "--features devname rx on tx on sg on tso on gso on gro on",
490 cmd_expect_set_features_ipv4_off_many_on },
491 { 1, "-K devname rx foo", cmd_expect_get_strings_old },
492 { 1, "-K devname rx foo", cmd_expect_get_strings },
493 { 1, "--offload devname rx", cmd_expect_get_strings_old },
494 { 1, "--features devname rx", cmd_expect_get_strings },
495 { 1, "--features devname foo on", cmd_expect_get_strings_old },
496 { 1, "--offload devname foo on", cmd_expect_get_strings },
497 };
498
499 static int expect_matched;
500 static const struct cmd_expect *expect_next;
501
send_ioctl(struct cmd_context * ctx,void * cmd)502 int send_ioctl(struct cmd_context *ctx, void *cmd)
503 {
504 int rc = test_ioctl(expect_next, cmd);
505
506 if (rc == TEST_IOCTL_MISMATCH) {
507 expect_matched = 0;
508 test_exit(0);
509 }
510 expect_next++;
511 return rc;
512 }
513
main(void)514 int main(void)
515 {
516 const struct test_case *tc;
517 int test_rc;
518 int rc = 0;
519
520 for (tc = test_cases; tc < test_cases + ARRAY_SIZE(test_cases); tc++) {
521 if (getenv("ETHTOOL_TEST_VERBOSE"))
522 printf("I: Test command line: ethtool %s\n", tc->args);
523 expect_matched = 1;
524 expect_next = tc->expect;
525 test_rc = test_cmdline(tc->args);
526
527 /* If we found a mismatch, or there is still another
528 * expected ioctl to match, the test failed.
529 */
530 if (!expect_matched || expect_next->cmd) {
531 fprintf(stderr,
532 "E: ethtool %s deviated from the expected "
533 "ioctl sequence after %zu calls\n",
534 tc->args, expect_next - tc->expect);
535 rc = 1;
536 } else if (test_rc != tc->rc) {
537 fprintf(stderr, "E: ethtool %s returns %d\n",
538 tc->args, test_rc);
539 rc = 1;
540 }
541 }
542
543 return rc;
544 }
545