DPDK usage discussions
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: "Lombardo, Ed" <Ed.Lombardo@netscout.com>
Cc: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>,
	"users@dpdk.org" <users@dpdk.org>
Subject: Re: mbuf refcnt issue
Date: Wed, 9 Apr 2025 20:25:38 -0700	[thread overview]
Message-ID: <20250409202538.46a08ba8@hermes.local> (raw)
In-Reply-To: <CH3PR01MB847082342280EA95227D9B468FB42@CH3PR01MB8470.prod.exchangelabs.com>

On Wed, 9 Apr 2025 23:22:50 +0000
"Lombardo, Ed" <Ed.Lombardo@netscout.com> wrote:

> Hi,
> I just finished modifying and testing our application to just do transmit of packets received on an NIC interface and let the rte_eth_tx_burst () free the mbuf and all works fine for both traffic types.  This proves to me that my implementation of processing the packets and queueing them to tx ring and transmit from the tx ring is not buggy, which I had carefully verified in gdb early on.  I still believe there is a problem with our application with many threads that can do rte_pktmbuf_free() on the same mbuf.  
> 
> I added these lines in my driver source file:
> #define RTE_LITRTE_MBUF_DEBUG 1
> #define RTE_LIBRTE_MEMPOOL_DEBUG 1
> #define RTE_ENABLE_ASSERT 1
> 
> I don't see any asserts occur during my tx packet testing.
> 
> The dpdk header files show the Atomic ifdef checks
> rte_build_config.h:#define RTE_MBUF_REFCNT_ATOMIC
> rte_mbuf_core.h:                         * or non-atomic) is controlled by the RTE_MBUF_REFCNT_ATOMIC flag.
> rte_mbuf.h:#ifdef RTE_MBUF_REFCNT_ATOMIC
> rte_mbuf.h:#else /* ! RTE_MBUF_REFCNT_ATOMIC */
> rte_mbuf.h:#endif /* RTE_MBUF_REFCNT_ATOMIC */
> 
> I verified in building our application with DPDK rte_mbuf.h header file that the atomic functions for mbuf refcnt read/writes are turned ON.  I added junk characters, and the compiler spotted syntax errors.
> 
> So, I am back to the question as to why I get mbuf issue with multiple threads processing the same mbuf?
> 
> Any more suggestions.
> 
> Thanks,
> Ed
> 
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org> 
> Sent: Wednesday, April 9, 2025 12:24 PM
> To: Lombardo, Ed <Ed.Lombardo@netscout.com>
> Cc: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>; users@dpdk.org
> Subject: Re: mbuf refcnt issue
> 
> External Email: This message originated outside of NETSCOUT. Do not click links or open attachments unless you recognize the sender and know the content is safe.
> 
> On Wed, 9 Apr 2025 04:46:09 +0000
> "Lombardo, Ed" <Ed.Lombardo@netscout.com> wrote:
> 
> > Hi Stephen,
> > I am looking a the rte_mbuf.h file for rte_pktmbuf_free() and it is not clear to me that it checks if the mbuf refcnt is 1 before decrementing it and allowing the mbuf and segments (if any) to be returned to free pool.
> > 
> > Could my application issue be I have tx threads that transmit packets and does rte_pktmbuf_free(), while one other thread will perform rte_pktmbuf_free() on the same mbuf?  I ensured I bump the mbuf refcnt to 2 before other threads can process the same mbuf.
> > 
> > Thanks,
> > Ed  
> 
> It doesn't need to check refcnt there. The check is done later (since mbuf can be multi segment).
> 
> rte_pktmbuf_free
>  -> rte_pktmbuf_free_seg
>     -> rte_pktmbuf_prefree_seg  
> 		
> static __rte_always_inline struct rte_mbuf * rte_pktmbuf_prefree_seg(struct rte_mbuf *m) {
> 	__rte_mbuf_sanity_check(m, 0);
> 
> 	if (likely(rte_mbuf_refcnt_read(m) == 1)) {
>             normal fast path. breaks the chain.
> 	} else if (__rte_mbuf_refcnt_update(m, -1) == 0) {
>             refcnt > 1 logic
> 
> Note, the refcnt doesn't always go to zero when the mbuf is put back in the pool.
> The refcnt for a freed mbuf (in the pool) doesn't matter, it is free, it is dead.
> The refcnt is reset to 1 when mbuf is extracted from the pool.
> 
> 
> 


You might find something by poisoning the mbuf when it is freed, so that any attempt to use
the data would get junk. Also, add check at start of rte_pktmbuf_free_seg() to catch dup free.
Something like this, but only compile tested.
It will break some of the functional tests, because they tend to make bogus dummy mbufs.

diff --git a/lib/mbuf/rte_mbuf.h b/lib/mbuf/rte_mbuf.h
index 06ab7502a5..6088b34506 100644
--- a/lib/mbuf/rte_mbuf.h
+++ b/lib/mbuf/rte_mbuf.h
@@ -1423,10 +1423,11 @@ static inline int __rte_pktmbuf_pinned_extbuf_decref(struct rte_mbuf *m)
 static __rte_always_inline struct rte_mbuf *
 rte_pktmbuf_prefree_seg(struct rte_mbuf *m)
 {
-	__rte_mbuf_sanity_check(m, 0);
 
-	if (likely(rte_mbuf_refcnt_read(m) == 1)) {
+	__rte_mbuf_sanity_check(m, 0);
 
+	unsigned int refcnt = rte_mbuf_refcnt_read(m);
+	if (likely(refcnt == 1)) {
 		if (!RTE_MBUF_DIRECT(m)) {
 			rte_pktmbuf_detach(m);
 			if (RTE_MBUF_HAS_EXTBUF(m) &&
@@ -1435,13 +1436,15 @@ rte_pktmbuf_prefree_seg(struct rte_mbuf *m)
 				return NULL;
 		}
 
+		m->refcnt = 0;
 		if (m->next != NULL)
 			m->next = NULL;
 		if (m->nb_segs != 1)
 			m->nb_segs = 1;
 
 		return m;
-
+	} else if (unlikely(refcnt == 0 || refcnt >= UINT16_MAX - 1)) {
+		rte_panic("mbuf refcnt underflow %u\n", refcnt);
 	} else if (__rte_mbuf_refcnt_update(m, -1) == 0) {
 
 		if (!RTE_MBUF_DIRECT(m)) {
@@ -1452,6 +1455,7 @@ rte_pktmbuf_prefree_seg(struct rte_mbuf *m)
 				return NULL;
 		}
 
+		m->refcnt = 0;
 		if (m->next != NULL)
 			m->next = NULL;
 		if (m->nb_segs != 1)


  reply	other threads:[~2025-04-10  3:25 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-04 22:00 Lombardo, Ed
2025-04-04 22:29 ` Dmitry Kozlyuk
2025-04-07 19:53   ` Lombardo, Ed
2025-04-08 22:33     ` Lombardo, Ed
2025-04-09  3:53       ` Stephen Hemminger
2025-04-09  4:46         ` Lombardo, Ed
2025-04-09 16:24           ` Stephen Hemminger
2025-04-09 23:22             ` Lombardo, Ed
2025-04-10  3:25               ` Stephen Hemminger [this message]
2025-04-10  3:58                 ` Lombardo, Ed
2025-04-10 21:15                   ` Lombardo, Ed
2025-04-15 13:10                     ` Lombardo, Ed
2025-04-16  0:01                       ` Stephen Hemminger
2025-04-16  3:51                         ` Lombardo, Ed
2025-04-09 16:15       ` Lombardo, Ed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250409202538.46a08ba8@hermes.local \
    --to=stephen@networkplumber.org \
    --cc=Ed.Lombardo@netscout.com \
    --cc=dmitry.kozliuk@gmail.com \
    --cc=users@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).