diff --git a/lib/libnetmap/libnetmap.h b/lib/libnetmap/libnetmap.h index 0367a1735c4f..ff03babc04b1 100644 --- a/lib/libnetmap/libnetmap.h +++ b/lib/libnetmap/libnetmap.h @@ -151,6 +151,22 @@ struct nmem_d; * causing netmap to take the corresponding values from * the priv_{if,ring,buf}_{num,size} sysctls. * + * offset (multi-key) + * reserve (part of) the ptr fields as an offset field + * and write an initial offset into them. + * + * The keys are: + * + * bits number of bits of ptr to use + * *initial initial offset value + * + * initial must be assigned. If bits is omitted, it + * defaults to the entire ptr field. The max offset is set + * at the same value as the initial offset. Note that the + * actual values may be increased by the kernel. + * + * This option is disabled by default (see + * nmport_enable_option() below) */ @@ -398,6 +414,47 @@ int nmport_extmem_from_file(struct nmport_d *d, const char *fname); struct nmreq_pools_info* nmport_extmem_getinfo(struct nmport_d *d); +/* nmport_offset - use offsets for this port + * @initial the initial offset for all the slots + * @maxoff the maximum offset + * @bits the number of bits of slot->ptr to use for the offsets + * @mingap the minimum gap betwen offsets (in shared buffers) + * + * With this option the lower @bits bits of the ptr field in the netmap_slot + * can be used to specify an offset into the buffer. All offsets will be set + * to the @initial value by netmap. + * + * The offset field can be read and updated using the bitmask found in + * ring->offset_mask after a successful register. netmap_user.h contains + * some helper macros (NETMAP_ROFFSET, NETMAP_WOFFSET and NETMAP_BUF_OFFSET). + * + * For RX rings, the user writes the offset o in an empty slot before passing + * it to netmap; then, netmap will write the incoming packet at an offset o' >= + * o in the buffer. o' may be larger than o because of, e.g., alignment + * constrains. If o' > o netmap will also update the offset field in the slot. + * Note that large offsets may cause the port to split the packet over several + * slots, setting the NS_MOREFRAG flag accordingly. + * + * For TX rings, the user may prepare the packet to send at an offset o into + * the buffer and write o in the offset field. Netmap will send the packets + * starting o bytes in the buffer. Note that the address of the packet must + * comply with any alignment constraints that the port may have, or the result + * will be undefined. The user may read the alignment constraint in the new + * ring->buf_align field. It is also possibile that empty slots already come + * with a non-zero offset o specified in the offset field. In this case, the + * user will have to write the packet at an offset o' >= o. + * + * The user must also declare the @maxoff offset that she is going to use. Any + * offset larger than this will be truncated. + * + * The user may also declare a @mingap (ignored if zero) if she plans to use + * offsets to share the same buffer among several slots. Netmap will guarantee + * that it will never write more than @mingap bytes for each slot, irrespective + * of the buffer length. + */ +int nmport_offset(struct nmport_d *d, uint64_t initial, uint64_t maxoff, + uint64_t bits, uint64_t mingap); + /* enable/disable options * * These functions can be used to disable options that the application cannot diff --git a/lib/libnetmap/nmctx.c b/lib/libnetmap/nmctx.c index 5f2c8c32febd..f5288e58fa9f 100644 --- a/lib/libnetmap/nmctx.c +++ b/lib/libnetmap/nmctx.c @@ -47,6 +47,7 @@ static void nmctx_default_error(struct nmctx *ctx, const char *errmsg) { + (void)ctx; fprintf(stderr, "%s\n", errmsg); } diff --git a/lib/libnetmap/nmport.c b/lib/libnetmap/nmport.c index a3fd7e87100f..58267bd8e9b1 100644 --- a/lib/libnetmap/nmport.c +++ b/lib/libnetmap/nmport.c @@ -178,6 +178,7 @@ struct nmport_extmem_from_file_cleanup_d { void nmport_extmem_from_file_cleanup(struct nmport_cleanup_d *c, struct nmport_d *d) { + (void)d; struct nmport_extmem_from_file_cleanup_d *cc = (struct nmport_extmem_from_file_cleanup_d *)c; @@ -247,6 +248,59 @@ nmport_extmem_getinfo(struct nmport_d *d) return &d->extmem->nro_info; } +struct nmport_offset_cleanup_d { + struct nmport_cleanup_d up; + struct nmreq_opt_offsets *opt; +}; + +static void +nmport_offset_cleanup(struct nmport_cleanup_d *c, + struct nmport_d *d) +{ + struct nmport_offset_cleanup_d *cc = + (struct nmport_offset_cleanup_d *)c; + + nmreq_remove_option(&d->hdr, &cc->opt->nro_opt); + nmctx_free(d->ctx, cc->opt); +} + +int +nmport_offset(struct nmport_d *d, uint64_t initial, + uint64_t maxoff, uint64_t bits, uint64_t mingap) +{ + struct nmctx *ctx = d->ctx; + struct nmreq_opt_offsets *opt; + struct nmport_offset_cleanup_d *clnup = NULL; + + clnup = nmctx_malloc(ctx, sizeof(*clnup)); + if (clnup == NULL) { + nmctx_ferror(ctx, "cannot allocate cleanup descriptor"); + errno = ENOMEM; + return -1; + } + + opt = nmctx_malloc(ctx, sizeof(*opt)); + if (opt == NULL) { + nmctx_ferror(ctx, "%s: cannot allocate offset option", d->hdr.nr_name); + nmctx_free(ctx, clnup); + errno = ENOMEM; + return -1; + } + memset(opt, 0, sizeof(*opt)); + opt->nro_opt.nro_reqtype = NETMAP_REQ_OPT_OFFSETS; + opt->nro_offset_bits = bits; + opt->nro_initial_offset = initial; + opt->nro_max_offset = maxoff; + opt->nro_min_gap = mingap; + nmreq_push_option(&d->hdr, &opt->nro_opt); + + clnup->up.cleanup = nmport_offset_cleanup; + clnup->opt = opt; + nmport_push_cleanup(d, &clnup->up); + + return 0; +} + /* head of the list of options */ static struct nmreq_opt_parser *nmport_opt_parsers; @@ -327,6 +381,9 @@ NPOPT_DECL(conf, 0) NPKEY_DECL(conf, host_rx_rings, 0) NPKEY_DECL(conf, tx_slots, 0) NPKEY_DECL(conf, rx_slots, 0) +NPOPT_DECL(offset, NMREQ_OPTF_DISABLED) + NPKEY_DECL(offset, initial, NMREQ_OPTK_DEFAULT|NMREQ_OPTK_MUSTSET) + NPKEY_DECL(offset, bits, 0) static int @@ -432,6 +489,23 @@ NPOPT_PARSER(conf)(struct nmreq_parse_ctx *p) return 0; } +static int +NPOPT_PARSER(offset)(struct nmreq_parse_ctx *p) +{ + struct nmport_d *d; + uint64_t initial, bits; + + d = p->token; + + initial = atoi(nmport_key(p, offset, initial)); + bits = 0; + if (nmport_key(p, offset, bits) != NULL) + bits = atoi(nmport_key(p, offset, bits)); + + return nmport_offset(d, initial, initial, bits, 0); +} + + void nmport_disable_option(const char *opt) { @@ -586,7 +660,7 @@ nmport_mmap(struct nmport_d *d) struct nmctx *ctx = d->ctx; struct nmem_d *m = NULL; u_int num_tx, num_rx; - int i; + unsigned int i; if (d->mmap_done) { errno = EINVAL; @@ -643,7 +717,7 @@ nmport_mmap(struct nmport_d *d) num_tx = d->reg.nr_tx_rings + d->nifp->ni_host_tx_rings; for (i = 0; i < num_tx && !d->nifp->ring_ofs[i]; i++) ; - d->first_tx_ring = i; + d->cur_tx_ring = d->first_tx_ring = i; for ( ; i < num_tx && d->nifp->ring_ofs[i]; i++) ; d->last_tx_ring = i - 1; @@ -651,7 +725,7 @@ nmport_mmap(struct nmport_d *d) num_rx = d->reg.nr_rx_rings + d->nifp->ni_host_rx_rings; for (i = 0; i < num_rx && !d->nifp->ring_ofs[i + num_tx]; i++) ; - d->first_rx_ring = i; + d->cur_rx_ring = d->first_rx_ring = i; for ( ; i < num_rx && d->nifp->ring_ofs[i + num_tx]; i++) ; d->last_rx_ring = i - 1; diff --git a/lib/libnetmap/nmreq.c b/lib/libnetmap/nmreq.c index 7f4b2703d22d..39ee53c818c5 100644 --- a/lib/libnetmap/nmreq.c +++ b/lib/libnetmap/nmreq.c @@ -603,9 +603,10 @@ nmreq_options_decode(const char *opt, struct nmreq_opt_parser parsers[], struct nmreq_option * nmreq_find_option(struct nmreq_header *h, uint32_t t) { - struct nmreq_option *o = NULL; + struct nmreq_option *o; - nmreq_foreach_option(h, o) { + for (o = (struct nmreq_option *)h->nr_options; o != NULL; + o = (struct nmreq_option *)o->nro_next) { if (o->nro_reqtype == t) break; } @@ -615,10 +616,10 @@ nmreq_find_option(struct nmreq_header *h, uint32_t t) void nmreq_remove_option(struct nmreq_header *h, struct nmreq_option *o) { - struct nmreq_option **nmo; + struct nmreq_option **nmo; for (nmo = (struct nmreq_option **)&h->nr_options; *nmo != NULL; - nmo = (struct nmreq_option **)&(*nmo)->nro_next) { + nmo = (struct nmreq_option **)&(*nmo)->nro_next) { if (*nmo == o) { *((uint64_t *)(*nmo)) = o->nro_next; o->nro_next = (uint64_t)(uintptr_t)NULL; @@ -632,14 +633,8 @@ nmreq_free_options(struct nmreq_header *h) { struct nmreq_option *o, *next; - /* - * Note: can't use nmreq_foreach_option() here; it frees the - * list as it's walking and nmreq_foreach_option() isn't - * modification-safe. - */ - for (o = (struct nmreq_option *)(uintptr_t)h->nr_options; o != NULL; - o = next) { - next = (struct nmreq_option *)(uintptr_t)o->nro_next; + for (o = (struct nmreq_option *)h->nr_options; o != NULL; o = next) { + next = (struct nmreq_option *)o->nro_next; free(o); } } @@ -656,6 +651,8 @@ nmreq_option_name(uint32_t nro_reqtype) return "csb"; case NETMAP_REQ_OPT_SYNC_KLOOP_MODE: return "sync-kloop-mode"; + case NETMAP_REQ_OPT_OFFSETS: + return "offsets"; default: return "unknown"; }