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