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