Skip to content

Commit

Permalink
mbuf: support dynamic fields and flags
Browse files Browse the repository at this point in the history
Many features require to store data inside the mbuf. As the room in mbuf
structure is limited, it is not possible to have a field for each
feature. Also, changing fields in the mbuf structure can break the API
or ABI.

This commit addresses these issues, by enabling the dynamic registration
of fields or flags:

- a dynamic field is a named area in the rte_mbuf structure, with a
  given size (>= 1 byte) and alignment constraint.
- a dynamic flag is a named bit in the rte_mbuf structure.

The typical use case is a PMD that registers space for an offload
feature, when the application requests to enable this feature.  As
the space in mbuf is limited, the space should only be reserved if it
is going to be used (i.e when the application explicitly asks for it).

The registration can be done at any moment, but it is not possible
to unregister fields or flags.

Signed-off-by: Olivier Matz <olivier.matz@6wind.com>
Acked-by: Thomas Monjalon <thomas@monjalon.net>
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
  • Loading branch information
olivier-matz-6wind authored and tmonjalo committed Oct 26, 2019
1 parent 6d3f991 commit 4958ca3
Show file tree
Hide file tree
Showing 10 changed files with 988 additions and 4 deletions.
143 changes: 143 additions & 0 deletions app/test/test_mbuf.c
Expand Up @@ -32,6 +32,7 @@
#include <rte_ether.h>
#include <rte_ip.h>
#include <rte_tcp.h>
#include <rte_mbuf_dyn.h>

#include "test.h"

Expand Down Expand Up @@ -2411,6 +2412,142 @@ test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool *pktmbuf_pool)
return -1;
}

