Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Mar 2021 16:41:32 GMT
From:      Vincenzo Maffione <vmaffione@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: f8113f0a65ad - main - libnetmap: add support for the offset features
Message-ID:  <202103291641.12TGfWvb081611@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by vmaffione:

URL: https://cgit.FreeBSD.org/src/commit/?id=f8113f0a65ada9367bcbfa6e0d5d8a8451dd8ac2

commit f8113f0a65ada9367bcbfa6e0d5d8a8451dd8ac2
Author:     Vincenzo Maffione <vmaffione@FreeBSD.org>
AuthorDate: 2021-03-29 16:38:37 +0000
Commit:     Vincenzo Maffione <vmaffione@FreeBSD.org>
CommitDate: 2021-03-29 16:38:37 +0000

    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'
---
 lib/libnetmap/libnetmap.h | 57 +++++++++++++++++++++++++++++++++
 lib/libnetmap/nmctx.c     |  1 +
 lib/libnetmap/nmport.c    | 80 +++++++++++++++++++++++++++++++++++++++++++++--
 lib/libnetmap/nmreq.c     | 21 ++++++-------
 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";
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202103291641.12TGfWvb081611>