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