xref: /dpdk/lib/mbuf/rte_mbuf_dyn.c (revision 08966fe7f79fdaa5019b7559eebe84a1e3787b89)
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