xref: /freebsd/lib/libnetmap/nmport.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
14c067f38SVincenzo Maffione /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
34c067f38SVincenzo Maffione  *
44c067f38SVincenzo Maffione  * Copyright (C) 2018 Universita` di Pisa
54c067f38SVincenzo Maffione  * All rights reserved.
64c067f38SVincenzo Maffione  *
74c067f38SVincenzo Maffione  * Redistribution and use in source and binary forms, with or without
84c067f38SVincenzo Maffione  * modification, are permitted provided that the following conditions
94c067f38SVincenzo Maffione  * are met:
104c067f38SVincenzo Maffione  *
114c067f38SVincenzo Maffione  *   1. Redistributions of source code must retain the above copyright
124c067f38SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer.
134c067f38SVincenzo Maffione  *   2. Redistributions in binary form must reproduce the above copyright
144c067f38SVincenzo Maffione  *      notice, this list of conditions and the following disclaimer in the
154c067f38SVincenzo Maffione  *      documentation and/or other materials provided with the distribution.
164c067f38SVincenzo Maffione  *
174c067f38SVincenzo Maffione  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
184c067f38SVincenzo Maffione  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
194c067f38SVincenzo Maffione  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
204c067f38SVincenzo Maffione  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
214c067f38SVincenzo Maffione  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
224c067f38SVincenzo Maffione  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
234c067f38SVincenzo Maffione  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
244c067f38SVincenzo Maffione  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
254c067f38SVincenzo Maffione  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
264c067f38SVincenzo Maffione  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
274c067f38SVincenzo Maffione  * SUCH DAMAGE.
284c067f38SVincenzo Maffione  */
294c067f38SVincenzo Maffione 
305c4f8d80SVincenzo Maffione #include <sys/types.h>
315c4f8d80SVincenzo Maffione #include <sys/stat.h>
325c4f8d80SVincenzo Maffione #include <sys/ioctl.h>
335c4f8d80SVincenzo Maffione #include <sys/mman.h>
345c4f8d80SVincenzo Maffione #include <fcntl.h>
355c4f8d80SVincenzo Maffione #include <inttypes.h>
365c4f8d80SVincenzo Maffione #include <stdlib.h>
375c4f8d80SVincenzo Maffione #include <stdio.h>
385c4f8d80SVincenzo Maffione #include <stdarg.h>
395c4f8d80SVincenzo Maffione #include <string.h>
405c4f8d80SVincenzo Maffione #include <unistd.h>
415c4f8d80SVincenzo Maffione #include <errno.h>
425c4f8d80SVincenzo Maffione #include <net/netmap_user.h>
435c4f8d80SVincenzo Maffione #define LIBNETMAP_NOTHREADSAFE
445c4f8d80SVincenzo Maffione #include "libnetmap.h"
455c4f8d80SVincenzo Maffione 
465c4f8d80SVincenzo Maffione struct nmport_cleanup_d {
475c4f8d80SVincenzo Maffione 	struct nmport_cleanup_d *next;
485c4f8d80SVincenzo Maffione 	void (*cleanup)(struct nmport_cleanup_d *, struct nmport_d *);
495c4f8d80SVincenzo Maffione };
505c4f8d80SVincenzo Maffione 
515c4f8d80SVincenzo Maffione static void
nmport_push_cleanup(struct nmport_d * d,struct nmport_cleanup_d * c)525c4f8d80SVincenzo Maffione nmport_push_cleanup(struct nmport_d *d, struct nmport_cleanup_d *c)
535c4f8d80SVincenzo Maffione {
545c4f8d80SVincenzo Maffione 	c->next = d->clist;
555c4f8d80SVincenzo Maffione 	d->clist = c;
565c4f8d80SVincenzo Maffione }
575c4f8d80SVincenzo Maffione 
585c4f8d80SVincenzo Maffione static void
nmport_pop_cleanup(struct nmport_d * d)595c4f8d80SVincenzo Maffione nmport_pop_cleanup(struct nmport_d *d)
605c4f8d80SVincenzo Maffione {
615c4f8d80SVincenzo Maffione 	struct nmport_cleanup_d *top;
625c4f8d80SVincenzo Maffione 
635c4f8d80SVincenzo Maffione 	top = d->clist;
645c4f8d80SVincenzo Maffione 	d->clist = d->clist->next;
655c4f8d80SVincenzo Maffione 	(*top->cleanup)(top, d);
665c4f8d80SVincenzo Maffione 	nmctx_free(d->ctx, top);
675c4f8d80SVincenzo Maffione }
685c4f8d80SVincenzo Maffione 
nmport_do_cleanup(struct nmport_d * d)695c4f8d80SVincenzo Maffione void nmport_do_cleanup(struct nmport_d *d)
705c4f8d80SVincenzo Maffione {
715c4f8d80SVincenzo Maffione 	while (d->clist != NULL) {
725c4f8d80SVincenzo Maffione 		nmport_pop_cleanup(d);
735c4f8d80SVincenzo Maffione 	}
745c4f8d80SVincenzo Maffione }
755c4f8d80SVincenzo Maffione 
765c4f8d80SVincenzo Maffione static struct nmport_d *
nmport_new_with_ctx(struct nmctx * ctx)775c4f8d80SVincenzo Maffione nmport_new_with_ctx(struct nmctx *ctx)
785c4f8d80SVincenzo Maffione {
795c4f8d80SVincenzo Maffione 	struct nmport_d *d;
805c4f8d80SVincenzo Maffione 
815c4f8d80SVincenzo Maffione 	/* allocate a descriptor */
825c4f8d80SVincenzo Maffione 	d = nmctx_malloc(ctx, sizeof(*d));
835c4f8d80SVincenzo Maffione 	if (d == NULL) {
845c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot allocate nmport descriptor");
855c4f8d80SVincenzo Maffione 		goto out;
865c4f8d80SVincenzo Maffione 	}
875c4f8d80SVincenzo Maffione 	memset(d, 0, sizeof(*d));
885c4f8d80SVincenzo Maffione 
895c4f8d80SVincenzo Maffione 	nmreq_header_init(&d->hdr, NETMAP_REQ_REGISTER, &d->reg);
905c4f8d80SVincenzo Maffione 
915c4f8d80SVincenzo Maffione 	d->ctx = ctx;
925c4f8d80SVincenzo Maffione 	d->fd = -1;
935c4f8d80SVincenzo Maffione 
945c4f8d80SVincenzo Maffione out:
955c4f8d80SVincenzo Maffione 	return d;
965c4f8d80SVincenzo Maffione }
975c4f8d80SVincenzo Maffione 
985c4f8d80SVincenzo Maffione struct nmport_d *
nmport_new(void)995c4f8d80SVincenzo Maffione nmport_new(void)
1005c4f8d80SVincenzo Maffione {
1015c4f8d80SVincenzo Maffione 	struct nmctx *ctx = nmctx_get();
1025c4f8d80SVincenzo Maffione 	return nmport_new_with_ctx(ctx);
1035c4f8d80SVincenzo Maffione }
1045c4f8d80SVincenzo Maffione 
1055c4f8d80SVincenzo Maffione 
1065c4f8d80SVincenzo Maffione void
nmport_delete(struct nmport_d * d)1075c4f8d80SVincenzo Maffione nmport_delete(struct nmport_d *d)
1085c4f8d80SVincenzo Maffione {
1095c4f8d80SVincenzo Maffione 	nmctx_free(d->ctx, d);
1105c4f8d80SVincenzo Maffione }
1115c4f8d80SVincenzo Maffione 
1125c4f8d80SVincenzo Maffione void
nmport_extmem_cleanup(struct nmport_cleanup_d * c,struct nmport_d * d)1135c4f8d80SVincenzo Maffione nmport_extmem_cleanup(struct nmport_cleanup_d *c, struct nmport_d *d)
1145c4f8d80SVincenzo Maffione {
1155c4f8d80SVincenzo Maffione 	(void)c;
1165c4f8d80SVincenzo Maffione 
1175c4f8d80SVincenzo Maffione 	if (d->extmem == NULL)
1185c4f8d80SVincenzo Maffione 		return;
1195c4f8d80SVincenzo Maffione 
1205c4f8d80SVincenzo Maffione 	nmreq_remove_option(&d->hdr, &d->extmem->nro_opt);
1215c4f8d80SVincenzo Maffione 	nmctx_free(d->ctx, d->extmem);
1225c4f8d80SVincenzo Maffione 	d->extmem = NULL;
1235c4f8d80SVincenzo Maffione }
1245c4f8d80SVincenzo Maffione 
1255c4f8d80SVincenzo Maffione 
1265c4f8d80SVincenzo Maffione int
nmport_extmem(struct nmport_d * d,void * base,size_t size)1275c4f8d80SVincenzo Maffione nmport_extmem(struct nmport_d *d, void *base, size_t size)
1285c4f8d80SVincenzo Maffione {
1295c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
1305c4f8d80SVincenzo Maffione 	struct nmport_cleanup_d *clnup = NULL;
1315c4f8d80SVincenzo Maffione 
1325c4f8d80SVincenzo Maffione 	if (d->register_done) {
1335c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: cannot set extmem of an already registered port", d->hdr.nr_name);
1345c4f8d80SVincenzo Maffione 		errno = EINVAL;
1355c4f8d80SVincenzo Maffione 		return -1;
1365c4f8d80SVincenzo Maffione 	}
1375c4f8d80SVincenzo Maffione 
1385c4f8d80SVincenzo Maffione 	if (d->extmem != NULL) {
1395c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: extmem already in use", d->hdr.nr_name);
1405c4f8d80SVincenzo Maffione 		errno = EINVAL;
1415c4f8d80SVincenzo Maffione 		return -1;
1425c4f8d80SVincenzo Maffione 	}
1435c4f8d80SVincenzo Maffione 
1445c4f8d80SVincenzo Maffione 	clnup = (struct nmport_cleanup_d *)nmctx_malloc(ctx, sizeof(*clnup));
1455c4f8d80SVincenzo Maffione 	if (clnup == NULL) {
1465c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "failed to allocate cleanup descriptor");
1475c4f8d80SVincenzo Maffione 		errno = ENOMEM;
1485c4f8d80SVincenzo Maffione 		return -1;
1495c4f8d80SVincenzo Maffione 	}
1505c4f8d80SVincenzo Maffione 
1515c4f8d80SVincenzo Maffione 	d->extmem = nmctx_malloc(ctx, sizeof(*d->extmem));
1525c4f8d80SVincenzo Maffione 	if (d->extmem == NULL) {
1535c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: cannot allocate extmem option", d->hdr.nr_name);
1545c4f8d80SVincenzo Maffione 		nmctx_free(ctx, clnup);
1555c4f8d80SVincenzo Maffione 		errno = ENOMEM;
1565c4f8d80SVincenzo Maffione 		return -1;
1575c4f8d80SVincenzo Maffione 	}
1585c4f8d80SVincenzo Maffione 	memset(d->extmem, 0, sizeof(*d->extmem));
1595c4f8d80SVincenzo Maffione 	d->extmem->nro_usrptr = (uintptr_t)base;
1605c4f8d80SVincenzo Maffione 	d->extmem->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1615c4f8d80SVincenzo Maffione 	d->extmem->nro_info.nr_memsize = size;
1625c4f8d80SVincenzo Maffione 	nmreq_push_option(&d->hdr, &d->extmem->nro_opt);
1635c4f8d80SVincenzo Maffione 
1645c4f8d80SVincenzo Maffione 	clnup->cleanup = nmport_extmem_cleanup;
1655c4f8d80SVincenzo Maffione 	nmport_push_cleanup(d, clnup);
1665c4f8d80SVincenzo Maffione 
1675c4f8d80SVincenzo Maffione 	return 0;
1685c4f8d80SVincenzo Maffione }
1695c4f8d80SVincenzo Maffione 
1705c4f8d80SVincenzo Maffione struct nmport_extmem_from_file_cleanup_d {
1715c4f8d80SVincenzo Maffione 	struct nmport_cleanup_d up;
1725c4f8d80SVincenzo Maffione 	void *p;
1735c4f8d80SVincenzo Maffione 	size_t size;
1745c4f8d80SVincenzo Maffione };
1755c4f8d80SVincenzo Maffione 
nmport_extmem_from_file_cleanup(struct nmport_cleanup_d * c,struct nmport_d * d)1765c4f8d80SVincenzo Maffione void nmport_extmem_from_file_cleanup(struct nmport_cleanup_d *c,
1775c4f8d80SVincenzo Maffione 		struct nmport_d *d)
1785c4f8d80SVincenzo Maffione {
179f8113f0aSVincenzo Maffione 	(void)d;
1805c4f8d80SVincenzo Maffione 	struct nmport_extmem_from_file_cleanup_d *cc =
1815c4f8d80SVincenzo Maffione 		(struct nmport_extmem_from_file_cleanup_d *)c;
1825c4f8d80SVincenzo Maffione 
1835c4f8d80SVincenzo Maffione 	munmap(cc->p, cc->size);
1845c4f8d80SVincenzo Maffione }
1855c4f8d80SVincenzo Maffione 
1865c4f8d80SVincenzo Maffione int
nmport_extmem_from_file(struct nmport_d * d,const char * fname)1875c4f8d80SVincenzo Maffione nmport_extmem_from_file(struct nmport_d *d, const char *fname)
1885c4f8d80SVincenzo Maffione {
1895c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
1905c4f8d80SVincenzo Maffione 	int fd = -1;
1915c4f8d80SVincenzo Maffione 	off_t mapsize;
1925c4f8d80SVincenzo Maffione 	void *p;
1935c4f8d80SVincenzo Maffione 	struct nmport_extmem_from_file_cleanup_d *clnup = NULL;
1945c4f8d80SVincenzo Maffione 
1955c4f8d80SVincenzo Maffione 	clnup = nmctx_malloc(ctx, sizeof(*clnup));
1965c4f8d80SVincenzo Maffione 	if (clnup == NULL) {
1975c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot allocate cleanup descriptor");
1985c4f8d80SVincenzo Maffione 		errno = ENOMEM;
1995c4f8d80SVincenzo Maffione 		goto fail;
2005c4f8d80SVincenzo Maffione 	}
2015c4f8d80SVincenzo Maffione 
2025c4f8d80SVincenzo Maffione 	fd = open(fname, O_RDWR);
2035c4f8d80SVincenzo Maffione 	if (fd < 0) {
2045c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot open '%s': %s", fname, strerror(errno));
2055c4f8d80SVincenzo Maffione 		goto fail;
2065c4f8d80SVincenzo Maffione 	}
2075c4f8d80SVincenzo Maffione 	mapsize = lseek(fd, 0, SEEK_END);
2085c4f8d80SVincenzo Maffione 	if (mapsize < 0) {
2095c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "failed to obtain filesize of '%s': %s", fname, strerror(errno));
2105c4f8d80SVincenzo Maffione 		goto fail;
2115c4f8d80SVincenzo Maffione 	}
2125c4f8d80SVincenzo Maffione 	p = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2135c4f8d80SVincenzo Maffione 	if (p == MAP_FAILED) {
2145c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot mmap '%s': %s", fname, strerror(errno));
2155c4f8d80SVincenzo Maffione 		goto fail;
2165c4f8d80SVincenzo Maffione 	}
2175c4f8d80SVincenzo Maffione 	close(fd);
2185c4f8d80SVincenzo Maffione 
2195c4f8d80SVincenzo Maffione 	clnup->p = p;
2205c4f8d80SVincenzo Maffione 	clnup->size = mapsize;
2215c4f8d80SVincenzo Maffione 	clnup->up.cleanup = nmport_extmem_from_file_cleanup;
2225c4f8d80SVincenzo Maffione 	nmport_push_cleanup(d, &clnup->up);
2235c4f8d80SVincenzo Maffione 
2245c4f8d80SVincenzo Maffione 	if (nmport_extmem(d, p, mapsize) < 0)
2255c4f8d80SVincenzo Maffione 		goto fail;
2265c4f8d80SVincenzo Maffione 
2275c4f8d80SVincenzo Maffione 	return 0;
2285c4f8d80SVincenzo Maffione 
2295c4f8d80SVincenzo Maffione fail:
2305c4f8d80SVincenzo Maffione 	if (fd >= 0)
2315c4f8d80SVincenzo Maffione 		close(fd);
2325c4f8d80SVincenzo Maffione 	if (clnup != NULL) {
2335c4f8d80SVincenzo Maffione 		if (clnup->p != MAP_FAILED)
2345c4f8d80SVincenzo Maffione 			nmport_pop_cleanup(d);
2355c4f8d80SVincenzo Maffione 		else
2365c4f8d80SVincenzo Maffione 			nmctx_free(ctx, clnup);
2375c4f8d80SVincenzo Maffione 	}
2385c4f8d80SVincenzo Maffione 	return -1;
2395c4f8d80SVincenzo Maffione }
2405c4f8d80SVincenzo Maffione 
2415c4f8d80SVincenzo Maffione struct nmreq_pools_info*
nmport_extmem_getinfo(struct nmport_d * d)2425c4f8d80SVincenzo Maffione nmport_extmem_getinfo(struct nmport_d *d)
2435c4f8d80SVincenzo Maffione {
2445c4f8d80SVincenzo Maffione 	if (d->extmem == NULL)
2455c4f8d80SVincenzo Maffione 		return NULL;
2465c4f8d80SVincenzo Maffione 	return &d->extmem->nro_info;
2475c4f8d80SVincenzo Maffione }
2485c4f8d80SVincenzo Maffione 
249f8113f0aSVincenzo Maffione struct nmport_offset_cleanup_d {
250f8113f0aSVincenzo Maffione 	struct nmport_cleanup_d up;
251f8113f0aSVincenzo Maffione 	struct nmreq_opt_offsets *opt;
252f8113f0aSVincenzo Maffione };
253f8113f0aSVincenzo Maffione 
254f8113f0aSVincenzo Maffione static void
nmport_offset_cleanup(struct nmport_cleanup_d * c,struct nmport_d * d)255f8113f0aSVincenzo Maffione nmport_offset_cleanup(struct nmport_cleanup_d *c,
256f8113f0aSVincenzo Maffione 		struct nmport_d *d)
257f8113f0aSVincenzo Maffione {
258f8113f0aSVincenzo Maffione 	struct nmport_offset_cleanup_d *cc =
259f8113f0aSVincenzo Maffione 		(struct nmport_offset_cleanup_d *)c;
260f8113f0aSVincenzo Maffione 
261f8113f0aSVincenzo Maffione 	nmreq_remove_option(&d->hdr, &cc->opt->nro_opt);
262f8113f0aSVincenzo Maffione 	nmctx_free(d->ctx, cc->opt);
263f8113f0aSVincenzo Maffione }
264f8113f0aSVincenzo Maffione 
265f8113f0aSVincenzo Maffione int
nmport_offset(struct nmport_d * d,uint64_t initial,uint64_t maxoff,uint64_t bits,uint64_t mingap)266f8113f0aSVincenzo Maffione nmport_offset(struct nmport_d *d, uint64_t initial,
267f8113f0aSVincenzo Maffione 		uint64_t maxoff, uint64_t bits, uint64_t mingap)
268f8113f0aSVincenzo Maffione {
269f8113f0aSVincenzo Maffione 	struct nmctx *ctx = d->ctx;
270f8113f0aSVincenzo Maffione 	struct nmreq_opt_offsets *opt;
271f8113f0aSVincenzo Maffione 	struct nmport_offset_cleanup_d *clnup = NULL;
272f8113f0aSVincenzo Maffione 
273f8113f0aSVincenzo Maffione 	clnup = nmctx_malloc(ctx, sizeof(*clnup));
274f8113f0aSVincenzo Maffione 	if (clnup == NULL) {
275f8113f0aSVincenzo Maffione 		nmctx_ferror(ctx, "cannot allocate cleanup descriptor");
276f8113f0aSVincenzo Maffione 		errno = ENOMEM;
277f8113f0aSVincenzo Maffione 		return -1;
278f8113f0aSVincenzo Maffione 	}
279f8113f0aSVincenzo Maffione 
280f8113f0aSVincenzo Maffione 	opt = nmctx_malloc(ctx, sizeof(*opt));
281f8113f0aSVincenzo Maffione 	if (opt == NULL) {
282f8113f0aSVincenzo Maffione 		nmctx_ferror(ctx, "%s: cannot allocate offset option", d->hdr.nr_name);
283f8113f0aSVincenzo Maffione 		nmctx_free(ctx, clnup);
284f8113f0aSVincenzo Maffione 		errno = ENOMEM;
285f8113f0aSVincenzo Maffione 		return -1;
286f8113f0aSVincenzo Maffione 	}
287f8113f0aSVincenzo Maffione 	memset(opt, 0, sizeof(*opt));
288f8113f0aSVincenzo Maffione 	opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS;
289f8113f0aSVincenzo Maffione 	opt->nro_offset_bits = bits;
290f8113f0aSVincenzo Maffione 	opt->nro_initial_offset = initial;
291f8113f0aSVincenzo Maffione 	opt->nro_max_offset = maxoff;
292f8113f0aSVincenzo Maffione 	opt->nro_min_gap = mingap;
293f8113f0aSVincenzo Maffione 	nmreq_push_option(&d->hdr, &opt->nro_opt);
294f8113f0aSVincenzo Maffione 
295f8113f0aSVincenzo Maffione 	clnup->up.cleanup = nmport_offset_cleanup;
296f8113f0aSVincenzo Maffione 	clnup->opt = opt;
297f8113f0aSVincenzo Maffione 	nmport_push_cleanup(d, &clnup->up);
298f8113f0aSVincenzo Maffione 
299f8113f0aSVincenzo Maffione 	return 0;
300f8113f0aSVincenzo Maffione }
301f8113f0aSVincenzo Maffione 
3025c4f8d80SVincenzo Maffione /* head of the list of options */
3035c4f8d80SVincenzo Maffione static struct nmreq_opt_parser *nmport_opt_parsers;
3045c4f8d80SVincenzo Maffione 
3055c4f8d80SVincenzo Maffione #define NPOPT_PARSER(o)		nmport_opt_##o##_parser
3065c4f8d80SVincenzo Maffione #define NPOPT_DESC(o)		nmport_opt_##o##_desc
3075c4f8d80SVincenzo Maffione #define NPOPT_NRKEYS(o)		(NPOPT_DESC(o).nr_keys)
3085c4f8d80SVincenzo Maffione #define NPOPT_DECL(o, f)						\
3095c4f8d80SVincenzo Maffione static int NPOPT_PARSER(o)(struct nmreq_parse_ctx *);			\
3105c4f8d80SVincenzo Maffione static struct nmreq_opt_parser NPOPT_DESC(o) = {			\
3115c4f8d80SVincenzo Maffione 	.prefix = #o,							\
3125c4f8d80SVincenzo Maffione 	.parse = NPOPT_PARSER(o),					\
3135c4f8d80SVincenzo Maffione 	.flags = (f),							\
3145c4f8d80SVincenzo Maffione 	.default_key = -1,						\
3155c4f8d80SVincenzo Maffione 	.nr_keys = 0,							\
3165c4f8d80SVincenzo Maffione 	.next = NULL,							\
3175c4f8d80SVincenzo Maffione };									\
3185c4f8d80SVincenzo Maffione static void __attribute__((constructor))				\
3195c4f8d80SVincenzo Maffione nmport_opt_##o##_ctor(void)						\
3205c4f8d80SVincenzo Maffione {									\
3215c4f8d80SVincenzo Maffione 	NPOPT_DESC(o).next = nmport_opt_parsers;			\
3225c4f8d80SVincenzo Maffione 	nmport_opt_parsers = &NPOPT_DESC(o);				\
3235c4f8d80SVincenzo Maffione }
3245c4f8d80SVincenzo Maffione struct nmport_key_desc {
3255c4f8d80SVincenzo Maffione 	struct nmreq_opt_parser *option;
3265c4f8d80SVincenzo Maffione 	const char *key;
3275c4f8d80SVincenzo Maffione 	unsigned int flags;
3285c4f8d80SVincenzo Maffione 	int id;
3295c4f8d80SVincenzo Maffione };
3305c4f8d80SVincenzo Maffione static void
nmport_opt_key_ctor(struct nmport_key_desc * k)3315c4f8d80SVincenzo Maffione nmport_opt_key_ctor(struct nmport_key_desc *k)
3325c4f8d80SVincenzo Maffione {
3335c4f8d80SVincenzo Maffione 	struct nmreq_opt_parser *o = k->option;
3345c4f8d80SVincenzo Maffione 	struct nmreq_opt_key *ok;
3355c4f8d80SVincenzo Maffione 
3365c4f8d80SVincenzo Maffione 	k->id = o->nr_keys;
3375c4f8d80SVincenzo Maffione 	ok = &o->keys[k->id];
3385c4f8d80SVincenzo Maffione 	ok->key = k->key;
3395c4f8d80SVincenzo Maffione 	ok->id = k->id;
3405c4f8d80SVincenzo Maffione 	ok->flags = k->flags;
3415c4f8d80SVincenzo Maffione 	o->nr_keys++;
3425c4f8d80SVincenzo Maffione 	if (ok->flags & NMREQ_OPTK_DEFAULT)
3435c4f8d80SVincenzo Maffione 		o->default_key = ok->id;
3445c4f8d80SVincenzo Maffione }
3455c4f8d80SVincenzo Maffione #define NPKEY_DESC(o, k)	nmport_opt_##o##_key_##k##_desc
3465c4f8d80SVincenzo Maffione #define NPKEY_ID(o, k)		(NPKEY_DESC(o, k).id)
3475c4f8d80SVincenzo Maffione #define NPKEY_DECL(o, k, f)						\
3485c4f8d80SVincenzo Maffione static struct nmport_key_desc NPKEY_DESC(o, k) = {			\
3495c4f8d80SVincenzo Maffione 	.option = &NPOPT_DESC(o),					\
3505c4f8d80SVincenzo Maffione 	.key = #k,							\
3515c4f8d80SVincenzo Maffione 	.flags = (f),							\
3525c4f8d80SVincenzo Maffione 	.id = -1,							\
3535c4f8d80SVincenzo Maffione };									\
3545c4f8d80SVincenzo Maffione static void __attribute__((constructor))				\
3555c4f8d80SVincenzo Maffione nmport_opt_##o##_key_##k##_ctor(void)					\
3565c4f8d80SVincenzo Maffione {									\
3575c4f8d80SVincenzo Maffione 	nmport_opt_key_ctor(&NPKEY_DESC(o, k));				\
3585c4f8d80SVincenzo Maffione }
3595c4f8d80SVincenzo Maffione #define nmport_key(p, o, k)	((p)->keys[NPKEY_ID(o, k)])
3605c4f8d80SVincenzo Maffione #define nmport_defkey(p, o)	((p)->keys[NPOPT_DESC(o).default_key])
3615c4f8d80SVincenzo Maffione 
3625c4f8d80SVincenzo Maffione NPOPT_DECL(share, 0)
3635c4f8d80SVincenzo Maffione 	NPKEY_DECL(share, port, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET)
3645c4f8d80SVincenzo Maffione NPOPT_DECL(extmem, 0)
3655c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, file, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET)
3665c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, if_num, 0)
3675c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, if_size, 0)
3685c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, ring_num, 0)
3695c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, ring_size, 0)
3705c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, buf_num, 0)
3715c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, buf_size, 0)
3725c4f8d80SVincenzo Maffione NPOPT_DECL(conf, 0)
3735c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, rings, 0)
3745c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, host_rings, 0)
3755c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, slots, 0)
3765c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, tx_rings, 0)
3775c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, rx_rings, 0)
3785c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, host_tx_rings, 0)
3795c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, host_rx_rings, 0)
3805c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, tx_slots, 0)
3815c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, rx_slots, 0)
NPOPT_DECL(offset,NMREQ_OPTF_DISABLED)382f8113f0aSVincenzo Maffione NPOPT_DECL(offset, NMREQ_OPTF_DISABLED)
383f8113f0aSVincenzo Maffione 	NPKEY_DECL(offset, initial, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET)
384f8113f0aSVincenzo Maffione 	NPKEY_DECL(offset, bits, 0)
3855c4f8d80SVincenzo Maffione 
3865c4f8d80SVincenzo Maffione 
3875c4f8d80SVincenzo Maffione static int
3885c4f8d80SVincenzo Maffione NPOPT_PARSER(share)(struct nmreq_parse_ctx *p)
3895c4f8d80SVincenzo Maffione {
3905c4f8d80SVincenzo Maffione 	struct nmctx *ctx = p->ctx;
3915c4f8d80SVincenzo Maffione 	struct nmport_d *d = p->token;
3925c4f8d80SVincenzo Maffione 	int32_t mem_id;
3935c4f8d80SVincenzo Maffione 	const char *v = nmport_defkey(p, share);
3945c4f8d80SVincenzo Maffione 
3955c4f8d80SVincenzo Maffione 	mem_id = nmreq_get_mem_id(&v, ctx);
3965c4f8d80SVincenzo Maffione 	if (mem_id < 0)
3975c4f8d80SVincenzo Maffione 		return -1;
3985c4f8d80SVincenzo Maffione 	if (d->reg.nr_mem_id && d->reg.nr_mem_id != mem_id) {
3995c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot set mem_id to %"PRId32", already set to %"PRIu16"",
4005c4f8d80SVincenzo Maffione 				mem_id, d->reg.nr_mem_id);
4015c4f8d80SVincenzo Maffione 		errno = EINVAL;
4025c4f8d80SVincenzo Maffione 		return -1;
4035c4f8d80SVincenzo Maffione 	}
4045c4f8d80SVincenzo Maffione 	d->reg.nr_mem_id = mem_id;
4055c4f8d80SVincenzo Maffione 	return 0;
4065c4f8d80SVincenzo Maffione }
4075c4f8d80SVincenzo Maffione 
4085c4f8d80SVincenzo Maffione static int
NPOPT_PARSER(extmem)4095c4f8d80SVincenzo Maffione NPOPT_PARSER(extmem)(struct nmreq_parse_ctx *p)
4105c4f8d80SVincenzo Maffione {
4115c4f8d80SVincenzo Maffione 	struct nmport_d *d;
4125c4f8d80SVincenzo Maffione 	struct nmreq_pools_info *pi;
4135c4f8d80SVincenzo Maffione 	int i;
4145c4f8d80SVincenzo Maffione 
4155c4f8d80SVincenzo Maffione 	d = p->token;
4165c4f8d80SVincenzo Maffione 
4175c4f8d80SVincenzo Maffione 	if (nmport_extmem_from_file(d, nmport_key(p, extmem, file)) < 0)
4185c4f8d80SVincenzo Maffione 		return -1;
4195c4f8d80SVincenzo Maffione 
4205c4f8d80SVincenzo Maffione 	pi = &d->extmem->nro_info;
4215c4f8d80SVincenzo Maffione 
4225c4f8d80SVincenzo Maffione 	for  (i = 0; i < NPOPT_NRKEYS(extmem); i++) {
4235c4f8d80SVincenzo Maffione 		const char *k = p->keys[i];
4245c4f8d80SVincenzo Maffione 		uint32_t v;
4255c4f8d80SVincenzo Maffione 
4265c4f8d80SVincenzo Maffione 		if (k == NULL)
4275c4f8d80SVincenzo Maffione 			continue;
4285c4f8d80SVincenzo Maffione 
4295c4f8d80SVincenzo Maffione 		v = atoi(k);
4305c4f8d80SVincenzo Maffione 		if (i == NPKEY_ID(extmem, if_num)) {
4315c4f8d80SVincenzo Maffione 			pi->nr_if_pool_objtotal = v;
4325c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, if_size)) {
4335c4f8d80SVincenzo Maffione 			pi->nr_if_pool_objsize = v;
4345c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, ring_num)) {
4355c4f8d80SVincenzo Maffione 			pi->nr_ring_pool_objtotal = v;
4365c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, ring_size)) {
4375c4f8d80SVincenzo Maffione 			pi->nr_ring_pool_objsize = v;
4385c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, buf_num)) {
4395c4f8d80SVincenzo Maffione 			pi->nr_buf_pool_objtotal = v;
4405c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, buf_size)) {
4415c4f8d80SVincenzo Maffione 			pi->nr_buf_pool_objsize = v;
4425c4f8d80SVincenzo Maffione 		}
4435c4f8d80SVincenzo Maffione 	}
4445c4f8d80SVincenzo Maffione 	return 0;
4455c4f8d80SVincenzo Maffione }
4465c4f8d80SVincenzo Maffione 
4475c4f8d80SVincenzo Maffione static int
NPOPT_PARSER(conf)4485c4f8d80SVincenzo Maffione NPOPT_PARSER(conf)(struct nmreq_parse_ctx *p)
4495c4f8d80SVincenzo Maffione {
4505c4f8d80SVincenzo Maffione 	struct nmport_d *d;
4515c4f8d80SVincenzo Maffione 
4525c4f8d80SVincenzo Maffione 	d = p->token;
4535c4f8d80SVincenzo Maffione 
4545c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, rings) != NULL) {
4555c4f8d80SVincenzo Maffione 		uint16_t nr_rings = atoi(nmport_key(p, conf, rings));
4565c4f8d80SVincenzo Maffione 		d->reg.nr_tx_rings = nr_rings;
4575c4f8d80SVincenzo Maffione 		d->reg.nr_rx_rings = nr_rings;
4585c4f8d80SVincenzo Maffione 	}
4595c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, host_rings) != NULL) {
4605c4f8d80SVincenzo Maffione 		uint16_t nr_rings = atoi(nmport_key(p, conf, host_rings));
4615c4f8d80SVincenzo Maffione 		d->reg.nr_host_tx_rings = nr_rings;
4625c4f8d80SVincenzo Maffione 		d->reg.nr_host_rx_rings = nr_rings;
4635c4f8d80SVincenzo Maffione 	}
4645c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, slots) != NULL) {
4655c4f8d80SVincenzo Maffione 		uint32_t nr_slots = atoi(nmport_key(p, conf, slots));
4665c4f8d80SVincenzo Maffione 		d->reg.nr_tx_slots = nr_slots;
4675c4f8d80SVincenzo Maffione 		d->reg.nr_rx_slots = nr_slots;
4685c4f8d80SVincenzo Maffione 	}
4695c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, tx_rings) != NULL) {
4705c4f8d80SVincenzo Maffione 		d->reg.nr_tx_rings = atoi(nmport_key(p, conf, tx_rings));
4715c4f8d80SVincenzo Maffione 	}
4725c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, rx_rings) != NULL) {
4735c4f8d80SVincenzo Maffione 		d->reg.nr_rx_rings = atoi(nmport_key(p, conf, rx_rings));
4745c4f8d80SVincenzo Maffione 	}
4755c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, host_tx_rings) != NULL) {
4765c4f8d80SVincenzo Maffione 		d->reg.nr_host_tx_rings = atoi(nmport_key(p, conf, host_tx_rings));
4775c4f8d80SVincenzo Maffione 	}
4785c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, host_rx_rings) != NULL) {
4795c4f8d80SVincenzo Maffione 		d->reg.nr_host_rx_rings = atoi(nmport_key(p, conf, host_rx_rings));
4805c4f8d80SVincenzo Maffione 	}
4815c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, tx_slots) != NULL) {
4825c4f8d80SVincenzo Maffione 		d->reg.nr_tx_slots = atoi(nmport_key(p, conf, tx_slots));
4835c4f8d80SVincenzo Maffione 	}
4845c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, rx_slots) != NULL) {
4855c4f8d80SVincenzo Maffione 		d->reg.nr_rx_slots = atoi(nmport_key(p, conf, rx_slots));
4865c4f8d80SVincenzo Maffione 	}
4875c4f8d80SVincenzo Maffione 	return 0;
4885c4f8d80SVincenzo Maffione }
4895c4f8d80SVincenzo Maffione 
490f8113f0aSVincenzo Maffione static int
NPOPT_PARSER(offset)491f8113f0aSVincenzo Maffione NPOPT_PARSER(offset)(struct nmreq_parse_ctx *p)
492f8113f0aSVincenzo Maffione {
493f8113f0aSVincenzo Maffione 	struct nmport_d *d;
494f8113f0aSVincenzo Maffione 	uint64_t initial, bits;
495f8113f0aSVincenzo Maffione 
496f8113f0aSVincenzo Maffione 	d = p->token;
497f8113f0aSVincenzo Maffione 
498f8113f0aSVincenzo Maffione 	initial = atoi(nmport_key(p, offset, initial));
499f8113f0aSVincenzo Maffione 	bits = 0;
500f8113f0aSVincenzo Maffione 	if (nmport_key(p, offset, bits) != NULL)
501f8113f0aSVincenzo Maffione 		bits = atoi(nmport_key(p, offset, bits));
502f8113f0aSVincenzo Maffione 
503f8113f0aSVincenzo Maffione 	return nmport_offset(d, initial, initial, bits, 0);
504f8113f0aSVincenzo Maffione }
505f8113f0aSVincenzo Maffione 
506f8113f0aSVincenzo Maffione 
5075c4f8d80SVincenzo Maffione void
nmport_disable_option(const char * opt)5085c4f8d80SVincenzo Maffione nmport_disable_option(const char *opt)
5095c4f8d80SVincenzo Maffione {
5105c4f8d80SVincenzo Maffione 	struct nmreq_opt_parser *p;
5115c4f8d80SVincenzo Maffione 
5125c4f8d80SVincenzo Maffione 	for (p = nmport_opt_parsers; p != NULL; p = p->next) {
5135c4f8d80SVincenzo Maffione 		if (!strcmp(p->prefix, opt)) {
5145c4f8d80SVincenzo Maffione 			p->flags |= NMREQ_OPTF_DISABLED;
5155c4f8d80SVincenzo Maffione 		}
5165c4f8d80SVincenzo Maffione 	}
5175c4f8d80SVincenzo Maffione }
5185c4f8d80SVincenzo Maffione 
5195c4f8d80SVincenzo Maffione int
nmport_enable_option(const char * opt)5205c4f8d80SVincenzo Maffione nmport_enable_option(const char *opt)
5215c4f8d80SVincenzo Maffione {
5225c4f8d80SVincenzo Maffione 	struct nmreq_opt_parser *p;
5235c4f8d80SVincenzo Maffione 
5245c4f8d80SVincenzo Maffione 	for (p = nmport_opt_parsers; p != NULL; p = p->next) {
5255c4f8d80SVincenzo Maffione 		if (!strcmp(p->prefix, opt)) {
5265c4f8d80SVincenzo Maffione 			p->flags &= ~NMREQ_OPTF_DISABLED;
5275c4f8d80SVincenzo Maffione 			return 0;
5285c4f8d80SVincenzo Maffione 		}
5295c4f8d80SVincenzo Maffione 	}
5305c4f8d80SVincenzo Maffione 	errno = EOPNOTSUPP;
5315c4f8d80SVincenzo Maffione 	return -1;
5325c4f8d80SVincenzo Maffione }
5335c4f8d80SVincenzo Maffione 
5345c4f8d80SVincenzo Maffione 
5355c4f8d80SVincenzo Maffione int
nmport_parse(struct nmport_d * d,const char * ifname)5365c4f8d80SVincenzo Maffione nmport_parse(struct nmport_d *d, const char *ifname)
5375c4f8d80SVincenzo Maffione {
5385c4f8d80SVincenzo Maffione 	const char *scan = ifname;
5395c4f8d80SVincenzo Maffione 
5405c4f8d80SVincenzo Maffione 	if (nmreq_header_decode(&scan, &d->hdr, d->ctx) < 0) {
5415c4f8d80SVincenzo Maffione 		goto err;
5425c4f8d80SVincenzo Maffione 	}
5435c4f8d80SVincenzo Maffione 
5445c4f8d80SVincenzo Maffione 	/* parse the register request */
5455c4f8d80SVincenzo Maffione 	if (nmreq_register_decode(&scan, &d->reg, d->ctx) < 0) {
5465c4f8d80SVincenzo Maffione 		goto err;
5475c4f8d80SVincenzo Maffione 	}
5485c4f8d80SVincenzo Maffione 
5495c4f8d80SVincenzo Maffione 	/* parse the options, if any */
5505c4f8d80SVincenzo Maffione 	if (nmreq_options_decode(scan, nmport_opt_parsers, d, d->ctx) < 0) {
5515c4f8d80SVincenzo Maffione 		goto err;
5525c4f8d80SVincenzo Maffione 	}
5535c4f8d80SVincenzo Maffione 	return 0;
5545c4f8d80SVincenzo Maffione 
5555c4f8d80SVincenzo Maffione err:
5565c4f8d80SVincenzo Maffione 	nmport_undo_parse(d);
5575c4f8d80SVincenzo Maffione 	return -1;
5585c4f8d80SVincenzo Maffione }
5595c4f8d80SVincenzo Maffione 
5605c4f8d80SVincenzo Maffione void
nmport_undo_parse(struct nmport_d * d)5615c4f8d80SVincenzo Maffione nmport_undo_parse(struct nmport_d *d)
5625c4f8d80SVincenzo Maffione {
5635c4f8d80SVincenzo Maffione 	nmport_do_cleanup(d);
5645c4f8d80SVincenzo Maffione 	memset(&d->reg, 0, sizeof(d->reg));
5655c4f8d80SVincenzo Maffione 	memset(&d->hdr, 0, sizeof(d->hdr));
5665c4f8d80SVincenzo Maffione }
5675c4f8d80SVincenzo Maffione 
5685c4f8d80SVincenzo Maffione struct nmport_d *
nmport_prepare(const char * ifname)5695c4f8d80SVincenzo Maffione nmport_prepare(const char *ifname)
5705c4f8d80SVincenzo Maffione {
5715c4f8d80SVincenzo Maffione 	struct nmport_d *d;
5725c4f8d80SVincenzo Maffione 
5735c4f8d80SVincenzo Maffione 	/* allocate a descriptor */
5745c4f8d80SVincenzo Maffione 	d = nmport_new();
5755c4f8d80SVincenzo Maffione 	if (d == NULL)
5765c4f8d80SVincenzo Maffione 		goto err;
5775c4f8d80SVincenzo Maffione 
5785c4f8d80SVincenzo Maffione 	/* parse the header */
5795c4f8d80SVincenzo Maffione 	if (nmport_parse(d, ifname) < 0)
5805c4f8d80SVincenzo Maffione 		goto err;
5815c4f8d80SVincenzo Maffione 
5825c4f8d80SVincenzo Maffione 	return d;
5835c4f8d80SVincenzo Maffione 
5845c4f8d80SVincenzo Maffione err:
5855c4f8d80SVincenzo Maffione 	nmport_undo_prepare(d);
5865c4f8d80SVincenzo Maffione 	return NULL;
5875c4f8d80SVincenzo Maffione }
5885c4f8d80SVincenzo Maffione 
5895c4f8d80SVincenzo Maffione void
nmport_undo_prepare(struct nmport_d * d)5905c4f8d80SVincenzo Maffione nmport_undo_prepare(struct nmport_d *d)
5915c4f8d80SVincenzo Maffione {
5925c4f8d80SVincenzo Maffione 	if (d == NULL)
5935c4f8d80SVincenzo Maffione 		return;
5945c4f8d80SVincenzo Maffione 	nmport_undo_parse(d);
5955c4f8d80SVincenzo Maffione 	nmport_delete(d);
5965c4f8d80SVincenzo Maffione }
5975c4f8d80SVincenzo Maffione 
5985c4f8d80SVincenzo Maffione int
nmport_register(struct nmport_d * d)5995c4f8d80SVincenzo Maffione nmport_register(struct nmport_d *d)
6005c4f8d80SVincenzo Maffione {
6015c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
6025c4f8d80SVincenzo Maffione 
6035c4f8d80SVincenzo Maffione 	if (d->register_done) {
6045c4f8d80SVincenzo Maffione 		errno = EINVAL;
6055c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: already registered", d->hdr.nr_name);
6065c4f8d80SVincenzo Maffione 		return -1;
6075c4f8d80SVincenzo Maffione 	}
6085c4f8d80SVincenzo Maffione 
6095c4f8d80SVincenzo Maffione 	d->fd = open("/dev/netmap", O_RDWR);
6105c4f8d80SVincenzo Maffione 	if (d->fd < 0) {
6115c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "/dev/netmap: %s", strerror(errno));
6125c4f8d80SVincenzo Maffione 		goto err;
6135c4f8d80SVincenzo Maffione 	}
6145c4f8d80SVincenzo Maffione 
6155c4f8d80SVincenzo Maffione 	if (ioctl(d->fd, NIOCCTRL, &d->hdr) < 0) {
6165c4f8d80SVincenzo Maffione 		struct nmreq_option *o;
6175c4f8d80SVincenzo Maffione 		int option_errors = 0;
6185c4f8d80SVincenzo Maffione 
6195c4f8d80SVincenzo Maffione 		nmreq_foreach_option(&d->hdr, o) {
6205c4f8d80SVincenzo Maffione 			if (o->nro_status) {
6215c4f8d80SVincenzo Maffione 				nmctx_ferror(ctx, "%s: option %s: %s",
6225c4f8d80SVincenzo Maffione 						d->hdr.nr_name,
6235c4f8d80SVincenzo Maffione 						nmreq_option_name(o->nro_reqtype),
6245c4f8d80SVincenzo Maffione 						strerror(o->nro_status));
6255c4f8d80SVincenzo Maffione 				option_errors++;
6265c4f8d80SVincenzo Maffione 			}
6275c4f8d80SVincenzo Maffione 
6285c4f8d80SVincenzo Maffione 		}
6295c4f8d80SVincenzo Maffione 		if (!option_errors)
6305c4f8d80SVincenzo Maffione 			nmctx_ferror(ctx, "%s: %s", d->hdr.nr_name, strerror(errno));
6315c4f8d80SVincenzo Maffione 		goto err;
6325c4f8d80SVincenzo Maffione 	}
6335c4f8d80SVincenzo Maffione 
6345c4f8d80SVincenzo Maffione 	d->register_done = 1;
6355c4f8d80SVincenzo Maffione 
6365c4f8d80SVincenzo Maffione 	return 0;
6375c4f8d80SVincenzo Maffione 
6385c4f8d80SVincenzo Maffione err:
6395c4f8d80SVincenzo Maffione 	nmport_undo_register(d);
6405c4f8d80SVincenzo Maffione 	return -1;
6415c4f8d80SVincenzo Maffione }
6425c4f8d80SVincenzo Maffione 
6435c4f8d80SVincenzo Maffione void
nmport_undo_register(struct nmport_d * d)6445c4f8d80SVincenzo Maffione nmport_undo_register(struct nmport_d *d)
6455c4f8d80SVincenzo Maffione {
6465c4f8d80SVincenzo Maffione 	if (d->fd >= 0)
6475c4f8d80SVincenzo Maffione 		close(d->fd);
6485c4f8d80SVincenzo Maffione 	d->fd = -1;
6495c4f8d80SVincenzo Maffione 	d->register_done = 0;
6505c4f8d80SVincenzo Maffione }
6515c4f8d80SVincenzo Maffione 
6525c4f8d80SVincenzo Maffione /* lookup the mem_id in the mem-list: do a new mmap() if
6535c4f8d80SVincenzo Maffione  * not found, reuse existing otherwise
6545c4f8d80SVincenzo Maffione  */
6555c4f8d80SVincenzo Maffione int
nmport_mmap(struct nmport_d * d)6565c4f8d80SVincenzo Maffione nmport_mmap(struct nmport_d *d)
6575c4f8d80SVincenzo Maffione {
6585c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
6595c4f8d80SVincenzo Maffione 	struct nmem_d *m = NULL;
6605c4f8d80SVincenzo Maffione 	u_int num_tx, num_rx;
661f8113f0aSVincenzo Maffione 	unsigned int i;
6625c4f8d80SVincenzo Maffione 
6635c4f8d80SVincenzo Maffione 	if (d->mmap_done) {
6645c4f8d80SVincenzo Maffione 		errno = EINVAL;
6655c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: already mapped", d->hdr.nr_name);
6665c4f8d80SVincenzo Maffione 		return -1;
6675c4f8d80SVincenzo Maffione 	}
6685c4f8d80SVincenzo Maffione 
6695c4f8d80SVincenzo Maffione 	if (!d->register_done) {
6705c4f8d80SVincenzo Maffione 		errno = EINVAL;
6715c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot map unregistered port");
6725c4f8d80SVincenzo Maffione 		return -1;
6735c4f8d80SVincenzo Maffione 	}
6745c4f8d80SVincenzo Maffione 
6755c4f8d80SVincenzo Maffione 	nmctx_lock(ctx);
6765c4f8d80SVincenzo Maffione 
6775c4f8d80SVincenzo Maffione 	for (m = ctx->mem_descs; m != NULL; m = m->next)
6785c4f8d80SVincenzo Maffione 		if (m->mem_id == d->reg.nr_mem_id)
6795c4f8d80SVincenzo Maffione 			break;
6805c4f8d80SVincenzo Maffione 
6815c4f8d80SVincenzo Maffione 	if (m == NULL) {
6825c4f8d80SVincenzo Maffione 		m = nmctx_malloc(ctx, sizeof(*m));
6835c4f8d80SVincenzo Maffione 		if (m == NULL) {
6845c4f8d80SVincenzo Maffione 			nmctx_ferror(ctx, "cannot allocate memory descriptor");
6855c4f8d80SVincenzo Maffione 			goto err;
6865c4f8d80SVincenzo Maffione 		}
6875c4f8d80SVincenzo Maffione 		memset(m, 0, sizeof(*m));
6885c4f8d80SVincenzo Maffione 		if (d->extmem != NULL) {
68992c5d82cSVincenzo Maffione 			m->mem = (void *)((uintptr_t)d->extmem->nro_usrptr);
6905c4f8d80SVincenzo Maffione 			m->size = d->extmem->nro_info.nr_memsize;
6915c4f8d80SVincenzo Maffione 			m->is_extmem = 1;
6925c4f8d80SVincenzo Maffione 		} else {
6935c4f8d80SVincenzo Maffione 			m->mem = mmap(NULL, d->reg.nr_memsize, PROT_READ|PROT_WRITE,
6945c4f8d80SVincenzo Maffione 					MAP_SHARED, d->fd, 0);
6955c4f8d80SVincenzo Maffione 			if (m->mem == MAP_FAILED) {
6965c4f8d80SVincenzo Maffione 				nmctx_ferror(ctx, "mmap: %s", strerror(errno));
6975c4f8d80SVincenzo Maffione 				goto err;
6985c4f8d80SVincenzo Maffione 			}
6995c4f8d80SVincenzo Maffione 			m->size = d->reg.nr_memsize;
7005c4f8d80SVincenzo Maffione 		}
7015c4f8d80SVincenzo Maffione 		m->mem_id = d->reg.nr_mem_id;
7025c4f8d80SVincenzo Maffione 		m->next = ctx->mem_descs;
7035c4f8d80SVincenzo Maffione 		if (ctx->mem_descs != NULL)
7045c4f8d80SVincenzo Maffione 			ctx->mem_descs->prev = m;
7055c4f8d80SVincenzo Maffione 		ctx->mem_descs = m;
7065c4f8d80SVincenzo Maffione 	}
7075c4f8d80SVincenzo Maffione 	m->refcount++;
7085c4f8d80SVincenzo Maffione 
7095c4f8d80SVincenzo Maffione 	nmctx_unlock(ctx);
7105c4f8d80SVincenzo Maffione 
7115c4f8d80SVincenzo Maffione 	d->mem = m;
7125c4f8d80SVincenzo Maffione 
7135c4f8d80SVincenzo Maffione 	d->nifp = NETMAP_IF(m->mem, d->reg.nr_offset);
7145c4f8d80SVincenzo Maffione 
7155c4f8d80SVincenzo Maffione 	num_tx = d->reg.nr_tx_rings + d->nifp->ni_host_tx_rings;
7165c4f8d80SVincenzo Maffione 	for (i = 0; i < num_tx && !d->nifp->ring_ofs[i]; i++)
7175c4f8d80SVincenzo Maffione 		;
718f8113f0aSVincenzo Maffione 	d->cur_tx_ring = d->first_tx_ring = i;
7195c4f8d80SVincenzo Maffione 	for ( ; i < num_tx && d->nifp->ring_ofs[i]; i++)
7205c4f8d80SVincenzo Maffione 		;
7215c4f8d80SVincenzo Maffione 	d->last_tx_ring = i - 1;
7225c4f8d80SVincenzo Maffione 
7235c4f8d80SVincenzo Maffione 	num_rx = d->reg.nr_rx_rings + d->nifp->ni_host_rx_rings;
7245c4f8d80SVincenzo Maffione 	for (i = 0; i < num_rx && !d->nifp->ring_ofs[i + num_tx]; i++)
7255c4f8d80SVincenzo Maffione 		;
726f8113f0aSVincenzo Maffione 	d->cur_rx_ring = d->first_rx_ring = i;
7275c4f8d80SVincenzo Maffione 	for ( ; i < num_rx && d->nifp->ring_ofs[i + num_tx]; i++)
7285c4f8d80SVincenzo Maffione 		;
7295c4f8d80SVincenzo Maffione 	d->last_rx_ring = i - 1;
7305c4f8d80SVincenzo Maffione 
7315c4f8d80SVincenzo Maffione 	d->mmap_done = 1;
7325c4f8d80SVincenzo Maffione 
7335c4f8d80SVincenzo Maffione 	return 0;
7345c4f8d80SVincenzo Maffione 
7355c4f8d80SVincenzo Maffione err:
7365c4f8d80SVincenzo Maffione 	nmctx_unlock(ctx);
7375c4f8d80SVincenzo Maffione 	nmport_undo_mmap(d);
7385c4f8d80SVincenzo Maffione 	return -1;
7395c4f8d80SVincenzo Maffione }
7405c4f8d80SVincenzo Maffione 
7415c4f8d80SVincenzo Maffione void
nmport_undo_mmap(struct nmport_d * d)7425c4f8d80SVincenzo Maffione nmport_undo_mmap(struct nmport_d *d)
7435c4f8d80SVincenzo Maffione {
7445c4f8d80SVincenzo Maffione 	struct nmem_d *m;
7455c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
7465c4f8d80SVincenzo Maffione 
7475c4f8d80SVincenzo Maffione 	m = d->mem;
7485c4f8d80SVincenzo Maffione 	if (m == NULL)
7495c4f8d80SVincenzo Maffione 		return;
7505c4f8d80SVincenzo Maffione 	nmctx_lock(ctx);
7515c4f8d80SVincenzo Maffione 	m->refcount--;
7525c4f8d80SVincenzo Maffione 	if (m->refcount <= 0) {
7535c4f8d80SVincenzo Maffione 		if (!m->is_extmem && m->mem != MAP_FAILED)
7545c4f8d80SVincenzo Maffione 			munmap(m->mem, m->size);
7555c4f8d80SVincenzo Maffione 		/* extract from the list and free */
7565c4f8d80SVincenzo Maffione 		if (m->next != NULL)
7575c4f8d80SVincenzo Maffione 			m->next->prev = m->prev;
7585c4f8d80SVincenzo Maffione 		if (m->prev != NULL)
7595c4f8d80SVincenzo Maffione 			m->prev->next = m->next;
7605c4f8d80SVincenzo Maffione 		else
7615c4f8d80SVincenzo Maffione 			ctx->mem_descs = m->next;
7625c4f8d80SVincenzo Maffione 		nmctx_free(ctx, m);
7635c4f8d80SVincenzo Maffione 		d->mem = NULL;
7645c4f8d80SVincenzo Maffione 	}
7655c4f8d80SVincenzo Maffione 	nmctx_unlock(ctx);
7665c4f8d80SVincenzo Maffione 	d->mmap_done = 0;
7675c4f8d80SVincenzo Maffione 	d->mem = NULL;
7685c4f8d80SVincenzo Maffione 	d->nifp = NULL;
7695c4f8d80SVincenzo Maffione 	d->first_tx_ring = 0;
7705c4f8d80SVincenzo Maffione 	d->last_tx_ring = 0;
7715c4f8d80SVincenzo Maffione 	d->first_rx_ring = 0;
7725c4f8d80SVincenzo Maffione 	d->last_rx_ring = 0;
7735c4f8d80SVincenzo Maffione 	d->cur_tx_ring = 0;
7745c4f8d80SVincenzo Maffione 	d->cur_rx_ring = 0;
7755c4f8d80SVincenzo Maffione }
7765c4f8d80SVincenzo Maffione 
7775c4f8d80SVincenzo Maffione int
nmport_open_desc(struct nmport_d * d)7785c4f8d80SVincenzo Maffione nmport_open_desc(struct nmport_d *d)
7795c4f8d80SVincenzo Maffione {
7805c4f8d80SVincenzo Maffione 	if (nmport_register(d) < 0)
7815c4f8d80SVincenzo Maffione 		goto err;
7825c4f8d80SVincenzo Maffione 
7835c4f8d80SVincenzo Maffione 	if (nmport_mmap(d) < 0)
7845c4f8d80SVincenzo Maffione 		goto err;
7855c4f8d80SVincenzo Maffione 
7865c4f8d80SVincenzo Maffione 	return 0;
7875c4f8d80SVincenzo Maffione err:
7885c4f8d80SVincenzo Maffione 	nmport_undo_open_desc(d);
7895c4f8d80SVincenzo Maffione 	return -1;
7905c4f8d80SVincenzo Maffione }
7915c4f8d80SVincenzo Maffione 
7925c4f8d80SVincenzo Maffione void
nmport_undo_open_desc(struct nmport_d * d)7935c4f8d80SVincenzo Maffione nmport_undo_open_desc(struct nmport_d *d)
7945c4f8d80SVincenzo Maffione {
7955c4f8d80SVincenzo Maffione 	nmport_undo_mmap(d);
7965c4f8d80SVincenzo Maffione 	nmport_undo_register(d);
7975c4f8d80SVincenzo Maffione }
7985c4f8d80SVincenzo Maffione 
7995c4f8d80SVincenzo Maffione 
8005c4f8d80SVincenzo Maffione struct nmport_d *
nmport_open(const char * ifname)8015c4f8d80SVincenzo Maffione nmport_open(const char *ifname)
8025c4f8d80SVincenzo Maffione {
8035c4f8d80SVincenzo Maffione 	struct nmport_d *d;
8045c4f8d80SVincenzo Maffione 
8055c4f8d80SVincenzo Maffione 	/* prepare the descriptor */
8065c4f8d80SVincenzo Maffione 	d = nmport_prepare(ifname);
8075c4f8d80SVincenzo Maffione 	if (d == NULL)
8085c4f8d80SVincenzo Maffione 		goto err;
8095c4f8d80SVincenzo Maffione 
8105c4f8d80SVincenzo Maffione 	/* open netmap and register */
8115c4f8d80SVincenzo Maffione 	if (nmport_open_desc(d) < 0)
8125c4f8d80SVincenzo Maffione 		goto err;
8135c4f8d80SVincenzo Maffione 
8145c4f8d80SVincenzo Maffione 	return d;
8155c4f8d80SVincenzo Maffione 
8165c4f8d80SVincenzo Maffione err:
8175c4f8d80SVincenzo Maffione 	nmport_close(d);
8185c4f8d80SVincenzo Maffione 	return NULL;
8195c4f8d80SVincenzo Maffione }
8205c4f8d80SVincenzo Maffione 
8215c4f8d80SVincenzo Maffione void
nmport_close(struct nmport_d * d)8225c4f8d80SVincenzo Maffione nmport_close(struct nmport_d *d)
8235c4f8d80SVincenzo Maffione {
8245c4f8d80SVincenzo Maffione 	if (d == NULL)
8255c4f8d80SVincenzo Maffione 		return;
8265c4f8d80SVincenzo Maffione 	nmport_undo_open_desc(d);
8275c4f8d80SVincenzo Maffione 	nmport_undo_prepare(d);
8285c4f8d80SVincenzo Maffione }
8295c4f8d80SVincenzo Maffione 
8305c4f8d80SVincenzo Maffione struct nmport_d *
nmport_clone(struct nmport_d * d)8315c4f8d80SVincenzo Maffione nmport_clone(struct nmport_d *d)
8325c4f8d80SVincenzo Maffione {
8335c4f8d80SVincenzo Maffione 	struct nmport_d *c;
8345c4f8d80SVincenzo Maffione 	struct nmctx *ctx;
8355c4f8d80SVincenzo Maffione 
8365c4f8d80SVincenzo Maffione 	ctx = d->ctx;
8375c4f8d80SVincenzo Maffione 
8385c4f8d80SVincenzo Maffione 	if (d->extmem != NULL && !d->register_done) {
8395c4f8d80SVincenzo Maffione 		errno = EINVAL;
8405c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot clone unregistered port that is using extmem");
8415c4f8d80SVincenzo Maffione 		return NULL;
8425c4f8d80SVincenzo Maffione 	}
8435c4f8d80SVincenzo Maffione 
8445c4f8d80SVincenzo Maffione 	c = nmport_new_with_ctx(ctx);
8455c4f8d80SVincenzo Maffione 	if (c == NULL)
8465c4f8d80SVincenzo Maffione 		return NULL;
8475c4f8d80SVincenzo Maffione 	/* copy the output of parse */
8485c4f8d80SVincenzo Maffione 	c->hdr = d->hdr;
8495c4f8d80SVincenzo Maffione 	/* redirect the pointer to the body */
8505c4f8d80SVincenzo Maffione 	c->hdr.nr_body = (uintptr_t)&c->reg;
8515c4f8d80SVincenzo Maffione 	/* options are not cloned */
8525c4f8d80SVincenzo Maffione 	c->hdr.nr_options = 0;
8535c4f8d80SVincenzo Maffione 	c->reg = d->reg; /* this also copies the mem_id */
8545c4f8d80SVincenzo Maffione 	/* put the new port in an un-registered, unmapped state */
8555c4f8d80SVincenzo Maffione 	c->fd = -1;
8565c4f8d80SVincenzo Maffione 	c->nifp = NULL;
8575c4f8d80SVincenzo Maffione 	c->register_done = 0;
8585c4f8d80SVincenzo Maffione 	c->mem = NULL;
8595c4f8d80SVincenzo Maffione 	c->extmem = NULL;
8605c4f8d80SVincenzo Maffione 	c->mmap_done = 0;
8615c4f8d80SVincenzo Maffione 	c->first_tx_ring = 0;
8625c4f8d80SVincenzo Maffione 	c->last_tx_ring = 0;
8635c4f8d80SVincenzo Maffione 	c->first_rx_ring = 0;
8645c4f8d80SVincenzo Maffione 	c->last_rx_ring = 0;
8655c4f8d80SVincenzo Maffione 	c->cur_tx_ring = 0;
8665c4f8d80SVincenzo Maffione 	c->cur_rx_ring = 0;
8675c4f8d80SVincenzo Maffione 
8685c4f8d80SVincenzo Maffione 	return c;
8695c4f8d80SVincenzo Maffione }
8705c4f8d80SVincenzo Maffione 
8715c4f8d80SVincenzo Maffione int
nmport_inject(struct nmport_d * d,const void * buf,size_t size)8725c4f8d80SVincenzo Maffione nmport_inject(struct nmport_d *d, const void *buf, size_t size)
8735c4f8d80SVincenzo Maffione {
8745c4f8d80SVincenzo Maffione 	u_int c, n = d->last_tx_ring - d->first_tx_ring + 1,
8755c4f8d80SVincenzo Maffione 		ri = d->cur_tx_ring;
8765c4f8d80SVincenzo Maffione 
8775c4f8d80SVincenzo Maffione 	for (c = 0; c < n ; c++, ri++) {
8785c4f8d80SVincenzo Maffione 		/* compute current ring to use */
8795c4f8d80SVincenzo Maffione 		struct netmap_ring *ring;
8805c4f8d80SVincenzo Maffione 		uint32_t i, j, idx;
8815c4f8d80SVincenzo Maffione 		size_t rem;
8825c4f8d80SVincenzo Maffione 
8835c4f8d80SVincenzo Maffione 		if (ri > d->last_tx_ring)
8845c4f8d80SVincenzo Maffione 			ri = d->first_tx_ring;
8855c4f8d80SVincenzo Maffione 		ring = NETMAP_TXRING(d->nifp, ri);
8865c4f8d80SVincenzo Maffione 		rem = size;
8875c4f8d80SVincenzo Maffione 		j = ring->cur;
8885c4f8d80SVincenzo Maffione 		while (rem > ring->nr_buf_size && j != ring->tail) {
8895c4f8d80SVincenzo Maffione 			rem -= ring->nr_buf_size;
8905c4f8d80SVincenzo Maffione 			j = nm_ring_next(ring, j);
8915c4f8d80SVincenzo Maffione 		}
8925c4f8d80SVincenzo Maffione 		if (j == ring->tail && rem > 0)
8935c4f8d80SVincenzo Maffione 			continue;
8945c4f8d80SVincenzo Maffione 		i = ring->cur;
8955c4f8d80SVincenzo Maffione 		while (i != j) {
8965c4f8d80SVincenzo Maffione 			idx = ring->slot[i].buf_idx;
8975c4f8d80SVincenzo Maffione 			ring->slot[i].len = ring->nr_buf_size;
8985c4f8d80SVincenzo Maffione 			ring->slot[i].flags = NS_MOREFRAG;
8995c4f8d80SVincenzo Maffione 			nm_pkt_copy(buf, NETMAP_BUF(ring, idx), ring->nr_buf_size);
9005c4f8d80SVincenzo Maffione 			i = nm_ring_next(ring, i);
9015c4f8d80SVincenzo Maffione 			buf = (char *)buf + ring->nr_buf_size;
9025c4f8d80SVincenzo Maffione 		}
9035c4f8d80SVincenzo Maffione 		idx = ring->slot[i].buf_idx;
9045c4f8d80SVincenzo Maffione 		ring->slot[i].len = rem;
9055c4f8d80SVincenzo Maffione 		ring->slot[i].flags = 0;
9065c4f8d80SVincenzo Maffione 		nm_pkt_copy(buf, NETMAP_BUF(ring, idx), rem);
9075c4f8d80SVincenzo Maffione 		ring->head = ring->cur = nm_ring_next(ring, i);
9085c4f8d80SVincenzo Maffione 		d->cur_tx_ring = ri;
9095c4f8d80SVincenzo Maffione 		return size;
9105c4f8d80SVincenzo Maffione 	}
9115c4f8d80SVincenzo Maffione 	return 0; /* fail */
9125c4f8d80SVincenzo Maffione }
913