Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2021 NVIDIA Corporation & Affiliates
3 : : */
4 : :
5 : : #define ALLOW_INTERNAL_API
6 : :
7 : : #include <stdlib.h>
8 : : #include <stdio.h>
9 : : #include <string.h>
10 : :
11 : : #include <ethdev_driver.h>
12 : : #include <rte_common.h>
13 : : #include <rte_devargs.h>
14 : : #include <rte_kvargs.h>
15 : : #include <rte_bus.h>
16 : : #include <rte_class.h>
17 : :
18 : : #include "test.h"
19 : :
20 : : /* Check layer arguments. */
21 : : static int
22 : 27 : test_args(const char *devargs, const char *layer, const char *args, const int n)
23 : : {
24 : : struct rte_kvargs *kvlist;
25 : :
26 [ + + ]: 27 : if (n == 0) {
27 [ + + - + ]: 15 : if (args != NULL && strlen(args) > 0) {
28 : : printf("rte_devargs_parse(%s) %s args parsed (not expected)\n",
29 : : devargs, layer);
30 : 0 : return -1;
31 : : } else {
32 : : return 0;
33 : : }
34 : : }
35 [ - + ]: 12 : if (args == NULL) {
36 : : printf("rte_devargs_parse(%s) %s args not parsed\n",
37 : : devargs, layer);
38 : 0 : return -1;
39 : : }
40 : 12 : kvlist = rte_kvargs_parse(args, NULL);
41 [ - + ]: 12 : if (kvlist == NULL) {
42 : : printf("rte_devargs_parse(%s) %s_str: %s not parsed\n",
43 : : devargs, layer, args);
44 : 0 : return -1;
45 : : }
46 [ - + ]: 12 : if ((int)kvlist->count != n) {
47 : : printf("rte_devargs_parse(%s) %s_str: %s kv number %u, not %d\n",
48 : : devargs, layer, args, kvlist->count, n);
49 : 0 : rte_kvargs_free(kvlist);
50 : 0 : return -1;
51 : : }
52 : 12 : rte_kvargs_free(kvlist);
53 : 12 : return 0;
54 : : }
55 : :
56 : : struct devargs_case {
57 : : const char *devargs;
58 : : int bus_kv;
59 : : int class_kv;
60 : : int driver_kv;
61 : : const char *bus;
62 : : const char *name;
63 : : const char *class;
64 : : };
65 : :
66 : : static int
67 : 1 : test_valid_devargs_cases(const struct devargs_case *list, size_t n)
68 : : {
69 : : struct rte_devargs da;
70 : : uint32_t i;
71 : : int ret;
72 : : int fail = TEST_SUCCESS;
73 : 1 : struct rte_bus *pci_bus = rte_bus_find_by_name("pci");
74 : 1 : struct rte_bus *vdev_bus = rte_bus_find_by_name("vdev");
75 : 1 : struct rte_class *eth_class = rte_class_find_by_name("eth");
76 : :
77 [ + + ]: 10 : for (i = 0; i < n; i++) {
78 [ - + - - ]: 9 : if (pci_bus == NULL && list[i].bus != NULL &&
79 [ # # ]: 0 : strcmp(list[i].bus, "pci") == 0)
80 : 0 : continue;
81 [ - + - - ]: 9 : if (vdev_bus == NULL && list[i].bus != NULL &&
82 [ # # ]: 0 : strcmp(list[i].bus, "vdev") == 0)
83 : 0 : continue;
84 [ - + - - ]: 9 : if (eth_class == NULL && list[i].class != NULL &&
85 [ # # ]: 0 : strcmp(list[i].class, "eth") == 0)
86 : 0 : continue;
87 : : memset(&da, 0, sizeof(da));
88 : 9 : ret = rte_devargs_parse(&da, list[i].devargs);
89 [ - + ]: 9 : if (ret < 0) {
90 : : printf("rte_devargs_parse(%s) returned %d (but should not)\n",
91 : 0 : list[i].devargs, ret);
92 : 0 : goto fail;
93 : : }
94 [ + + + + ]: 9 : if ((list[i].bus_kv > 0 || list[i].bus != NULL) &&
95 [ - + ]: 8 : da.bus == NULL) {
96 : : printf("rte_devargs_parse(%s) bus not parsed\n",
97 : 0 : list[i].devargs);
98 : 0 : goto fail;
99 : : }
100 [ - + ]: 9 : if (test_args(list[i].devargs, "bus", da.bus_str,
101 : : list[i].bus_kv) != 0)
102 : 0 : goto fail;
103 [ + + ]: 9 : if (list[i].bus != NULL &&
104 [ - + ]: 8 : strcmp(rte_bus_name(da.bus), list[i].bus) != 0) {
105 : 0 : printf("rte_devargs_parse(%s) bus name (%s) not expected (%s)\n",
106 : 0 : list[i].devargs, rte_bus_name(da.bus), list[i].bus);
107 : 0 : goto fail;
108 : : }
109 [ + + - + ]: 9 : if ((list[i].class_kv > 0 || list[i].class != NULL) &&
110 [ - + ]: 5 : da.cls == NULL) {
111 : : printf("rte_devargs_parse(%s) class not parsed\n",
112 : 0 : list[i].devargs);
113 : 0 : goto fail;
114 : : }
115 [ - + ]: 9 : if (test_args(list[i].devargs, "class", da.cls_str,
116 : : list[i].class_kv) != 0)
117 : 0 : goto fail;
118 [ + + ]: 9 : if (list[i].class != NULL &&
119 [ - + ]: 5 : strcmp(da.cls->name, list[i].class) != 0) {
120 : : printf("rte_devargs_parse(%s) class name (%s) not expected (%s)\n",
121 : 0 : list[i].devargs, da.cls->name, list[i].class);
122 : 0 : goto fail;
123 : : }
124 [ - + ]: 9 : if (test_args(list[i].devargs, "driver", da.drv_str,
125 : 9 : list[i].driver_kv) != 0)
126 : 0 : goto fail;
127 [ + + ]: 9 : if (list[i].name != NULL &&
128 [ - + ]: 7 : strcmp(da.name, list[i].name) != 0) {
129 : : printf("rte_devargs_parse(%s) device name (%s) not expected (%s)\n",
130 : 0 : list[i].devargs, da.name, list[i].name);
131 : 0 : goto fail;
132 : : }
133 : 9 : goto cleanup;
134 : : fail:
135 : : fail = TEST_FAILED;
136 : 9 : cleanup:
137 : 9 : rte_devargs_reset(&da);
138 : : }
139 : 1 : return fail;
140 : : }
141 : :
142 : : /* Test several valid cases */
143 : : static int
144 : : test_valid_devargs(void)
145 : : {
146 : : static const struct devargs_case list[] = {
147 : : /* Global devargs syntax: */
148 : : { "bus=pci",
149 : : 1, 0, 0, "pci", NULL, NULL},
150 : : { "class=eth",
151 : : 0, 1, 0, NULL, NULL, "eth" },
152 : : { "bus=pci,addr=1:2.3/class=eth/driver=abc,k0=v0",
153 : : 2, 1, 2, "pci", "0000:01:02.3", "eth" },
154 : : { "bus=vdev,name=/dev/file/name/class=eth",
155 : : 2, 1, 0, "vdev", "/dev/file/name", "eth" },
156 : : { "bus=vdev,name=/class/bus/path/class=eth",
157 : : 2, 1, 0, "vdev", "/class/bus/path", "eth" },
158 : : { "bus=vdev,name=///dblslsh/class=eth",
159 : : 2, 1, 0, "vdev", "///dblslsh", "eth" },
160 : : /* Legacy devargs syntax: */
161 : : { "1:2.3", 0, 0, 0,
162 : : "pci", "1:2.3", NULL },
163 : : { "pci:1:2.3,k0=v0",
164 : : 0, 0, 1, "pci", "1:2.3", NULL },
165 : : { "net_null0",
166 : : 0, 0, 0, "vdev", "net_null0", NULL },
167 : : };
168 : :
169 : 1 : return test_valid_devargs_cases(list, RTE_DIM(list));
170 : : }
171 : :
172 : : /* Test several invalid cases */
173 : : static int
174 : 1 : test_invalid_devargs(void)
175 : : {
176 : : static const char * const list[] = {
177 : : "bus=wrong-bus",
178 : : "class=wrong-class"};
179 : : struct rte_devargs da;
180 : : uint32_t i;
181 : : int ret;
182 : : int fail = 0;
183 : :
184 [ + + ]: 3 : for (i = 0; i < RTE_DIM(list); i++) {
185 : 2 : ret = rte_devargs_parse(&da, list[i]);
186 [ - + ]: 2 : if (ret >= 0) {
187 : : printf("rte_devargs_parse(%s) returned %d (but should not)\n",
188 : : list[i], ret);
189 : : fail = ret;
190 : : }
191 : 2 : rte_devargs_reset(&da);
192 : : }
193 : 1 : return fail;
194 : : }
195 : :
196 : : struct devargs_parse_case {
197 : : const char *devargs;
198 : : uint8_t devargs_count;
199 : : };
200 : :
201 : : static int
202 : 1 : test_valid_devargs_parsing(void)
203 : : {
204 : : static const struct devargs_parse_case list[] = {
205 : : /* Single representors patterns */
206 : : {"representor=1", 1},
207 : : {"representor=[1,2,3]", 1},
208 : : {"representor=[0-3,5,7]", 1},
209 : : {"representor=vf[0-1]", 1},
210 : : {"representor=sf[0-1]", 1},
211 : : {"representor=pf1vf[0-1]", 1},
212 : : {"representor=pf[0-1]vf[1-2]", 1},
213 : : {"representor=pf[0-1]sf[1-2]", 1},
214 : : {"representor=c0pf[0-1]", 1},
215 : : {"representor=sf[1,2]vf[2]", 1}, /* Only SF ports will be represented */
216 : : {"representor=vf2sf[1-2]", 1}, /* Only VF ports will be represented */
217 : : {"representor=c[0-1]pf[0-1]vf[1-2]", 1},
218 : : /* Single devarg inside multiple representor pattern */
219 : : {"representor=[c[0-1]pf[0-1]vf[1-2]]", 1},
220 : : /* Multiple representors patterns */
221 : : {"representor=[vf0,3]", 2},
222 : : {"representor=[vf0,vf1]", 2},
223 : : {"representor=[vf[0],vf[1]]", 2},
224 : : {"representor=[vf[0,1],3]", 2},
225 : : {"representor=[vf[0,1],[3]]", 2},
226 : : {"representor=[pf1vf[0-1],3]", 2},
227 : : {"representor=[pf1vf[0-1],pf[0-1]]", 2},
228 : : {"representor=[pf1,pf3,pf1vf[0-1],vf[0],vf[1],vf0,vf1,vf2]", 8},
229 : : {"representor=[1,3,5,pf1,pf2,pf3,pf1vf[0-1],vf[0],vf[1],vf0,vf1,vf2]", 12},
230 : : {"representor=[[1,3,5],pf1,pf2,pf3,pf1vf[0-1],vf[0],vf[1],vf0,vf1,vf2]", 10},
231 : : {"representor=[c[0,2-4]pf[1,6]vf[0-1],vf[0],vf4,[3-5,7],pf1vf[0-1,6],pf[2,4,6]]", 6}
232 : : };
233 : : struct rte_eth_devargs eth_da[RTE_MAX_ETHPORTS];
234 : : uint32_t i;
235 : : int ret;
236 : : int fail = 0;
237 : :
238 [ + + ]: 25 : for (i = 0; i < RTE_DIM(list); i++) {
239 : : memset(eth_da, 0, RTE_MAX_ETHPORTS * sizeof(*eth_da));
240 : 24 : ret = rte_eth_devargs_parse(list[i].devargs, eth_da, RTE_MAX_ETHPORTS);
241 [ - + ]: 24 : if (ret <= 0) {
242 : : printf("rte_devargs_parse(%s) returned %d (but should not)\n",
243 : : list[i].devargs, ret);
244 : : fail = ret;
245 : 0 : break;
246 : : }
247 : :
248 : : /* Check the return value, count should be equivalent to no of devargs. */
249 [ - + ]: 24 : if (ret != list[i].devargs_count) {
250 : : printf("Devargs returned count %d != expected count %d\n", ret,
251 : : list[i].devargs_count);
252 : : fail = -1;
253 : 0 : break;
254 : : }
255 : : }
256 : 1 : return fail;
257 : : }
258 : :
259 : : static int
260 : 1 : test_invalid_devargs_parsing(void)
261 : : {
262 : : static const char * const list[] = {
263 : : "representor=1,2,3,4", /* Out [] missing */
264 : : "representor=[1 2 3]", /* , missing */
265 : : "representor=c[1,2]", /* Only controller no valid */
266 : : "representor=c0vf[0-1]", /* Controller with vf alone not valid */
267 : : "representor=c0sf[0-1]", /* Controller with sf alone not valid */
268 : : "representor=vf[0-1],vf3", /* Out [] missing */
269 : : "representor=[[vf0,3]]", /* Double [] is invalid */
270 : : "representor=pfvf[1-2]", /* No PF index provided */
271 : : "representor=pf1[vf[1-2]]", /* Additional [] across vf */
272 : : "representor=c0[pf1vf[1-2]]", /* Additional [] across pfvf */
273 : : "representor=c0[pf1[vf[1-2]]]", /* Additional [] across pfvf */
274 : : "representor=[pf1vf[0-1], pf[0-1]]", /* Space between two devargs is invalid */
275 : : "representor=[pf1vf[0-1], 3]", /* Space between two devargs is invalid */
276 : : "representor=pf1vf[1-2],representor=1", /* Multiple representor keys */
277 : : };
278 : : struct rte_eth_devargs eth_da[RTE_MAX_ETHPORTS];
279 : : uint32_t i;
280 : : int ret;
281 : : int fail = 0;
282 : :
283 [ + + ]: 15 : for (i = 0; i < RTE_DIM(list); i++) {
284 : : memset(eth_da, 0, RTE_MAX_ETHPORTS * sizeof(*eth_da));
285 : 14 : ret = rte_eth_devargs_parse(list[i], eth_da, RTE_MAX_ETHPORTS);
286 [ - + ]: 14 : if (ret > 0) {
287 : : printf("rte_devargs_parse(%s) returned %d (but should not)\n",
288 : : list[i], ret);
289 : : fail = ret;
290 : 0 : break;
291 : : }
292 : : }
293 : 1 : return fail;
294 : : }
295 : :
296 : : static int
297 : 1 : test_devargs(void)
298 : : {
299 : : printf("== test valid case ==\n");
300 [ + - ]: 1 : if (test_valid_devargs() < 0)
301 : : return -1;
302 : : printf("== test invalid case ==\n");
303 [ + - ]: 1 : if (test_invalid_devargs() < 0)
304 : : return -1;
305 : : printf("== test devargs parsing valid case ==\n");
306 [ + - ]: 1 : if (test_valid_devargs_parsing() < 0)
307 : : return -1;
308 : : printf("== test devargs parsing invalid case ==\n");
309 [ - + ]: 1 : if (test_invalid_devargs_parsing() < 0)
310 : 0 : return -1;
311 : : return 0;
312 : : }
313 : :
314 : 302 : REGISTER_FAST_TEST(devargs_autotest, NOHUGE_OK, ASAN_OK, test_devargs);
|