> From: Randy L Tice [mailto:[email protected]] > Sent: Thursday, 24 September 2026 21.38 > > Add build-time support for optional cache-line-aligned dynamic-field > storage at the end of struct rte_mbuf. > > The mbuf_dynfield3_cnt Meson option sets RTE_MBUF_DYNFIELD3_CNT in > rte_build_config.h. A non-zero value enables the extra area. > > When enabled, dynfield3 is made available to the mbuf dynamic field > allocator and is copied by the generic mbuf dynamic-field copy helper. > This extends the existing Dynamic Mbuf Fields backing storage without > changing the default mbuf layout.
Sorry about not responding to your earlier email... it got drowned in my TODO list. You are absolutely on the right track with this patch! Two high-level comments: 1. Configuration of the field's size. For 32/64 bit CPU architecture independence, please make it configurable by size (in bytes), instead of by count of pointers. Or provide both configuration options (byte size, and pointer count), and calculate the actual size as the sum = sz + cnt * sizeof(uintptr_t). IMHO, it is perfectly reasonable to require that the actual size (i.e. the sum) is a multiple of sizeof(uint64_t). Instead of using the uintptr_t type in the mbuf structure: uintptr_t dynfield3[RTE_MBUF_DYNFIELD3_CNT]; Please use the uint64_t type: uint64_t dynfield3[RTE_MBUF_DYNFIELD3_CNT]; 2. Don't copy dynfield3 on mbuf copy/clone. (Feature creep - optional improvement) I recall you didn't want these dynamic fields to be copied on mbuf copy and clone. You can implement that as follows: Somewhere at the top of rte_mbuf_dyn.h, add: /* Flags for use in struct rte_mbuf_dynfield. */ /** * Isolate the dynamic field to each mbuf. * Do not reset, copy or overwrite it by any operation performed by the mbuf library. */ #define RTE_MBUF_DYN_F_ISOLATE 1 And, in rte_mbuf_dyn.c, in the rte_mbuf_dynfield_register[_offset]() functions, if (params->flags & RTE_MBUF_DYN_F_ISOLATE) is set, use the dynfield3 region for the dynamic field being registered, otherwise use the dynfield1/dynfield2 region. Keep the existing behavior (copy on copy/clone) for the existing "normal" dynamic fields stored in dynfield1/dynfield2 region, i.e. copy them on mbuf copy/clone operations. And use the dynfield3 region exclusively for "isolated" dynamic fields; do not reset or copy the mbuf's dynfield3 array anywhere in the mbuf library. By reserving fixed regions in the mbuf for respectively "normal" and "isolated" dynamic fields, the mbuf library can perform mbuf copy/clone operations without having to go through the list of dynamic fields to determine if each field must be copied or not. If you implement this "isolation" detail, maybe you can come up with a more saying name than "dynfield3", e.g. "dynfield_isolated". -Morten > > Validate that the configured element count is non-negative and that the > reserved space is a multiple of the cache line size. > > Signed-off-by: Randy L Tice <[email protected]> > --- > app/test/test_mbuf.c | 5 +++-- > config/meson.build | 10 ++++++++++ > doc/guides/rel_notes/release_26_11.rst | 15 +++++++++++++++ > lib/mbuf/rte_mbuf.h | 3 +++ > lib/mbuf/rte_mbuf_core.h | 16 ++++++++++++++++ > lib/mbuf/rte_mbuf_dyn.c | 3 +++ > meson_options.txt | 2 ++ > 7 files changed, 52 insertions(+), 2 deletions(-) > > diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c > index db23259745..9f3b396a61 100644 > --- a/app/test/test_mbuf.c > +++ b/app/test/test_mbuf.c > @@ -2776,8 +2776,9 @@ test_mbuf(void) > struct rte_mempool *pktmbuf_pool = NULL; > struct rte_mempool *pktmbuf_pool2 = NULL; > > - > - RTE_BUILD_BUG_ON(sizeof(struct rte_mbuf) != > RTE_CACHE_LINE_MIN_SIZE * 2); > + RTE_BUILD_BUG_ON(sizeof(struct rte_mbuf) != > + RTE_CACHE_LINE_MIN_SIZE * 2 + > + RTE_MBUF_DYNFIELD3_SIZE); > > /* create pktmbuf pool if it does not exist */ > pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool", > diff --git a/config/meson.build b/config/meson.build > index 344f68822b..e500a7b075 100644 > --- a/config/meson.build > +++ b/config/meson.build > @@ -384,6 +384,11 @@ dpdk_conf.set('RTE_LIBEAL_USE_HPET', > get_option('use_hpet')) > dpdk_conf.set('RTE_ENABLE_STDATOMIC', get_option('enable_stdatomic')) > dpdk_conf.set('RTE_ENABLE_TRACE_FP', get_option('enable_trace_fp')) > dpdk_conf.set('RTE_PKTMBUF_HEADROOM', get_option('pkt_mbuf_headroom')) > +mbuf_dynfield3_cnt = get_option('mbuf_dynfield3_cnt') > +if mbuf_dynfield3_cnt < 0 > + error('mbuf_dynfield3_cnt must be greater than or equal to 0') > +endif > +dpdk_conf.set('RTE_MBUF_DYNFIELD3_CNT', mbuf_dynfield3_cnt) > # values which have defaults which may be overridden > dpdk_conf.set('RTE_MAX_VFIO_GROUPS', 64) > dpdk_conf.set('RTE_DRIVER_MEMPOOL_BUCKET_SIZE_KB', 64) > @@ -395,6 +400,11 @@ dpdk_conf.set10('RTE_IOVA_IN_MBUF', > get_option('enable_iova_as_pa')) > > compile_time_cpuflags = [] > subdir(arch_subdir) > +mbuf_dynfield3_size = mbuf_dynfield3_cnt * cc.sizeof('uintptr_t', > + prefix: '#include <stdint.h>') > +if mbuf_dynfield3_size % dpdk_conf.get('RTE_CACHE_LINE_SIZE') != 0 > + error('mbuf_dynfield3_cnt must reserve a multiple of > RTE_CACHE_LINE_SIZE') > +endif > dpdk_conf.set('RTE_COMPILE_TIME_CPUFLAGS', > ','.join(compile_time_cpuflags)) > > # apply cross-specific options > diff --git a/doc/guides/rel_notes/release_26_11.rst > b/doc/guides/rel_notes/release_26_11.rst > index dec96ccbc7..abe82e7e3f 100644 > --- a/doc/guides/rel_notes/release_26_11.rst > +++ b/doc/guides/rel_notes/release_26_11.rst > @@ -60,6 +60,13 @@ New Features > Added the experimental ``rte_cpu_socket_id()`` function > to map an OS logical CPU ID to the NUMA socket containing that CPU. > > +* **Added optional extra mbuf dynamic-field storage.** > + > + Added ``mbuf_dynfield3_cnt`` build option to reserve a > + cache-line-aligned ``dynfield3`` area in ``struct rte_mbuf``. > + The value is defined as ``RTE_MBUF_DYNFIELD3_CNT`` in > + ``rte_build_config.h``; a non-zero value enables the extra area. > + > * **Added TPID support to VLAN tag insertion.** > > Added ``rte_vlan_insert_tpid()`` to the net library. > @@ -338,6 +345,14 @@ Known Issues > Also, make sure to start the actual text at the margin. > ======================================================= > > +* **Some drivers may require changes for enlarged mbufs.** > + > + Enabling ``mbuf_dynfield3_cnt`` with a non-zero value increases > + ``sizeof(struct rte_mbuf)``. Drivers or applications that assume a > + fixed mbuf size may require follow-up changes. The > + ``mempool/octeontx`` driver currently asserts that > + ``sizeof(struct rte_mbuf)`` does not exceed its fixed buffer offset. > + > > Tested Platforms > ---------------- > diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h > index 60ec8158cd..6a567a9e43 100644 > --- a/lib/mbuf/rte_mbuf.h > +++ b/lib/mbuf/rte_mbuf.h > @@ -1231,6 +1231,9 @@ rte_mbuf_dynfield_copy(struct rte_mbuf *mdst, > const struct rte_mbuf *msrc) > mdst->dynfield2 = msrc->dynfield2; > #endif > memcpy(&mdst->dynfield1, msrc->dynfield1, sizeof(mdst- > >dynfield1)); > +#if RTE_MBUF_DYNFIELD3_CNT > 0 > + memcpy(&mdst->dynfield3, msrc->dynfield3, sizeof(mdst- > >dynfield3)); > +#endif > } > > /* internal */ > diff --git a/lib/mbuf/rte_mbuf_core.h b/lib/mbuf/rte_mbuf_core.h > index 98b0bd9ca7..bb57397bb6 100644 > --- a/lib/mbuf/rte_mbuf_core.h > +++ b/lib/mbuf/rte_mbuf_core.h > @@ -17,6 +17,7 @@ > */ > > #include <stdalign.h> > +#include <stddef.h> > #include <stdint.h> > > #include <rte_byteorder.h> > @@ -686,8 +687,23 @@ struct __rte_cache_aligned rte_mbuf { > uint16_t timesync; > > uint32_t dynfield1[9]; /**< Reserved for dynamic fields. */ > + > +#if RTE_MBUF_DYNFIELD3_CNT > 0 > + alignas(RTE_CACHE_LINE_SIZE) > + uintptr_t dynfield3[RTE_MBUF_DYNFIELD3_CNT]; > + /**< Reserved for dynamic fields. */ > +#endif /* RTE_MBUF_DYNFIELD3_CNT > 0 */ > }; > > +#define RTE_MBUF_DYNFIELD3_SIZE \ > + (RTE_MBUF_DYNFIELD3_CNT * sizeof(uintptr_t)) > +#if RTE_MBUF_DYNFIELD3_CNT > 0 > +#define RTE_MBUF_DYNFIELD3_OFFSET \ > + offsetof(struct rte_mbuf, dynfield3) > +#else > +#define RTE_MBUF_DYNFIELD3_OFFSET 0 > +#endif > + > /** > * Function typedef of callback to free externally attached buffer. > */ > diff --git a/lib/mbuf/rte_mbuf_dyn.c b/lib/mbuf/rte_mbuf_dyn.c > index 5987c9dee8..dcbe0a8416 100644 > --- a/lib/mbuf/rte_mbuf_dyn.c > +++ b/lib/mbuf/rte_mbuf_dyn.c > @@ -135,6 +135,9 @@ init_shared_mem(void) > #if !RTE_IOVA_IN_MBUF > mark_free(dynfield2); > #endif > +#if RTE_MBUF_DYNFIELD3_CNT > 0 > + mark_free(dynfield3); > +#endif > > /* init free_flags */ > for (mask = RTE_MBUF_F_FIRST_FREE; mask <= > RTE_MBUF_F_LAST_FREE; mask <<= 1) > diff --git a/meson_options.txt b/meson_options.txt > index e28d24054c..337f9e5e49 100644 > --- a/meson_options.txt > +++ b/meson_options.txt > @@ -44,6 +44,8 @@ option('max_numa_nodes', type: 'string', value: > 'default', description: > 'Set the highest NUMA node supported by EAL; "default" is > different per-arch, "detect" detects the highest NUMA node on the build > machine.') > option('enable_iova_as_pa', type: 'boolean', value: true, description: > 'Support the use of physical addresses for IO addresses, such > as used by UIO or VFIO in no-IOMMU mode. When disabled, DPDK can only > run with IOMMU support for address mappings, but will have more space > available in the mbuf structure.') > +option('mbuf_dynfield3_cnt', type: 'integer', value: 0, description: > + 'Size of optional extra mbuf dynamic field area, in uintptr_t > units.') > option('mbuf_refcnt_atomic', type: 'boolean', value: true, > description: > 'Atomically access the mbuf refcnt.') > option('platform', type: 'string', value: 'native', description: > -- > 2.35.6

