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