static int
test_mbuf_dyn(struct rte_mempool *pktmbuf_pool)
{
const struct rte_mbuf_dynfield dynfield = {
.name = "test-dynfield",
.size = sizeof(uint8_t),
.align = __alignof__(uint8_t),
.flags = 0,
};
const struct rte_mbuf_dynfield dynfield2 = {
.name = "test-dynfield2",
.size = sizeof(uint16_t),
.align = __alignof__(uint16_t),
.flags = 0,
};
const struct rte_mbuf_dynfield dynfield3 = {
.name = "test-dynfield3",
.size = sizeof(uint8_t),
.align = __alignof__(uint8_t),
.flags = 0,
};
const struct rte_mbuf_dynfield dynfield_fail_big = {
.name = "test-dynfield-fail-big",
.size = 256,
.align = 1,
.flags = 0,
};
const struct rte_mbuf_dynfield dynfield_fail_align = {
.name = "test-dynfield-fail-align",
.size = 1,
.align = 3,
.flags = 0,
};
const struct rte_mbuf_dynflag dynflag = {
.name = "test-dynflag",
.flags = 0,
};
const struct rte_mbuf_dynflag dynflag2 = {
.name = "test-dynflag2",
.flags = 0,
};
const struct rte_mbuf_dynflag dynflag3 = {
.name = "test-dynflag3",
.flags = 0,
};
struct rte_mbuf *m = NULL;
int offset, offset2, offset3;
int flag, flag2, flag3;
int ret;

printf("Test mbuf dynamic fields and flags\n");
rte_mbuf_dyn_dump(stdout);

offset = rte_mbuf_dynfield_register(&dynfield);
if (offset == -1)
GOTO_FAIL("failed to register dynamic field, offset=%d: %s",
offset, strerror(errno));

ret = rte_mbuf_dynfield_register(&dynfield);
if (ret != offset)
GOTO_FAIL("failed to lookup dynamic field, ret=%d: %s",
ret, strerror(errno));

offset2 = rte_mbuf_dynfield_register(&dynfield2);
if (offset2 == -1 || offset2 == offset || (offset2 & 1))
GOTO_FAIL("failed to register dynamic field 2, offset2=%d: %s",
offset2, strerror(errno));

offset3 = rte_mbuf_dynfield_register_offset(&dynfield3,
offsetof(struct rte_mbuf, dynfield1[1]));
if (offset3 != offsetof(struct rte_mbuf, dynfield1[1]))
GOTO_FAIL("failed to register dynamic field 3, offset=%d: %s",
offset3, strerror(errno));

printf("dynfield: offset=%d, offset2=%d, offset3=%d\n",
offset, offset2, offset3);

ret = rte_mbuf_dynfield_register(&dynfield_fail_big);
if (ret != -1)
GOTO_FAIL("dynamic field creation should fail (too big)");

ret = rte_mbuf_dynfield_register(&dynfield_fail_align);
if (ret != -1)
GOTO_FAIL("dynamic field creation should fail (bad alignment)");

ret = rte_mbuf_dynfield_register_offset(&dynfield_fail_align,
offsetof(struct rte_mbuf, ol_flags));
if (ret != -1)
GOTO_FAIL("dynamic field creation should fail (not avail)");

flag = rte_mbuf_dynflag_register(&dynflag);
if (flag == -1)
GOTO_FAIL("failed to register dynamic flag, flag=%d: %s",
flag, strerror(errno));

ret = rte_mbuf_dynflag_register(&dynflag);
if (ret != flag)
GOTO_FAIL("failed to lookup dynamic flag, ret=%d: %s",
ret, strerror(errno));

flag2 = rte_mbuf_dynflag_register(&dynflag2);
if (flag2 == -1 || flag2 == flag)
GOTO_FAIL("failed to register dynamic flag 2, flag2=%d: %s",
flag2, strerror(errno));

flag3 = rte_mbuf_dynflag_register_bitnum(&dynflag3,
rte_bsf64(PKT_LAST_FREE));
if (flag3 != rte_bsf64(PKT_LAST_FREE))
GOTO_FAIL("failed to register dynamic flag 3, flag2=%d: %s",
flag3, strerror(errno));

printf("dynflag: flag=%d, flag2=%d, flag3=%d\n", flag, flag2, flag3);

/* set, get dynamic field */
m = rte_pktmbuf_alloc(pktmbuf_pool);
if (m == NULL)
GOTO_FAIL("Cannot allocate mbuf");

*RTE_MBUF_DYNFIELD(m, offset, uint8_t *) = 1;
if (*RTE_MBUF_DYNFIELD(m, offset, uint8_t *) != 1)
GOTO_FAIL("failed to read dynamic field");
*RTE_MBUF_DYNFIELD(m, offset2, uint16_t *) = 1000;
if (*RTE_MBUF_DYNFIELD(m, offset2, uint16_t *) != 1000)
GOTO_FAIL("failed to read dynamic field");

/* set a dynamic flag */
m->ol_flags |= (1ULL << flag);

rte_mbuf_dyn_dump(stdout);
rte_pktmbuf_free(m);
return 0;
fail:
rte_pktmbuf_free(m);
return -1;
}

static int
test_mbuf(void)
{
Expand All @@ -2431,6 +2568,12 @@ test_mbuf(void)
goto err;
}

/* test registration of dynamic fields and flags */
if (test_mbuf_dyn(pktmbuf_pool) < 0) {
printf("mbuf dynflag test failed\n");
goto err;
}

/* create a specific pktmbuf pool with a priv_size != 0 and no data
* room size */
pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
Expand Down
7 changes: 7 additions & 0 deletions doc/guides/rel_notes/release_19_11.rst
Expand Up @@ -65,6 +65,13 @@ New Features

The lock-free stack implementation is enabled for aarch64 platforms.

* **Added support of dynamic fields and flags in mbuf.**

This new feature adds the ability to dynamically register some room
for a field or a flag in the mbuf structure. This is typically used
for specific offload features, where adding a static field or flag
in the mbuf is not justified.

* **Updated the enic driver.**

* Added support for Geneve with options offload.
Expand Down
12 changes: 12 additions & 0 deletions lib/librte_eal/common/include/rte_common.h
Expand Up @@ -675,6 +675,18 @@ rte_log2_u64(uint64_t v)
})
#endif

/**
* Get the size of a field in a structure.
*
* @param type
* The type of the structure.
* @param field
* The field in the structure.
* @return
* The size of the field in the structure, in bytes.
*/
#define RTE_SIZEOF_FIELD(type, field) (sizeof(((type *)0)->field))

