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