1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2019 6WIND S.A.
7 #include <rte_common.h>
9 #include <rte_eal_memconfig.h>
10 #include <rte_tailq.h>
11 #include <rte_errno.h>
12 #include <rte_malloc.h>
13 #include <rte_string_fns.h>
15 #include <rte_mbuf_dyn.h>
17 #define RTE_MBUF_DYN_MZNAME "rte_mbuf_dyn"
19 struct mbuf_dynfield {
20 TAILQ_ENTRY(mbuf_dynfield) next;
21 char name[RTE_MBUF_DYN_NAMESIZE];
27 TAILQ_HEAD(mbuf_dynfield_list, rte_tailq_entry);
29 static struct rte_tailq_elem mbuf_dynfield_tailq = {
30 .name = "RTE_MBUF_DYNFIELD",
32 EAL_REGISTER_TAILQ(mbuf_dynfield_tailq);
35 TAILQ_ENTRY(mbuf_dynflag) next;
36 char name[RTE_MBUF_DYN_NAMESIZE];
39 TAILQ_HEAD(mbuf_dynflag_list, rte_tailq_entry);
41 static struct rte_tailq_elem mbuf_dynflag_tailq = {
42 .name = "RTE_MBUF_DYNFLAG",
44 EAL_REGISTER_TAILQ(mbuf_dynflag_tailq);
47 /** For each mbuf byte, free_space[i] == 1 if space is free. */
48 uint8_t free_space[sizeof(struct rte_mbuf)];
49 /** Bitfield of available flags. */
52 static struct mbuf_dyn_shm *shm;
54 /* allocate and initialize the shared memory */
58 const struct rte_memzone *mz;
61 if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
62 mz = rte_memzone_reserve_aligned(RTE_MBUF_DYN_MZNAME,
63 sizeof(struct mbuf_dyn_shm),
67 mz = rte_memzone_lookup(RTE_MBUF_DYN_MZNAME);
74 #define mark_free(field) \
75 memset(&shm->free_space[offsetof(struct rte_mbuf, field)], \
76 0xff, sizeof(((struct rte_mbuf *)0)->field))
78 if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
79 /* init free_space, keep it sync'd with
80 * rte_mbuf_dynfield_copy().
82 memset(shm, 0, sizeof(*shm));
87 for (mask = PKT_FIRST_FREE; mask <= PKT_LAST_FREE; mask <<= 1)
88 shm->free_flags |= mask;
95 /* check if this offset can be used */
97 check_offset(size_t offset, size_t size, size_t align, unsigned int flags)
103 if ((offset & (align - 1)) != 0)
105 if (offset + size > sizeof(struct rte_mbuf))
108 for (i = 0; i < size; i++) {
109 if (!shm->free_space[i + offset])
116 /* assume tailq is locked */
117 static struct mbuf_dynfield *
118 __mbuf_dynfield_lookup(const char *name)
120 struct mbuf_dynfield_list *mbuf_dynfield_list;
121 struct mbuf_dynfield *mbuf_dynfield;
122 struct rte_tailq_entry *te;
124 mbuf_dynfield_list = RTE_TAILQ_CAST(
125 mbuf_dynfield_tailq.head, mbuf_dynfield_list);
127 TAILQ_FOREACH(te, mbuf_dynfield_list, next) {
128 mbuf_dynfield = (struct mbuf_dynfield *)te->data;
129 if (strncmp(name, mbuf_dynfield->name,
130 RTE_MBUF_DYN_NAMESIZE) == 0)
139 return mbuf_dynfield;
143 rte_mbuf_dynfield_lookup(const char *name, size_t *size, size_t *align)
145 struct mbuf_dynfield *mbuf_dynfield;
152 rte_mcfg_tailq_read_lock();
153 mbuf_dynfield = __mbuf_dynfield_lookup(name);
154 rte_mcfg_tailq_read_unlock();
156 if (mbuf_dynfield == NULL) {
162 *size = mbuf_dynfield->size;
164 *align = mbuf_dynfield->align;
166 return mbuf_dynfield->offset;
170 rte_mbuf_dynfield_register(const char *name, size_t size, size_t align,
173 struct mbuf_dynfield_list *mbuf_dynfield_list;
174 struct mbuf_dynfield *mbuf_dynfield = NULL;
175 struct rte_tailq_entry *te = NULL;
179 if (shm == NULL && init_shared_mem() < 0)
181 if (size >= sizeof(struct rte_mbuf)) {
185 if (!rte_is_power_of_2(align)) {
190 rte_mcfg_tailq_write_lock();
192 mbuf_dynfield = __mbuf_dynfield_lookup(name);
193 if (mbuf_dynfield != NULL) {
194 if (mbuf_dynfield->size != size ||
195 mbuf_dynfield->align != align ||
196 mbuf_dynfield->flags != flags) {
200 offset = mbuf_dynfield->offset;
204 if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
210 offset < (int)sizeof(struct rte_mbuf);
212 if (check_offset(offset, size, align, flags) == 0)
216 if (offset == sizeof(struct rte_mbuf)) {
221 mbuf_dynfield_list = RTE_TAILQ_CAST(
222 mbuf_dynfield_tailq.head, mbuf_dynfield_list);
224 te = rte_zmalloc("MBUF_DYNFIELD_TAILQ_ENTRY", sizeof(*te), 0);
228 mbuf_dynfield = rte_zmalloc("mbuf_dynfield", sizeof(*mbuf_dynfield), 0);
229 if (mbuf_dynfield == NULL)
232 ret = strlcpy(mbuf_dynfield->name, name, sizeof(mbuf_dynfield->name));
233 if (ret < 0 || ret >= (int)sizeof(mbuf_dynfield->name)) {
234 rte_errno = ENAMETOOLONG;
237 mbuf_dynfield->size = size;
238 mbuf_dynfield->align = align;
239 mbuf_dynfield->flags = flags;
240 mbuf_dynfield->offset = offset;
241 te->data = mbuf_dynfield;
243 TAILQ_INSERT_TAIL(mbuf_dynfield_list, te, next);
245 for (i = offset; i < offset + size; i++)
246 shm->free_space[i] = 0;
249 rte_mcfg_tailq_write_unlock();
254 rte_mcfg_tailq_write_unlock();
256 rte_free(mbuf_dynfield);
261 /* assume tailq is locked */
262 static struct mbuf_dynflag *
263 __mbuf_dynflag_lookup(const char *name)
265 struct mbuf_dynflag_list *mbuf_dynflag_list;
266 struct mbuf_dynflag *mbuf_dynflag;
267 struct rte_tailq_entry *te;
269 mbuf_dynflag_list = RTE_TAILQ_CAST(
270 mbuf_dynflag_tailq.head, mbuf_dynflag_list);
272 TAILQ_FOREACH(te, mbuf_dynflag_list, next) {
273 mbuf_dynflag = (struct mbuf_dynflag *)te->data;
274 if (strncmp(name, mbuf_dynflag->name,
275 RTE_MBUF_DYN_NAMESIZE) == 0)
288 rte_mbuf_dynflag_lookup(const char *name)
290 struct mbuf_dynflag *mbuf_dynflag;
297 rte_mcfg_tailq_read_lock();
298 mbuf_dynflag = __mbuf_dynflag_lookup(name);
299 rte_mcfg_tailq_read_unlock();
301 if (mbuf_dynflag == NULL) {
306 return mbuf_dynflag->bitnum;
310 rte_mbuf_dynflag_register(const char *name)
312 struct mbuf_dynflag_list *mbuf_dynflag_list;
313 struct mbuf_dynflag *mbuf_dynflag = NULL;
314 struct rte_tailq_entry *te = NULL;
317 if (shm == NULL && init_shared_mem() < 0)
320 rte_mcfg_tailq_write_lock();
322 mbuf_dynflag = __mbuf_dynflag_lookup(name);
323 if (mbuf_dynflag != NULL) {
324 bitnum = mbuf_dynflag->bitnum;
328 if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
333 if (shm->free_flags == 0) {
337 bitnum = rte_bsf64(shm->free_flags);
339 mbuf_dynflag_list = RTE_TAILQ_CAST(
340 mbuf_dynflag_tailq.head, mbuf_dynflag_list);
342 te = rte_zmalloc("MBUF_DYNFLAG_TAILQ_ENTRY", sizeof(*te), 0);
346 mbuf_dynflag = rte_zmalloc("mbuf_dynflag", sizeof(*mbuf_dynflag), 0);
347 if (mbuf_dynflag == NULL)
350 ret = strlcpy(mbuf_dynflag->name, name, sizeof(mbuf_dynflag->name));
351 if (ret < 0 || ret >= (int)sizeof(mbuf_dynflag->name)) {
352 rte_errno = ENAMETOOLONG;
355 mbuf_dynflag->bitnum = bitnum;
356 te->data = mbuf_dynflag;
358 TAILQ_INSERT_TAIL(mbuf_dynflag_list, te, next);
360 shm->free_flags &= ~(1ULL << bitnum);
363 rte_mcfg_tailq_write_unlock();
368 rte_mcfg_tailq_write_unlock();
370 rte_free(mbuf_dynflag);