xref: /freebsd-13.1/lib/libnetmap/nmport.c (revision 92c5d82c)
14c067f38SVincenzo Maffione /*-
24c067f38SVincenzo Maffione  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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  * $FreeBSD$
304c067f38SVincenzo Maffione  */
314c067f38SVincenzo Maffione 
325c4f8d80SVincenzo Maffione #include <sys/types.h>
335c4f8d80SVincenzo Maffione #include <sys/stat.h>
345c4f8d80SVincenzo Maffione #include <sys/ioctl.h>
355c4f8d80SVincenzo Maffione #include <sys/mman.h>
365c4f8d80SVincenzo Maffione #include <fcntl.h>
375c4f8d80SVincenzo Maffione #include <inttypes.h>
385c4f8d80SVincenzo Maffione #include <stdlib.h>
395c4f8d80SVincenzo Maffione #include <stdio.h>
405c4f8d80SVincenzo Maffione #include <stdarg.h>
415c4f8d80SVincenzo Maffione #include <string.h>
425c4f8d80SVincenzo Maffione #include <unistd.h>
435c4f8d80SVincenzo Maffione #include <errno.h>
445c4f8d80SVincenzo Maffione #include <net/netmap_user.h>
455c4f8d80SVincenzo Maffione #define LIBNETMAP_NOTHREADSAFE
465c4f8d80SVincenzo Maffione #include "libnetmap.h"
475c4f8d80SVincenzo Maffione 
485c4f8d80SVincenzo Maffione struct nmport_cleanup_d {
495c4f8d80SVincenzo Maffione 	struct nmport_cleanup_d *next;
505c4f8d80SVincenzo Maffione 	void (*cleanup)(struct nmport_cleanup_d *, struct nmport_d *);
515c4f8d80SVincenzo Maffione };
525c4f8d80SVincenzo Maffione 
535c4f8d80SVincenzo Maffione static void
nmport_push_cleanup(struct nmport_d * d,struct nmport_cleanup_d * c)545c4f8d80SVincenzo Maffione nmport_push_cleanup(struct nmport_d *d, struct nmport_cleanup_d *c)
555c4f8d80SVincenzo Maffione {
565c4f8d80SVincenzo Maffione 	c->next = d->clist;
575c4f8d80SVincenzo Maffione 	d->clist = c;
585c4f8d80SVincenzo Maffione }
595c4f8d80SVincenzo Maffione 
605c4f8d80SVincenzo Maffione static void
nmport_pop_cleanup(struct nmport_d * d)615c4f8d80SVincenzo Maffione nmport_pop_cleanup(struct nmport_d *d)
625c4f8d80SVincenzo Maffione {
635c4f8d80SVincenzo Maffione 	struct nmport_cleanup_d *top;
645c4f8d80SVincenzo Maffione 
655c4f8d80SVincenzo Maffione 	top = d->clist;
665c4f8d80SVincenzo Maffione 	d->clist = d->clist->next;
675c4f8d80SVincenzo Maffione 	(*top->cleanup)(top, d);
685c4f8d80SVincenzo Maffione 	nmctx_free(d->ctx, top);
695c4f8d80SVincenzo Maffione }
705c4f8d80SVincenzo Maffione 
nmport_do_cleanup(struct nmport_d * d)715c4f8d80SVincenzo Maffione void nmport_do_cleanup(struct nmport_d *d)
725c4f8d80SVincenzo Maffione {
735c4f8d80SVincenzo Maffione 	while (d->clist != NULL) {
745c4f8d80SVincenzo Maffione 		nmport_pop_cleanup(d);
755c4f8d80SVincenzo Maffione 	}
765c4f8d80SVincenzo Maffione }
775c4f8d80SVincenzo Maffione 
785c4f8d80SVincenzo Maffione static struct nmport_d *
nmport_new_with_ctx(struct nmctx * ctx)795c4f8d80SVincenzo Maffione nmport_new_with_ctx(struct nmctx *ctx)
805c4f8d80SVincenzo Maffione {
815c4f8d80SVincenzo Maffione 	struct nmport_d *d;
825c4f8d80SVincenzo Maffione 
835c4f8d80SVincenzo Maffione 	/* allocate a descriptor */
845c4f8d80SVincenzo Maffione 	d = nmctx_malloc(ctx, sizeof(*d));
855c4f8d80SVincenzo Maffione 	if (d == NULL) {
865c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot allocate nmport descriptor");
875c4f8d80SVincenzo Maffione 		goto out;
885c4f8d80SVincenzo Maffione 	}
895c4f8d80SVincenzo Maffione 	memset(d, 0, sizeof(*d));
905c4f8d80SVincenzo Maffione 
915c4f8d80SVincenzo Maffione 	nmreq_header_init(&d->hdr, NETMAP_REQ_REGISTER, &d->reg);
925c4f8d80SVincenzo Maffione 
935c4f8d80SVincenzo Maffione 	d->ctx = ctx;
945c4f8d80SVincenzo Maffione 	d->fd = -1;
955c4f8d80SVincenzo Maffione 
965c4f8d80SVincenzo Maffione out:
975c4f8d80SVincenzo Maffione 	return d;
985c4f8d80SVincenzo Maffione }
995c4f8d80SVincenzo Maffione 
1005c4f8d80SVincenzo Maffione struct nmport_d *
nmport_new(void)1015c4f8d80SVincenzo Maffione nmport_new(void)
1025c4f8d80SVincenzo Maffione {
1035c4f8d80SVincenzo Maffione 	struct nmctx *ctx = nmctx_get();
1045c4f8d80SVincenzo Maffione 	return nmport_new_with_ctx(ctx);
1055c4f8d80SVincenzo Maffione }
1065c4f8d80SVincenzo Maffione 
1075c4f8d80SVincenzo Maffione 
1085c4f8d80SVincenzo Maffione void
nmport_delete(struct nmport_d * d)1095c4f8d80SVincenzo Maffione nmport_delete(struct nmport_d *d)
1105c4f8d80SVincenzo Maffione {
1115c4f8d80SVincenzo Maffione 	nmctx_free(d->ctx, d);
1125c4f8d80SVincenzo Maffione }
1135c4f8d80SVincenzo Maffione 
1145c4f8d80SVincenzo Maffione void
nmport_extmem_cleanup(struct nmport_cleanup_d * c,struct nmport_d * d)1155c4f8d80SVincenzo Maffione nmport_extmem_cleanup(struct nmport_cleanup_d *c, struct nmport_d *d)
1165c4f8d80SVincenzo Maffione {
1175c4f8d80SVincenzo Maffione 	(void)c;
1185c4f8d80SVincenzo Maffione 
1195c4f8d80SVincenzo Maffione 	if (d->extmem == NULL)
1205c4f8d80SVincenzo Maffione 		return;
1215c4f8d80SVincenzo Maffione 
1225c4f8d80SVincenzo Maffione 	nmreq_remove_option(&d->hdr, &d->extmem->nro_opt);
1235c4f8d80SVincenzo Maffione 	nmctx_free(d->ctx, d->extmem);
1245c4f8d80SVincenzo Maffione 	d->extmem = NULL;
1255c4f8d80SVincenzo Maffione }
1265c4f8d80SVincenzo Maffione 
1275c4f8d80SVincenzo Maffione 
1285c4f8d80SVincenzo Maffione int
nmport_extmem(struct nmport_d * d,void * base,size_t size)1295c4f8d80SVincenzo Maffione nmport_extmem(struct nmport_d *d, void *base, size_t size)
1305c4f8d80SVincenzo Maffione {
1315c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
1325c4f8d80SVincenzo Maffione 	struct nmport_cleanup_d *clnup = NULL;
1335c4f8d80SVincenzo Maffione 
1345c4f8d80SVincenzo Maffione 	if (d->register_done) {
1355c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: cannot set extmem of an already registered port", d->hdr.nr_name);
1365c4f8d80SVincenzo Maffione 		errno = EINVAL;
1375c4f8d80SVincenzo Maffione 		return -1;
1385c4f8d80SVincenzo Maffione 	}
1395c4f8d80SVincenzo Maffione 
1405c4f8d80SVincenzo Maffione 	if (d->extmem != NULL) {
1415c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: extmem already in use", d->hdr.nr_name);
1425c4f8d80SVincenzo Maffione 		errno = EINVAL;
1435c4f8d80SVincenzo Maffione 		return -1;
1445c4f8d80SVincenzo Maffione 	}
1455c4f8d80SVincenzo Maffione 
1465c4f8d80SVincenzo Maffione 	clnup = (struct nmport_cleanup_d *)nmctx_malloc(ctx, sizeof(*clnup));
1475c4f8d80SVincenzo Maffione 	if (clnup == NULL) {
1485c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "failed to allocate cleanup descriptor");
1495c4f8d80SVincenzo Maffione 		errno = ENOMEM;
1505c4f8d80SVincenzo Maffione 		return -1;
1515c4f8d80SVincenzo Maffione 	}
1525c4f8d80SVincenzo Maffione 
1535c4f8d80SVincenzo Maffione 	d->extmem = nmctx_malloc(ctx, sizeof(*d->extmem));
1545c4f8d80SVincenzo Maffione 	if (d->extmem == NULL) {
1555c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: cannot allocate extmem option", d->hdr.nr_name);
1565c4f8d80SVincenzo Maffione 		nmctx_free(ctx, clnup);
1575c4f8d80SVincenzo Maffione 		errno = ENOMEM;
1585c4f8d80SVincenzo Maffione 		return -1;
1595c4f8d80SVincenzo Maffione 	}
1605c4f8d80SVincenzo Maffione 	memset(d->extmem, 0, sizeof(*d->extmem));
1615c4f8d80SVincenzo Maffione 	d->extmem->nro_usrptr = (uintptr_t)base;
1625c4f8d80SVincenzo Maffione 	d->extmem->nro_opt.nro_reqtype = NETMAP_REQ_OPT_EXTMEM;
1635c4f8d80SVincenzo Maffione 	d->extmem->nro_info.nr_memsize = size;
1645c4f8d80SVincenzo Maffione 	nmreq_push_option(&d->hdr, &d->extmem->nro_opt);
1655c4f8d80SVincenzo Maffione 
1665c4f8d80SVincenzo Maffione 	clnup->cleanup = nmport_extmem_cleanup;
1675c4f8d80SVincenzo Maffione 	nmport_push_cleanup(d, clnup);
1685c4f8d80SVincenzo Maffione 
1695c4f8d80SVincenzo Maffione 	return 0;
1705c4f8d80SVincenzo Maffione }
1715c4f8d80SVincenzo Maffione 
1725c4f8d80SVincenzo Maffione struct nmport_extmem_from_file_cleanup_d {
1735c4f8d80SVincenzo Maffione 	struct nmport_cleanup_d up;
1745c4f8d80SVincenzo Maffione 	void *p;
1755c4f8d80SVincenzo Maffione 	size_t size;
1765c4f8d80SVincenzo Maffione };
1775c4f8d80SVincenzo Maffione 
nmport_extmem_from_file_cleanup(struct nmport_cleanup_d * c,struct nmport_d * d)1785c4f8d80SVincenzo Maffione void nmport_extmem_from_file_cleanup(struct nmport_cleanup_d *c,
1795c4f8d80SVincenzo Maffione 		struct nmport_d *d)
1805c4f8d80SVincenzo Maffione {
1815c4f8d80SVincenzo Maffione 	struct nmport_extmem_from_file_cleanup_d *cc =
1825c4f8d80SVincenzo Maffione 		(struct nmport_extmem_from_file_cleanup_d *)c;
1835c4f8d80SVincenzo Maffione 
1845c4f8d80SVincenzo Maffione 	munmap(cc->p, cc->size);
1855c4f8d80SVincenzo Maffione }
1865c4f8d80SVincenzo Maffione 
1875c4f8d80SVincenzo Maffione int
nmport_extmem_from_file(struct nmport_d * d,const char * fname)1885c4f8d80SVincenzo Maffione nmport_extmem_from_file(struct nmport_d *d, const char *fname)
1895c4f8d80SVincenzo Maffione {
1905c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
1915c4f8d80SVincenzo Maffione 	int fd = -1;
1925c4f8d80SVincenzo Maffione 	off_t mapsize;
1935c4f8d80SVincenzo Maffione 	void *p;
1945c4f8d80SVincenzo Maffione 	struct nmport_extmem_from_file_cleanup_d *clnup = NULL;
1955c4f8d80SVincenzo Maffione 
1965c4f8d80SVincenzo Maffione 	clnup = nmctx_malloc(ctx, sizeof(*clnup));
1975c4f8d80SVincenzo Maffione 	if (clnup == NULL) {
1985c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot allocate cleanup descriptor");
1995c4f8d80SVincenzo Maffione 		errno = ENOMEM;
2005c4f8d80SVincenzo Maffione 		goto fail;
2015c4f8d80SVincenzo Maffione 	}
2025c4f8d80SVincenzo Maffione 
2035c4f8d80SVincenzo Maffione 	fd = open(fname, O_RDWR);
2045c4f8d80SVincenzo Maffione 	if (fd < 0) {
2055c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot open '%s': %s", fname, strerror(errno));
2065c4f8d80SVincenzo Maffione 		goto fail;
2075c4f8d80SVincenzo Maffione 	}
2085c4f8d80SVincenzo Maffione 	mapsize = lseek(fd, 0, SEEK_END);
2095c4f8d80SVincenzo Maffione 	if (mapsize < 0) {
2105c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "failed to obtain filesize of '%s': %s", fname, strerror(errno));
2115c4f8d80SVincenzo Maffione 		goto fail;
2125c4f8d80SVincenzo Maffione 	}
2135c4f8d80SVincenzo Maffione 	p = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2145c4f8d80SVincenzo Maffione 	if (p == MAP_FAILED) {
2155c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot mmap '%s': %s", fname, strerror(errno));
2165c4f8d80SVincenzo Maffione 		goto fail;
2175c4f8d80SVincenzo Maffione 	}
2185c4f8d80SVincenzo Maffione 	close(fd);
2195c4f8d80SVincenzo Maffione 
2205c4f8d80SVincenzo Maffione 	clnup->p = p;
2215c4f8d80SVincenzo Maffione 	clnup->size = mapsize;
2225c4f8d80SVincenzo Maffione 	clnup->up.cleanup = nmport_extmem_from_file_cleanup;
2235c4f8d80SVincenzo Maffione 	nmport_push_cleanup(d, &clnup->up);
2245c4f8d80SVincenzo Maffione 
2255c4f8d80SVincenzo Maffione 	if (nmport_extmem(d, p, mapsize) < 0)
2265c4f8d80SVincenzo Maffione 		goto fail;
2275c4f8d80SVincenzo Maffione 
2285c4f8d80SVincenzo Maffione 	return 0;
2295c4f8d80SVincenzo Maffione 
2305c4f8d80SVincenzo Maffione fail:
2315c4f8d80SVincenzo Maffione 	if (fd >= 0)
2325c4f8d80SVincenzo Maffione 		close(fd);
2335c4f8d80SVincenzo Maffione 	if (clnup != NULL) {
2345c4f8d80SVincenzo Maffione 		if (clnup->p != MAP_FAILED)
2355c4f8d80SVincenzo Maffione 			nmport_pop_cleanup(d);
2365c4f8d80SVincenzo Maffione 		else
2375c4f8d80SVincenzo Maffione 			nmctx_free(ctx, clnup);
2385c4f8d80SVincenzo Maffione 	}
2395c4f8d80SVincenzo Maffione 	return -1;
2405c4f8d80SVincenzo Maffione }
2415c4f8d80SVincenzo Maffione 
2425c4f8d80SVincenzo Maffione struct nmreq_pools_info*
nmport_extmem_getinfo(struct nmport_d * d)2435c4f8d80SVincenzo Maffione nmport_extmem_getinfo(struct nmport_d *d)
2445c4f8d80SVincenzo Maffione {
2455c4f8d80SVincenzo Maffione 	if (d->extmem == NULL)
2465c4f8d80SVincenzo Maffione 		return NULL;
2475c4f8d80SVincenzo Maffione 	return &d->extmem->nro_info;
2485c4f8d80SVincenzo Maffione }
2495c4f8d80SVincenzo Maffione 
2505c4f8d80SVincenzo Maffione /* head of the list of options */
2515c4f8d80SVincenzo Maffione static struct nmreq_opt_parser *nmport_opt_parsers;
2525c4f8d80SVincenzo Maffione 
2535c4f8d80SVincenzo Maffione #define NPOPT_PARSER(o)		nmport_opt_##o##_parser
2545c4f8d80SVincenzo Maffione #define NPOPT_DESC(o)		nmport_opt_##o##_desc
2555c4f8d80SVincenzo Maffione #define NPOPT_NRKEYS(o)		(NPOPT_DESC(o).nr_keys)
2565c4f8d80SVincenzo Maffione #define NPOPT_DECL(o, f)						\
2575c4f8d80SVincenzo Maffione static int NPOPT_PARSER(o)(struct nmreq_parse_ctx *);			\
2585c4f8d80SVincenzo Maffione static struct nmreq_opt_parser NPOPT_DESC(o) = {			\
2595c4f8d80SVincenzo Maffione 	.prefix = #o,							\
2605c4f8d80SVincenzo Maffione 	.parse = NPOPT_PARSER(o),					\
2615c4f8d80SVincenzo Maffione 	.flags = (f),							\
2625c4f8d80SVincenzo Maffione 	.default_key = -1,						\
2635c4f8d80SVincenzo Maffione 	.nr_keys = 0,							\
2645c4f8d80SVincenzo Maffione 	.next = NULL,							\
2655c4f8d80SVincenzo Maffione };									\
2665c4f8d80SVincenzo Maffione static void __attribute__((constructor))				\
2675c4f8d80SVincenzo Maffione nmport_opt_##o##_ctor(void)						\
2685c4f8d80SVincenzo Maffione {									\
2695c4f8d80SVincenzo Maffione 	NPOPT_DESC(o).next = nmport_opt_parsers;			\
2705c4f8d80SVincenzo Maffione 	nmport_opt_parsers = &NPOPT_DESC(o);				\
2715c4f8d80SVincenzo Maffione }
2725c4f8d80SVincenzo Maffione struct nmport_key_desc {
2735c4f8d80SVincenzo Maffione 	struct nmreq_opt_parser *option;
2745c4f8d80SVincenzo Maffione 	const char *key;
2755c4f8d80SVincenzo Maffione 	unsigned int flags;
2765c4f8d80SVincenzo Maffione 	int id;
2775c4f8d80SVincenzo Maffione };
2785c4f8d80SVincenzo Maffione static void
nmport_opt_key_ctor(struct nmport_key_desc * k)2795c4f8d80SVincenzo Maffione nmport_opt_key_ctor(struct nmport_key_desc *k)
2805c4f8d80SVincenzo Maffione {
2815c4f8d80SVincenzo Maffione 	struct nmreq_opt_parser *o = k->option;
2825c4f8d80SVincenzo Maffione 	struct nmreq_opt_key *ok;
2835c4f8d80SVincenzo Maffione 
2845c4f8d80SVincenzo Maffione 	k->id = o->nr_keys;
2855c4f8d80SVincenzo Maffione 	ok = &o->keys[k->id];
2865c4f8d80SVincenzo Maffione 	ok->key = k->key;
2875c4f8d80SVincenzo Maffione 	ok->id = k->id;
2885c4f8d80SVincenzo Maffione 	ok->flags = k->flags;
2895c4f8d80SVincenzo Maffione 	o->nr_keys++;
2905c4f8d80SVincenzo Maffione 	if (ok->flags & NMREQ_OPTK_DEFAULT)
2915c4f8d80SVincenzo Maffione 		o->default_key = ok->id;
2925c4f8d80SVincenzo Maffione }
2935c4f8d80SVincenzo Maffione #define NPKEY_DESC(o, k)	nmport_opt_##o##_key_##k##_desc
2945c4f8d80SVincenzo Maffione #define NPKEY_ID(o, k)		(NPKEY_DESC(o, k).id)
2955c4f8d80SVincenzo Maffione #define NPKEY_DECL(o, k, f)						\
2965c4f8d80SVincenzo Maffione static struct nmport_key_desc NPKEY_DESC(o, k) = {			\
2975c4f8d80SVincenzo Maffione 	.option = &NPOPT_DESC(o),					\
2985c4f8d80SVincenzo Maffione 	.key = #k,							\
2995c4f8d80SVincenzo Maffione 	.flags = (f),							\
3005c4f8d80SVincenzo Maffione 	.id = -1,							\
3015c4f8d80SVincenzo Maffione };									\
3025c4f8d80SVincenzo Maffione static void __attribute__((constructor))				\
3035c4f8d80SVincenzo Maffione nmport_opt_##o##_key_##k##_ctor(void)					\
3045c4f8d80SVincenzo Maffione {									\
3055c4f8d80SVincenzo Maffione 	nmport_opt_key_ctor(&NPKEY_DESC(o, k));				\
3065c4f8d80SVincenzo Maffione }
3075c4f8d80SVincenzo Maffione #define nmport_key(p, o, k)	((p)->keys[NPKEY_ID(o, k)])
3085c4f8d80SVincenzo Maffione #define nmport_defkey(p, o)	((p)->keys[NPOPT_DESC(o).default_key])
3095c4f8d80SVincenzo Maffione 
3105c4f8d80SVincenzo Maffione NPOPT_DECL(share, 0)
3115c4f8d80SVincenzo Maffione 	NPKEY_DECL(share, port, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET)
3125c4f8d80SVincenzo Maffione NPOPT_DECL(extmem, 0)
3135c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, file, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET)
3145c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, if_num, 0)
3155c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, if_size, 0)
3165c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, ring_num, 0)
3175c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, ring_size, 0)
3185c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, buf_num, 0)
3195c4f8d80SVincenzo Maffione 	NPKEY_DECL(extmem, buf_size, 0)
3205c4f8d80SVincenzo Maffione NPOPT_DECL(conf, 0)
3215c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, rings, 0)
3225c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, host_rings, 0)
3235c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, slots, 0)
3245c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, tx_rings, 0)
3255c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, rx_rings, 0)
3265c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, host_tx_rings, 0)
3275c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, host_rx_rings, 0)
3285c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, tx_slots, 0)
3295c4f8d80SVincenzo Maffione 	NPKEY_DECL(conf, rx_slots, 0)
3305c4f8d80SVincenzo Maffione 
3315c4f8d80SVincenzo Maffione 
3325c4f8d80SVincenzo Maffione static int
NPOPT_PARSER(share)3335c4f8d80SVincenzo Maffione NPOPT_PARSER(share)(struct nmreq_parse_ctx *p)
3345c4f8d80SVincenzo Maffione {
3355c4f8d80SVincenzo Maffione 	struct nmctx *ctx = p->ctx;
3365c4f8d80SVincenzo Maffione 	struct nmport_d *d = p->token;
3375c4f8d80SVincenzo Maffione 	int32_t mem_id;
3385c4f8d80SVincenzo Maffione 	const char *v = nmport_defkey(p, share);
3395c4f8d80SVincenzo Maffione 
3405c4f8d80SVincenzo Maffione 	mem_id = nmreq_get_mem_id(&v, ctx);
3415c4f8d80SVincenzo Maffione 	if (mem_id < 0)
3425c4f8d80SVincenzo Maffione 		return -1;
3435c4f8d80SVincenzo Maffione 	if (d->reg.nr_mem_id && d->reg.nr_mem_id != mem_id) {
3445c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot set mem_id to %"PRId32", already set to %"PRIu16"",
3455c4f8d80SVincenzo Maffione 				mem_id, d->reg.nr_mem_id);
3465c4f8d80SVincenzo Maffione 		errno = EINVAL;
3475c4f8d80SVincenzo Maffione 		return -1;
3485c4f8d80SVincenzo Maffione 	}
3495c4f8d80SVincenzo Maffione 	d->reg.nr_mem_id = mem_id;
3505c4f8d80SVincenzo Maffione 	return 0;
3515c4f8d80SVincenzo Maffione }
3525c4f8d80SVincenzo Maffione 
3535c4f8d80SVincenzo Maffione static int
NPOPT_PARSER(extmem)3545c4f8d80SVincenzo Maffione NPOPT_PARSER(extmem)(struct nmreq_parse_ctx *p)
3555c4f8d80SVincenzo Maffione {
3565c4f8d80SVincenzo Maffione 	struct nmport_d *d;
3575c4f8d80SVincenzo Maffione 	struct nmreq_pools_info *pi;
3585c4f8d80SVincenzo Maffione 	int i;
3595c4f8d80SVincenzo Maffione 
3605c4f8d80SVincenzo Maffione 	d = p->token;
3615c4f8d80SVincenzo Maffione 
3625c4f8d80SVincenzo Maffione 	if (nmport_extmem_from_file(d, nmport_key(p, extmem, file)) < 0)
3635c4f8d80SVincenzo Maffione 		return -1;
3645c4f8d80SVincenzo Maffione 
3655c4f8d80SVincenzo Maffione 	pi = &d->extmem->nro_info;
3665c4f8d80SVincenzo Maffione 
3675c4f8d80SVincenzo Maffione 	for  (i = 0; i < NPOPT_NRKEYS(extmem); i++) {
3685c4f8d80SVincenzo Maffione 		const char *k = p->keys[i];
3695c4f8d80SVincenzo Maffione 		uint32_t v;
3705c4f8d80SVincenzo Maffione 
3715c4f8d80SVincenzo Maffione 		if (k == NULL)
3725c4f8d80SVincenzo Maffione 			continue;
3735c4f8d80SVincenzo Maffione 
3745c4f8d80SVincenzo Maffione 		v = atoi(k);
3755c4f8d80SVincenzo Maffione 		if (i == NPKEY_ID(extmem, if_num)) {
3765c4f8d80SVincenzo Maffione 			pi->nr_if_pool_objtotal = v;
3775c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, if_size)) {
3785c4f8d80SVincenzo Maffione 			pi->nr_if_pool_objsize = v;
3795c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, ring_num)) {
3805c4f8d80SVincenzo Maffione 			pi->nr_ring_pool_objtotal = v;
3815c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, ring_size)) {
3825c4f8d80SVincenzo Maffione 			pi->nr_ring_pool_objsize = v;
3835c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, buf_num)) {
3845c4f8d80SVincenzo Maffione 			pi->nr_buf_pool_objtotal = v;
3855c4f8d80SVincenzo Maffione 		} else if (i == NPKEY_ID(extmem, buf_size)) {
3865c4f8d80SVincenzo Maffione 			pi->nr_buf_pool_objsize = v;
3875c4f8d80SVincenzo Maffione 		}
3885c4f8d80SVincenzo Maffione 	}
3895c4f8d80SVincenzo Maffione 	return 0;
3905c4f8d80SVincenzo Maffione }
3915c4f8d80SVincenzo Maffione 
3925c4f8d80SVincenzo Maffione static int
NPOPT_PARSER(conf)3935c4f8d80SVincenzo Maffione NPOPT_PARSER(conf)(struct nmreq_parse_ctx *p)
3945c4f8d80SVincenzo Maffione {
3955c4f8d80SVincenzo Maffione 	struct nmport_d *d;
3965c4f8d80SVincenzo Maffione 
3975c4f8d80SVincenzo Maffione 	d = p->token;
3985c4f8d80SVincenzo Maffione 
3995c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, rings) != NULL) {
4005c4f8d80SVincenzo Maffione 		uint16_t nr_rings = atoi(nmport_key(p, conf, rings));
4015c4f8d80SVincenzo Maffione 		d->reg.nr_tx_rings = nr_rings;
4025c4f8d80SVincenzo Maffione 		d->reg.nr_rx_rings = nr_rings;
4035c4f8d80SVincenzo Maffione 	}
4045c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, host_rings) != NULL) {
4055c4f8d80SVincenzo Maffione 		uint16_t nr_rings = atoi(nmport_key(p, conf, host_rings));
4065c4f8d80SVincenzo Maffione 		d->reg.nr_host_tx_rings = nr_rings;
4075c4f8d80SVincenzo Maffione 		d->reg.nr_host_rx_rings = nr_rings;
4085c4f8d80SVincenzo Maffione 	}
4095c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, slots) != NULL) {
4105c4f8d80SVincenzo Maffione 		uint32_t nr_slots = atoi(nmport_key(p, conf, slots));
4115c4f8d80SVincenzo Maffione 		d->reg.nr_tx_slots = nr_slots;
4125c4f8d80SVincenzo Maffione 		d->reg.nr_rx_slots = nr_slots;
4135c4f8d80SVincenzo Maffione 	}
4145c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, tx_rings) != NULL) {
4155c4f8d80SVincenzo Maffione 		d->reg.nr_tx_rings = atoi(nmport_key(p, conf, tx_rings));
4165c4f8d80SVincenzo Maffione 	}
4175c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, rx_rings) != NULL) {
4185c4f8d80SVincenzo Maffione 		d->reg.nr_rx_rings = atoi(nmport_key(p, conf, rx_rings));
4195c4f8d80SVincenzo Maffione 	}
4205c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, host_tx_rings) != NULL) {
4215c4f8d80SVincenzo Maffione 		d->reg.nr_host_tx_rings = atoi(nmport_key(p, conf, host_tx_rings));
4225c4f8d80SVincenzo Maffione 	}
4235c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, host_rx_rings) != NULL) {
4245c4f8d80SVincenzo Maffione 		d->reg.nr_host_rx_rings = atoi(nmport_key(p, conf, host_rx_rings));
4255c4f8d80SVincenzo Maffione 	}
4265c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, tx_slots) != NULL) {
4275c4f8d80SVincenzo Maffione 		d->reg.nr_tx_slots = atoi(nmport_key(p, conf, tx_slots));
4285c4f8d80SVincenzo Maffione 	}
4295c4f8d80SVincenzo Maffione 	if (nmport_key(p, conf, rx_slots) != NULL) {
4305c4f8d80SVincenzo Maffione 		d->reg.nr_rx_slots = atoi(nmport_key(p, conf, rx_slots));
4315c4f8d80SVincenzo Maffione 	}
4325c4f8d80SVincenzo Maffione 	return 0;
4335c4f8d80SVincenzo Maffione }
4345c4f8d80SVincenzo Maffione 
4355c4f8d80SVincenzo Maffione void
nmport_disable_option(const char * opt)4365c4f8d80SVincenzo Maffione nmport_disable_option(const char *opt)
4375c4f8d80SVincenzo Maffione {
4385c4f8d80SVincenzo Maffione 	struct nmreq_opt_parser *p;
4395c4f8d80SVincenzo Maffione 
4405c4f8d80SVincenzo Maffione 	for (p = nmport_opt_parsers; p != NULL; p = p->next) {
4415c4f8d80SVincenzo Maffione 		if (!strcmp(p->prefix, opt)) {
4425c4f8d80SVincenzo Maffione 			p->flags |= NMREQ_OPTF_DISABLED;
4435c4f8d80SVincenzo Maffione 		}
4445c4f8d80SVincenzo Maffione 	}
4455c4f8d80SVincenzo Maffione }
4465c4f8d80SVincenzo Maffione 
4475c4f8d80SVincenzo Maffione int
nmport_enable_option(const char * opt)4485c4f8d80SVincenzo Maffione nmport_enable_option(const char *opt)
4495c4f8d80SVincenzo Maffione {
4505c4f8d80SVincenzo Maffione 	struct nmreq_opt_parser *p;
4515c4f8d80SVincenzo Maffione 
4525c4f8d80SVincenzo Maffione 	for (p = nmport_opt_parsers; p != NULL; p = p->next) {
4535c4f8d80SVincenzo Maffione 		if (!strcmp(p->prefix, opt)) {
4545c4f8d80SVincenzo Maffione 			p->flags &= ~NMREQ_OPTF_DISABLED;
4555c4f8d80SVincenzo Maffione 			return 0;
4565c4f8d80SVincenzo Maffione 		}
4575c4f8d80SVincenzo Maffione 	}
4585c4f8d80SVincenzo Maffione 	errno = EOPNOTSUPP;
4595c4f8d80SVincenzo Maffione 	return -1;
4605c4f8d80SVincenzo Maffione }
4615c4f8d80SVincenzo Maffione 
4625c4f8d80SVincenzo Maffione 
4635c4f8d80SVincenzo Maffione int
nmport_parse(struct nmport_d * d,const char * ifname)4645c4f8d80SVincenzo Maffione nmport_parse(struct nmport_d *d, const char *ifname)
4655c4f8d80SVincenzo Maffione {
4665c4f8d80SVincenzo Maffione 	const char *scan = ifname;
4675c4f8d80SVincenzo Maffione 
4685c4f8d80SVincenzo Maffione 	if (nmreq_header_decode(&scan, &d->hdr, d->ctx) < 0) {
4695c4f8d80SVincenzo Maffione 		goto err;
4705c4f8d80SVincenzo Maffione 	}
4715c4f8d80SVincenzo Maffione 
4725c4f8d80SVincenzo Maffione 	/* parse the register request */
4735c4f8d80SVincenzo Maffione 	if (nmreq_register_decode(&scan, &d->reg, d->ctx) < 0) {
4745c4f8d80SVincenzo Maffione 		goto err;
4755c4f8d80SVincenzo Maffione 	}
4765c4f8d80SVincenzo Maffione 
4775c4f8d80SVincenzo Maffione 	/* parse the options, if any */
4785c4f8d80SVincenzo Maffione 	if (nmreq_options_decode(scan, nmport_opt_parsers, d, d->ctx) < 0) {
4795c4f8d80SVincenzo Maffione 		goto err;
4805c4f8d80SVincenzo Maffione 	}
4815c4f8d80SVincenzo Maffione 	return 0;
4825c4f8d80SVincenzo Maffione 
4835c4f8d80SVincenzo Maffione err:
4845c4f8d80SVincenzo Maffione 	nmport_undo_parse(d);
4855c4f8d80SVincenzo Maffione 	return -1;
4865c4f8d80SVincenzo Maffione }
4875c4f8d80SVincenzo Maffione 
4885c4f8d80SVincenzo Maffione void
nmport_undo_parse(struct nmport_d * d)4895c4f8d80SVincenzo Maffione nmport_undo_parse(struct nmport_d *d)
4905c4f8d80SVincenzo Maffione {
4915c4f8d80SVincenzo Maffione 	nmport_do_cleanup(d);
4925c4f8d80SVincenzo Maffione 	memset(&d->reg, 0, sizeof(d->reg));
4935c4f8d80SVincenzo Maffione 	memset(&d->hdr, 0, sizeof(d->hdr));
4945c4f8d80SVincenzo Maffione }
4955c4f8d80SVincenzo Maffione 
4965c4f8d80SVincenzo Maffione struct nmport_d *
nmport_prepare(const char * ifname)4975c4f8d80SVincenzo Maffione nmport_prepare(const char *ifname)
4985c4f8d80SVincenzo Maffione {
4995c4f8d80SVincenzo Maffione 	struct nmport_d *d;
5005c4f8d80SVincenzo Maffione 
5015c4f8d80SVincenzo Maffione 	/* allocate a descriptor */
5025c4f8d80SVincenzo Maffione 	d = nmport_new();
5035c4f8d80SVincenzo Maffione 	if (d == NULL)
5045c4f8d80SVincenzo Maffione 		goto err;
5055c4f8d80SVincenzo Maffione 
5065c4f8d80SVincenzo Maffione 	/* parse the header */
5075c4f8d80SVincenzo Maffione 	if (nmport_parse(d, ifname) < 0)
5085c4f8d80SVincenzo Maffione 		goto err;
5095c4f8d80SVincenzo Maffione 
5105c4f8d80SVincenzo Maffione 	return d;
5115c4f8d80SVincenzo Maffione 
5125c4f8d80SVincenzo Maffione err:
5135c4f8d80SVincenzo Maffione 	nmport_undo_prepare(d);
5145c4f8d80SVincenzo Maffione 	return NULL;
5155c4f8d80SVincenzo Maffione }
5165c4f8d80SVincenzo Maffione 
5175c4f8d80SVincenzo Maffione void
nmport_undo_prepare(struct nmport_d * d)5185c4f8d80SVincenzo Maffione nmport_undo_prepare(struct nmport_d *d)
5195c4f8d80SVincenzo Maffione {
5205c4f8d80SVincenzo Maffione 	if (d == NULL)
5215c4f8d80SVincenzo Maffione 		return;
5225c4f8d80SVincenzo Maffione 	nmport_undo_parse(d);
5235c4f8d80SVincenzo Maffione 	nmport_delete(d);
5245c4f8d80SVincenzo Maffione }
5255c4f8d80SVincenzo Maffione 
5265c4f8d80SVincenzo Maffione int
nmport_register(struct nmport_d * d)5275c4f8d80SVincenzo Maffione nmport_register(struct nmport_d *d)
5285c4f8d80SVincenzo Maffione {
5295c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
5305c4f8d80SVincenzo Maffione 
5315c4f8d80SVincenzo Maffione 	if (d->register_done) {
5325c4f8d80SVincenzo Maffione 		errno = EINVAL;
5335c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: already registered", d->hdr.nr_name);
5345c4f8d80SVincenzo Maffione 		return -1;
5355c4f8d80SVincenzo Maffione 	}
5365c4f8d80SVincenzo Maffione 
5375c4f8d80SVincenzo Maffione 	d->fd = open("/dev/netmap", O_RDWR);
5385c4f8d80SVincenzo Maffione 	if (d->fd < 0) {
5395c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "/dev/netmap: %s", strerror(errno));
5405c4f8d80SVincenzo Maffione 		goto err;
5415c4f8d80SVincenzo Maffione 	}
5425c4f8d80SVincenzo Maffione 
5435c4f8d80SVincenzo Maffione 	if (ioctl(d->fd, NIOCCTRL, &d->hdr) < 0) {
5445c4f8d80SVincenzo Maffione 		struct nmreq_option *o;
5455c4f8d80SVincenzo Maffione 		int option_errors = 0;
5465c4f8d80SVincenzo Maffione 
5475c4f8d80SVincenzo Maffione 		nmreq_foreach_option(&d->hdr, o) {
5485c4f8d80SVincenzo Maffione 			if (o->nro_status) {
5495c4f8d80SVincenzo Maffione 				nmctx_ferror(ctx, "%s: option %s: %s",
5505c4f8d80SVincenzo Maffione 						d->hdr.nr_name,
5515c4f8d80SVincenzo Maffione 						nmreq_option_name(o->nro_reqtype),
5525c4f8d80SVincenzo Maffione 						strerror(o->nro_status));
5535c4f8d80SVincenzo Maffione 				option_errors++;
5545c4f8d80SVincenzo Maffione 			}
5555c4f8d80SVincenzo Maffione 
5565c4f8d80SVincenzo Maffione 		}
5575c4f8d80SVincenzo Maffione 		if (!option_errors)
5585c4f8d80SVincenzo Maffione 			nmctx_ferror(ctx, "%s: %s", d->hdr.nr_name, strerror(errno));
5595c4f8d80SVincenzo Maffione 		goto err;
5605c4f8d80SVincenzo Maffione 	}
5615c4f8d80SVincenzo Maffione 
5625c4f8d80SVincenzo Maffione 	d->register_done = 1;
5635c4f8d80SVincenzo Maffione 
5645c4f8d80SVincenzo Maffione 	return 0;
5655c4f8d80SVincenzo Maffione 
5665c4f8d80SVincenzo Maffione err:
5675c4f8d80SVincenzo Maffione 	nmport_undo_register(d);
5685c4f8d80SVincenzo Maffione 	return -1;
5695c4f8d80SVincenzo Maffione }
5705c4f8d80SVincenzo Maffione 
5715c4f8d80SVincenzo Maffione void
nmport_undo_register(struct nmport_d * d)5725c4f8d80SVincenzo Maffione nmport_undo_register(struct nmport_d *d)
5735c4f8d80SVincenzo Maffione {
5745c4f8d80SVincenzo Maffione 	if (d->fd >= 0)
5755c4f8d80SVincenzo Maffione 		close(d->fd);
5765c4f8d80SVincenzo Maffione 	d->fd = -1;
5775c4f8d80SVincenzo Maffione 	d->register_done = 0;
5785c4f8d80SVincenzo Maffione }
5795c4f8d80SVincenzo Maffione 
5805c4f8d80SVincenzo Maffione /* lookup the mem_id in the mem-list: do a new mmap() if
5815c4f8d80SVincenzo Maffione  * not found, reuse existing otherwise
5825c4f8d80SVincenzo Maffione  */
5835c4f8d80SVincenzo Maffione int
nmport_mmap(struct nmport_d * d)5845c4f8d80SVincenzo Maffione nmport_mmap(struct nmport_d *d)
5855c4f8d80SVincenzo Maffione {
5865c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
5875c4f8d80SVincenzo Maffione 	struct nmem_d *m = NULL;
5885c4f8d80SVincenzo Maffione 	u_int num_tx, num_rx;
5895c4f8d80SVincenzo Maffione 	int i;
5905c4f8d80SVincenzo Maffione 
5915c4f8d80SVincenzo Maffione 	if (d->mmap_done) {
5925c4f8d80SVincenzo Maffione 		errno = EINVAL;
5935c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "%s: already mapped", d->hdr.nr_name);
5945c4f8d80SVincenzo Maffione 		return -1;
5955c4f8d80SVincenzo Maffione 	}
5965c4f8d80SVincenzo Maffione 
5975c4f8d80SVincenzo Maffione 	if (!d->register_done) {
5985c4f8d80SVincenzo Maffione 		errno = EINVAL;
5995c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot map unregistered port");
6005c4f8d80SVincenzo Maffione 		return -1;
6015c4f8d80SVincenzo Maffione 	}
6025c4f8d80SVincenzo Maffione 
6035c4f8d80SVincenzo Maffione 	nmctx_lock(ctx);
6045c4f8d80SVincenzo Maffione 
6055c4f8d80SVincenzo Maffione 	for (m = ctx->mem_descs; m != NULL; m = m->next)
6065c4f8d80SVincenzo Maffione 		if (m->mem_id == d->reg.nr_mem_id)
6075c4f8d80SVincenzo Maffione 			break;
6085c4f8d80SVincenzo Maffione 
6095c4f8d80SVincenzo Maffione 	if (m == NULL) {
6105c4f8d80SVincenzo Maffione 		m = nmctx_malloc(ctx, sizeof(*m));
6115c4f8d80SVincenzo Maffione 		if (m == NULL) {
6125c4f8d80SVincenzo Maffione 			nmctx_ferror(ctx, "cannot allocate memory descriptor");
6135c4f8d80SVincenzo Maffione 			goto err;
6145c4f8d80SVincenzo Maffione 		}
6155c4f8d80SVincenzo Maffione 		memset(m, 0, sizeof(*m));
6165c4f8d80SVincenzo Maffione 		if (d->extmem != NULL) {
617*92c5d82cSVincenzo Maffione 			m->mem = (void *)((uintptr_t)d->extmem->nro_usrptr);
6185c4f8d80SVincenzo Maffione 			m->size = d->extmem->nro_info.nr_memsize;
6195c4f8d80SVincenzo Maffione 			m->is_extmem = 1;
6205c4f8d80SVincenzo Maffione 		} else {
6215c4f8d80SVincenzo Maffione 			m->mem = mmap(NULL, d->reg.nr_memsize, PROT_READ|PROT_WRITE,
6225c4f8d80SVincenzo Maffione 					MAP_SHARED, d->fd, 0);
6235c4f8d80SVincenzo Maffione 			if (m->mem == MAP_FAILED) {
6245c4f8d80SVincenzo Maffione 				nmctx_ferror(ctx, "mmap: %s", strerror(errno));
6255c4f8d80SVincenzo Maffione 				goto err;
6265c4f8d80SVincenzo Maffione 			}
6275c4f8d80SVincenzo Maffione 			m->size = d->reg.nr_memsize;
6285c4f8d80SVincenzo Maffione 		}
6295c4f8d80SVincenzo Maffione 		m->mem_id = d->reg.nr_mem_id;
6305c4f8d80SVincenzo Maffione 		m->next = ctx->mem_descs;
6315c4f8d80SVincenzo Maffione 		if (ctx->mem_descs != NULL)
6325c4f8d80SVincenzo Maffione 			ctx->mem_descs->prev = m;
6335c4f8d80SVincenzo Maffione 		ctx->mem_descs = m;
6345c4f8d80SVincenzo Maffione 	}
6355c4f8d80SVincenzo Maffione 	m->refcount++;
6365c4f8d80SVincenzo Maffione 
6375c4f8d80SVincenzo Maffione 	nmctx_unlock(ctx);
6385c4f8d80SVincenzo Maffione 
6395c4f8d80SVincenzo Maffione 	d->mem = m;
6405c4f8d80SVincenzo Maffione 
6415c4f8d80SVincenzo Maffione 	d->nifp = NETMAP_IF(m->mem, d->reg.nr_offset);
6425c4f8d80SVincenzo Maffione 
6435c4f8d80SVincenzo Maffione 	num_tx = d->reg.nr_tx_rings + d->nifp->ni_host_tx_rings;
6445c4f8d80SVincenzo Maffione 	for (i = 0; i < num_tx && !d->nifp->ring_ofs[i]; i++)
6455c4f8d80SVincenzo Maffione 		;
6465c4f8d80SVincenzo Maffione 	d->first_tx_ring = i;
6475c4f8d80SVincenzo Maffione 	for ( ; i < num_tx && d->nifp->ring_ofs[i]; i++)
6485c4f8d80SVincenzo Maffione 		;
6495c4f8d80SVincenzo Maffione 	d->last_tx_ring = i - 1;
6505c4f8d80SVincenzo Maffione 
6515c4f8d80SVincenzo Maffione 	num_rx = d->reg.nr_rx_rings + d->nifp->ni_host_rx_rings;
6525c4f8d80SVincenzo Maffione 	for (i = 0; i < num_rx && !d->nifp->ring_ofs[i + num_tx]; i++)
6535c4f8d80SVincenzo Maffione 		;
6545c4f8d80SVincenzo Maffione 	d->first_rx_ring = i;
6555c4f8d80SVincenzo Maffione 	for ( ; i < num_rx && d->nifp->ring_ofs[i + num_tx]; i++)
6565c4f8d80SVincenzo Maffione 		;
6575c4f8d80SVincenzo Maffione 	d->last_rx_ring = i - 1;
6585c4f8d80SVincenzo Maffione 
6595c4f8d80SVincenzo Maffione 	d->mmap_done = 1;
6605c4f8d80SVincenzo Maffione 
6615c4f8d80SVincenzo Maffione 	return 0;
6625c4f8d80SVincenzo Maffione 
6635c4f8d80SVincenzo Maffione err:
6645c4f8d80SVincenzo Maffione 	nmctx_unlock(ctx);
6655c4f8d80SVincenzo Maffione 	nmport_undo_mmap(d);
6665c4f8d80SVincenzo Maffione 	return -1;
6675c4f8d80SVincenzo Maffione }
6685c4f8d80SVincenzo Maffione 
6695c4f8d80SVincenzo Maffione void
nmport_undo_mmap(struct nmport_d * d)6705c4f8d80SVincenzo Maffione nmport_undo_mmap(struct nmport_d *d)
6715c4f8d80SVincenzo Maffione {
6725c4f8d80SVincenzo Maffione 	struct nmem_d *m;
6735c4f8d80SVincenzo Maffione 	struct nmctx *ctx = d->ctx;
6745c4f8d80SVincenzo Maffione 
6755c4f8d80SVincenzo Maffione 	m = d->mem;
6765c4f8d80SVincenzo Maffione 	if (m == NULL)
6775c4f8d80SVincenzo Maffione 		return;
6785c4f8d80SVincenzo Maffione 	nmctx_lock(ctx);
6795c4f8d80SVincenzo Maffione 	m->refcount--;
6805c4f8d80SVincenzo Maffione 	if (m->refcount <= 0) {
6815c4f8d80SVincenzo Maffione 		if (!m->is_extmem && m->mem != MAP_FAILED)
6825c4f8d80SVincenzo Maffione 			munmap(m->mem, m->size);
6835c4f8d80SVincenzo Maffione 		/* extract from the list and free */
6845c4f8d80SVincenzo Maffione 		if (m->next != NULL)
6855c4f8d80SVincenzo Maffione 			m->next->prev = m->prev;
6865c4f8d80SVincenzo Maffione 		if (m->prev != NULL)
6875c4f8d80SVincenzo Maffione 			m->prev->next = m->next;
6885c4f8d80SVincenzo Maffione 		else
6895c4f8d80SVincenzo Maffione 			ctx->mem_descs = m->next;
6905c4f8d80SVincenzo Maffione 		nmctx_free(ctx, m);
6915c4f8d80SVincenzo Maffione 		d->mem = NULL;
6925c4f8d80SVincenzo Maffione 	}
6935c4f8d80SVincenzo Maffione 	nmctx_unlock(ctx);
6945c4f8d80SVincenzo Maffione 	d->mmap_done = 0;
6955c4f8d80SVincenzo Maffione 	d->mem = NULL;
6965c4f8d80SVincenzo Maffione 	d->nifp = NULL;
6975c4f8d80SVincenzo Maffione 	d->first_tx_ring = 0;
6985c4f8d80SVincenzo Maffione 	d->last_tx_ring = 0;
6995c4f8d80SVincenzo Maffione 	d->first_rx_ring = 0;
7005c4f8d80SVincenzo Maffione 	d->last_rx_ring = 0;
7015c4f8d80SVincenzo Maffione 	d->cur_tx_ring = 0;
7025c4f8d80SVincenzo Maffione 	d->cur_rx_ring = 0;
7035c4f8d80SVincenzo Maffione }
7045c4f8d80SVincenzo Maffione 
7055c4f8d80SVincenzo Maffione int
nmport_open_desc(struct nmport_d * d)7065c4f8d80SVincenzo Maffione nmport_open_desc(struct nmport_d *d)
7075c4f8d80SVincenzo Maffione {
7085c4f8d80SVincenzo Maffione 	if (nmport_register(d) < 0)
7095c4f8d80SVincenzo Maffione 		goto err;
7105c4f8d80SVincenzo Maffione 
7115c4f8d80SVincenzo Maffione 	if (nmport_mmap(d) < 0)
7125c4f8d80SVincenzo Maffione 		goto err;
7135c4f8d80SVincenzo Maffione 
7145c4f8d80SVincenzo Maffione 	return 0;
7155c4f8d80SVincenzo Maffione err:
7165c4f8d80SVincenzo Maffione 	nmport_undo_open_desc(d);
7175c4f8d80SVincenzo Maffione 	return -1;
7185c4f8d80SVincenzo Maffione }
7195c4f8d80SVincenzo Maffione 
7205c4f8d80SVincenzo Maffione void
nmport_undo_open_desc(struct nmport_d * d)7215c4f8d80SVincenzo Maffione nmport_undo_open_desc(struct nmport_d *d)
7225c4f8d80SVincenzo Maffione {
7235c4f8d80SVincenzo Maffione 	nmport_undo_mmap(d);
7245c4f8d80SVincenzo Maffione 	nmport_undo_register(d);
7255c4f8d80SVincenzo Maffione }
7265c4f8d80SVincenzo Maffione 
7275c4f8d80SVincenzo Maffione 
7285c4f8d80SVincenzo Maffione struct nmport_d *
nmport_open(const char * ifname)7295c4f8d80SVincenzo Maffione nmport_open(const char *ifname)
7305c4f8d80SVincenzo Maffione {
7315c4f8d80SVincenzo Maffione 	struct nmport_d *d;
7325c4f8d80SVincenzo Maffione 
7335c4f8d80SVincenzo Maffione 	/* prepare the descriptor */
7345c4f8d80SVincenzo Maffione 	d = nmport_prepare(ifname);
7355c4f8d80SVincenzo Maffione 	if (d == NULL)
7365c4f8d80SVincenzo Maffione 		goto err;
7375c4f8d80SVincenzo Maffione 
7385c4f8d80SVincenzo Maffione 	/* open netmap and register */
7395c4f8d80SVincenzo Maffione 	if (nmport_open_desc(d) < 0)
7405c4f8d80SVincenzo Maffione 		goto err;
7415c4f8d80SVincenzo Maffione 
7425c4f8d80SVincenzo Maffione 	return d;
7435c4f8d80SVincenzo Maffione 
7445c4f8d80SVincenzo Maffione err:
7455c4f8d80SVincenzo Maffione 	nmport_close(d);
7465c4f8d80SVincenzo Maffione 	return NULL;
7475c4f8d80SVincenzo Maffione }
7485c4f8d80SVincenzo Maffione 
7495c4f8d80SVincenzo Maffione void
nmport_close(struct nmport_d * d)7505c4f8d80SVincenzo Maffione nmport_close(struct nmport_d *d)
7515c4f8d80SVincenzo Maffione {
7525c4f8d80SVincenzo Maffione 	if (d == NULL)
7535c4f8d80SVincenzo Maffione 		return;
7545c4f8d80SVincenzo Maffione 	nmport_undo_open_desc(d);
7555c4f8d80SVincenzo Maffione 	nmport_undo_prepare(d);
7565c4f8d80SVincenzo Maffione }
7575c4f8d80SVincenzo Maffione 
7585c4f8d80SVincenzo Maffione struct nmport_d *
nmport_clone(struct nmport_d * d)7595c4f8d80SVincenzo Maffione nmport_clone(struct nmport_d *d)
7605c4f8d80SVincenzo Maffione {
7615c4f8d80SVincenzo Maffione 	struct nmport_d *c;
7625c4f8d80SVincenzo Maffione 	struct nmctx *ctx;
7635c4f8d80SVincenzo Maffione 
7645c4f8d80SVincenzo Maffione 	ctx = d->ctx;
7655c4f8d80SVincenzo Maffione 
7665c4f8d80SVincenzo Maffione 	if (d->extmem != NULL && !d->register_done) {
7675c4f8d80SVincenzo Maffione 		errno = EINVAL;
7685c4f8d80SVincenzo Maffione 		nmctx_ferror(ctx, "cannot clone unregistered port that is using extmem");
7695c4f8d80SVincenzo Maffione 		return NULL;
7705c4f8d80SVincenzo Maffione 	}
7715c4f8d80SVincenzo Maffione 
7725c4f8d80SVincenzo Maffione 	c = nmport_new_with_ctx(ctx);
7735c4f8d80SVincenzo Maffione 	if (c == NULL)
7745c4f8d80SVincenzo Maffione 		return NULL;
7755c4f8d80SVincenzo Maffione 	/* copy the output of parse */
7765c4f8d80SVincenzo Maffione 	c->hdr = d->hdr;
7775c4f8d80SVincenzo Maffione 	/* redirect the pointer to the body */
7785c4f8d80SVincenzo Maffione 	c->hdr.nr_body = (uintptr_t)&c->reg;
7795c4f8d80SVincenzo Maffione 	/* options are not cloned */
7805c4f8d80SVincenzo Maffione 	c->hdr.nr_options = 0;
7815c4f8d80SVincenzo Maffione 	c->reg = d->reg; /* this also copies the mem_id */
7825c4f8d80SVincenzo Maffione 	/* put the new port in an un-registered, unmapped state */
7835c4f8d80SVincenzo Maffione 	c->fd = -1;
7845c4f8d80SVincenzo Maffione 	c->nifp = NULL;
7855c4f8d80SVincenzo Maffione 	c->register_done = 0;
7865c4f8d80SVincenzo Maffione 	c->mem = NULL;
7875c4f8d80SVincenzo Maffione 	c->extmem = NULL;
7885c4f8d80SVincenzo Maffione 	c->mmap_done = 0;
7895c4f8d80SVincenzo Maffione 	c->first_tx_ring = 0;
7905c4f8d80SVincenzo Maffione 	c->last_tx_ring = 0;
7915c4f8d80SVincenzo Maffione 	c->first_rx_ring = 0;
7925c4f8d80SVincenzo Maffione 	c->last_rx_ring = 0;
7935c4f8d80SVincenzo Maffione 	c->cur_tx_ring = 0;
7945c4f8d80SVincenzo Maffione 	c->cur_rx_ring = 0;
7955c4f8d80SVincenzo Maffione 
7965c4f8d80SVincenzo Maffione 	return c;
7975c4f8d80SVincenzo Maffione }
7985c4f8d80SVincenzo Maffione 
7995c4f8d80SVincenzo Maffione int
nmport_inject(struct nmport_d * d,const void * buf,size_t size)8005c4f8d80SVincenzo Maffione nmport_inject(struct nmport_d *d, const void *buf, size_t size)
8015c4f8d80SVincenzo Maffione {
8025c4f8d80SVincenzo Maffione 	u_int c, n = d->last_tx_ring - d->first_tx_ring + 1,
8035c4f8d80SVincenzo Maffione 		ri = d->cur_tx_ring;
8045c4f8d80SVincenzo Maffione 
8055c4f8d80SVincenzo Maffione 	for (c = 0; c < n ; c++, ri++) {
8065c4f8d80SVincenzo Maffione 		/* compute current ring to use */
8075c4f8d80SVincenzo Maffione 		struct netmap_ring *ring;
8085c4f8d80SVincenzo Maffione 		uint32_t i, j, idx;
8095c4f8d80SVincenzo Maffione 		size_t rem;
8105c4f8d80SVincenzo Maffione 
8115c4f8d80SVincenzo Maffione 		if (ri > d->last_tx_ring)
8125c4f8d80SVincenzo Maffione 			ri = d->first_tx_ring;
8135c4f8d80SVincenzo Maffione 		ring = NETMAP_TXRING(d->nifp, ri);
8145c4f8d80SVincenzo Maffione 		rem = size;
8155c4f8d80SVincenzo Maffione 		j = ring->cur;
8165c4f8d80SVincenzo Maffione 		while (rem > ring->nr_buf_size && j != ring->tail) {
8175c4f8d80SVincenzo Maffione 			rem -= ring->nr_buf_size;
8185c4f8d80SVincenzo Maffione 			j = nm_ring_next(ring, j);
8195c4f8d80SVincenzo Maffione 		}
8205c4f8d80SVincenzo Maffione 		if (j == ring->tail && rem > 0)
8215c4f8d80SVincenzo Maffione 			continue;
8225c4f8d80SVincenzo Maffione 		i = ring->cur;
8235c4f8d80SVincenzo Maffione 		while (i != j) {
8245c4f8d80SVincenzo Maffione 			idx = ring->slot[i].buf_idx;
8255c4f8d80SVincenzo Maffione 			ring->slot[i].len = ring->nr_buf_size;
8265c4f8d80SVincenzo Maffione 			ring->slot[i].flags = NS_MOREFRAG;
8275c4f8d80SVincenzo Maffione 			nm_pkt_copy(buf, NETMAP_BUF(ring, idx), ring->nr_buf_size);
8285c4f8d80SVincenzo Maffione 			i = nm_ring_next(ring, i);
8295c4f8d80SVincenzo Maffione 			buf = (char *)buf + ring->nr_buf_size;
8305c4f8d80SVincenzo Maffione 		}
8315c4f8d80SVincenzo Maffione 		idx = ring->slot[i].buf_idx;
8325c4f8d80SVincenzo Maffione 		ring->slot[i].len = rem;
8335c4f8d80SVincenzo Maffione 		ring->slot[i].flags = 0;
8345c4f8d80SVincenzo Maffione 		nm_pkt_copy(buf, NETMAP_BUF(ring, idx), rem);
8355c4f8d80SVincenzo Maffione 		ring->head = ring->cur = nm_ring_next(ring, i);
8365c4f8d80SVincenzo Maffione 		d->cur_tx_ring = ri;
8375c4f8d80SVincenzo Maffione 		return size;
8385c4f8d80SVincenzo Maffione 	}
8395c4f8d80SVincenzo Maffione 	return 0; /* fail */
8405c4f8d80SVincenzo Maffione }
841