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 #if 0
1600 static int
1601 sync_kloop_conflict(struct TestContext *ctx)
1602 {
1603 struct nmreq_opt_csb opt;
1604 pthread_t th1, th2;
1605 void *thret1 = THRET_FAILURE, *thret2 = THRET_FAILURE;
1606 struct timespec to;
1607 sem_t sem;
1608 int err = 0;
1609 int ret;
1610
1611 ret = push_csb_option(ctx, &opt);
1612 if (ret != 0) {
1613 return ret;
1614 }
1615
1616 ret = port_register_hwall(ctx);
1617 if (ret != 0) {
1618 return ret;
1619 }
1620 clear_options(ctx);
1621
1622 ret = sem_init(&sem, 0, 0);
1623 if (ret != 0) {
1624 printf("sem_init() failed: %s\n", strerror(ret));
1625 return ret;
1626 }
1627 ctx->sem = &sem;
1628
1629 ret = pthread_create(&th1, NULL, sync_kloop_worker, ctx);
1630 err |= ret;
1631 if (ret != 0) {
1632 printf("pthread_create(kloop1): %s\n", strerror(ret));
1633 }
1634
1635 ret = pthread_create(&th2, NULL, sync_kloop_worker, ctx);
1636 err |= ret;
1637 if (ret != 0) {
1638 printf("pthread_create(kloop2): %s\n", strerror(ret));
1639 }
1640
1641 /* Wait for one of the two threads to fail to start the kloop, to
1642 * avoid a race condition where th1 starts the loop and stops,
1643 * and after that th2 starts the loop successfully. */
1644 /*
1645 * XXX: This doesn't fully close the race. th2 might fail to
1646 * start executing since th1 can enter the kernel and hog the
1647 * CPU on a single-CPU system until the semaphore timeout
1648 * awakens this thread and it calls sync_kloop_stop. Once th1
1649 * exits the kernel, th2 can finally run and will then loop
1650 * forever in the ioctl handler.
1651 */
1652 clock_gettime(CLOCK_REALTIME, &to);
1653 to.tv_sec += 2;
1654 ret = sem_timedwait(&sem, &to);
1655 err |= ret;
1656 if (ret != 0) {
1657 printf("sem_timedwait() failed: %s\n", strerror(errno));
1658 }
1659
1660 err |= sync_kloop_stop(ctx);
1661
1662 ret = pthread_join(th1, &thret1);
1663 err |= ret;
1664 if (ret != 0) {
1665 printf("pthread_join(kloop1): %s\n", strerror(ret));
1666 }
1667
1668 ret = pthread_join(th2, &thret2);
1669 err |= ret;
1670 if (ret != 0) {
1671 printf("pthread_join(kloop2): %s %d\n", strerror(ret), ret);
1672 }
1673
1674 sem_destroy(&sem);
1675 ctx->sem = NULL;
1676 if (err) {
1677 return err;
1678 }
1679
1680 /* Check that one of the two failed, while the other one succeeded. */
1681 return ((thret1 == THRET_SUCCESS && thret2 == THRET_FAILURE) ||
1682 (thret1 == THRET_FAILURE && thret2 == THRET_SUCCESS))
1683 ? 0
1684 : -1;
1685 }
1686 #endif
1687
1688 static int
sync_kloop_eventfds_mismatch(struct TestContext * ctx)1689 sync_kloop_eventfds_mismatch(struct TestContext *ctx)
1690 {
1691 struct nmreq_opt_csb opt;
1692 int ret;
1693
1694 ret = push_csb_option(ctx, &opt);
1695 if (ret != 0) {
1696 return ret;
1697 }
1698
1699 ret = port_register_hwall_rx(ctx);
1700 if (ret != 0) {
1701 return ret;
1702 }
1703 clear_options(ctx);
1704
1705 /* Deceive num_registered_rings() to trigger a failure of
1706 * sync_kloop_eventfds(). The latter will think that all the
1707 * rings were registered, and allocate the wrong number of
1708 * eventfds. */
1709 ctx->nr_flags &= ~NR_RX_RINGS_ONLY;
1710
1711 return (sync_kloop_eventfds(ctx) != 0) ? 0 : -1;
1712 }
1713
1714 static int
null_port(struct TestContext * ctx)1715 null_port(struct TestContext *ctx)
1716 {
1717 int ret;
1718
1719 ctx->nr_mem_id = 1;
1720 ctx->nr_mode = NR_REG_NULL;
1721 ctx->nr_tx_rings = 10;
1722 ctx->nr_rx_rings = 5;
1723 ctx->nr_tx_slots = 256;
1724 ctx->nr_rx_slots = 100;
1725 ret = port_register(ctx);
1726 if (ret != 0) {
1727 return ret;
1728 }
1729 return 0;
1730 }
1731
1732 static int
null_port_all_zero(struct TestContext * ctx)1733 null_port_all_zero(struct TestContext *ctx)
1734 {
1735 int ret;
1736
1737 ctx->nr_mem_id = 1;
1738 ctx->nr_mode = NR_REG_NULL;
1739 ctx->nr_tx_rings = 0;
1740 ctx->nr_rx_rings = 0;
1741 ctx->nr_tx_slots = 0;
1742 ctx->nr_rx_slots = 0;
1743 ret = port_register(ctx);
1744 if (ret != 0) {
1745 return ret;
1746 }
1747 return 0;
1748 }
1749
1750 static int
null_port_sync(struct TestContext * ctx)1751 null_port_sync(struct TestContext *ctx)
1752 {
1753 int ret;
1754
1755 ctx->nr_mem_id = 1;
1756 ctx->nr_mode = NR_REG_NULL;
1757 ctx->nr_tx_rings = 10;
1758 ctx->nr_rx_rings = 5;
1759 ctx->nr_tx_slots = 256;
1760 ctx->nr_rx_slots = 100;
1761 ret = port_register(ctx);
1762 if (ret != 0) {
1763 return ret;
1764 }
1765 ret = ioctl(ctx->fd, NIOCTXSYNC, 0);
1766 if (ret != 0) {
1767 return ret;
1768 }
1769 return 0;
1770 }
1771
1772 struct nmreq_parse_test {
1773 const char *ifname;
1774 const char *exp_port;
1775 const char *exp_suff;
1776 int exp_error;
1777 uint32_t exp_mode;
1778 uint16_t exp_ringid;
1779 uint64_t exp_flags;
1780 };
1781
1782 static struct nmreq_parse_test nmreq_parse_tests[] = {
1783 /* port spec is the input. The expected results are as follows:
1784 * - port: what should go into hdr.nr_name
1785 * - suff: the trailing part of the input after parsing (NULL means equal to port spec)
1786 * - err: the expected return value, interpreted as follows
1787 * err > 0 => nmreq_header_parse should fail with the given error
1788 * err < 0 => nrmeq_header_parse should succeed, but nmreq_register_decode should
1789 * fail with error |err|
1790 * err = 0 => should succeed
1791 * - mode, ringid flags: what should go into the corresponding nr_* fields in the
1792 * nmreq_register struct in case of success
1793 */
1794
1795 /*port spec*/ /*port*/ /*suff*/ /*err*/ /*mode*/ /*ringid*/ /*flags*/
1796 { "netmap:eth0", "eth0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1797 { "netmap:eth0-1", "eth0", "", 0, NR_REG_ONE_NIC, 1, 0 },
1798 { "netmap:eth0-", "eth0", "-", -EINVAL,0, 0, 0 },
1799 { "netmap:eth0/x", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_EXCLUSIVE },
1800 { "netmap:eth0/z", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_ZCOPY_MON },
1801 { "netmap:eth0/r", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_MONITOR_RX },
1802 { "netmap:eth0/t", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_MONITOR_TX },
1803 { "netmap:eth0-2/Tx", "eth0", "", 0, NR_REG_ONE_NIC, 2, NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1804 { "netmap:eth0*", "eth0", "", 0, NR_REG_NIC_SW, 0, 0 },
1805 { "netmap:eth0^", "eth0", "", 0, NR_REG_SW, 0, 0 },
1806 { "netmap:eth0@2", "eth0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1807 { "netmap:eth0@2/R", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
1808 { "netmap:eth0@netmap:lo/R", "eth0", "@netmap:lo/R", 0, NR_REG_ALL_NIC, 0, 0 },
1809 { "netmap:eth0/R@xxx", "eth0", "@xxx", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
1810 { "netmap:eth0@2/R@2", "eth0", "", 0, NR_REG_ALL_NIC, 0, NR_RX_RINGS_ONLY },
1811 { "netmap:eth0@2/R@3", "eth0", "@2/R@3", -EINVAL,0, 0, 0 },
1812 { "netmap:eth0@", "eth0", "@", -EINVAL,0, 0, 0 },
1813 { "netmap:", "", NULL, EINVAL, 0, 0, 0 },
1814 { "netmap:^", "", NULL, EINVAL, 0, 0, 0 },
1815 { "netmap:{", "", NULL, EINVAL, 0, 0, 0 },
1816 { "eth0", NULL, NULL, EINVAL, 0, 0, 0 },
1817 { "vale0:0", "vale0:0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1818 { "vale:0", "vale:0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1819 { "valeXXX:YYY", "valeXXX:YYY", "", 0, NR_REG_ALL_NIC, 0, 0 },
1820 { "valeXXX:YYY-4", "valeXXX:YYY", "", 0, NR_REG_ONE_NIC, 4, 0 },
1821 { "netmapXXX:eth0", NULL, NULL, EINVAL, 0, 0, 0 },
1822 { "netmap:14", "14", "", 0, NR_REG_ALL_NIC, 0, 0 },
1823 { "netmap:pipe{0", "pipe{0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1824 { "netmap:pipe{in", "pipe{in", "", 0, NR_REG_ALL_NIC, 0, 0 },
1825 { "netmap:pipe{in-7", "pipe{in", "", 0, NR_REG_ONE_NIC, 7, 0 },
1826 { "vale0:0{0", "vale0:0{0", "", 0, NR_REG_ALL_NIC, 0, 0 },
1827 { "netmap:pipe{1}2", NULL, NULL, EINVAL, 0, 0, 0 },
1828 { "vale0:0@opt", "vale0:0", "@opt", 0, NR_REG_ALL_NIC, 0, 0 },
1829 { "vale0:0/Tx@opt", "vale0:0", "@opt", 0, NR_REG_ALL_NIC, 0, NR_TX_RINGS_ONLY|NR_EXCLUSIVE },
1830 { "vale0:0-3@opt", "vale0:0", "@opt", 0, NR_REG_ONE_NIC, 3, 0 },
1831 { "vale0:0@", "vale0:0", "@", -EINVAL,0, 0, 0 },
1832 { "", NULL, NULL, EINVAL, 0, 0, 0 },
1833 { NULL, NULL, NULL, 0, 0, 0, 0 },
1834 };
1835
1836 static void
randomize(void * dst,size_t n)1837 randomize(void *dst, size_t n)
1838 {
1839 size_t i;
1840 char *dst_ = dst;
1841
1842 for (i = 0; i < n; i++)
1843 dst_[i] = (char)random();
1844 }
1845
1846 static int
nmreq_hdr_parsing(struct TestContext * ctx,struct nmreq_parse_test * t,struct nmreq_header * hdr)1847 nmreq_hdr_parsing(struct TestContext *ctx,
1848 struct nmreq_parse_test *t,
1849 struct nmreq_header *hdr)
1850 {
1851 const char *save;
1852 struct nmreq_header orig_hdr;
1853
1854 save = ctx->ifparse = t->ifname;
1855 orig_hdr = *hdr;
1856
1857 printf("nmreq_header: \"%s\"\n", ctx->ifparse);
1858 if (nmreq_header_decode(&ctx->ifparse, hdr, ctx->nmctx) < 0) {
1859 if (t->exp_error > 0) {
1860 if (errno != t->exp_error) {
1861 printf("!!! got errno=%d, want %d\n",
1862 errno, t->exp_error);
1863 return -1;
1864 }
1865 if (ctx->ifparse != save) {
1866 printf("!!! parse error, but first arg changed\n");
1867 return -1;
1868 }
1869 if (memcmp(&orig_hdr, hdr, sizeof(*hdr))) {
1870 printf("!!! parse error, but header changed\n");
1871 return -1;
1872 }
1873 return 0;
1874 }
1875 printf ("!!! nmreq_header_decode was expected to succeed, but it failed with error %d\n", errno);
1876 return -1;
1877 }
1878 if (t->exp_error > 0) {
1879 printf("!!! nmreq_header_decode returns 0, but error %d was expected\n", t->exp_error);
1880 return -1;
1881 }
1882 if (strcmp(t->exp_port, hdr->nr_name) != 0) {
1883 printf("!!! got '%s', want '%s'\n", hdr->nr_name, t->exp_port);
1884 return -1;
1885 }
1886 if (hdr->nr_reqtype != orig_hdr.nr_reqtype ||
1887 hdr->nr_options != orig_hdr.nr_options ||
1888 hdr->nr_body != orig_hdr.nr_body) {
1889 printf("!!! some fields of the nmreq_header where changed unexpectedly\n");
1890 return -1;
1891 }
1892 return 0;
1893 }
1894
1895 static int
nmreq_reg_parsing(struct TestContext * ctx,struct nmreq_parse_test * t,struct nmreq_register * reg)1896 nmreq_reg_parsing(struct TestContext *ctx,
1897 struct nmreq_parse_test *t,
1898 struct nmreq_register *reg)
1899 {
1900 const char *save;
1901 struct nmreq_register orig_reg;
1902
1903
1904 save = ctx->ifparse;
1905 orig_reg = *reg;
1906
1907 printf("nmreq_register: \"%s\"\n", ctx->ifparse);
1908 if (nmreq_register_decode(&ctx->ifparse, reg, ctx->nmctx) < 0) {
1909 if (t->exp_error < 0) {
1910 if (errno != -t->exp_error) {
1911 printf("!!! got errno=%d, want %d\n",
1912 errno, -t->exp_error);
1913 return -1;
1914 }
1915 if (ctx->ifparse != save) {
1916 printf("!!! parse error, but first arg changed\n");
1917 return -1;
1918 }
1919 if (memcmp(&orig_reg, reg, sizeof(*reg))) {
1920 printf("!!! parse error, but nmreq_register changed\n");
1921 return -1;
1922 }
1923 return 0;
1924 }
1925 printf ("!!! parse failed but it should have succeeded\n");
1926 return -1;
1927 }
1928 if (t->exp_error < 0) {
1929 printf("!!! nmreq_register_decode returns 0, but error %d was expected\n", -t->exp_error);
1930 return -1;
1931 }
1932 if (reg->nr_mode != t->exp_mode) {
1933 printf("!!! got nr_mode '%d', want '%d'\n", reg->nr_mode, t->exp_mode);
1934 return -1;
1935 }
1936 if (reg->nr_ringid != t->exp_ringid) {
1937 printf("!!! got nr_ringid '%d', want '%d'\n", reg->nr_ringid, t->exp_ringid);
1938 return -1;
1939 }
1940 if (reg->nr_flags != t->exp_flags) {
1941 printf("!!! got nm_flags '%llx', want '%llx\n", (unsigned long long)reg->nr_flags,
1942 (unsigned long long)t->exp_flags);
1943 return -1;
1944 }
1945 if (reg->nr_offset != orig_reg.nr_offset ||
1946 reg->nr_memsize != orig_reg.nr_memsize ||
1947 reg->nr_tx_slots != orig_reg.nr_tx_slots ||
1948 reg->nr_rx_slots != orig_reg.nr_rx_slots ||
1949 reg->nr_tx_rings != orig_reg.nr_tx_rings ||
1950 reg->nr_rx_rings != orig_reg.nr_rx_rings ||
1951 reg->nr_extra_bufs != orig_reg.nr_extra_bufs)
1952 {
1953 printf("!!! some fields of the nmreq_register where changed unexpectedly\n");
1954 return -1;
1955 }
1956 return 0;
1957 }
1958
1959 static void
nmctx_parsing_error(struct nmctx * ctx,const char * msg)1960 nmctx_parsing_error(struct nmctx *ctx, const char *msg)
1961 {
1962 (void)ctx;
1963 printf(" got message: %s\n", msg);
1964 }
1965
1966 static int
nmreq_parsing(struct TestContext * ctx)1967 nmreq_parsing(struct TestContext *ctx)
1968 {
1969 struct nmreq_parse_test *t;
1970 struct nmreq_header hdr;
1971 struct nmreq_register reg;
1972 struct nmctx test_nmctx, *nmctx;
1973 int ret = 0;
1974
1975 nmctx = nmctx_get();
1976 if (nmctx == NULL) {
1977 printf("Failed to acquire nmctx: %s", strerror(errno));
1978 return -1;
1979 }
1980 test_nmctx = *nmctx;
1981 test_nmctx.error = nmctx_parsing_error;
1982 ctx->nmctx = &test_nmctx;
1983 for (t = nmreq_parse_tests; t->ifname != NULL; t++) {
1984 const char *exp_suff = t->exp_suff != NULL ?
1985 t->exp_suff : t->ifname;
1986
1987 randomize(&hdr, sizeof(hdr));
1988 randomize(®, sizeof(reg));
1989 reg.nr_mem_id = 0;
1990 if (nmreq_hdr_parsing(ctx, t, &hdr) < 0) {
1991 ret = -1;
1992 } else if (t->exp_error <= 0 && nmreq_reg_parsing(ctx, t, ®) < 0) {
1993 ret = -1;
1994 }
1995 if (strcmp(ctx->ifparse, exp_suff) != 0) {
1996 printf("!!! string suffix after parse is '%s', but it should be '%s'\n",
1997 ctx->ifparse, exp_suff);
1998 ret = -1;
1999 }
2000 }
2001 ctx->nmctx = NULL;
2002 return ret;
2003 }
2004
2005 static int
binarycomp(struct TestContext * ctx)2006 binarycomp(struct TestContext *ctx)
2007 {
2008 #define ckroff(f, o) do {\
2009 if (offsetof(struct netmap_ring, f) != (o)) {\
2010 printf("offset of netmap_ring.%s is %zd, but it should be %d",\
2011 #f, offsetof(struct netmap_ring, f), (o));\
2012 return -1;\
2013 }\
2014 } while (0)
2015
2016 (void)ctx;
2017
2018 ckroff(buf_ofs, 0);
2019 ckroff(num_slots, 8);
2020 ckroff(nr_buf_size, 12);
2021 ckroff(ringid, 16);
2022 ckroff(dir, 18);
2023 ckroff(head, 20);
2024 ckroff(cur, 24);
2025 ckroff(tail, 28);
2026 ckroff(flags, 32);
2027 ckroff(ts, 40);
2028 ckroff(offset_mask, 56);
2029 ckroff(buf_align, 64);
2030 ckroff(sem, 128);
2031 ckroff(slot, 256);
2032
2033 return 0;
2034 }
2035
2036 static void
usage(const char * prog)2037 usage(const char *prog)
2038 {
2039 printf("%s -i IFNAME\n"
2040 "[-j TEST_NUM1[-[TEST_NUM2]] | -[TEST_NUM_2]]\n"
2041 "[-l (list test cases)]\n",
2042 prog);
2043 }
2044
2045 struct mytest {
2046 testfunc_t test;
2047 const char *name;
2048 };
2049
2050 #define decltest(f) \
2051 { \
2052 .test = f, .name = #f \
2053 }
2054
2055 static struct mytest tests[] = {
2056 decltest(port_info_get),
2057 decltest(port_register_hwall_host),
2058 decltest(port_register_hwall),
2059 decltest(port_register_hostall),
2060 decltest(port_register_single_hw_pair),
2061 decltest(port_register_single_host_pair),
2062 decltest(port_register_hostall_many),
2063 decltest(vale_attach_detach),
2064 decltest(vale_attach_detach_host_rings),
2065 decltest(vale_ephemeral_port_hdr_manipulation),
2066 decltest(vale_persistent_port),
2067 decltest(pools_info_get_and_register),
2068 decltest(pools_info_get_empty_ifname),
2069 decltest(pipe_master),
2070 decltest(pipe_slave),
2071 decltest(pipe_port_info_get),
2072 decltest(pipe_pools_info_get),
2073 decltest(vale_polling_enable_disable),
2074 decltest(unsupported_option),
2075 decltest(infinite_options),
2076 decltest(infinite_options2),
2077 #ifdef CONFIG_NETMAP_EXTMEM
2078 decltest(extmem_option),
2079 decltest(bad_extmem_option),
2080 decltest(duplicate_extmem_options),
2081 #endif /* CONFIG_NETMAP_EXTMEM */
2082 decltest(csb_mode),
2083 decltest(csb_mode_invalid_memory),
2084 decltest(sync_kloop),
2085 decltest(sync_kloop_eventfds_all),
2086 decltest(sync_kloop_eventfds_all_tx),
2087 decltest(sync_kloop_eventfds_all_direct),
2088 decltest(sync_kloop_eventfds_all_direct_tx),
2089 decltest(sync_kloop_eventfds_all_direct_rx),
2090 decltest(sync_kloop_nocsb),
2091 decltest(sync_kloop_csb_enable),
2092 #if 0
2093 decltest(sync_kloop_conflict),
2094 #endif
2095 decltest(sync_kloop_eventfds_mismatch),
2096 decltest(null_port),
2097 decltest(null_port_all_zero),
2098 decltest(null_port_sync),
2099 decltest(legacy_regif_default),
2100 decltest(legacy_regif_all_nic),
2101 decltest(legacy_regif_12),
2102 decltest(legacy_regif_sw),
2103 decltest(legacy_regif_future),
2104 decltest(legacy_regif_extra_bufs),
2105 decltest(legacy_regif_extra_bufs_pipe),
2106 decltest(legacy_regif_extra_bufs_pipe_vale),
2107 decltest(nmreq_parsing),
2108 decltest(binarycomp),
2109 };
2110
2111 static void
context_cleanup(struct TestContext * ctx)2112 context_cleanup(struct TestContext *ctx)
2113 {
2114 if (ctx->csb) {
2115 free(ctx->csb);
2116 ctx->csb = NULL;
2117 }
2118
2119 close(ctx->fd);
2120 ctx->fd = -1;
2121 }
2122
2123 static int
parse_interval(const char * arg,int * j,int * k)2124 parse_interval(const char *arg, int *j, int *k)
2125 {
2126 const char *scan = arg;
2127 char *rest;
2128
2129 *j = 0;
2130 *k = -1;
2131 if (*scan == '-') {
2132 scan++;
2133 goto get_k;
2134 }
2135 if (!isdigit(*scan))
2136 goto err;
2137 *k = strtol(scan, &rest, 10);
2138 *j = *k - 1;
2139 scan = rest;
2140 if (*scan == '-') {
2141 *k = -1;
2142 scan++;
2143 }
2144 get_k:
2145 if (*scan == '\0')
2146 return 0;
2147 if (!isdigit(*scan))
2148 goto err;
2149 *k = strtol(scan, &rest, 10);
2150 scan = rest;
2151 if (!(*scan == '\0'))
2152 goto err;
2153
2154 return 0;
2155
2156 err:
2157 fprintf(stderr, "syntax error in '%s', must be num[-[num]] or -[num]\n", arg);
2158 return -1;
2159 }
2160
2161 #define ARGV_APPEND(_av, _ac, _x)\
2162 do {\
2163 assert((int)(_ac) < (int)(sizeof(_av)/sizeof((_av)[0])));\
2164 (_av)[(_ac)++] = _x;\
2165 } while (0)
2166
2167 static void
tap_cleanup(int signo)2168 tap_cleanup(int signo)
2169 {
2170 const char *av[8];
2171 int ac = 0;
2172
2173 (void)signo;
2174 #ifdef __FreeBSD__
2175 ARGV_APPEND(av, ac, "ifconfig");
2176 ARGV_APPEND(av, ac, ctx_.ifname);
2177 ARGV_APPEND(av, ac, "destroy");
2178 #else
2179 ARGV_APPEND(av, ac, "ip");
2180 ARGV_APPEND(av, ac, "link");
2181 ARGV_APPEND(av, ac, "del");
2182 ARGV_APPEND(av, ac, ctx_.ifname);
2183 #endif
2184 ARGV_APPEND(av, ac, NULL);
2185 if (exec_command(ac, av)) {
2186 printf("Failed to destroy tap interface\n");
2187 }
2188 }
2189
2190 int
main(int argc,char ** argv)2191 main(int argc, char **argv)
2192 {
2193 int create_tap = 1;
2194 int num_tests;
2195 int ret = 0;
2196 int j = 0;
2197 int k = -1;
2198 int list = 0;
2199 int opt;
2200 int i;
2201
2202 #ifdef __FreeBSD__
2203 PLAIN_REQUIRE_KERNEL_MODULE("if_tap", 0);
2204 PLAIN_REQUIRE_KERNEL_MODULE("netmap", 0);
2205 #endif
2206
2207 memset(&ctx_, 0, sizeof(ctx_));
2208
2209 {
2210 struct timespec t;
2211 int idx;
2212
2213 clock_gettime(CLOCK_REALTIME, &t);
2214 srand((unsigned int)t.tv_nsec);
2215 idx = rand() % 8000 + 100;
2216 snprintf(ctx_.ifname, sizeof(ctx_.ifname), "tap%d", idx);
2217 idx = rand() % 800 + 100;
2218 snprintf(ctx_.bdgname, sizeof(ctx_.bdgname), "vale%d", idx);
2219 }
2220
2221 while ((opt = getopt(argc, argv, "hi:j:l")) != -1) {
2222 switch (opt) {
2223 case 'h':
2224 usage(argv[0]);
2225 return 0;
2226
2227 case 'i':
2228 strncpy(ctx_.ifname, optarg, sizeof(ctx_.ifname) - 1);
2229 create_tap = 0;
2230 break;
2231
2232 case 'j':
2233 if (parse_interval(optarg, &j, &k) < 0) {
2234 usage(argv[0]);
2235 return -1;
2236 }
2237 break;
2238
2239 case 'l':
2240 list = 1;
2241 create_tap = 0;
2242 break;
2243
2244 default:
2245 printf(" Unrecognized option %c\n", opt);
2246 usage(argv[0]);
2247 return -1;
2248 }
2249 }
2250
2251 num_tests = sizeof(tests) / sizeof(tests[0]);
2252
2253 if (j < 0 || j >= num_tests || k > num_tests) {
2254 fprintf(stderr, "Test interval %d-%d out of range (%d-%d)\n",
2255 j + 1, k, 1, num_tests + 1);
2256 return -1;
2257 }
2258
2259 if (k < 0)
2260 k = num_tests;
2261
2262 if (list) {
2263 printf("Available tests:\n");
2264 for (i = 0; i < num_tests; i++) {
2265 printf("#%03d: %s\n", i + 1, tests[i].name);
2266 }
2267 return 0;
2268 }
2269
2270 if (create_tap) {
2271 struct sigaction sa;
2272 const char *av[8];
2273 int ac = 0;
2274 #ifdef __FreeBSD__
2275 ARGV_APPEND(av, ac, "ifconfig");
2276 ARGV_APPEND(av, ac, ctx_.ifname);
2277 ARGV_APPEND(av, ac, "create");
2278 ARGV_APPEND(av, ac, "up");
2279 #else
2280 ARGV_APPEND(av, ac, "ip");
2281 ARGV_APPEND(av, ac, "tuntap");
2282 ARGV_APPEND(av, ac, "add");
2283 ARGV_APPEND(av, ac, "mode");
2284 ARGV_APPEND(av, ac, "tap");
2285 ARGV_APPEND(av, ac, "name");
2286 ARGV_APPEND(av, ac, ctx_.ifname);
2287 #endif
2288 ARGV_APPEND(av, ac, NULL);
2289 if (exec_command(ac, av)) {
2290 printf("Failed to create tap interface\n");
2291 return -1;
2292 }
2293
2294 sa.sa_handler = tap_cleanup;
2295 sigemptyset(&sa.sa_mask);
2296 sa.sa_flags = SA_RESTART;
2297 ret = sigaction(SIGINT, &sa, NULL);
2298 if (ret) {
2299 perror("sigaction(SIGINT)");
2300 goto out;
2301 }
2302 ret = sigaction(SIGTERM, &sa, NULL);
2303 if (ret) {
2304 perror("sigaction(SIGTERM)");
2305 goto out;
2306 }
2307 }
2308
2309 for (i = j; i < k; i++) {
2310 struct TestContext ctxcopy;
2311 int fd;
2312 printf("==> Start of Test #%d [%s]\n", i + 1, tests[i].name);
2313 fd = open("/dev/netmap", O_RDWR);
2314 if (fd < 0) {
2315 perror("open(/dev/netmap)");
2316 ret = fd;
2317 goto out;
2318 }
2319 memcpy(&ctxcopy, &ctx_, sizeof(ctxcopy));
2320 ctxcopy.fd = fd;
2321 memcpy(ctxcopy.ifname_ext, ctxcopy.ifname,
2322 sizeof(ctxcopy.ifname));
2323 ret = tests[i].test(&ctxcopy);
2324 if (ret != 0) {
2325 printf("Test #%d [%s] failed\n", i + 1, tests[i].name);
2326 goto out;
2327 }
2328 printf("==> Test #%d [%s] successful\n", i + 1, tests[i].name);
2329 context_cleanup(&ctxcopy);
2330 }
2331 out:
2332 tap_cleanup(0);
2333
2334 return ret;
2335 }
2336