#define _RTE_STR(x) #x
/** Take a macro value and get a string version of it */
#define RTE_STR(x) _RTE_STR(x)
Expand Down
2 changes: 2 additions & 0 deletions lib/librte_mbuf/Makefile
Expand Up @@ -17,11 +17,13 @@ LIBABIVER := 5

# all source are stored in SRCS-y
SRCS-$(CONFIG_RTE_LIBRTE_MBUF) := rte_mbuf.c rte_mbuf_ptype.c rte_mbuf_pool_ops.c
SRCS-$(CONFIG_RTE_LIBRTE_MBUF) += rte_mbuf_dyn.c

# install includes
SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include := rte_mbuf.h
SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include += rte_mbuf_core.h
SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include += rte_mbuf_ptype.h
SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include += rte_mbuf_pool_ops.h
SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include += rte_mbuf_dyn.h

include $(RTE_SDK)/mk/rte.lib.mk
6 changes: 4 additions & 2 deletions lib/librte_mbuf/meson.build
Expand Up @@ -2,9 +2,11 @@
# Copyright(c) 2017 Intel Corporation

version = 5
sources = files('rte_mbuf.c', 'rte_mbuf_ptype.c', 'rte_mbuf_pool_ops.c')
sources = files('rte_mbuf.c', 'rte_mbuf_ptype.c', 'rte_mbuf_pool_ops.c',
'rte_mbuf_dyn.c')
headers = files('rte_mbuf.h', 'rte_mbuf_core.h',
'rte_mbuf_ptype.h', 'rte_mbuf_pool_ops.h')
'rte_mbuf_ptype.h', 'rte_mbuf_pool_ops.h',
'rte_mbuf_dyn.h')
deps += ['mempool']

allow_experimental_apis = true
15 changes: 15 additions & 0 deletions lib/librte_mbuf/rte_mbuf.h
Expand Up @@ -1000,6 +1000,20 @@ rte_pktmbuf_attach_extbuf(struct rte_mbuf *m, void *buf_addr,
*/
#define rte_pktmbuf_detach_extbuf(m) rte_pktmbuf_detach(m)

/**
* Copy dynamic fields from msrc to mdst.
*
* @param mdst
* The destination mbuf.
* @param msrc
* The source mbuf.
*/
static inline void
rte_mbuf_dynfield_copy(struct rte_mbuf *mdst, const struct rte_mbuf *msrc)
{
memcpy(&mdst->dynfield1, msrc->dynfield1, sizeof(mdst->dynfield1));
}

/* internal */
static inline void
__rte_pktmbuf_copy_hdr(struct rte_mbuf *mdst, const struct rte_mbuf *msrc)
Expand All @@ -1011,6 +1025,7 @@ __rte_pktmbuf_copy_hdr(struct rte_mbuf *mdst, const struct rte_mbuf *msrc)
mdst->hash = msrc->hash;
mdst->packet_type = msrc->packet_type;
mdst->timestamp = msrc->timestamp;
rte_mbuf_dynfield_copy(mdst, msrc);
}

/**
Expand Down
8 changes: 6 additions & 2 deletions lib/librte_mbuf/rte_mbuf_core.h
Expand Up @@ -184,9 +184,12 @@ extern "C" {
#define PKT_RX_OUTER_L4_CKSUM_GOOD (1ULL << 22)
#define PKT_RX_OUTER_L4_CKSUM_INVALID ((1ULL << 21) | (1ULL << 22))

/* add new RX flags here */
/* add new RX flags here, don't forget to update PKT_FIRST_FREE */

/* add new TX flags here */
#define PKT_FIRST_FREE (1ULL << 23)
#define PKT_LAST_FREE (1ULL << 39)

/* add new TX flags here, don't forget to update PKT_LAST_FREE */

/**
* Indicate that the metadata field in the mbuf is in use.
Expand Down Expand Up @@ -689,6 +692,7 @@ struct rte_mbuf {
*/
struct rte_mbuf_ext_shared_info *shinfo;

uint64_t dynfield1[2]; /**< Reserved for dynamic fields. */
} __rte_cache_aligned;

/**
Expand Down

0 comments on commit 4958ca3

Please sign in to comment.