199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright 2019 6WIND S.A.
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
5*08966fe7STyler Retzlaff #include <stdalign.h>
699a2dd95SBruce Richardson #include <sys/queue.h>
799a2dd95SBruce Richardson #include <stdint.h>
899a2dd95SBruce Richardson #include <limits.h>
999a2dd95SBruce Richardson
1099a2dd95SBruce Richardson #include <rte_common.h>
1199a2dd95SBruce Richardson #include <rte_eal.h>
1299a2dd95SBruce Richardson #include <rte_eal_memconfig.h>
1399a2dd95SBruce Richardson #include <rte_tailq.h>
1499a2dd95SBruce Richardson #include <rte_errno.h>
1599a2dd95SBruce Richardson #include <rte_malloc.h>
1699a2dd95SBruce Richardson #include <rte_string_fns.h>
1799a2dd95SBruce Richardson #include <rte_bitops.h>
1899a2dd95SBruce Richardson #include <rte_mbuf.h>
1999a2dd95SBruce Richardson #include <rte_mbuf_dyn.h>
2099a2dd95SBruce Richardson
21e906c931SStephen Hemminger #include "mbuf_log.h"
22e906c931SStephen Hemminger
2399a2dd95SBruce Richardson #define RTE_MBUF_DYN_MZNAME "rte_mbuf_dyn"
2499a2dd95SBruce Richardson
2599a2dd95SBruce Richardson struct mbuf_dynfield_elt {
2699a2dd95SBruce Richardson struct rte_mbuf_dynfield params;
2799a2dd95SBruce Richardson size_t offset;
2899a2dd95SBruce Richardson };
2999a2dd95SBruce Richardson TAILQ_HEAD(mbuf_dynfield_list, rte_tailq_entry);
3099a2dd95SBruce Richardson
3199a2dd95SBruce Richardson static struct rte_tailq_elem mbuf_dynfield_tailq = {
3299a2dd95SBruce Richardson .name = "RTE_MBUF_DYNFIELD",
3399a2dd95SBruce Richardson };
3499a2dd95SBruce Richardson EAL_REGISTER_TAILQ(mbuf_dynfield_tailq);
3599a2dd95SBruce Richardson
3699a2dd95SBruce Richardson struct mbuf_dynflag_elt {
3799a2dd95SBruce Richardson struct rte_mbuf_dynflag params;
3899a2dd95SBruce Richardson unsigned int bitnum;
3999a2dd95SBruce Richardson };
4099a2dd95SBruce Richardson TAILQ_HEAD(mbuf_dynflag_list, rte_tailq_entry);
4199a2dd95SBruce Richardson
4299a2dd95SBruce Richardson static struct rte_tailq_elem mbuf_dynflag_tailq = {
4399a2dd95SBruce Richardson .name = "RTE_MBUF_DYNFLAG",
4499a2dd95SBruce Richardson };
4599a2dd95SBruce Richardson EAL_REGISTER_TAILQ(mbuf_dynflag_tailq);
4699a2dd95SBruce Richardson
4799a2dd95SBruce Richardson struct mbuf_dyn_shm {
4899a2dd95SBruce Richardson /**
4999a2dd95SBruce Richardson * For each mbuf byte, free_space[i] != 0 if space is free.
5099a2dd95SBruce Richardson * The value is the size of the biggest aligned element that
5199a2dd95SBruce Richardson * can fit in the zone.
5299a2dd95SBruce Richardson */
5399a2dd95SBruce Richardson uint8_t free_space[sizeof(struct rte_mbuf)];
5499a2dd95SBruce Richardson /** Bitfield of available flags. */
5599a2dd95SBruce Richardson uint64_t free_flags;
5699a2dd95SBruce Richardson };
5799a2dd95SBruce Richardson static struct mbuf_dyn_shm *shm;
5899a2dd95SBruce Richardson
5999a2dd95SBruce Richardson /* Set the value of free_space[] according to the size and alignment of
6099a2dd95SBruce Richardson * the free areas. This helps to select the best place when reserving a
6199a2dd95SBruce Richardson * dynamic field. Assume tailq is locked.
6299a2dd95SBruce Richardson */
6399a2dd95SBruce Richardson static void
process_score(void)6499a2dd95SBruce Richardson process_score(void)
6599a2dd95SBruce Richardson {
6699a2dd95SBruce Richardson size_t off, align, size, i;
6799a2dd95SBruce Richardson
6899a2dd95SBruce Richardson /* first, erase previous info */
6999a2dd95SBruce Richardson for (i = 0; i < sizeof(struct rte_mbuf); i++) {
7099a2dd95SBruce Richardson if (shm->free_space[i])
7199a2dd95SBruce Richardson shm->free_space[i] = 1;
7299a2dd95SBruce Richardson }
7399a2dd95SBruce Richardson
7499a2dd95SBruce Richardson off = 0;
7599a2dd95SBruce Richardson while (off < sizeof(struct rte_mbuf)) {
7699a2dd95SBruce Richardson /* get the size of the free zone */
7799a2dd95SBruce Richardson for (size = 0; (off + size) < sizeof(struct rte_mbuf) &&
7899a2dd95SBruce Richardson shm->free_space[off + size]; size++)
7999a2dd95SBruce Richardson ;
8099a2dd95SBruce Richardson if (size == 0) {
8199a2dd95SBruce Richardson off++;
8299a2dd95SBruce Richardson continue;
8399a2dd95SBruce Richardson }
8499a2dd95SBruce Richardson
8599a2dd95SBruce Richardson /* get the alignment of biggest object that can fit in
8699a2dd95SBruce Richardson * the zone at this offset.
8799a2dd95SBruce Richardson */
8899a2dd95SBruce Richardson for (align = 1;
8999a2dd95SBruce Richardson (off % (align << 1)) == 0 && (align << 1) <= size;
9099a2dd95SBruce Richardson align <<= 1)
9199a2dd95SBruce Richardson ;
9299a2dd95SBruce Richardson
9399a2dd95SBruce Richardson /* save it in free_space[] */
9499a2dd95SBruce Richardson for (i = off; i < off + align; i++)
9599a2dd95SBruce Richardson shm->free_space[i] = RTE_MAX(align, shm->free_space[i]);
9699a2dd95SBruce Richardson
9799a2dd95SBruce Richardson off += align;
9899a2dd95SBruce Richardson }
9999a2dd95SBruce Richardson }
10099a2dd95SBruce Richardson
10199a2dd95SBruce Richardson /* Mark the area occupied by a mbuf field as available in the shm. */
10299a2dd95SBruce Richardson #define mark_free(field) \
10399a2dd95SBruce Richardson memset(&shm->free_space[offsetof(struct rte_mbuf, field)], \
10499a2dd95SBruce Richardson 1, sizeof(((struct rte_mbuf *)0)->field))
10599a2dd95SBruce Richardson
10699a2dd95SBruce Richardson /* Allocate and initialize the shared memory. Assume tailq is locked */
10799a2dd95SBruce Richardson static int
init_shared_mem(void)10899a2dd95SBruce Richardson init_shared_mem(void)
10999a2dd95SBruce Richardson {
11099a2dd95SBruce Richardson const struct rte_memzone *mz;
11199a2dd95SBruce Richardson uint64_t mask;
11299a2dd95SBruce Richardson
11399a2dd95SBruce Richardson if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
11499a2dd95SBruce Richardson mz = rte_memzone_reserve_aligned(RTE_MBUF_DYN_MZNAME,
11599a2dd95SBruce Richardson sizeof(struct mbuf_dyn_shm),
11699a2dd95SBruce Richardson SOCKET_ID_ANY, 0,
11799a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE);
11899a2dd95SBruce Richardson } else {
11999a2dd95SBruce Richardson mz = rte_memzone_lookup(RTE_MBUF_DYN_MZNAME);
12099a2dd95SBruce Richardson }
121d4902ed3SChengwen Feng if (mz == NULL) {
122ae67895bSDavid Marchand MBUF_LOG(ERR, "Failed to get mbuf dyn shared memory");
12399a2dd95SBruce Richardson return -1;
124d4902ed3SChengwen Feng }
12599a2dd95SBruce Richardson
12699a2dd95SBruce Richardson shm = mz->addr;
12799a2dd95SBruce Richardson
12899a2dd95SBruce Richardson if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
12999a2dd95SBruce Richardson /* init free_space, keep it sync'd with
13099a2dd95SBruce Richardson * rte_mbuf_dynfield_copy().
13199a2dd95SBruce Richardson */
13299a2dd95SBruce Richardson memset(shm, 0, sizeof(*shm));
13399a2dd95SBruce Richardson mark_free(dynfield1);
134d5d9e8feSThomas Monjalon #if !RTE_IOVA_IN_MBUF
13503b57eb7SShijith Thotton mark_free(dynfield2);
13603b57eb7SShijith Thotton #endif
13799a2dd95SBruce Richardson
13899a2dd95SBruce Richardson /* init free_flags */
139daa02b5cSOlivier Matz for (mask = RTE_MBUF_F_FIRST_FREE; mask <= RTE_MBUF_F_LAST_FREE; mask <<= 1)
14099a2dd95SBruce Richardson shm->free_flags |= mask;
14199a2dd95SBruce Richardson
14299a2dd95SBruce Richardson process_score();
14399a2dd95SBruce Richardson }
14499a2dd95SBruce Richardson
14599a2dd95SBruce Richardson return 0;
14699a2dd95SBruce Richardson }
14799a2dd95SBruce Richardson
14899a2dd95SBruce Richardson /* check if this offset can be used */
14999a2dd95SBruce Richardson static int
check_offset(size_t offset,size_t size,size_t align)15099a2dd95SBruce Richardson check_offset(size_t offset, size_t size, size_t align)
15199a2dd95SBruce Richardson {
15299a2dd95SBruce Richardson size_t i;
15399a2dd95SBruce Richardson
15499a2dd95SBruce Richardson if ((offset & (align - 1)) != 0)
15599a2dd95SBruce Richardson return -1;
15699a2dd95SBruce Richardson if (offset + size > sizeof(struct rte_mbuf))
15799a2dd95SBruce Richardson return -1;
15899a2dd95SBruce Richardson
15999a2dd95SBruce Richardson for (i = 0; i < size; i++) {
16099a2dd95SBruce Richardson if (!shm->free_space[i + offset])
16199a2dd95SBruce Richardson return -1;
16299a2dd95SBruce Richardson }
16399a2dd95SBruce Richardson
16499a2dd95SBruce Richardson return 0;
16599a2dd95SBruce Richardson }
16699a2dd95SBruce Richardson
16799a2dd95SBruce Richardson /* assume tailq is locked */
16899a2dd95SBruce Richardson static struct mbuf_dynfield_elt *
__mbuf_dynfield_lookup(const char * name)16999a2dd95SBruce Richardson __mbuf_dynfield_lookup(const char *name)
17099a2dd95SBruce Richardson {
17199a2dd95SBruce Richardson struct mbuf_dynfield_list *mbuf_dynfield_list;
17299a2dd95SBruce Richardson struct mbuf_dynfield_elt *mbuf_dynfield;
17399a2dd95SBruce Richardson struct rte_tailq_entry *te;
17499a2dd95SBruce Richardson
17599a2dd95SBruce Richardson mbuf_dynfield_list = RTE_TAILQ_CAST(
17699a2dd95SBruce Richardson mbuf_dynfield_tailq.head, mbuf_dynfield_list);
17799a2dd95SBruce Richardson
17899a2dd95SBruce Richardson TAILQ_FOREACH(te, mbuf_dynfield_list, next) {
17999a2dd95SBruce Richardson mbuf_dynfield = (struct mbuf_dynfield_elt *)te->data;
18099a2dd95SBruce Richardson if (strcmp(name, mbuf_dynfield->params.name) == 0)
18199a2dd95SBruce Richardson break;
18299a2dd95SBruce Richardson }
18399a2dd95SBruce Richardson
18499a2dd95SBruce Richardson if (te == NULL || mbuf_dynfield == NULL) {
18599a2dd95SBruce Richardson rte_errno = ENOENT;
18699a2dd95SBruce Richardson return NULL;
18799a2dd95SBruce Richardson }
18899a2dd95SBruce Richardson
18999a2dd95SBruce Richardson return mbuf_dynfield;
19099a2dd95SBruce Richardson }
19199a2dd95SBruce Richardson
19299a2dd95SBruce Richardson int
rte_mbuf_dynfield_lookup(const char * name,struct rte_mbuf_dynfield * params)19399a2dd95SBruce Richardson rte_mbuf_dynfield_lookup(const char *name, struct rte_mbuf_dynfield *params)
19499a2dd95SBruce Richardson {
19599a2dd95SBruce Richardson struct mbuf_dynfield_elt *mbuf_dynfield;
19699a2dd95SBruce Richardson
19799a2dd95SBruce Richardson rte_mcfg_tailq_read_lock();
19899a2dd95SBruce Richardson if (shm == NULL && init_shared_mem() < 0)
19999a2dd95SBruce Richardson mbuf_dynfield = NULL;
20099a2dd95SBruce Richardson else
20199a2dd95SBruce Richardson mbuf_dynfield = __mbuf_dynfield_lookup(name);
20299a2dd95SBruce Richardson rte_mcfg_tailq_read_unlock();
20399a2dd95SBruce Richardson
20499a2dd95SBruce Richardson if (mbuf_dynfield == NULL)
20599a2dd95SBruce Richardson return -1;
20699a2dd95SBruce Richardson
20799a2dd95SBruce Richardson if (params != NULL)
20899a2dd95SBruce Richardson memcpy(params, &mbuf_dynfield->params, sizeof(*params));
20999a2dd95SBruce Richardson
21099a2dd95SBruce Richardson return mbuf_dynfield->offset;
21199a2dd95SBruce Richardson }
21299a2dd95SBruce Richardson
mbuf_dynfield_cmp(const struct rte_mbuf_dynfield * params1,const struct rte_mbuf_dynfield * params2)21399a2dd95SBruce Richardson static int mbuf_dynfield_cmp(const struct rte_mbuf_dynfield *params1,
21499a2dd95SBruce Richardson const struct rte_mbuf_dynfield *params2)
21599a2dd95SBruce Richardson {
21699a2dd95SBruce Richardson if (strcmp(params1->name, params2->name))
21799a2dd95SBruce Richardson return -1;
21899a2dd95SBruce Richardson if (params1->size != params2->size)
21999a2dd95SBruce Richardson return -1;
22099a2dd95SBruce Richardson if (params1->align != params2->align)
22199a2dd95SBruce Richardson return -1;
22299a2dd95SBruce Richardson if (params1->flags != params2->flags)
22399a2dd95SBruce Richardson return -1;
22499a2dd95SBruce Richardson return 0;
22599a2dd95SBruce Richardson }
22699a2dd95SBruce Richardson
22799a2dd95SBruce Richardson /* assume tailq is locked */
22899a2dd95SBruce Richardson static int
__rte_mbuf_dynfield_register_offset(const struct rte_mbuf_dynfield * params,size_t req)22999a2dd95SBruce Richardson __rte_mbuf_dynfield_register_offset(const struct rte_mbuf_dynfield *params,
23099a2dd95SBruce Richardson size_t req)
23199a2dd95SBruce Richardson {
23299a2dd95SBruce Richardson struct mbuf_dynfield_list *mbuf_dynfield_list;
23399a2dd95SBruce Richardson struct mbuf_dynfield_elt *mbuf_dynfield = NULL;
23499a2dd95SBruce Richardson struct rte_tailq_entry *te = NULL;
23599a2dd95SBruce Richardson unsigned int best_zone = UINT_MAX;
23699a2dd95SBruce Richardson size_t i, offset;
23799a2dd95SBruce Richardson int ret;
23899a2dd95SBruce Richardson
23999a2dd95SBruce Richardson if (shm == NULL && init_shared_mem() < 0)
24099a2dd95SBruce Richardson return -1;
24199a2dd95SBruce Richardson
24299a2dd95SBruce Richardson mbuf_dynfield = __mbuf_dynfield_lookup(params->name);
24399a2dd95SBruce Richardson if (mbuf_dynfield != NULL) {
24499a2dd95SBruce Richardson if (req != SIZE_MAX && req != mbuf_dynfield->offset) {
24599a2dd95SBruce Richardson rte_errno = EEXIST;
24699a2dd95SBruce Richardson return -1;
24799a2dd95SBruce Richardson }
24899a2dd95SBruce Richardson if (mbuf_dynfield_cmp(params, &mbuf_dynfield->params) < 0) {
24999a2dd95SBruce Richardson rte_errno = EEXIST;
25099a2dd95SBruce Richardson return -1;
25199a2dd95SBruce Richardson }
25299a2dd95SBruce Richardson return mbuf_dynfield->offset;
25399a2dd95SBruce Richardson }
25499a2dd95SBruce Richardson
25599a2dd95SBruce Richardson if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
25699a2dd95SBruce Richardson rte_errno = EPERM;
25799a2dd95SBruce Richardson return -1;
25899a2dd95SBruce Richardson }
25999a2dd95SBruce Richardson
26099a2dd95SBruce Richardson if (req == SIZE_MAX) {
26199a2dd95SBruce Richardson /* Find the best place to put this field: we search the
26299a2dd95SBruce Richardson * lowest value of shm->free_space[offset]: the zones
26399a2dd95SBruce Richardson * containing room for larger fields are kept for later.
26499a2dd95SBruce Richardson */
26599a2dd95SBruce Richardson for (offset = 0;
26699a2dd95SBruce Richardson offset < sizeof(struct rte_mbuf);
26799a2dd95SBruce Richardson offset++) {
26899a2dd95SBruce Richardson if (check_offset(offset, params->size,
26999a2dd95SBruce Richardson params->align) == 0 &&
27099a2dd95SBruce Richardson shm->free_space[offset] < best_zone) {
27199a2dd95SBruce Richardson best_zone = shm->free_space[offset];
27299a2dd95SBruce Richardson req = offset;
27399a2dd95SBruce Richardson }
27499a2dd95SBruce Richardson }
27599a2dd95SBruce Richardson if (req == SIZE_MAX) {
27699a2dd95SBruce Richardson rte_errno = ENOENT;
27799a2dd95SBruce Richardson return -1;
27899a2dd95SBruce Richardson }
27999a2dd95SBruce Richardson } else {
28099a2dd95SBruce Richardson if (check_offset(req, params->size, params->align) < 0) {
28199a2dd95SBruce Richardson rte_errno = EBUSY;
28299a2dd95SBruce Richardson return -1;
28399a2dd95SBruce Richardson }
28499a2dd95SBruce Richardson }
28599a2dd95SBruce Richardson
28699a2dd95SBruce Richardson offset = req;
28799a2dd95SBruce Richardson mbuf_dynfield_list = RTE_TAILQ_CAST(
28899a2dd95SBruce Richardson mbuf_dynfield_tailq.head, mbuf_dynfield_list);
28999a2dd95SBruce Richardson
29099a2dd95SBruce Richardson te = rte_zmalloc("MBUF_DYNFIELD_TAILQ_ENTRY", sizeof(*te), 0);
29199a2dd95SBruce Richardson if (te == NULL) {
29299a2dd95SBruce Richardson rte_errno = ENOMEM;
29399a2dd95SBruce Richardson return -1;
29499a2dd95SBruce Richardson }
29599a2dd95SBruce Richardson
29699a2dd95SBruce Richardson mbuf_dynfield = rte_zmalloc("mbuf_dynfield", sizeof(*mbuf_dynfield), 0);
29799a2dd95SBruce Richardson if (mbuf_dynfield == NULL) {
29899a2dd95SBruce Richardson rte_free(te);
29999a2dd95SBruce Richardson rte_errno = ENOMEM;
30099a2dd95SBruce Richardson return -1;
30199a2dd95SBruce Richardson }
30299a2dd95SBruce Richardson
30399a2dd95SBruce Richardson ret = strlcpy(mbuf_dynfield->params.name, params->name,
30499a2dd95SBruce Richardson sizeof(mbuf_dynfield->params.name));
30599a2dd95SBruce Richardson if (ret < 0 || ret >= (int)sizeof(mbuf_dynfield->params.name)) {
30699a2dd95SBruce Richardson rte_errno = ENAMETOOLONG;
30799a2dd95SBruce Richardson rte_free(mbuf_dynfield);
30899a2dd95SBruce Richardson rte_free(te);
30999a2dd95SBruce Richardson return -1;
31099a2dd95SBruce Richardson }
31199a2dd95SBruce Richardson memcpy(&mbuf_dynfield->params, params, sizeof(mbuf_dynfield->params));
31299a2dd95SBruce Richardson mbuf_dynfield->offset = offset;
31399a2dd95SBruce Richardson te->data = mbuf_dynfield;
31499a2dd95SBruce Richardson
31599a2dd95SBruce Richardson TAILQ_INSERT_TAIL(mbuf_dynfield_list, te, next);
31699a2dd95SBruce Richardson
31799a2dd95SBruce Richardson for (i = offset; i < offset + params->size; i++)
31899a2dd95SBruce Richardson shm->free_space[i] = 0;
31999a2dd95SBruce Richardson process_score();
32099a2dd95SBruce Richardson
321ae67895bSDavid Marchand MBUF_LOG(DEBUG, "Registered dynamic field %s (sz=%zu, al=%zu, fl=0x%x) -> %zd",
32299a2dd95SBruce Richardson params->name, params->size, params->align, params->flags,
32399a2dd95SBruce Richardson offset);
32499a2dd95SBruce Richardson
32599a2dd95SBruce Richardson return offset;
32699a2dd95SBruce Richardson }
32799a2dd95SBruce Richardson
32899a2dd95SBruce Richardson int
rte_mbuf_dynfield_register_offset(const struct rte_mbuf_dynfield * params,size_t req)32999a2dd95SBruce Richardson rte_mbuf_dynfield_register_offset(const struct rte_mbuf_dynfield *params,
33099a2dd95SBruce Richardson size_t req)
33199a2dd95SBruce Richardson {
33299a2dd95SBruce Richardson int ret;
33399a2dd95SBruce Richardson
33499a2dd95SBruce Richardson if (params->size >= sizeof(struct rte_mbuf)) {
33599a2dd95SBruce Richardson rte_errno = EINVAL;
33699a2dd95SBruce Richardson return -1;
33799a2dd95SBruce Richardson }
33899a2dd95SBruce Richardson if (!rte_is_power_of_2(params->align)) {
33999a2dd95SBruce Richardson rte_errno = EINVAL;
34099a2dd95SBruce Richardson return -1;
34199a2dd95SBruce Richardson }
34299a2dd95SBruce Richardson if (params->flags != 0) {
34399a2dd95SBruce Richardson rte_errno = EINVAL;
34499a2dd95SBruce Richardson return -1;
34599a2dd95SBruce Richardson }
34699a2dd95SBruce Richardson
34799a2dd95SBruce Richardson rte_mcfg_tailq_write_lock();
34899a2dd95SBruce Richardson ret = __rte_mbuf_dynfield_register_offset(params, req);
34999a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock();
35099a2dd95SBruce Richardson
35199a2dd95SBruce Richardson return ret;
35299a2dd95SBruce Richardson }
35399a2dd95SBruce Richardson
35499a2dd95SBruce Richardson int
rte_mbuf_dynfield_register(const struct rte_mbuf_dynfield * params)35599a2dd95SBruce Richardson rte_mbuf_dynfield_register(const struct rte_mbuf_dynfield *params)
35699a2dd95SBruce Richardson {
35799a2dd95SBruce Richardson return rte_mbuf_dynfield_register_offset(params, SIZE_MAX);
35899a2dd95SBruce Richardson }
35999a2dd95SBruce Richardson
36099a2dd95SBruce Richardson /* assume tailq is locked */
36199a2dd95SBruce Richardson static struct mbuf_dynflag_elt *
__mbuf_dynflag_lookup(const char * name)36299a2dd95SBruce Richardson __mbuf_dynflag_lookup(const char *name)
36399a2dd95SBruce Richardson {
36499a2dd95SBruce Richardson struct mbuf_dynflag_list *mbuf_dynflag_list;
36599a2dd95SBruce Richardson struct mbuf_dynflag_elt *mbuf_dynflag;
36699a2dd95SBruce Richardson struct rte_tailq_entry *te;
36799a2dd95SBruce Richardson
36899a2dd95SBruce Richardson mbuf_dynflag_list = RTE_TAILQ_CAST(
36999a2dd95SBruce Richardson mbuf_dynflag_tailq.head, mbuf_dynflag_list);
37099a2dd95SBruce Richardson
37199a2dd95SBruce Richardson TAILQ_FOREACH(te, mbuf_dynflag_list, next) {
37299a2dd95SBruce Richardson mbuf_dynflag = (struct mbuf_dynflag_elt *)te->data;
37399a2dd95SBruce Richardson if (strncmp(name, mbuf_dynflag->params.name,
37499a2dd95SBruce Richardson RTE_MBUF_DYN_NAMESIZE) == 0)
37599a2dd95SBruce Richardson break;
37699a2dd95SBruce Richardson }
37799a2dd95SBruce Richardson
37899a2dd95SBruce Richardson if (te == NULL) {
37999a2dd95SBruce Richardson rte_errno = ENOENT;
38099a2dd95SBruce Richardson return NULL;
38199a2dd95SBruce Richardson }
38299a2dd95SBruce Richardson
38399a2dd95SBruce Richardson return mbuf_dynflag;
38499a2dd95SBruce Richardson }
38599a2dd95SBruce Richardson
38699a2dd95SBruce Richardson int
rte_mbuf_dynflag_lookup(const char * name,struct rte_mbuf_dynflag * params)38799a2dd95SBruce Richardson rte_mbuf_dynflag_lookup(const char *name,
38899a2dd95SBruce Richardson struct rte_mbuf_dynflag *params)
38999a2dd95SBruce Richardson {
39099a2dd95SBruce Richardson struct mbuf_dynflag_elt *mbuf_dynflag;
39199a2dd95SBruce Richardson
39299a2dd95SBruce Richardson rte_mcfg_tailq_read_lock();
39399a2dd95SBruce Richardson if (shm == NULL && init_shared_mem() < 0)
39499a2dd95SBruce Richardson mbuf_dynflag = NULL;
39599a2dd95SBruce Richardson else
39699a2dd95SBruce Richardson mbuf_dynflag = __mbuf_dynflag_lookup(name);
39799a2dd95SBruce Richardson rte_mcfg_tailq_read_unlock();
39899a2dd95SBruce Richardson
39999a2dd95SBruce Richardson if (mbuf_dynflag == NULL)
40099a2dd95SBruce Richardson return -1;
40199a2dd95SBruce Richardson
40299a2dd95SBruce Richardson if (params != NULL)
40399a2dd95SBruce Richardson memcpy(params, &mbuf_dynflag->params, sizeof(*params));
40499a2dd95SBruce Richardson
40599a2dd95SBruce Richardson return mbuf_dynflag->bitnum;
40699a2dd95SBruce Richardson }
40799a2dd95SBruce Richardson
mbuf_dynflag_cmp(const struct rte_mbuf_dynflag * params1,const struct rte_mbuf_dynflag * params2)40899a2dd95SBruce Richardson static int mbuf_dynflag_cmp(const struct rte_mbuf_dynflag *params1,
40999a2dd95SBruce Richardson const struct rte_mbuf_dynflag *params2)
41099a2dd95SBruce Richardson {
41199a2dd95SBruce Richardson if (strcmp(params1->name, params2->name))
41299a2dd95SBruce Richardson return -1;
41399a2dd95SBruce Richardson if (params1->flags != params2->flags)
41499a2dd95SBruce Richardson return -1;
41599a2dd95SBruce Richardson return 0;
41699a2dd95SBruce Richardson }
41799a2dd95SBruce Richardson
41899a2dd95SBruce Richardson /* assume tailq is locked */
41999a2dd95SBruce Richardson static int
__rte_mbuf_dynflag_register_bitnum(const struct rte_mbuf_dynflag * params,unsigned int req)42099a2dd95SBruce Richardson __rte_mbuf_dynflag_register_bitnum(const struct rte_mbuf_dynflag *params,
42199a2dd95SBruce Richardson unsigned int req)
42299a2dd95SBruce Richardson {
42399a2dd95SBruce Richardson struct mbuf_dynflag_list *mbuf_dynflag_list;
42499a2dd95SBruce Richardson struct mbuf_dynflag_elt *mbuf_dynflag = NULL;
42599a2dd95SBruce Richardson struct rte_tailq_entry *te = NULL;
42699a2dd95SBruce Richardson unsigned int bitnum;
42799a2dd95SBruce Richardson int ret;
42899a2dd95SBruce Richardson
42999a2dd95SBruce Richardson if (shm == NULL && init_shared_mem() < 0)
43099a2dd95SBruce Richardson return -1;
43199a2dd95SBruce Richardson
43299a2dd95SBruce Richardson mbuf_dynflag = __mbuf_dynflag_lookup(params->name);
43399a2dd95SBruce Richardson if (mbuf_dynflag != NULL) {
43499a2dd95SBruce Richardson if (req != UINT_MAX && req != mbuf_dynflag->bitnum) {
43599a2dd95SBruce Richardson rte_errno = EEXIST;
43699a2dd95SBruce Richardson return -1;
43799a2dd95SBruce Richardson }
43899a2dd95SBruce Richardson if (mbuf_dynflag_cmp(params, &mbuf_dynflag->params) < 0) {
43999a2dd95SBruce Richardson rte_errno = EEXIST;
44099a2dd95SBruce Richardson return -1;
44199a2dd95SBruce Richardson }
44299a2dd95SBruce Richardson return mbuf_dynflag->bitnum;
44399a2dd95SBruce Richardson }
44499a2dd95SBruce Richardson
44599a2dd95SBruce Richardson if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
44699a2dd95SBruce Richardson rte_errno = EPERM;
44799a2dd95SBruce Richardson return -1;
44899a2dd95SBruce Richardson }
44999a2dd95SBruce Richardson
45099a2dd95SBruce Richardson if (req == UINT_MAX) {
45199a2dd95SBruce Richardson if (shm->free_flags == 0) {
45299a2dd95SBruce Richardson rte_errno = ENOENT;
45399a2dd95SBruce Richardson return -1;
45499a2dd95SBruce Richardson }
45599a2dd95SBruce Richardson bitnum = rte_bsf64(shm->free_flags);
45699a2dd95SBruce Richardson } else {
45799a2dd95SBruce Richardson if ((shm->free_flags & (1ULL << req)) == 0) {
45899a2dd95SBruce Richardson rte_errno = EBUSY;
45999a2dd95SBruce Richardson return -1;
46099a2dd95SBruce Richardson }
46199a2dd95SBruce Richardson bitnum = req;
46299a2dd95SBruce Richardson }
46399a2dd95SBruce Richardson
46499a2dd95SBruce Richardson mbuf_dynflag_list = RTE_TAILQ_CAST(
46599a2dd95SBruce Richardson mbuf_dynflag_tailq.head, mbuf_dynflag_list);
46699a2dd95SBruce Richardson
46799a2dd95SBruce Richardson te = rte_zmalloc("MBUF_DYNFLAG_TAILQ_ENTRY", sizeof(*te), 0);
46899a2dd95SBruce Richardson if (te == NULL) {
46999a2dd95SBruce Richardson rte_errno = ENOMEM;
47099a2dd95SBruce Richardson return -1;
47199a2dd95SBruce Richardson }
47299a2dd95SBruce Richardson
47399a2dd95SBruce Richardson mbuf_dynflag = rte_zmalloc("mbuf_dynflag", sizeof(*mbuf_dynflag), 0);
47499a2dd95SBruce Richardson if (mbuf_dynflag == NULL) {
47599a2dd95SBruce Richardson rte_free(te);
47699a2dd95SBruce Richardson rte_errno = ENOMEM;
47799a2dd95SBruce Richardson return -1;
47899a2dd95SBruce Richardson }
47999a2dd95SBruce Richardson
48099a2dd95SBruce Richardson ret = strlcpy(mbuf_dynflag->params.name, params->name,
48199a2dd95SBruce Richardson sizeof(mbuf_dynflag->params.name));
48299a2dd95SBruce Richardson if (ret < 0 || ret >= (int)sizeof(mbuf_dynflag->params.name)) {
48399a2dd95SBruce Richardson rte_free(mbuf_dynflag);
48499a2dd95SBruce Richardson rte_free(te);
48599a2dd95SBruce Richardson rte_errno = ENAMETOOLONG;
48699a2dd95SBruce Richardson return -1;
48799a2dd95SBruce Richardson }
48899a2dd95SBruce Richardson mbuf_dynflag->bitnum = bitnum;
48999a2dd95SBruce Richardson te->data = mbuf_dynflag;
49099a2dd95SBruce Richardson
49199a2dd95SBruce Richardson TAILQ_INSERT_TAIL(mbuf_dynflag_list, te, next);
49299a2dd95SBruce Richardson
49399a2dd95SBruce Richardson shm->free_flags &= ~(1ULL << bitnum);
49499a2dd95SBruce Richardson
495ae67895bSDavid Marchand MBUF_LOG(DEBUG, "Registered dynamic flag %s (fl=0x%x) -> %u",
49699a2dd95SBruce Richardson params->name, params->flags, bitnum);
49799a2dd95SBruce Richardson
49899a2dd95SBruce Richardson return bitnum;
49999a2dd95SBruce Richardson }
50099a2dd95SBruce Richardson
50199a2dd95SBruce Richardson int
rte_mbuf_dynflag_register_bitnum(const struct rte_mbuf_dynflag * params,unsigned int req)50299a2dd95SBruce Richardson rte_mbuf_dynflag_register_bitnum(const struct rte_mbuf_dynflag *params,
50399a2dd95SBruce Richardson unsigned int req)
50499a2dd95SBruce Richardson {
50599a2dd95SBruce Richardson int ret;
50699a2dd95SBruce Richardson
507e9123c46SDavid Marchand if (params->flags != 0) {
508e9123c46SDavid Marchand rte_errno = EINVAL;
509e9123c46SDavid Marchand return -1;
510e9123c46SDavid Marchand }
51199a2dd95SBruce Richardson if (req >= RTE_SIZEOF_FIELD(struct rte_mbuf, ol_flags) * CHAR_BIT &&
51299a2dd95SBruce Richardson req != UINT_MAX) {
51399a2dd95SBruce Richardson rte_errno = EINVAL;
51499a2dd95SBruce Richardson return -1;
51599a2dd95SBruce Richardson }
51699a2dd95SBruce Richardson
51799a2dd95SBruce Richardson rte_mcfg_tailq_write_lock();
51899a2dd95SBruce Richardson ret = __rte_mbuf_dynflag_register_bitnum(params, req);
51999a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock();
52099a2dd95SBruce Richardson
52199a2dd95SBruce Richardson return ret;
52299a2dd95SBruce Richardson }
52399a2dd95SBruce Richardson
52499a2dd95SBruce Richardson int
rte_mbuf_dynflag_register(const struct rte_mbuf_dynflag * params)52599a2dd95SBruce Richardson rte_mbuf_dynflag_register(const struct rte_mbuf_dynflag *params)
52699a2dd95SBruce Richardson {
52799a2dd95SBruce Richardson return rte_mbuf_dynflag_register_bitnum(params, UINT_MAX);
52899a2dd95SBruce Richardson }
52999a2dd95SBruce Richardson
rte_mbuf_dyn_dump(FILE * out)53099a2dd95SBruce Richardson void rte_mbuf_dyn_dump(FILE *out)
53199a2dd95SBruce Richardson {
53299a2dd95SBruce Richardson struct mbuf_dynfield_list *mbuf_dynfield_list;
53399a2dd95SBruce Richardson struct mbuf_dynfield_elt *dynfield;
53499a2dd95SBruce Richardson struct mbuf_dynflag_list *mbuf_dynflag_list;
53599a2dd95SBruce Richardson struct mbuf_dynflag_elt *dynflag;
53699a2dd95SBruce Richardson struct rte_tailq_entry *te;
53799a2dd95SBruce Richardson size_t i;
53899a2dd95SBruce Richardson
53999a2dd95SBruce Richardson rte_mcfg_tailq_write_lock();
540c0b48da4SAlexander Bechikov if (shm == NULL && init_shared_mem() < 0) {
541d4902ed3SChengwen Feng rte_mcfg_tailq_write_unlock();
542d4902ed3SChengwen Feng return;
543d4902ed3SChengwen Feng }
544d4902ed3SChengwen Feng
54599a2dd95SBruce Richardson fprintf(out, "Reserved fields:\n");
54699a2dd95SBruce Richardson mbuf_dynfield_list = RTE_TAILQ_CAST(
54799a2dd95SBruce Richardson mbuf_dynfield_tailq.head, mbuf_dynfield_list);
54899a2dd95SBruce Richardson TAILQ_FOREACH(te, mbuf_dynfield_list, next) {
54999a2dd95SBruce Richardson dynfield = (struct mbuf_dynfield_elt *)te->data;
55099a2dd95SBruce Richardson fprintf(out, " name=%s offset=%zd size=%zd align=%zd flags=%x\n",
55199a2dd95SBruce Richardson dynfield->params.name, dynfield->offset,
55299a2dd95SBruce Richardson dynfield->params.size, dynfield->params.align,
55399a2dd95SBruce Richardson dynfield->params.flags);
55499a2dd95SBruce Richardson }
55599a2dd95SBruce Richardson fprintf(out, "Reserved flags:\n");
55699a2dd95SBruce Richardson mbuf_dynflag_list = RTE_TAILQ_CAST(
55799a2dd95SBruce Richardson mbuf_dynflag_tailq.head, mbuf_dynflag_list);
55899a2dd95SBruce Richardson TAILQ_FOREACH(te, mbuf_dynflag_list, next) {
55999a2dd95SBruce Richardson dynflag = (struct mbuf_dynflag_elt *)te->data;
56099a2dd95SBruce Richardson fprintf(out, " name=%s bitnum=%u flags=%x\n",
56199a2dd95SBruce Richardson dynflag->params.name, dynflag->bitnum,
56299a2dd95SBruce Richardson dynflag->params.flags);
56399a2dd95SBruce Richardson }
56499a2dd95SBruce Richardson fprintf(out, "Free space in mbuf (0 = occupied, value = free zone alignment):\n");
56599a2dd95SBruce Richardson for (i = 0; i < sizeof(struct rte_mbuf); i++) {
56699a2dd95SBruce Richardson if ((i % 8) == 0)
56799a2dd95SBruce Richardson fprintf(out, " %4.4zx: ", i);
56899a2dd95SBruce Richardson fprintf(out, "%2.2x%s", shm->free_space[i],
56999a2dd95SBruce Richardson (i % 8 != 7) ? " " : "\n");
57099a2dd95SBruce Richardson }
57199a2dd95SBruce Richardson fprintf(out, "Free bit in mbuf->ol_flags (0 = occupied, 1 = free):\n");
57299a2dd95SBruce Richardson for (i = 0; i < sizeof(uint64_t) * CHAR_BIT; i++) {
57399a2dd95SBruce Richardson if ((i % 8) == 0)
57499a2dd95SBruce Richardson fprintf(out, " %4.4zx: ", i);
57599a2dd95SBruce Richardson fprintf(out, "%1.1x%s", (shm->free_flags & (1ULL << i)) ? 1 : 0,
57699a2dd95SBruce Richardson (i % 8 != 7) ? " " : "\n");
57799a2dd95SBruce Richardson }
57899a2dd95SBruce Richardson
57999a2dd95SBruce Richardson rte_mcfg_tailq_write_unlock();
58099a2dd95SBruce Richardson }
58199a2dd95SBruce Richardson
58299a2dd95SBruce Richardson static int
rte_mbuf_dyn_timestamp_register(int * field_offset,uint64_t * flag,const char * direction,const char * flag_name)58399a2dd95SBruce Richardson rte_mbuf_dyn_timestamp_register(int *field_offset, uint64_t *flag,
58499a2dd95SBruce Richardson const char *direction, const char *flag_name)
58599a2dd95SBruce Richardson {
58699a2dd95SBruce Richardson static const struct rte_mbuf_dynfield field_desc = {
58799a2dd95SBruce Richardson .name = RTE_MBUF_DYNFIELD_TIMESTAMP_NAME,
58899a2dd95SBruce Richardson .size = sizeof(rte_mbuf_timestamp_t),
589*08966fe7STyler Retzlaff .align = alignof(rte_mbuf_timestamp_t),
59099a2dd95SBruce Richardson };
59199a2dd95SBruce Richardson struct rte_mbuf_dynflag flag_desc = {};
59299a2dd95SBruce Richardson int offset;
59399a2dd95SBruce Richardson
59499a2dd95SBruce Richardson offset = rte_mbuf_dynfield_register(&field_desc);
59599a2dd95SBruce Richardson if (offset < 0) {
596ae67895bSDavid Marchand MBUF_LOG(ERR,
597ae67895bSDavid Marchand "Failed to register mbuf field for timestamp");
59899a2dd95SBruce Richardson return -1;
59999a2dd95SBruce Richardson }
60099a2dd95SBruce Richardson if (field_offset != NULL)
60199a2dd95SBruce Richardson *field_offset = offset;
60299a2dd95SBruce Richardson
60399a2dd95SBruce Richardson strlcpy(flag_desc.name, flag_name, sizeof(flag_desc.name));
60499a2dd95SBruce Richardson offset = rte_mbuf_dynflag_register(&flag_desc);
60599a2dd95SBruce Richardson if (offset < 0) {
606ae67895bSDavid Marchand MBUF_LOG(ERR,
607ae67895bSDavid Marchand "Failed to register mbuf flag for %s timestamp",
60899a2dd95SBruce Richardson direction);
60999a2dd95SBruce Richardson return -1;
61099a2dd95SBruce Richardson }
61199a2dd95SBruce Richardson if (flag != NULL)
61299a2dd95SBruce Richardson *flag = RTE_BIT64(offset);
61399a2dd95SBruce Richardson
61499a2dd95SBruce Richardson return 0;
61599a2dd95SBruce Richardson }
61699a2dd95SBruce Richardson
61799a2dd95SBruce Richardson int
rte_mbuf_dyn_rx_timestamp_register(int * field_offset,uint64_t * rx_flag)61899a2dd95SBruce Richardson rte_mbuf_dyn_rx_timestamp_register(int *field_offset, uint64_t *rx_flag)
61999a2dd95SBruce Richardson {
62099a2dd95SBruce Richardson return rte_mbuf_dyn_timestamp_register(field_offset, rx_flag,
62199a2dd95SBruce Richardson "Rx", RTE_MBUF_DYNFLAG_RX_TIMESTAMP_NAME);
62299a2dd95SBruce Richardson }
62399a2dd95SBruce Richardson
62499a2dd95SBruce Richardson int
rte_mbuf_dyn_tx_timestamp_register(int * field_offset,uint64_t * tx_flag)62599a2dd95SBruce Richardson rte_mbuf_dyn_tx_timestamp_register(int *field_offset, uint64_t *tx_flag)
62699a2dd95SBruce Richardson {
62799a2dd95SBruce Richardson return rte_mbuf_dyn_timestamp_register(field_offset, tx_flag,
62899a2dd95SBruce Richardson "Tx", RTE_MBUF_DYNFLAG_TX_TIMESTAMP_NAME);
62999a2dd95SBruce Richardson }
630