aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincenzo Maffione <vmaffione@FreeBSD.org>2021-03-29 16:38:37 +0000
committerVincenzo Maffione <vmaffione@FreeBSD.org>2021-03-29 16:38:37 +0000
commitf8113f0a65ada9367bcbfa6e0d5d8a8451dd8ac2 (patch)
tree0d956a6900b762f54bd129a636b8468d59e5159b
parent660a47cb991d5a7ca69cd8dd9c09a5288d49e405 (diff)
downloadsrc-f8113f0a65ada9367bcbfa6e0d5d8a8451dd8ac2.tar.gz
src-f8113f0a65ada9367bcbfa6e0d5d8a8451dd8ac2.zip
libnetmap: add support for the offset features
The companion libnetmap changes for the "offsets" kernel support added in a6d768d845c173823785c. This includes code to parse the "@offset=NNN" option that can be appended to the port name by any nmport_* application. Example: # pkt-gen -i 'netmap:em0@offset=16'
-rw-r--r--lib/libnetmap/libnetmap.h57
-rw-r--r--lib/libnetmap/nmctx.c1
-rw-r--r--lib/libnetmap/nmport.c80
-rw-r--r--lib/libnetmap/nmreq.c21
4 files changed, 144 insertions, 15 deletions
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";
}