1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2018 Vincenzo Maffione
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * This program contains a suite of unit tests for the netmap control device.
30 *
31 * On FreeBSD, you can run these tests with Kyua once installed in the system:
32 * # kyua test -k /usr/tests/sys/netmap/Kyuafile
33 *
34 * On Linux, you can run them directly:
35 * # ./ctrl-api-test
36 */
37
38 #include <sys/ioctl.h>
39 #include <sys/mman.h>
40 #include <sys/wait.h>
41
42 #include <assert.h>
43 #include <ctype.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <inttypes.h>
47 #include <libnetmap.h>
48 #include <net/if.h>
49 #include <net/netmap.h>
50 #include <pthread.h>
51 #include <semaphore.h>
52 #include <stdint.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <time.h>
57 #include <unistd.h>
58 #include <signal.h>
59 #include <stddef.h>
60
61 #ifdef __FreeBSD__
62 static int
eventfd(int x __unused,int y __unused)63 eventfd(int x __unused, int y __unused)
64 {
65 errno = ENODEV;
66 return -1;
67 }
68 #else /* __linux__ */
69 #include <sys/eventfd.h>
70 #endif
71
72 #define NM_IFNAMSZ 64
73
74 static int
exec_command(int argc,const char * const argv[])75 exec_command(int argc, const char *const argv[])
76 {
77 pid_t child_pid;
78 pid_t wret;
79 int child_status;
80 int i;
81
82 printf("Executing command: ");
83 for (i = 0; i < argc - 1; i++) {
84 if (!argv[i]) {
85 /* Invalid argument. */
86 return -1;
87 }
88 if (i > 0) {
89 putchar(' ');
90 }
91 printf("%s", argv[i]);
92 }
93 putchar('\n');
94
95 child_pid = fork();
96 if (child_pid == 0) {
97 char **av;
98 int fds[3];
99
100 /* Child process. Redirect stdin, stdout
101 * and stderr. */
102 for (i = 0; i < 3; i++) {
103 close(i);
104 fds[i] = open("/dev/null", O_RDONLY);
105 if (fds[i] < 0) {
106 for (i--; i >= 0; i--) {
107 close(fds[i]);
108 }
109 return -1;
110 }
111 }
112
113 /* Make a copy of the arguments, passing them to execvp. */
114 av = calloc(argc, sizeof(av[0]));
115 if (!av) {
116 exit(EXIT_FAILURE);
117 }
118 for (i = 0; i < argc - 1; i++) {
119 av[i] = strdup(argv[i]);
120 if (!av[i]) {
121 exit(EXIT_FAILURE);
122 }
123 }
124 execvp(av[0], av);
125 perror("execvp()");
126 exit(EXIT_FAILURE);
127 }
128
129 wret = waitpid(child_pid, &child_status, 0);
130 if (wret < 0) {
131 fprintf(stderr, "waitpid() failed: %s\n", strerror(errno));
132 return wret;
133 }
134 if (WIFEXITED(child_status)) {
135 return WEXITSTATUS(child_status);
136 }
137
138 return -1;
139 }
140
141
142 #define THRET_SUCCESS ((void *)128)
143 #define THRET_FAILURE ((void *)0)
144
145 struct TestContext {
146 char ifname[NM_IFNAMSZ];
147 char ifname_ext[NM_IFNAMSZ];
148 char bdgname[NM_IFNAMSZ];
149 uint32_t nr_tx_slots; /* slots in tx rings */
150 uint32_t nr_rx_slots; /* slots in rx rings */
151 uint16_t nr_tx_rings; /* number of tx rings */
152 uint16_t nr_rx_rings; /* number of rx rings */
153 uint16_t nr_host_tx_rings; /* number of host tx rings */
154 uint16_t nr_host_rx_rings; /* number of host rx rings */
155 uint16_t nr_mem_id; /* id of the memory allocator */
156 uint16_t nr_ringid; /* ring(s) we care about */
157 uint32_t nr_mode; /* specify NR_REG_* modes */
158 uint32_t nr_extra_bufs; /* number of requested extra buffers */
159 uint64_t nr_flags; /* additional flags (see below) */
160 uint32_t nr_hdr_len; /* for PORT_HDR_SET and PORT_HDR_GET */
161 uint32_t nr_first_cpu_id; /* vale polling */
162 uint32_t nr_num_polling_cpus; /* vale polling */
163 uint32_t sync_kloop_mode; /* sync-kloop */
164 int fd; /* netmap file descriptor */
165
166 void *csb; /* CSB entries (atok and ktoa) */
167 struct nmreq_option *nr_opt; /* list of options */
168 sem_t *sem; /* for thread synchronization */
169
170 struct nmctx *nmctx;
171 const char *ifparse;
172 struct nmport_d *nmport; /* nmport descriptor from libnetmap */
173 };
174
175 static struct TestContext ctx_;
176
177 typedef int (*testfunc_t)(struct TestContext *ctx);
178
179 static void
nmreq_hdr_init(struct nmreq_header * hdr,const char * ifname)180 nmreq_hdr_init(struct nmreq_header *hdr, const char *ifname)
181 {
182 memset(hdr, 0, sizeof(*hdr));
183 hdr->nr_version = NETMAP_API;
184 assert(strlen(ifname) < NM_IFNAMSZ);
185 strncpy(hdr->nr_name, ifname, sizeof(hdr->nr_name));
186 }
187
188 /* Single NETMAP_REQ_PORT_INFO_GET. */
189 static int
port_info_get(struct TestContext * ctx)190 port_info_get(struct TestContext *ctx)
191 {
192 struct nmreq_port_info_get req;
193 struct nmreq_header hdr;
194 int success;
195 int ret;
196
197 printf("Testing NETMAP_REQ_PORT_INFO_GET on '%s'\n", ctx->ifname_ext);
198
199 nmreq_hdr_init(&hdr, ctx->ifname_ext);
200 hdr.nr_reqtype = NETMAP_REQ_PORT_INFO_GET;
201 hdr.nr_body = (uintptr_t)&req;
202 memset(&req, 0, sizeof(req));
203 req.nr_mem_id = ctx->nr_mem_id;
204 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
205 if (ret != 0) {
206 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_INFO_GET)");
207 return ret;
208 }
209 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
210 printf("nr_tx_slots %u\n", req.nr_tx_slots);
211 printf("nr_rx_slots %u\n", req.nr_rx_slots);
212 printf("nr_tx_rings %u\n", req.nr_tx_rings);
213 printf("nr_rx_rings %u\n", req.nr_rx_rings);
214 printf("nr_mem_id %u\n", req.nr_mem_id);
215
216 success = req.nr_memsize && req.nr_tx_slots && req.nr_rx_slots &&
217 req.nr_tx_rings && req.nr_rx_rings && req.nr_tx_rings;
218 if (!success) {
219 return -1;
220 }
221
222 /* Write back results to the context structure. */
223 ctx->nr_tx_slots = req.nr_tx_slots;
224 ctx->nr_rx_slots = req.nr_rx_slots;
225 ctx->nr_tx_rings = req.nr_tx_rings;
226 ctx->nr_rx_rings = req.nr_rx_rings;
227 ctx->nr_mem_id = req.nr_mem_id;
228
229 return 0;
230 }
231
232 /* Single NETMAP_REQ_REGISTER, no use. */
233 static int
port_register(struct TestContext * ctx)234 port_register(struct TestContext *ctx)
235 {
236 struct nmreq_register req;
237 struct nmreq_header hdr;
238 int success;
239 int ret;
240
241 printf("Testing NETMAP_REQ_REGISTER(mode=%d,ringid=%d,"
242 "flags=0x%llx) on '%s'\n",
243 ctx->nr_mode, ctx->nr_ringid, (unsigned long long)ctx->nr_flags,
244 ctx->ifname_ext);
245
246 nmreq_hdr_init(&hdr, ctx->ifname_ext);
247 hdr.nr_reqtype = NETMAP_REQ_REGISTER;
248 hdr.nr_body = (uintptr_t)&req;
249 hdr.nr_options = (uintptr_t)ctx->nr_opt;
250 memset(&req, 0, sizeof(req));
251 req.nr_mem_id = ctx->nr_mem_id;
252 req.nr_mode = ctx->nr_mode;
253 req.nr_ringid = ctx->nr_ringid;
254 req.nr_flags = ctx->nr_flags;
255 req.nr_tx_slots = ctx->nr_tx_slots;
256 req.nr_rx_slots = ctx->nr_rx_slots;
257 req.nr_tx_rings = ctx->nr_tx_rings;
258 req.nr_host_tx_rings = ctx->nr_host_tx_rings;
259 req.nr_host_rx_rings = ctx->nr_host_rx_rings;
260 req.nr_rx_rings = ctx->nr_rx_rings;
261 req.nr_extra_bufs = ctx->nr_extra_bufs;
262 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
263 if (ret != 0) {
264 perror("ioctl(/dev/netmap, NIOCCTRL, REGISTER)");
265 return ret;
266 }
267 printf("nr_offset 0x%llx\n", (unsigned long long)req.nr_offset);
268 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
269 printf("nr_tx_slots %u\n", req.nr_tx_slots);
270 printf("nr_rx_slots %u\n", req.nr_rx_slots);
271 printf("nr_tx_rings %u\n", req.nr_tx_rings);
272 printf("nr_rx_rings %u\n", req.nr_rx_rings);
273 printf("nr_host_tx_rings %u\n", req.nr_host_tx_rings);
274 printf("nr_host_rx_rings %u\n", req.nr_host_rx_rings);
275 printf("nr_mem_id %u\n", req.nr_mem_id);
276 printf("nr_extra_bufs %u\n", req.nr_extra_bufs);
277
278 success = req.nr_memsize && (ctx->nr_mode == req.nr_mode) &&
279 (ctx->nr_ringid == req.nr_ringid) &&
280 (ctx->nr_flags == req.nr_flags) &&
281 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
282 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
283 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
284 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
285 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
286 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
287 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
288 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
289 ((!ctx->nr_host_tx_rings && req.nr_host_tx_rings) ||
290 (ctx->nr_host_tx_rings == req.nr_host_tx_rings)) &&
291 ((!ctx->nr_host_rx_rings && req.nr_host_rx_rings) ||
292 (ctx->nr_host_rx_rings == req.nr_host_rx_rings)) &&
293 ((!ctx->nr_mem_id && req.nr_mem_id) ||
294 (ctx->nr_mem_id == req.nr_mem_id)) &&
295 (ctx->nr_extra_bufs == req.nr_extra_bufs);
296 if (!success) {
297 return -1;
298 }
299
300 /* Write back results to the context structure.*/
301 ctx->nr_tx_slots = req.nr_tx_slots;
302 ctx->nr_rx_slots = req.nr_rx_slots;
303 ctx->nr_tx_rings = req.nr_tx_rings;
304 ctx->nr_rx_rings = req.nr_rx_rings;
305 ctx->nr_host_tx_rings = req.nr_host_tx_rings;
306 ctx->nr_host_rx_rings = req.nr_host_rx_rings;
307 ctx->nr_mem_id = req.nr_mem_id;
308 ctx->nr_extra_bufs = req.nr_extra_bufs;
309
310 return 0;
311 }
312
313 static int
niocregif(struct TestContext * ctx,int netmap_api)314 niocregif(struct TestContext *ctx, int netmap_api)
315 {
316 struct nmreq req;
317 int success;
318 int ret;
319
320 printf("Testing legacy NIOCREGIF on '%s'\n", ctx->ifname_ext);
321
322 memset(&req, 0, sizeof(req));
323 memcpy(req.nr_name, ctx->ifname_ext, sizeof(req.nr_name));
324 req.nr_name[sizeof(req.nr_name) - 1] = '\0';
325 req.nr_version = netmap_api;
326 req.nr_ringid = ctx->nr_ringid;
327 req.nr_flags = ctx->nr_mode | ctx->nr_flags;
328 req.nr_tx_slots = ctx->nr_tx_slots;
329 req.nr_rx_slots = ctx->nr_rx_slots;
330 req.nr_tx_rings = ctx->nr_tx_rings;
331 req.nr_rx_rings = ctx->nr_rx_rings;
332 req.nr_arg2 = ctx->nr_mem_id;
333 req.nr_arg3 = ctx->nr_extra_bufs;
334
335 ret = ioctl(ctx->fd, NIOCREGIF, &req);
336 if (ret != 0) {
337 perror("ioctl(/dev/netmap, NIOCREGIF)");
338 return ret;
339 }
340
341 printf("nr_offset 0x%x\n", req.nr_offset);
342 printf("nr_memsize %u\n", req.nr_memsize);
343 printf("nr_tx_slots %u\n", req.nr_tx_slots);
344 printf("nr_rx_slots %u\n", req.nr_rx_slots);
345 printf("nr_tx_rings %u\n", req.nr_tx_rings);
346 printf("nr_rx_rings %u\n", req.nr_rx_rings);
347 printf("nr_version %d\n", req.nr_version);
348 printf("nr_ringid %x\n", req.nr_ringid);
349 printf("nr_flags %x\n", req.nr_flags);
350 printf("nr_arg2 %u\n", req.nr_arg2);
351 printf("nr_arg3 %u\n", req.nr_arg3);
352
353 success = req.nr_memsize &&
354 (ctx->nr_ringid == req.nr_ringid) &&
355 ((ctx->nr_mode | ctx->nr_flags) == req.nr_flags) &&
356 ((!ctx->nr_tx_slots && req.nr_tx_slots) ||
357 (ctx->nr_tx_slots == req.nr_tx_slots)) &&
358 ((!ctx->nr_rx_slots && req.nr_rx_slots) ||
359 (ctx->nr_rx_slots == req.nr_rx_slots)) &&
360 ((!ctx->nr_tx_rings && req.nr_tx_rings) ||
361 (ctx->nr_tx_rings == req.nr_tx_rings)) &&
362 ((!ctx->nr_rx_rings && req.nr_rx_rings) ||
363 (ctx->nr_rx_rings == req.nr_rx_rings)) &&
364 ((!ctx->nr_mem_id && req.nr_arg2) ||
365 (ctx->nr_mem_id == req.nr_arg2)) &&
366 (ctx->nr_extra_bufs == req.nr_arg3);
367 if (!success) {
368 return -1;
369 }
370
371 /* Write back results to the context structure.*/
372 ctx->nr_tx_slots = req.nr_tx_slots;
373 ctx->nr_rx_slots = req.nr_rx_slots;
374 ctx->nr_tx_rings = req.nr_tx_rings;
375 ctx->nr_rx_rings = req.nr_rx_rings;
376 ctx->nr_mem_id = req.nr_arg2;
377 ctx->nr_extra_bufs = req.nr_arg3;
378
379 return ret;
380 }
381
382 /* The 11 ABI is the one right before the introduction of the new NIOCCTRL
383 * ABI. The 11 ABI is useful to perform tests with legacy applications
384 * (which use the 11 ABI) and new kernel (which uses 12, or higher).
385 * However, version 14 introduced a change in the layout of struct netmap_if,
386 * so that binary backward compatibility to 11 is not supported anymore.
387 */
388 #define NETMAP_API_NIOCREGIF 14
389
390 static int
legacy_regif_default(struct TestContext * ctx)391 legacy_regif_default(struct TestContext *ctx)
392 {
393 return niocregif(ctx, NETMAP_API_NIOCREGIF);
394 }
395
396 static int
legacy_regif_all_nic(struct TestContext * ctx)397 legacy_regif_all_nic(struct TestContext *ctx)
398 {
399 ctx->nr_mode = NR_REG_ALL_NIC;
400 return niocregif(ctx, NETMAP_API);
401 }
402
403 static int
legacy_regif_12(struct TestContext * ctx)404 legacy_regif_12(struct TestContext *ctx)
405 {
406 ctx->nr_mode = NR_REG_ALL_NIC;
407 return niocregif(ctx, NETMAP_API_NIOCREGIF+1);
408 }
409
410 static int
legacy_regif_sw(struct TestContext * ctx)411 legacy_regif_sw(struct TestContext *ctx)
412 {
413 ctx->nr_mode = NR_REG_SW;
414 return niocregif(ctx, NETMAP_API_NIOCREGIF);
415 }
416
417 static int
legacy_regif_future(struct TestContext * ctx)418 legacy_regif_future(struct TestContext *ctx)
419 {
420 ctx->nr_mode = NR_REG_NIC_SW;
421 /* Test forward compatibility for the legacy ABI. This means
422 * using an older kernel (with ABI 12 or higher) and a newer
423 * application (with ABI greater than NETMAP_API). */
424 return niocregif(ctx, NETMAP_API+2);
425 }
426
427 static int
legacy_regif_extra_bufs(struct TestContext * ctx)428 legacy_regif_extra_bufs(struct TestContext *ctx)
429 {
430 ctx->nr_mode = NR_REG_ALL_NIC;
431 ctx->nr_extra_bufs = 20; /* arbitrary number of extra bufs */
432 return niocregif(ctx, NETMAP_API_NIOCREGIF);
433 }
434
435 static int
legacy_regif_extra_bufs_pipe(struct TestContext * ctx)436 legacy_regif_extra_bufs_pipe(struct TestContext *ctx)
437 {
438 strncat(ctx->ifname_ext, "{pipeexbuf", sizeof(ctx->ifname_ext));
439 ctx->nr_mode = NR_REG_ALL_NIC;
440 ctx->nr_extra_bufs = 58; /* arbitrary number of extra bufs */
441
442 return niocregif(ctx, NETMAP_API_NIOCREGIF);
443 }
444
445 static int
legacy_regif_extra_bufs_pipe_vale(struct TestContext * ctx)446 legacy_regif_extra_bufs_pipe_vale(struct TestContext *ctx)
447 {
448 strncpy(ctx->ifname_ext, "valeX1:Y4", sizeof(ctx->ifname_ext));
449 return legacy_regif_extra_bufs_pipe(ctx);
450 }
451
452 /* Only valid after a successful port_register(). */
453 static int
num_registered_rings(struct TestContext * ctx)454 num_registered_rings(struct TestContext *ctx)
455 {
456 if (ctx->nr_flags & NR_TX_RINGS_ONLY) {
457 return ctx->nr_tx_rings;
458 }
459 if (ctx->nr_flags & NR_RX_RINGS_ONLY) {
460 return ctx->nr_rx_rings;
461 }
462
463 return ctx->nr_tx_rings + ctx->nr_rx_rings;
464 }
465
466 static int
port_register_hwall_host(struct TestContext * ctx)467 port_register_hwall_host(struct TestContext *ctx)
468 {
469 ctx->nr_mode = NR_REG_NIC_SW;
470 return port_register(ctx);
471 }
472
473 static int
port_register_hostall(struct TestContext * ctx)474 port_register_hostall(struct TestContext *ctx)
475 {
476 ctx->nr_mode = NR_REG_SW;
477 return port_register(ctx);
478 }
479
480 static int
port_register_hwall(struct TestContext * ctx)481 port_register_hwall(struct TestContext *ctx)
482 {
483 ctx->nr_mode = NR_REG_ALL_NIC;
484 return port_register(ctx);
485 }
486
487 static int
port_register_single_hw_pair(struct TestContext * ctx)488 port_register_single_hw_pair(struct TestContext *ctx)
489 {
490 ctx->nr_mode = NR_REG_ONE_NIC;
491 ctx->nr_ringid = 0;
492 return port_register(ctx);
493 }
494
495 static int
port_register_single_host_pair(struct TestContext * ctx)496 port_register_single_host_pair(struct TestContext *ctx)
497 {
498 ctx->nr_mode = NR_REG_ONE_SW;
499 ctx->nr_host_tx_rings = 2;
500 ctx->nr_host_rx_rings = 2;
501 ctx->nr_ringid = 1;
502 return port_register(ctx);
503 }
504
505 static int
port_register_hostall_many(struct TestContext * ctx)506 port_register_hostall_many(struct TestContext *ctx)
507 {
508 ctx->nr_mode = NR_REG_SW;
509 ctx->nr_host_tx_rings = 5;
510 ctx->nr_host_rx_rings = 4;
511 return port_register(ctx);
512 }
513
514 static int
port_register_hwall_tx(struct TestContext * ctx)515 port_register_hwall_tx(struct TestContext *ctx)
516 {
517 ctx->nr_mode = NR_REG_ALL_NIC;
518 ctx->nr_flags |= NR_TX_RINGS_ONLY;
519 return port_register(ctx);
520 }
521
522 static int
port_register_hwall_rx(struct TestContext * ctx)523 port_register_hwall_rx(struct TestContext *ctx)
524 {
525 ctx->nr_mode = NR_REG_ALL_NIC;
526 ctx->nr_flags |= NR_RX_RINGS_ONLY;
527 return port_register(ctx);
528 }
529
530
531 static int
vale_mkname(char * vpname,struct TestContext * ctx)532 vale_mkname(char *vpname, struct TestContext *ctx)
533 {
534 if (snprintf(vpname, NM_IFNAMSZ, "%s:%s", ctx->bdgname, ctx->ifname_ext) >= NM_IFNAMSZ) {
535 fprintf(stderr, "%s:%s too long (max %d chars)\n", ctx->bdgname, ctx->ifname_ext,
536 NM_IFNAMSZ - 1);
537 return -1;
538 }
539 return 0;
540 }
541
542
543 /* NETMAP_REQ_VALE_ATTACH */
544 static int
vale_attach(struct TestContext * ctx)545 vale_attach(struct TestContext *ctx)
546 {
547 struct nmreq_vale_attach req;
548 struct nmreq_header hdr;
549 char vpname[NM_IFNAMSZ];
550 int ret;
551
552 if (vale_mkname(vpname, ctx) < 0)
553 return -1;
554
555 printf("Testing NETMAP_REQ_VALE_ATTACH on '%s'\n", vpname);
556 nmreq_hdr_init(&hdr, vpname);
557 hdr.nr_reqtype = NETMAP_REQ_VALE_ATTACH;
558 hdr.nr_body = (uintptr_t)&req;
559 memset(&req, 0, sizeof(req));
560 req.reg.nr_mem_id = ctx->nr_mem_id;
561 if (ctx->nr_mode == 0) {
562 ctx->nr_mode = NR_REG_ALL_NIC; /* default */
563 }
564 req.reg.nr_mode = ctx->nr_mode;
565 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
566 if (ret != 0) {
567 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_ATTACH)");
568 return ret;
569 }
570 printf("nr_mem_id %u\n", req.reg.nr_mem_id);
571
572 return ((!ctx->nr_mem_id && req.reg.nr_mem_id > 1) ||
573 (ctx->nr_mem_id == req.reg.nr_mem_id)) &&
574 (ctx->nr_flags == req.reg.nr_flags)
575 ? 0
576 : -1;
577 }
578
579 /* NETMAP_REQ_VALE_DETACH */
580 static int
vale_detach(struct TestContext * ctx)581 vale_detach(struct TestContext *ctx)
582 {
583 struct nmreq_header hdr;
584 struct nmreq_vale_detach req;
585 char vpname[NM_IFNAMSZ];
586 int ret;
587
588 if (vale_mkname(vpname, ctx) < 0)
589 return -1;
590
591 printf("Testing NETMAP_REQ_VALE_DETACH on '%s'\n", vpname);
592 nmreq_hdr_init(&hdr, vpname);
593 hdr.nr_reqtype = NETMAP_REQ_VALE_DETACH;
594 hdr.nr_body = (uintptr_t)&req;
595 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
596 if (ret != 0) {
597 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_DETACH)");
598 return ret;
599 }
600
601 return 0;
602 }
603
604 /* First NETMAP_REQ_VALE_ATTACH, then NETMAP_REQ_VALE_DETACH. */
605 static int
vale_attach_detach(struct TestContext * ctx)606 vale_attach_detach(struct TestContext *ctx)
607 {
608 int ret;
609
610 if ((ret = vale_attach(ctx)) != 0) {
611 return ret;
612 }
613
614 return vale_detach(ctx);
615 }
616
617 static int
vale_attach_detach_host_rings(struct TestContext * ctx)618 vale_attach_detach_host_rings(struct TestContext *ctx)
619 {
620 ctx->nr_mode = NR_REG_NIC_SW;
621 return vale_attach_detach(ctx);
622 }
623
624 /* First NETMAP_REQ_PORT_HDR_SET and the NETMAP_REQ_PORT_HDR_GET
625 * to check that we get the same value. */
626 static int
port_hdr_set_and_get(struct TestContext * ctx)627 port_hdr_set_and_get(struct TestContext *ctx)
628 {
629 struct nmreq_port_hdr req;
630 struct nmreq_header hdr;
631 int ret;
632
633 printf("Testing NETMAP_REQ_PORT_HDR_SET on '%s'\n", ctx->ifname_ext);
634
635 nmreq_hdr_init(&hdr, ctx->ifname_ext);
636 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_SET;
637 hdr.nr_body = (uintptr_t)&req;
638 memset(&req, 0, sizeof(req));
639 req.nr_hdr_len = ctx->nr_hdr_len;
640 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
641 if (ret != 0) {
642 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
643 return ret;
644 }
645
646 if (req.nr_hdr_len != ctx->nr_hdr_len) {
647 return -1;
648 }
649
650 printf("Testing NETMAP_REQ_PORT_HDR_GET on '%s'\n", ctx->ifname_ext);
651 hdr.nr_reqtype = NETMAP_REQ_PORT_HDR_GET;
652 req.nr_hdr_len = 0;
653 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
654 if (ret != 0) {
655 perror("ioctl(/dev/netmap, NIOCCTRL, PORT_HDR_SET)");
656 return ret;
657 }
658 printf("nr_hdr_len %u\n", req.nr_hdr_len);
659
660 return (req.nr_hdr_len == ctx->nr_hdr_len) ? 0 : -1;
661 }
662
663 /*
664 * Possible lengths for the VirtIO network header, as specified by
665 * the standard:
666 * http://docs.oasis-open.org/virtio/virtio/v1.0/cs04/virtio-v1.0-cs04.html
667 */
668 #define VIRTIO_NET_HDR_LEN 10
669 #define VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS 12
670
671 static int
vale_ephemeral_port_hdr_manipulation(struct TestContext * ctx)672 vale_ephemeral_port_hdr_manipulation(struct TestContext *ctx)
673 {
674 int ret;
675
676 strncpy(ctx->ifname_ext, "vale:eph0", sizeof(ctx->ifname_ext));
677 ctx->nr_mode = NR_REG_ALL_NIC;
678 if ((ret = port_register(ctx))) {
679 return ret;
680 }
681 /* Try to set and get all the acceptable values. */
682 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN_WITH_MERGEABLE_RXBUFS;
683 if ((ret = port_hdr_set_and_get(ctx))) {
684 return ret;
685 }
686 ctx->nr_hdr_len = 0;
687 if ((ret = port_hdr_set_and_get(ctx))) {
688 return ret;
689 }
690 ctx->nr_hdr_len = VIRTIO_NET_HDR_LEN;
691 if ((ret = port_hdr_set_and_get(ctx))) {
692 return ret;
693 }
694 return 0;
695 }
696
697 static int
vale_persistent_port(struct TestContext * ctx)698 vale_persistent_port(struct TestContext *ctx)
699 {
700 struct nmreq_vale_newif req;
701 struct nmreq_header hdr;
702 int result;
703 int ret;
704
705 strncpy(ctx->ifname_ext, "per4", sizeof(ctx->ifname_ext));
706
707 printf("Testing NETMAP_REQ_VALE_NEWIF on '%s'\n", ctx->ifname_ext);
708
709 nmreq_hdr_init(&hdr, ctx->ifname_ext);
710 hdr.nr_reqtype = NETMAP_REQ_VALE_NEWIF;
711 hdr.nr_body = (uintptr_t)&req;
712 memset(&req, 0, sizeof(req));
713 req.nr_mem_id = ctx->nr_mem_id;
714 req.nr_tx_slots = ctx->nr_tx_slots;
715 req.nr_rx_slots = ctx->nr_rx_slots;
716 req.nr_tx_rings = ctx->nr_tx_rings;
717 req.nr_rx_rings = ctx->nr_rx_rings;
718 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
719 if (ret != 0) {
720 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
721 return ret;
722 }
723
724 /* Attach the persistent VALE port to a switch and then detach. */
725 result = vale_attach_detach(ctx);
726
727 printf("Testing NETMAP_REQ_VALE_DELIF on '%s'\n", ctx->ifname_ext);
728 hdr.nr_reqtype = NETMAP_REQ_VALE_DELIF;
729 hdr.nr_body = (uintptr_t)NULL;
730 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
731 if (ret != 0) {
732 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_NEWIF)");
733 if (result == 0) {
734 result = ret;
735 }
736 }
737
738 return result;
739 }
740
741 /* Single NETMAP_REQ_POOLS_INFO_GET. */
742 static int
pools_info_get(struct TestContext * ctx)743 pools_info_get(struct TestContext *ctx)
744 {
745 struct nmreq_pools_info req;
746 struct nmreq_header hdr;
747 int ret;
748
749 printf("Testing NETMAP_REQ_POOLS_INFO_GET on '%s'\n", ctx->ifname_ext);
750
751 nmreq_hdr_init(&hdr, ctx->ifname_ext);
752 hdr.nr_reqtype = NETMAP_REQ_POOLS_INFO_GET;
753 hdr.nr_body = (uintptr_t)&req;
754 memset(&req, 0, sizeof(req));
755 req.nr_mem_id = ctx->nr_mem_id;
756 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
757 if (ret != 0) {
758 perror("ioctl(/dev/netmap, NIOCCTRL, POOLS_INFO_GET)");
759 return ret;
760 }
761 printf("nr_memsize %llu\n", (unsigned long long)req.nr_memsize);
762 printf("nr_mem_id %u\n", req.nr_mem_id);
763 printf("nr_if_pool_offset 0x%llx\n",
764 (unsigned long long)req.nr_if_pool_offset);
765 printf("nr_if_pool_objtotal %u\n", req.nr_if_pool_objtotal);
766 printf("nr_if_pool_objsize %u\n", req.nr_if_pool_objsize);
767 printf("nr_ring_pool_offset 0x%llx\n",
768 (unsigned long long)req.nr_if_pool_offset);
769 printf("nr_ring_pool_objtotal %u\n", req.nr_ring_pool_objtotal);
770 printf("nr_ring_pool_objsize %u\n", req.nr_ring_pool_objsize);
771 printf("nr_buf_pool_offset 0x%llx\n",
772 (unsigned long long)req.nr_buf_pool_offset);
773 printf("nr_buf_pool_objtotal %u\n", req.nr_buf_pool_objtotal);
774 printf("nr_buf_pool_objsize %u\n", req.nr_buf_pool_objsize);
775
776 return req.nr_memsize && req.nr_if_pool_objtotal &&
777 req.nr_if_pool_objsize &&
778 req.nr_ring_pool_objtotal &&
779 req.nr_ring_pool_objsize &&
780 req.nr_buf_pool_objtotal &&
781 req.nr_buf_pool_objsize
782 ? 0
783 : -1;
784 }
785
786 static int
pools_info_get_and_register(struct TestContext * ctx)787 pools_info_get_and_register(struct TestContext *ctx)
788 {
789 int ret;
790
791 /* Check that we can get pools info before we register
792 * a netmap interface. */
793 ret = pools_info_get(ctx);
794 if (ret != 0) {
795 return ret;
796 }
797
798 ctx->nr_mode = NR_REG_ONE_NIC;
799 ret = port_register(ctx);
800 if (ret != 0) {
801 return ret;
802 }
803 ctx->nr_mem_id = 1;
804
805 /* Check that we can get pools info also after we register. */
806 return pools_info_get(ctx);
807 }
808
809 static int
pools_info_get_empty_ifname(struct TestContext * ctx)810 pools_info_get_empty_ifname(struct TestContext *ctx)
811 {
812 strncpy(ctx->ifname_ext, "", sizeof(ctx->ifname_ext));
813 return pools_info_get(ctx) != 0 ? 0 : -1;
814 }
815
816 static int
pipe_master(struct TestContext * ctx)817 pipe_master(struct TestContext *ctx)
818 {
819 strncat(ctx->ifname_ext, "{pipeid1", sizeof(ctx->ifname_ext));
820 ctx->nr_mode = NR_REG_NIC_SW;
821
822 if (port_register(ctx) == 0) {
823 printf("pipes should not accept NR_REG_NIC_SW\n");
824 return -1;
825 }
826 ctx->nr_mode = NR_REG_ALL_NIC;
827
828 return port_register(ctx);
829 }
830
831 static int
pipe_slave(struct TestContext * ctx)832 pipe_slave(struct TestContext *ctx)
833 {
834 strncat(ctx->ifname_ext, "}pipeid2", sizeof(ctx->ifname_ext));
835 ctx->nr_mode = NR_REG_ALL_NIC;
836
837 return port_register(ctx);
838 }
839
840 /* Test PORT_INFO_GET and POOLS_INFO_GET on a pipe. This is useful to test the
841 * registration request used internally by netmap. */
842 static int
pipe_port_info_get(struct TestContext * ctx)843 pipe_port_info_get(struct TestContext *ctx)
844 {
845 strncat(ctx->ifname_ext, "}pipeid3", sizeof(ctx->ifname_ext));
846
847 return port_info_get(ctx);
848 }
849
850 static int
pipe_pools_info_get(struct TestContext * ctx)851 pipe_pools_info_get(struct TestContext *ctx)
852 {
853 strncat(ctx->ifname_ext, "{xid", sizeof(ctx->ifname_ext));
854
855 return pools_info_get(ctx);
856 }
857
858 /* NETMAP_REQ_VALE_POLLING_ENABLE */
859 static int
vale_polling_enable(struct TestContext * ctx)860 vale_polling_enable(struct TestContext *ctx)
861 {
862 struct nmreq_vale_polling req;
863 struct nmreq_header hdr;
864 char vpname[NM_IFNAMSZ];
865 int ret;
866
867 if (vale_mkname(vpname, ctx) < 0)
868 return -1;
869
870 printf("Testing NETMAP_REQ_VALE_POLLING_ENABLE on '%s'\n", vpname);
871
872 nmreq_hdr_init(&hdr, vpname);
873 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_ENABLE;
874 hdr.nr_body = (uintptr_t)&req;
875 memset(&req, 0, sizeof(req));
876 req.nr_mode = ctx->nr_mode;
877 req.nr_first_cpu_id = ctx->nr_first_cpu_id;
878 req.nr_num_polling_cpus = ctx->nr_num_polling_cpus;
879 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
880 if (ret != 0) {
881 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_ENABLE)");
882 return ret;
883 }
884
885 return (req.nr_mode == ctx->nr_mode &&
886 req.nr_first_cpu_id == ctx->nr_first_cpu_id &&
887 req.nr_num_polling_cpus == ctx->nr_num_polling_cpus)
888 ? 0
889 : -1;
890 }
891
892 /* NETMAP_REQ_VALE_POLLING_DISABLE */
893 static int
vale_polling_disable(struct TestContext * ctx)894 vale_polling_disable(struct TestContext *ctx)
895 {
896 struct nmreq_vale_polling req;
897 struct nmreq_header hdr;
898 char vpname[NM_IFNAMSZ];
899 int ret;
900
901 if (vale_mkname(vpname, ctx) < 0)
902 return -1;
903
904 printf("Testing NETMAP_REQ_VALE_POLLING_DISABLE on '%s'\n", vpname);
905
906 nmreq_hdr_init(&hdr, vpname);
907 hdr.nr_reqtype = NETMAP_REQ_VALE_POLLING_DISABLE;
908 hdr.nr_body = (uintptr_t)&req;
909 memset(&req, 0, sizeof(req));
910 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
911 if (ret != 0) {
912 perror("ioctl(/dev/netmap, NIOCCTRL, VALE_POLLING_DISABLE)");
913 return ret;
914 }
915
916 return 0;
917 }
918
919 static int
vale_polling_enable_disable(struct TestContext * ctx)920 vale_polling_enable_disable(struct TestContext *ctx)
921 {
922 int ret = 0;
923
924 if ((ret = vale_attach(ctx)) != 0) {
925 return ret;
926 }
927
928 ctx->nr_mode = NETMAP_POLLING_MODE_SINGLE_CPU;
929 ctx->nr_num_polling_cpus = 1;
930 ctx->nr_first_cpu_id = 0;
931 if ((ret = vale_polling_enable(ctx))) {
932 vale_detach(ctx);
933 #ifdef __FreeBSD__
934 /* NETMAP_REQ_VALE_POLLING_DISABLE is disabled on FreeBSD,
935 * because it is currently broken. We are happy to see that
936 * it fails. */
937 return 0;
938 #else
939 return ret;
940 #endif
941 }
942
943 if ((ret = vale_polling_disable(ctx))) {
944 vale_detach(ctx);
945 return ret;
946 }
947
948 return vale_detach(ctx);
949 }
950
951 static void
push_option(struct nmreq_option * opt,struct TestContext * ctx)952 push_option(struct nmreq_option *opt, struct TestContext *ctx)
953 {
954 opt->nro_next = (uintptr_t)ctx->nr_opt;
955 ctx->nr_opt = opt;
956 }
957
958 static void
clear_options(struct TestContext * ctx)959 clear_options(struct TestContext *ctx)
960 {
961 ctx->nr_opt = NULL;
962 }
963
964 static int
checkoption(struct nmreq_option * opt,struct nmreq_option * exp)965 checkoption(struct nmreq_option *opt, struct nmreq_option *exp)
966 {
967 if (opt->nro_next != exp->nro_next) {
968 printf("nro_next %p expected %p\n",
969 (void *)(uintptr_t)opt->nro_next,
970 (void *)(uintptr_t)exp->nro_next);
971 return -1;
972 }
973 if (opt->nro_reqtype != exp->nro_reqtype) {
974 printf("nro_reqtype %u expected %u\n", opt->nro_reqtype,
975 exp->nro_reqtype);
976 return -1;
977 }
978 if (opt->nro_status != exp->nro_status) {
979 printf("nro_status %u expected %u\n", opt->nro_status,
980 exp->nro_status);
981 return -1;
982 }
983 return 0;
984 }
985
986 static int
unsupported_option(struct TestContext * ctx)987 unsupported_option(struct TestContext *ctx)
988 {
989 struct nmreq_option opt, save;
990
991 printf("Testing unsupported option on %s\n", ctx->ifname_ext);
992
993 memset(&opt, 0, sizeof(opt));
994 opt.nro_reqtype = 1234;
995 push_option(&opt, ctx);
996 save = opt;
997
998 if (port_register_hwall(ctx) >= 0)
999 return -1;
1000
1001 clear_options(ctx);
1002 save.nro_status = EOPNOTSUPP;
1003 return checkoption(&opt, &save);
1004 }
1005
1006 static int
infinite_options(struct TestContext * ctx)1007 infinite_options(struct TestContext *ctx)
1008 {
1009 struct nmreq_option opt;
1010
1011 printf("Testing infinite list of options on %s (invalid options)\n", ctx->ifname_ext);
1012
1013 memset(&opt, 0, sizeof(opt));
1014 opt.nro_reqtype = NETMAP_REQ_OPT_MAX + 1;
1015 push_option(&opt, ctx);
1016 opt.nro_next = (uintptr_t)&opt;
1017 if (port_register_hwall(ctx) >= 0)
1018 return -1;
1019 clear_options(ctx);
1020 return (errno == EMSGSIZE ? 0 : -1);
1021 }
1022
1023 static int
infinite_options2(struct TestContext * ctx)1024 infinite_options2(struct TestContext *ctx)
1025 {
1026 struct nmreq_option opt;
1027
1028 printf("Testing infinite list of options on %s (valid options)\n", ctx->ifname_ext);
1029
1030 memset(&opt, 0, sizeof(opt));
1031 opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS;
1032 push_option(&opt, ctx);
1033 opt.nro_next = (uintptr_t)&opt;
1034 if (port_register_hwall(ctx) >= 0)
1035 return -1;
1036 clear_options(ctx);
1037 return (errno == EINVAL ? 0 : -1);
1038 }
1039
1040 #ifdef CONFIG_NETMAP_EXTMEM
1041 int
change_param(const char * pname,unsigned long newv,unsigned long * poldv)1042 change_param(const char *pname, unsigned long newv, unsigned long *poldv)
1043 {
1044 #ifdef __linux__
1045 char param[256] = "/sys/module/netmap/parameters/";
1046 unsigned long oldv;
1047 FILE *f;
1048
1049 strncat(param, pname, sizeof(param) - 1);
1050
1051 f = fopen(param, "r+");
1052 if (f == NULL) {
1053 perror(param);
1054 return -1;
1055 }
1056 if (fscanf(f, "%ld", &oldv) != 1) {
1057 perror(param);
1058 fclose(f);
1059 return -1;
1060 }
1061 if (poldv)
1062 *poldv = oldv;
1063 rewind(f);
1064 if (fprintf(f, "%ld\n", newv) < 0) {
1065 perror(param);
1066 fclose(f);
1067 return -1;
1068 }
1069 fclose(f);
1070 printf("change_param: %s: %ld -> %ld\n", pname, oldv, newv);
1071 #endif /* __linux__ */
1072 return 0;
1073 }
1074
1075 static int
push_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi,struct nmreq_opt_extmem * e)1076 push_extmem_option(struct TestContext *ctx, const struct nmreq_pools_info *pi,
1077 struct nmreq_opt_extmem *e)
1078 {
1079 void *addr;
1080
1081 addr = mmap(NULL, pi->nr_memsize, PROT_READ | PROT_WRITE,
1082 MAP_ANONYMOUS | MAP_SHARED, -1, 0);
1083 if (addr == MAP_FAILED) {
1084 perror("mmap");
1085 return -1;
1086 }
1087
1088 memset(e, 0, sizeof(*e));
1089 e->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1090 e->nro_info = *pi;
1091 e->nro_usrptr = (uintptr_t)addr;
1092
1093 push_option(&e->nro_opt, ctx);
1094
1095 return 0;
1096 }
1097
1098 static int
pop_extmem_option(struct TestContext * ctx,struct nmreq_opt_extmem * exp)1099 pop_extmem_option(struct TestContext *ctx, struct nmreq_opt_extmem *exp)
1100 {
1101 struct nmreq_opt_extmem *e;
1102 int ret;
1103
1104 e = (struct nmreq_opt_extmem *)(uintptr_t)ctx->nr_opt;
1105 ctx->nr_opt = (struct nmreq_option *)(uintptr_t)ctx->nr_opt->nro_next;
1106
1107 if ((ret = checkoption(&e->nro_opt, &exp->nro_opt))) {
1108 return ret;
1109 }
1110
1111 if (e->nro_usrptr != exp->nro_usrptr) {
1112 printf("usrptr %" PRIu64 " expected %" PRIu64 "\n",
1113 e->nro_usrptr, exp->nro_usrptr);
1114 return -1;
1115 }
1116 if (e->nro_info.nr_memsize != exp->nro_info.nr_memsize) {
1117 printf("memsize %" PRIu64 " expected %" PRIu64 "\n",
1118 e->nro_info.nr_memsize, exp->nro_info.nr_memsize);
1119 return -1;
1120 }
1121
1122 if ((ret = munmap((void *)(uintptr_t)e->nro_usrptr,
1123 e->nro_info.nr_memsize)))
1124 return ret;
1125
1126 return 0;
1127 }
1128
1129 static int
_extmem_option(struct TestContext * ctx,const struct nmreq_pools_info * pi)1130 _extmem_option(struct TestContext *ctx,
1131 const struct nmreq_pools_info *pi)
1132 {
1133 struct nmreq_opt_extmem e, save;
1134 int ret;
1135
1136 if ((ret = push_extmem_option(ctx, pi, &e)) < 0)
1137 return ret;
1138
1139 save = e;
1140
1141 strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1142 ctx->nr_tx_slots = 16;
1143 ctx->nr_rx_slots = 16;
1144
1145 if ((ret = port_register_hwall(ctx)))
1146 return ret;
1147
1148 ret = pop_extmem_option(ctx, &save);
1149
1150 return ret;
1151 }
1152
1153 static size_t
pools_info_min_memsize(const struct nmreq_pools_info * pi)1154 pools_info_min_memsize(const struct nmreq_pools_info *pi)
1155 {
1156 size_t tot = 0;
1157
1158 tot += pi->nr_if_pool_objtotal * pi->nr_if_pool_objsize;
1159 tot += pi->nr_ring_pool_objtotal * pi->nr_ring_pool_objsize;
1160 tot += pi->nr_buf_pool_objtotal * pi->nr_buf_pool_objsize;
1161
1162 return tot;
1163 }
1164
1165 /*
1166 * Fill the specification of a netmap memory allocator to be
1167 * used with the 'struct nmreq_opt_extmem' option. Arbitrary
1168 * values are used for the parameters, but with enough netmap
1169 * rings, netmap ifs, and buffers to support a VALE port.
1170 */
1171 static void
pools_info_fill(struct nmreq_pools_info * pi)1172 pools_info_fill(struct nmreq_pools_info *pi)
1173 {
1174 pi->nr_if_pool_objtotal = 2;
1175 pi->nr_if_pool_objsize = 1024;
1176 pi->nr_ring_pool_objtotal = 64;
1177 pi->nr_ring_pool_objsize = 512;
1178 pi->nr_buf_pool_objtotal = 4096;
1179 pi->nr_buf_pool_objsize = 2048;
1180 pi->nr_memsize = pools_info_min_memsize(pi);
1181 }
1182
1183 static int
extmem_option(struct TestContext * ctx)1184 extmem_option(struct TestContext *ctx)
1185 {
1186 struct nmreq_pools_info pools_info;
1187
1188 pools_info_fill(&pools_info);
1189
1190 printf("Testing extmem option on vale0:0\n");
1191 return _extmem_option(ctx, &pools_info);
1192 }
1193
1194 static int
bad_extmem_option(struct TestContext * ctx)1195 bad_extmem_option(struct TestContext *ctx)
1196 {
1197 struct nmreq_pools_info pools_info;
1198
1199 printf("Testing bad extmem option on vale0:0\n");
1200
1201 pools_info_fill(&pools_info);
1202 /* Request a large ring size, to make sure that the kernel
1203 * rejects our request. */
1204 pools_info.nr_ring_pool_objsize = (1 << 20);
1205
1206 return _extmem_option(ctx, &pools_info) < 0 ? 0 : -1;
1207 }
1208
1209 static int
duplicate_extmem_options(struct TestContext * ctx)1210 duplicate_extmem_options(struct TestContext *ctx)
1211 {
1212 struct nmreq_opt_extmem e1, save1, e2, save2;
1213 struct nmreq_pools_info pools_info;
1214 int ret;
1215
1216 printf("Testing duplicate extmem option on vale0:0\n");
1217
1218 pools_info_fill(&pools_info);
1219
1220 if ((ret = push_extmem_option(ctx, &pools_info, &e1)) < 0)
1221 return ret;
1222
1223 if ((ret = push_extmem_option(ctx, &pools_info, &e2)) < 0) {
1224 clear_options(ctx);
1225 return ret;
1226 }
1227
1228 save1 = e1;
1229 save2 = e2;
1230
1231 strncpy(ctx->ifname_ext, "vale0:0", sizeof(ctx->ifname_ext));
1232 ctx->nr_tx_slots = 16;
1233 ctx->nr_rx_slots = 16;
1234
1235 ret = port_register_hwall(ctx);
1236 if (ret >= 0) {
1237 printf("duplicate option not detected\n");
1238 return -1;
1239 }
1240
1241 save2.nro_opt.nro_status = EINVAL;
1242 if ((ret = pop_extmem_option(ctx, &save2)))
1243 return ret;
1244
1245 save1.nro_opt.nro_status = EINVAL;
1246 if ((ret = pop_extmem_option(ctx, &save1)))
1247 return ret;
1248
1249 return 0;
1250 }
1251 #endif /* CONFIG_NETMAP_EXTMEM */
1252
1253 static int
push_csb_option(struct TestContext * ctx,struct nmreq_opt_csb * opt)1254 push_csb_option(struct TestContext *ctx, struct nmreq_opt_csb *opt)
1255 {
1256 size_t csb_size;
1257 int num_entries;
1258 int ret;
1259
1260 ctx->nr_flags |= NR_EXCLUSIVE;
1261
1262 /* Get port info in order to use num_registered_rings(). */
1263 ret = port_info_get(ctx);
1264 if (ret != 0) {
1265 return ret;
1266 }
1267 num_entries = num_registered_rings(ctx);
1268
1269 csb_size = (sizeof(struct nm_csb_atok) + sizeof(struct nm_csb_ktoa)) *
1270 num_entries;
1271 assert(csb_size > 0);
1272 if (ctx->csb) {
1273 free(ctx->csb);
1274 }
1275 ret = posix_memalign(&ctx->csb, sizeof(struct nm_csb_atok), csb_size);
1276 if (ret != 0) {
1277 printf("Failed to allocate CSB memory\n");
1278 exit(EXIT_FAILURE);
1279 }
1280
1281 memset(opt, 0, sizeof(*opt));
1282 opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1283 opt->csb_atok = (uintptr_t)ctx->csb;
1284 opt->csb_ktoa = (uintptr_t)(((uint8_t *)ctx->csb) +
1285 sizeof(struct nm_csb_atok) * num_entries);
1286
1287 printf("Pushing option NETMAP_REQ_OPT_CSB\n");
1288 push_option(&opt->nro_opt, ctx);
1289
1290 return 0;
1291 }
1292
1293 static int
csb_mode(struct TestContext * ctx)1294 csb_mode(struct TestContext *ctx)
1295 {
1296 struct nmreq_opt_csb opt;
1297 int ret;
1298
1299 ret = push_csb_option(ctx, &opt);
1300 if (ret != 0) {
1301 return ret;
1302 }
1303
1304 ret = port_register_hwall(ctx);
1305 clear_options(ctx);
1306
1307 return ret;
1308 }
1309
1310 static int
csb_mode_invalid_memory(struct TestContext * ctx)1311 csb_mode_invalid_memory(struct TestContext *ctx)
1312 {
1313 struct nmreq_opt_csb opt;
1314 int ret;
1315
1316 memset(&opt, 0, sizeof(opt));
1317 opt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_CSB;
1318 opt.csb_atok = (uintptr_t)0x10;
1319 opt.csb_ktoa = (uintptr_t)0x800;
1320 push_option(&opt.nro_opt, ctx);
1321
1322 ctx->nr_flags = NR_EXCLUSIVE;
1323 ret = port_register_hwall(ctx);
1324 clear_options(ctx);
1325
1326 return (ret < 0) ? 0 : -1;
1327 }
1328
1329 static int
sync_kloop_stop(struct TestContext * ctx)1330 sync_kloop_stop(struct TestContext *ctx)
1331 {
1332 struct nmreq_header hdr;
1333 int ret;
1334
1335 printf("Testing NETMAP_REQ_SYNC_KLOOP_STOP on '%s'\n", ctx->ifname_ext);
1336
1337 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1338 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_STOP;
1339 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1340 if (ret != 0) {
1341 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_STOP)");
1342 }
1343
1344 return ret;
1345 }
1346
1347 static void *
sync_kloop_worker(void * opaque)1348 sync_kloop_worker(void *opaque)
1349 {
1350 struct TestContext *ctx = opaque;
1351 struct nmreq_sync_kloop_start req;
1352 struct nmreq_header hdr;
1353 int ret;
1354
1355 printf("Testing NETMAP_REQ_SYNC_KLOOP_START on '%s'\n", ctx->ifname_ext);
1356
1357 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1358 hdr.nr_reqtype = NETMAP_REQ_SYNC_KLOOP_START;
1359 hdr.nr_body = (uintptr_t)&req;
1360 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1361 memset(&req, 0, sizeof(req));
1362 req.sleep_us = 500;
1363 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1364 if (ret != 0) {
1365 perror("ioctl(/dev/netmap, NIOCCTRL, SYNC_KLOOP_START)");
1366 }
1367
1368 if (ctx->sem) {
1369 sem_post(ctx->sem);
1370 }
1371
1372 pthread_exit(ret ? (void *)THRET_FAILURE : (void *)THRET_SUCCESS);
1373 }
1374
1375 static int
sync_kloop_start_stop(struct TestContext * ctx)1376 sync_kloop_start_stop(struct TestContext *ctx)
1377 {
1378 pthread_t th;
1379 void *thret = THRET_FAILURE;
1380 int ret;
1381
1382 ret = pthread_create(&th, NULL, sync_kloop_worker, ctx);
1383 if (ret != 0) {
1384 printf("pthread_create(kloop): %s\n", strerror(ret));
1385 return -1;
1386 }
1387
1388 ret = sync_kloop_stop(ctx);
1389 if (ret != 0) {
1390 return ret;
1391 }
1392
1393 ret = pthread_join(th, &thret);
1394 if (ret != 0) {
1395 printf("pthread_join(kloop): %s\n", strerror(ret));
1396 }
1397
1398 return thret == THRET_SUCCESS ? 0 : -1;
1399 }
1400
1401 static int
sync_kloop(struct TestContext * ctx)1402 sync_kloop(struct TestContext *ctx)
1403 {
1404 int ret;
1405
1406 ret = csb_mode(ctx);
1407 if (ret != 0) {
1408 return ret;
1409 }
1410
1411 return sync_kloop_start_stop(ctx);
1412 }
1413
1414 static int
sync_kloop_eventfds(struct TestContext * ctx)1415 sync_kloop_eventfds(struct TestContext *ctx)
1416 {
1417 struct nmreq_opt_sync_kloop_eventfds *evopt = NULL;
1418 struct nmreq_opt_sync_kloop_mode modeopt;
1419 struct nmreq_option evsave;
1420 int num_entries;
1421 size_t opt_size;
1422 int ret, i;
1423
1424 memset(&modeopt, 0, sizeof(modeopt));
1425 modeopt.nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_MODE;
1426 modeopt.mode = ctx->sync_kloop_mode;
1427 push_option(&modeopt.nro_opt, ctx);
1428
1429 num_entries = num_registered_rings(ctx);
1430 opt_size = sizeof(*evopt) + num_entries * sizeof(evopt->eventfds[0]);
1431 evopt = calloc(1, opt_size);
1432 evopt->nro_opt.nro_next = 0;
1433 evopt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_SYNC_KLOOP_EVENTFDS;
1434 evopt->nro_opt.nro_status = 0;
1435 evopt->nro_opt.nro_size = opt_size;
1436 for (i = 0; i < num_entries; i++) {
1437 int efd = eventfd(0, 0);
1438
1439 evopt->eventfds[i].ioeventfd = efd;
1440 efd = eventfd(0, 0);
1441 evopt->eventfds[i].irqfd = efd;
1442 }
1443
1444 push_option(&evopt->nro_opt, ctx);
1445 evsave = evopt->nro_opt;
1446
1447 ret = sync_kloop_start_stop(ctx);
1448 if (ret != 0) {
1449 free(evopt);
1450 clear_options(ctx);
1451 return ret;
1452 }
1453 #ifdef __linux__
1454 evsave.nro_status = 0;
1455 #else /* !__linux__ */
1456 evsave.nro_status = EOPNOTSUPP;
1457 #endif /* !__linux__ */
1458
1459 ret = checkoption(&evopt->nro_opt, &evsave);
1460 free(evopt);
1461 clear_options(ctx);
1462
1463 return ret;
1464 }
1465
1466 static int
sync_kloop_eventfds_all_mode(struct TestContext * ctx,uint32_t sync_kloop_mode)1467 sync_kloop_eventfds_all_mode(struct TestContext *ctx,
1468 uint32_t sync_kloop_mode)
1469 {
1470 int ret;
1471
1472 ret = csb_mode(ctx);
1473 if (ret != 0) {
1474 return ret;
1475 }
1476
1477 ctx->sync_kloop_mode = sync_kloop_mode;
1478
1479 return sync_kloop_eventfds(ctx);
1480 }
1481
1482 static int
sync_kloop_eventfds_all(struct TestContext * ctx)1483 sync_kloop_eventfds_all(struct TestContext *ctx)
1484 {
1485 return sync_kloop_eventfds_all_mode(ctx, 0);
1486 }
1487
1488 static int
sync_kloop_eventfds_all_tx(struct TestContext * ctx)1489 sync_kloop_eventfds_all_tx(struct TestContext *ctx)
1490 {
1491 struct nmreq_opt_csb opt;
1492 int ret;
1493
1494 ret = push_csb_option(ctx, &opt);
1495 if (ret != 0) {
1496 return ret;
1497 }
1498
1499 ret = port_register_hwall_tx(ctx);
1500 if (ret != 0) {
1501 return ret;
1502 }
1503 clear_options(ctx);
1504
1505 return sync_kloop_eventfds(ctx);
1506 }
1507
1508 static int
sync_kloop_eventfds_all_direct(struct TestContext * ctx)1509 sync_kloop_eventfds_all_direct(struct TestContext *ctx)
1510 {
1511 return sync_kloop_eventfds_all_mode(ctx,
1512 NM_OPT_SYNC_KLOOP_DIRECT_TX | NM_OPT_SYNC_KLOOP_DIRECT_RX);
1513 }
1514
1515 static int
sync_kloop_eventfds_all_direct_tx(struct TestContext * ctx)1516 sync_kloop_eventfds_all_direct_tx(struct TestContext *ctx)
1517 {
1518 return sync_kloop_eventfds_all_mode(ctx,
1519 NM_OPT_SYNC_KLOOP_DIRECT_TX);
1520 }
1521
1522 static int
sync_kloop_eventfds_all_direct_rx(struct TestContext * ctx)1523 sync_kloop_eventfds_all_direct_rx(struct TestContext *ctx)
1524 {
1525 return sync_kloop_eventfds_all_mode(ctx,
1526 NM_OPT_SYNC_KLOOP_DIRECT_RX);
1527 }
1528
1529 static int
sync_kloop_nocsb(struct TestContext * ctx)1530 sync_kloop_nocsb(struct TestContext *ctx)
1531 {
1532 int ret;
1533
1534 ret = port_register_hwall(ctx);
1535 if (ret != 0) {
1536 return ret;
1537 }
1538
1539 /* Sync kloop must fail because we did not use
1540 * NETMAP_REQ_CSB_ENABLE. */
1541 return sync_kloop_start_stop(ctx) != 0 ? 0 : -1;
1542 }
1543
1544 static int
csb_enable(struct TestContext * ctx)1545 csb_enable(struct TestContext *ctx)
1546 {
1547 struct nmreq_option saveopt;
1548 struct nmreq_opt_csb opt;
1549 struct nmreq_header hdr;
1550 int ret;
1551
1552 ret = push_csb_option(ctx, &opt);
1553 if (ret != 0) {
1554 return ret;
1555 }
1556 saveopt = opt.nro_opt;
1557 saveopt.nro_status = 0;
1558
1559 nmreq_hdr_init(&hdr, ctx->ifname_ext);
1560 hdr.nr_reqtype = NETMAP_REQ_CSB_ENABLE;
1561 hdr.nr_options = (uintptr_t)ctx->nr_opt;
1562 hdr.nr_body = (uintptr_t)NULL;
1563
1564 printf("Testing NETMAP_REQ_CSB_ENABLE on '%s'\n", ctx->ifname_ext);
1565
1566 ret = ioctl(ctx->fd, NIOCCTRL, &hdr);
1567 if (ret != 0) {
1568 perror("ioctl(/dev/netmap, NIOCCTRL, CSB_ENABLE)");
1569 return ret;
1570 }
1571
1572 ret = checkoption(&opt.nro_opt, &saveopt);
1573 clear_options(ctx);
1574
1575 return ret;
1576 }
1577
1578 static int
sync_kloop_csb_enable(struct TestContext * ctx)1579 sync_kloop_csb_enable(struct TestContext *ctx)
1580 {
1581 int ret;
1582
1583 ctx->nr_flags |= NR_EXCLUSIVE;
1584 ret = port_register_hwall(ctx);
1585 if (ret != 0) {
1586 return ret;
1587 }
1588
1589 ret = csb_enable(ctx);
1590 if (ret != 0) {
1591 return ret;
1592 }
1593
1594 return sync_kloop_start_stop(ctx);
1595 }
1596
1597 #if 0
1598 static int
1599 sync_kloop_conflict(struct TestContext *ctx)
1600 {
1601 struct nmreq_opt_csb opt;
1602 pthread_t th1, th2;
1603 void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1604 struct timespec to;
1605 sem_t sem;
1606 int err = 0;
1607 int ret;
1608
1609 ret = push_csb_option(ctx, &opt);
1610 if (ret != 0) {
1611 return ret;
1612 }
1613
1614 ret = port_register_hwall(ctx);
1615 if (ret != 0) {
1616 return ret;
1617 }
1618 clear_options(ctx);
1619
1620 ret = sem_init(&sem, 0, 0);
1621 if (ret != 0) {
1622 printf("sem_init() failed: %s\n", strerror(ret));
1623 return ret;
1624 }
1625 ctx->sem = &sem;
1626
1627 ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1628 err |= ret;
1629 if (ret != 0) {
1630 printf("pthread_create(kloop1): %s\n", strerror(ret));
1631 }
1632
1633 ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1634 err |= ret;
1635 if (ret != 0) {
1636 printf("pthread_create(kloop2): %s\n", strerror(ret));
1637 }
1638
1639 /* Wait for one of the two threads to fail to start the kloop, to
1640 * avoid a race condition where th1 starts the loop and stops,
1641 * and after that th2 starts the loop successfully. */
1642 /*
1643 * XXX: This doesn't fully close the race. th2 might fail to
1644 * start executing since th1 can enter the kernel and hog the
1645 * CPU on a single-CPU system until the semaphore timeout
1646 * awakens this thread and it calls sync_kloop_stop. Once th1
1647 * exits the kernel, th2 can finally run and will then loop
1648 * forever in the ioctl handler.
1649 */
1650 clock_gettime(CLOCK_REALTIME, &to);
1651 to.tv_sec += 2;
1652 ret = sem_timedwait(&sem, &to);
1653 err |= ret;
1654 if (ret != 0) {
1655 printf("sem_timedwait() failed: %s\n", strerror(errno));
1656 }
1657
1658 err |= sync_kloop_stop(ctx);
1659
1660 ret = pthread_join(th1, &thret1);
1661 err |= ret;
1662 if (ret != 0) {
1663 printf("pthread_join(kloop1): %s\n", strerror(ret));
1664 }
1665
1666 ret = pthread_join(th2, &thret2);
1667 err |= ret;
1668 if (ret != 0) {
1669 printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1670 }
1671
1672 sem_destroy(&sem);
1673 ctx->sem = NULL;
1674 if (err) {
1675 return err;
1676 }
1677
1678 /* Check that one of the two failed, while the other one succeeded. */
1679 return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1680 (thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1681 ? 0
1682 : -1;
1683 }
1684 #endif
1685
1686 static int
sync_kloop_eventfds_mismatch(struct TestContext * ctx)1687 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1688 {
1689 struct nmreq_opt_csb opt;
1690 int ret;
1691
1692 ret = push_csb_option(ctx, &opt);
1693 if (ret != 0) {
1694 return ret;
1695 }
1696
1697 ret = port_register_hwall_rx(ctx);
1698 if (ret != 0) {
1699 return ret;
1700 }
1701 clear_options(ctx);
1702
1703 /* Deceive num_registered_rings() to trigger a failure of
1704 * sync_kloop_eventfds(). The latter will think that all the
1705 * rings were registered, and allocate the wrong number of
1706 * eventfds. */
1707 ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1708
1709 return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1710 }
1711
1712 static int
null_port(struct TestContext * ctx)1713 null_port(struct TestContext *ctx)
1714 {
1715 int ret;
1716
1717 ctx->nr_mem_id = 1;
1718 ctx->nr_mode = NR_REG_NULL;
1719 ctx->nr_tx_rings = 10;
1720 ctx->nr_rx_rings = 5;
1721 ctx->nr_tx_slots = 256;
1722 ctx->nr_rx_slots = 100;
1723 ret = port_register(ctx);
1724 if (ret != 0) {
1725 return ret;
1726 }
1727 return 0;
1728 }
1729
1730 static int
null_port_all_zero(struct TestContext * ctx)1731 null_port_all_zero(struct TestContext *ctx)
1732 {
1733 int ret;
1734
1735 ctx->nr_mem_id = 1;
1736 ctx->nr_mode = NR_REG_NULL;
1737 ctx->nr_tx_rings = 0;
1738 ctx->nr_rx_rings = 0;
1739 ctx->nr_tx_slots = 0;
1740 ctx->nr_rx_slots = 0;
1741 ret = port_register(ctx);
1742 if (ret != 0) {
1743 return ret;
1744 }
1745 return 0;
1746 }
1747
1748 static int
null_port_sync(struct TestContext * ctx)1749 null_port_sync(struct TestContext *ctx)
1750 {
1751 int ret;
1752
1753 ctx->nr_mem_id = 1;
1754 ctx->nr_mode = NR_REG_NULL;
1755 ctx->nr_tx_rings = 10;
1756 ctx->nr_rx_rings = 5;
1757 ctx->nr_tx_slots = 256;
1758 ctx->nr_rx_slots = 100;
1759 ret = port_register(ctx);
1760 if (ret != 0) {
1761 return ret;
1762 }
1763 ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1764 if (ret != 0) {
1765 return ret;
1766 }
1767 return 0;
1768 }
1769
1770 struct nmreq_parse_test {
1771 const char *ifname;
1772 const char *exp_port;
1773 const char *exp_suff;
1774 int exp_error;
1775 uint32_t exp_mode;
1776 uint16_t exp_ringid;
1777 uint64_t exp_flags;
1778 };
1779
1780 static struct nmreq_parse_test nmreq_parse_tests[] = {
1781 /* port spec is the input. The expected results are as follows:
1782 * - port: what should go into hdr.nr_name
1783 * - suff: the trailing part of the input after parsing (NULL means equal to port spec)
1784 * - err: the expected return value, interpreted as follows
1785 * err > 0 => nmreq_header_parse should fail with the given error
1786 * err < 0 => nrmeq_header_parse should succeed, but nmreq_register_decode should
1787 * fail with error |err|
1788 * err = 0 => should succeed
1789 * - mode, ringid flags: what should go into the corresponding nr_* fields in the
1790 * nmreq_register struct in case of success
1791 */
1792
1793 /*port spec*/ /*port*/ /*suff*/ /*err*/ /*mode*/ /*ringid*/ /*flags*/
1794 { "netmap:eth0", "eth0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1795 { "netmap:eth0-1", "eth0", "", 0, NR_REG_ONE_NIC, 1, 0 },
1796 { "netmap:eth0-", "eth0", "-", -EINVAL,0, 0, 0 },
1797 { "netmap:eth0/x", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_EXCLUSIVE },
1798 { "netmap:eth0/z", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_ZCOPY_MON },
1799 { "netmap:eth0/r", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_MONITOR_RX },
1800 { "netmap:eth0/t", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_MONITOR_TX },
1801 { "netmap:eth0-2/Tx", "eth0", "", 0, NR_REG_ONE_NIC, 2, NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1802 { "netmap:eth0*", "eth0", "", 0, NR_REG_NIC_SW, 0, 0 },
1803 { "netmap:eth0^", "eth0", "", 0, NR_REG_SW, 0, 0 },
1804 { "netmap:eth0@2", "eth0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1805 { "netmap:eth0@2/R", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
1806 { "netmap:eth0@netmap:lo/R", "eth0", "@netmap:lo/R", 0, NR_REG_ALL_NIC, 0, 0 },
1807 { "netmap:eth0/R@xxx", "eth0", "@xxx", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
1808 { "netmap:eth0@2/R@2", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
1809 { "netmap:eth0@2/R@3", "eth0", "@2/R@3", -EINVAL,0, 0, 0 },
1810 { "netmap:eth0@", "eth0", "@", -EINVAL,0, 0, 0 },
1811 { "netmap:", "", NULL, EINVAL, 0, 0, 0 },
1812 { "netmap:^", "", NULL, EINVAL, 0, 0, 0 },
1813 { "netmap:{", "", NULL, EINVAL, 0, 0, 0 },
1814 { "eth0", NULL, NULL, EINVAL, 0, 0, 0 },
1815 { "vale0:0", "vale0:0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1816 { "vale:0", "vale:0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1817 { "valeXXX:YYY", "valeXXX:YYY", "", 0, NR_REG_ALL_NIC, 0, 0 },
1818 { "valeXXX:YYY-4", "valeXXX:YYY", "", 0, NR_REG_ONE_NIC, 4, 0 },
1819 { "netmapXXX:eth0", NULL, NULL, EINVAL, 0, 0, 0 },
1820 { "netmap:14", "14", "", 0, NR_REG_ALL_NIC, 0, 0 },
1821 { "netmap:pipe{0", "pipe{0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1822 { "netmap:pipe{in", "pipe{in", "", 0, NR_REG_ALL_NIC, 0, 0 },
1823 { "netmap:pipe{in-7", "pipe{in", "", 0, NR_REG_ONE_NIC, 7, 0 },
1824 { "vale0:0{0", "vale0:0{0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1825 { "netmap:pipe{1}2", NULL, NULL, EINVAL, 0, 0, 0 },
1826 { "vale0:0@opt", "vale0:0", "@opt", 0, NR_REG_ALL_NIC, 0, 0 },
1827 { "vale0:0/Tx@opt", "vale0:0", "@opt", 0, NR_REG_ALL_NIC, 0, NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1828 { "vale0:0-3@opt", "vale0:0", "@opt", 0, NR_REG_ONE_NIC, 3, 0 },
1829 { "vale0:0@", "vale0:0", "@", -EINVAL,0, 0, 0 },
1830 { "", NULL, NULL, EINVAL, 0, 0, 0 },
1831 { NULL, NULL, NULL, 0, 0, 0, 0 },
1832 };
1833
1834 static void
randomize(void * dst,size_t n)1835 randomize(void *dst, size_t n)
1836 {
1837 size_t i;
1838 char *dst_ = dst;
1839
1840 for (i = 0; i < n; i++)
1841 dst_[i] = (char)random();
1842 }
1843
1844 static int
nmreq_hdr_parsing(struct TestContext * ctx,struct nmreq_parse_test * t,struct nmreq_header * hdr)1845 nmreq_hdr_parsing(struct TestContext *ctx,
1846 struct nmreq_parse_test *t,
1847 struct nmreq_header *hdr)
1848 {
1849 const char *save;
1850 struct nmreq_header orig_hdr;
1851
1852 save = ctx->ifparse = t->ifname;
1853 orig_hdr = *hdr;
1854
1855 printf("nmreq_header: \"%s\"\n", ctx->ifparse);
1856 if (nmreq_header_decode(&ctx->ifparse, hdr, ctx->nmctx) < 0) {
1857 if (t->exp_error > 0) {
1858 if (errno != t->exp_error) {
1859 printf("!!! got errno=%d, want %d\n",
1860 errno, t->exp_error);
1861 return -1;
1862 }
1863 if (ctx->ifparse != save) {
1864 printf("!!! parse error, but first arg changed\n");
1865 return -1;
1866 }
1867 if (memcmp(&orig_hdr, hdr, sizeof(*hdr))) {
1868 printf("!!! parse error, but header changed\n");
1869 return -1;
1870 }
1871 return 0;
1872 }
1873 printf ("!!! nmreq_header_decode was expected to succeed, but it failed with error %d\n", errno);
1874 return -1;
1875 }
1876 if (t->exp_error > 0) {
1877 printf("!!! nmreq_header_decode returns 0, but error %d was expected\n", t->exp_error);
1878 return -1;
1879 }
1880 if (strcmp(t->exp_port, hdr->nr_name) != 0) {
1881 printf("!!! got '%s', want '%s'\n", hdr->nr_name, t->exp_port);
1882 return -1;
1883 }
1884 if (hdr->nr_reqtype != orig_hdr.nr_reqtype ||
1885 hdr->nr_options != orig_hdr.nr_options ||
1886 hdr->nr_body != orig_hdr.nr_body) {
1887 printf("!!! some fields of the nmreq_header where changed unexpectedly\n");
1888 return -1;
1889 }
1890 return 0;
1891 }
1892
1893 static int
nmreq_reg_parsing(struct TestContext * ctx,struct nmreq_parse_test * t,struct nmreq_register * reg)1894 nmreq_reg_parsing(struct TestContext *ctx,
1895 struct nmreq_parse_test *t,
1896 struct nmreq_register *reg)
1897 {
1898 const char *save;
1899 struct nmreq_register orig_reg;
1900
1901
1902 save = ctx->ifparse;
1903 orig_reg = *reg;
1904
1905 printf("nmreq_register: \"%s\"\n", ctx->ifparse);
1906 if (nmreq_register_decode(&ctx->ifparse, reg, ctx->nmctx) < 0) {
1907 if (t->exp_error < 0) {
1908 if (errno != -t->exp_error) {
1909 printf("!!! got errno=%d, want %d\n",
1910 errno, -t->exp_error);
1911 return -1;
1912 }
1913 if (ctx->ifparse != save) {
1914 printf("!!! parse error, but first arg changed\n");
1915 return -1;
1916 }
1917 if (memcmp(&orig_reg, reg, sizeof(*reg))) {
1918 printf("!!! parse error, but nmreq_register changed\n");
1919 return -1;
1920 }
1921 return 0;
1922 }
1923 printf ("!!! parse failed but it should have succeeded\n");
1924 return -1;
1925 }
1926 if (t->exp_error < 0) {
1927 printf("!!! nmreq_register_decode returns 0, but error %d was expected\n", -t->exp_error);
1928 return -1;
1929 }
1930 if (reg->nr_mode != t->exp_mode) {
1931 printf("!!! got nr_mode '%d', want '%d'\n", reg->nr_mode, t->exp_mode);
1932 return -1;
1933 }
1934 if (reg->nr_ringid != t->exp_ringid) {
1935 printf("!!! got nr_ringid '%d', want '%d'\n", reg->nr_ringid, t->exp_ringid);
1936 return -1;
1937 }
1938 if (reg->nr_flags != t->exp_flags) {
1939 printf("!!! got nm_flags '%llx', want '%llx\n", (unsigned long long)reg->nr_flags,
1940 (unsigned long long)t->exp_flags);
1941 return -1;
1942 }
1943 if (reg->nr_offset != orig_reg.nr_offset ||
1944 reg->nr_memsize != orig_reg.nr_memsize ||
1945 reg->nr_tx_slots != orig_reg.nr_tx_slots ||
1946 reg->nr_rx_slots != orig_reg.nr_rx_slots ||
1947 reg->nr_tx_rings != orig_reg.nr_tx_rings ||
1948 reg->nr_rx_rings != orig_reg.nr_rx_rings ||
1949 reg->nr_extra_bufs != orig_reg.nr_extra_bufs)
1950 {
1951 printf("!!! some fields of the nmreq_register where changed unexpectedly\n");
1952 return -1;
1953 }
1954 return 0;
1955 }
1956
1957 static void
nmctx_parsing_error(struct nmctx * ctx,const char * msg)1958 nmctx_parsing_error(struct nmctx *ctx, const char *msg)
1959 {
1960 (void)ctx;
1961 printf(" got message: %s\n", msg);
1962 }
1963
1964 static int
nmreq_parsing(struct TestContext * ctx)1965 nmreq_parsing(struct TestContext *ctx)
1966 {
1967 struct nmreq_parse_test *t;
1968 struct nmreq_header hdr;
1969 struct nmreq_register reg;
1970 struct nmctx test_nmctx, *nmctx;
1971 int ret = 0;
1972
1973 nmctx = nmctx_get();
1974 if (nmctx == NULL) {
1975 printf("Failed to acquire nmctx: %s", strerror(errno));
1976 return -1;
1977 }
1978 test_nmctx = *nmctx;
1979 test_nmctx.error = nmctx_parsing_error;
1980 ctx->nmctx = &test_nmctx;
1981 for (t = nmreq_parse_tests; t->ifname != NULL; t++) {
1982 const char *exp_suff = t->exp_suff != NULL ?
1983 t->exp_suff : t->ifname;
1984
1985 randomize(&hdr, sizeof(hdr));
1986 randomize(®, sizeof(reg));
1987 reg.nr_mem_id = 0;
1988 if (nmreq_hdr_parsing(ctx, t, &hdr) < 0) {
1989 ret = -1;
1990 } else if (t->exp_error <= 0 && nmreq_reg_parsing(ctx, t, ®) < 0) {
1991 ret = -1;
1992 }
1993 if (strcmp(ctx->ifparse, exp_suff) != 0) {
1994 printf("!!! string suffix after parse is '%s', but it should be '%s'\n",
1995 ctx->ifparse, exp_suff);
1996 ret = -1;
1997 }
1998 }
1999 ctx->nmctx = NULL;
2000 return ret;
2001 }
2002
2003 static int
binarycomp(struct TestContext * ctx)2004 binarycomp(struct TestContext *ctx)
2005 {
2006 #define ckroff(f, o) do {\
2007 if (offsetof(struct netmap_ring, f) != (o)) {\
2008 printf("offset of netmap_ring.%s is %zd, but it should be %d",\
2009 #f, offsetof(struct netmap_ring, f), (o));\
2010 return -1;\
2011 }\
2012 } while (0)
2013
2014 (void)ctx;
2015
2016 ckroff(buf_ofs, 0);
2017 ckroff(num_slots, 8);
2018 ckroff(nr_buf_size, 12);
2019 ckroff(ringid, 16);
2020 ckroff(dir, 18);
2021 ckroff(head, 20);
2022 ckroff(cur, 24);
2023 ckroff(tail, 28);
2024 ckroff(flags, 32);
2025 ckroff(ts, 40);
2026 ckroff(offset_mask, 56);
2027 ckroff(buf_align, 64);
2028 ckroff(sem, 128);
2029 ckroff(slot, 256);
2030
2031 return 0;
2032 }
2033
2034 static void
usage(const char * prog)2035 usage(const char *prog)
2036 {
2037 printf("%s -i IFNAME\n"
2038 "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
2039 "[-l (list test cases)]\n",
2040 prog);
2041 }
2042
2043 struct mytest {
2044 testfunc_t test;
2045 const char *name;
2046 };
2047
2048 #define decltest(f) \
2049 { \
2050 .test = f, .name = #f \
2051 }
2052
2053 static struct mytest tests[] = {
2054 decltest(port_info_get),
2055 decltest(port_register_hwall_host),
2056 decltest(port_register_hwall),
2057 decltest(port_register_hostall),
2058 decltest(port_register_single_hw_pair),
2059 decltest(port_register_single_host_pair),
2060 decltest(port_register_hostall_many),
2061 decltest(vale_attach_detach),
2062 decltest(vale_attach_detach_host_rings),
2063 decltest(vale_ephemeral_port_hdr_manipulation),
2064 decltest(vale_persistent_port),
2065 decltest(pools_info_get_and_register),
2066 decltest(pools_info_get_empty_ifname),
2067 decltest(pipe_master),
2068 decltest(pipe_slave),
2069 decltest(pipe_port_info_get),
2070 decltest(pipe_pools_info_get),
2071 decltest(vale_polling_enable_disable),
2072 decltest(unsupported_option),
2073 decltest(infinite_options),
2074 decltest(infinite_options2),
2075 #ifdef CONFIG_NETMAP_EXTMEM
2076 decltest(extmem_option),
2077 decltest(bad_extmem_option),
2078 decltest(duplicate_extmem_options),
2079 #endif /* CONFIG_NETMAP_EXTMEM */
2080 decltest(csb_mode),
2081 decltest(csb_mode_invalid_memory),
2082 decltest(sync_kloop),
2083 decltest(sync_kloop_eventfds_all),
2084 decltest(sync_kloop_eventfds_all_tx),
2085 decltest(sync_kloop_eventfds_all_direct),
2086 decltest(sync_kloop_eventfds_all_direct_tx),
2087 decltest(sync_kloop_eventfds_all_direct_rx),
2088 decltest(sync_kloop_nocsb),
2089 decltest(sync_kloop_csb_enable),
2090 #if 0
2091 decltest(sync_kloop_conflict),
2092 #endif
2093 decltest(sync_kloop_eventfds_mismatch),
2094 decltest(null_port),
2095 decltest(null_port_all_zero),
2096 decltest(null_port_sync),
2097 decltest(legacy_regif_default),
2098 decltest(legacy_regif_all_nic),
2099 decltest(legacy_regif_12),
2100 decltest(legacy_regif_sw),
2101 decltest(legacy_regif_future),
2102 decltest(legacy_regif_extra_bufs),
2103 decltest(legacy_regif_extra_bufs_pipe),
2104 decltest(legacy_regif_extra_bufs_pipe_vale),
2105 decltest(nmreq_parsing),
2106 decltest(binarycomp),
2107 };
2108
2109 static void
context_cleanup(struct TestContext * ctx)2110 context_cleanup(struct TestContext *ctx)
2111 {
2112 if (ctx->csb) {
2113 free(ctx->csb);
2114 ctx->csb = NULL;
2115 }
2116
2117 close(ctx->fd);
2118 ctx->fd = -1;
2119 }
2120
2121 static int
parse_interval(const char * arg,int * j,int * k)2122 parse_interval(const char *arg, int *j, int *k)
2123 {
2124 const char *scan = arg;
2125 char *rest;
2126
2127 *j = 0;
2128 *k = -1;
2129 if (*scan == '-') {
2130 scan++;
2131 goto get_k;
2132 }
2133 if (!isdigit(*scan))
2134 goto err;
2135 *k = strtol(scan, &rest, 10);
2136 *j = *k - 1;
2137 scan = rest;
2138 if (*scan == '-') {
2139 *k = -1;
2140 scan++;
2141 }
2142 get_k:
2143 if (*scan == '\0')
2144 return 0;
2145 if (!isdigit(*scan))
2146 goto err;
2147 *k = strtol(scan, &rest, 10);
2148 scan = rest;
2149 if (!(*scan == '\0'))
2150 goto err;
2151
2152 return 0;
2153
2154 err:
2155 fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
2156 return -1;
2157 }
2158
2159 #define ARGV_APPEND(_av, _ac, _x)\
2160 do {\
2161 assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
2162 (_av)[(_ac)++] = _x;\
2163 } while (0)
2164
2165 static void
tap_cleanup(int signo)2166 tap_cleanup(int signo)
2167 {
2168 const char *av[8];
2169 int ac = 0;
2170
2171 (void)signo;
2172 #ifdef __FreeBSD__
2173 ARGV_APPEND(av, ac, "ifconfig");
2174 ARGV_APPEND(av, ac, ctx_.ifname);
2175 ARGV_APPEND(av, ac, "destroy");
2176 #else
2177 ARGV_APPEND(av, ac, "ip");
2178 ARGV_APPEND(av, ac, "link");
2179 ARGV_APPEND(av, ac, "del");
2180 ARGV_APPEND(av, ac, ctx_.ifname);
2181 #endif
2182 ARGV_APPEND(av, ac, NULL);
2183 if (exec_command(ac, av)) {
2184 printf("Failed to destroy tap interface\n");
2185 }
2186 }
2187
2188 int
main(int argc,char ** argv)2189 main(int argc, char **argv)
2190 {
2191 int create_tap = 1;
2192 int num_tests;
2193 int ret = 0;
2194 int j = 0;
2195 int k = -1;
2196 int list = 0;
2197 int opt;
2198 int i;
2199
2200 memset(&ctx_, 0, sizeof(ctx_));
2201
2202 {
2203 struct timespec t;
2204 int idx;
2205
2206 clock_gettime(CLOCK_REALTIME, &t);
2207 srand((unsigned int)t.tv_nsec);
2208 idx = rand() % 8000 + 100;
2209 snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
2210 idx = rand() % 800 + 100;
2211 snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
2212 }
2213
2214 while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
2215 switch (opt) {
2216 case 'h':
2217 usage(argv[0]);
2218 return 0;
2219
2220 case 'i':
2221 strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
2222 create_tap = 0;
2223 break;
2224
2225 case 'j':
2226 if (parse_interval(optarg, &j, &k) < 0) {
2227 usage(argv[0]);
2228 return -1;
2229 }
2230 break;
2231
2232 case 'l':
2233 list = 1;
2234 create_tap = 0;
2235 break;
2236
2237 default:
2238 printf(" Unrecognized option %c\n", opt);
2239 usage(argv[0]);
2240 return -1;
2241 }
2242 }
2243
2244 num_tests = sizeof(tests) / sizeof(tests[0]);
2245
2246 if (j < 0 || j >= num_tests || k > num_tests) {
2247 fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
2248 j + 1, k, 1, num_tests + 1);
2249 return -1;
2250 }
2251
2252 if (k < 0)
2253 k = num_tests;
2254
2255 if (list) {
2256 printf("Available tests:\n");
2257 for (i = 0; i < num_tests; i++) {
2258 printf("#%03d: %s\n", i + 1, tests[i].name);
2259 }
2260 return 0;
2261 }
2262
2263 if (create_tap) {
2264 struct sigaction sa;
2265 const char *av[8];
2266 int ac = 0;
2267 #ifdef __FreeBSD__
2268 ARGV_APPEND(av, ac, "ifconfig");
2269 ARGV_APPEND(av, ac, ctx_.ifname);
2270 ARGV_APPEND(av, ac, "create");
2271 ARGV_APPEND(av, ac, "up");
2272 #else
2273 ARGV_APPEND(av, ac, "ip");
2274 ARGV_APPEND(av, ac, "tuntap");
2275 ARGV_APPEND(av, ac, "add");
2276 ARGV_APPEND(av, ac, "mode");
2277 ARGV_APPEND(av, ac, "tap");
2278 ARGV_APPEND(av, ac, "name");
2279 ARGV_APPEND(av, ac, ctx_.ifname);
2280 #endif
2281 ARGV_APPEND(av, ac, NULL);
2282 if (exec_command(ac, av)) {
2283 printf("Failed to create tap interface\n");
2284 return -1;
2285 }
2286
2287 sa.sa_handler = tap_cleanup;
2288 sigemptyset(&sa.sa_mask);
2289 sa.sa_flags = SA_RESTART;
2290 ret = sigaction(SIGINT, &sa, NULL);
2291 if (ret) {
2292 perror("sigaction(SIGINT)");
2293 goto out;
2294 }
2295 ret = sigaction(SIGTERM, &sa, NULL);
2296 if (ret) {
2297 perror("sigaction(SIGTERM)");
2298 goto out;
2299 }
2300 }
2301
2302 for (i = j; i < k; i++) {
2303 struct TestContext ctxcopy;
2304 int fd;
2305 printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
2306 fd = open("/dev/netmap", O_RDWR);
2307 if (fd < 0) {
2308 perror("open(/dev/netmap)");
2309 ret = fd;
2310 goto out;
2311 }
2312 memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
2313 ctxcopy.fd = fd;
2314 memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
2315 sizeof(ctxcopy.ifname));
2316 ret = tests[i].test(&ctxcopy);
2317 if (ret != 0) {
2318 printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
2319 goto out;
2320 }
2321 printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
2322 context_cleanup(&ctxcopy);
2323 }
2324 out:
2325 tap_cleanup(0);
2326
2327 return ret;
2328 }
2329