[v2] app/testpmd: fix testpmd packets dump overlapping

Message ID 1605355308-427475-1-git-send-email-jiaweiw@nvidia.com (mailing list archive)
State Changes Requested, archived
Delegated to: Ferruh Yigit
Headers
Series [v2] app/testpmd: fix testpmd packets dump overlapping |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-testing success Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/travis-robot success Travis build: passed

Commit Message

Jiawei Wang Nov. 14, 2020, 12:01 p.m. UTC
  When testpmd enabled the verbosity for the received packets, if two packets
was received at the same time, for example, sampling packet and normal
packet, the dump output of these packets may be overlapping due to multiple
core handled the multiple queues simultaneously.

The patch uses one string buffer that collects all the packet dump output
into this buffer and then printout it at last, that guarantee to printout
separately the dump output per packet.

Fixes: d862c45 ("app/testpmd: move dumping packets to a separate function")

Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
---
v2:
* Print dump output of per packet instead of per burst.
* Add the checking for return value of 'snprintf' and exit if required size exceed the print buffer size.
* Update the log messages.
---
 app/test-pmd/util.c | 378 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 295 insertions(+), 83 deletions(-)
  

Comments

Ferruh Yigit Nov. 17, 2020, 12:06 p.m. UTC | #1
On 11/14/2020 12:01 PM, Jiawei Wang wrote:
> When testpmd enabled the verbosity for the received packets, if two packets
> was received at the same time, for example, sampling packet and normal
> packet, the dump output of these packets may be overlapping due to multiple
> core handled the multiple queues simultaneously.
> 
> The patch uses one string buffer that collects all the packet dump output
> into this buffer and then printout it at last, that guarantee to printout
> separately the dump output per packet.
> 
> Fixes: d862c45 ("app/testpmd: move dumping packets to a separate function")
> 
> Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
> ---
> v2:
> * Print dump output of per packet instead of per burst.
> * Add the checking for return value of 'snprintf' and exit if required size exceed the print buffer size.
> * Update the log messages.
> ---
>   app/test-pmd/util.c | 378 ++++++++++++++++++++++++++++++++++++++++------------
>   1 file changed, 295 insertions(+), 83 deletions(-)
> 
> diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c
> index 649bf8f..ffae590 100644
> --- a/app/test-pmd/util.c
> +++ b/app/test-pmd/util.c
> @@ -12,15 +12,20 @@
>   #include <rte_vxlan.h>
>   #include <rte_ethdev.h>
>   #include <rte_flow.h>
> +#include <rte_log.h>
>   
>   #include "testpmd.h"
>   
> -static inline void
> -print_ether_addr(const char *what, const struct rte_ether_addr *eth_addr)
> +#define MAX_STRING_LEN 8192

Isn't '8192' too large for a single packet, what do you think for '2048'?

<...>

> @@ -93,95 +103,269 @@
>   		is_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);
>   		ret = rte_flow_get_restore_info(port_id, mb, &info, &error);
>   		if (!ret) {
> -			printf("restore info:");
> +			cur_len += snprintf(print_buf + cur_len,
> +					    buf_size - cur_len,
> +					    "restore info:");

What do you think having a macro like below to simplfy the code:

  #define FOO(buf, buf_size, cur_len, ...) \
  do { \
         if (cur_len >= buf_size) break; \
         cur_len += snprintf(buf + cur_len, buf_size - cur_len, __VA_ARGS__); \
  } while (0)

It can be used as:
  FOO(print_buf, buf_size, cur_len, "restore info:");

> +			if (cur_len >= buf_size)
> +				goto error;

This 'goto' goes out of the loop, not sure about breking the loop and not 
processing all packets if buffer is out of space for one of the packets.
Anyway if you switch to macro above, the 'goto' is removed completely.

<...>

> +		if (cur_len >= buf_size)
> +			goto error;
> +		TESTPMD_LOG(INFO, "%s", print_buf);

Using 'TESTPMD_LOG' appends "testpmd: " at the beggining of the each line, for 
this case it is noise I think, what do you think turning back to printf() as 
done originally?

> +		cur_len = 0;
>   	}
> +	return;
> +error:
> +	TESTPMD_LOG(INFO, "%s the output was truncated ...\n", print_buf);

What do you think having something shorter to notify the truncation, I think 
some special chars can work better, something like "...", "@@", "-->", "???" ?

>   }
>   
>   uint16_t
>
  
Jiawei Wang Nov. 18, 2020, 6:09 p.m. UTC | #2
Hi Ferruh,

> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@intel.com>
> Sent: Tuesday, November 17, 2020 8:07 PM
> To: Jiawei(Jonny) Wang <jiaweiw@nvidia.com>; wenzhuo.lu@intel.com;
> beilei.xing@intel.com; bernard.iremonger@intel.com; Ori Kam
> <orika@nvidia.com>; NBU-Contact-Thomas Monjalon
> <thomas@monjalon.net>; Raslan Darawsheh <rasland@nvidia.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2] app/testpmd: fix testpmd packets dump
> overlapping
> 
> On 11/14/2020 12:01 PM, Jiawei Wang wrote:
> > When testpmd enabled the verbosity for the received packets, if two
> > packets was received at the same time, for example, sampling packet
> > and normal packet, the dump output of these packets may be overlapping
> > due to multiple core handled the multiple queues simultaneously.
> >
> > The patch uses one string buffer that collects all the packet dump
> > output into this buffer and then printout it at last, that guarantee
> > to printout separately the dump output per packet.
> >
> > Fixes: d862c45 ("app/testpmd: move dumping packets to a separate
> > function")
> >
> > Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
> > ---
> > v2:
> > * Print dump output of per packet instead of per burst.
> > * Add the checking for return value of 'snprintf' and exit if required size
> exceed the print buffer size.
> > * Update the log messages.
> > ---
> >   app/test-pmd/util.c | 378
> ++++++++++++++++++++++++++++++++++++++++------------
> >   1 file changed, 295 insertions(+), 83 deletions(-)
> >
> > diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c index
> > 649bf8f..ffae590 100644
> > --- a/app/test-pmd/util.c
> > +++ b/app/test-pmd/util.c
> > @@ -12,15 +12,20 @@
> >   #include <rte_vxlan.h>
> >   #include <rte_ethdev.h>
> >   #include <rte_flow.h>
> > +#include <rte_log.h>
> >
> >   #include "testpmd.h"
> >
> > -static inline void
> > -print_ether_addr(const char *what, const struct rte_ether_addr
> > *eth_addr)
> > +#define MAX_STRING_LEN 8192
> 
> Isn't '8192' too large for a single packet, what do you think for '2048'?
> 
2K is ok for the normal case, here consider the case that registered mbuf dynamic flags names, 
Then total maximum length can reach to   64* RTE_MBUF_DYN_NAMESIZE = 4096
 // char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
So 2048 is not enough if all dynf_names be configured as maximum length of dyn_names.

How about the 5K? I think should be enough for now.
> <...>
> 
> > @@ -93,95 +103,269 @@
> >   		is_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);
> >   		ret = rte_flow_get_restore_info(port_id, mb, &info, &error);
> >   		if (!ret) {
> > -			printf("restore info:");
> > +			cur_len += snprintf(print_buf + cur_len,
> > +					    buf_size - cur_len,
> > +					    "restore info:");
> 
> What do you think having a macro like below to simplfy the code:
> 
>   #define FOO(buf, buf_size, cur_len, ...) \
>   do { \
>          if (cur_len >= buf_size) break; \
>          cur_len += snprintf(buf + cur_len, buf_size - cur_len, __VA_ARGS__); \
>   } while (0)
> 
> It can be used as:
>   FOO(print_buf, buf_size, cur_len, "restore info:");
> 
Agree, will move these common code into a MARCO, 
I will use the  "MKDUMPSTR" as MARCO name,  means that  making a dump string buffer.

> > +			if (cur_len >= buf_size)
> > +				goto error;
> 
> This 'goto' goes out of the loop, not sure about breking the loop and not
> processing all packets if buffer is out of space for one of the packets.
> Anyway if you switch to macro above, the 'goto' is removed completely.
> 
Use 'break' only break the do{} while and continue to following processing, but won't filled anymore into printbuf since it will break firstly in the MARCO checking.
Or could use 'goto lable' instead 'break' in the marco?
> <...>
> 
> > +		if (cur_len >= buf_size)
> > +			goto error;
> > +		TESTPMD_LOG(INFO, "%s", print_buf);
> 
> Using 'TESTPMD_LOG' appends "testpmd: " at the beggining of the each line,
> for this case it is noise I think, what do you think turning back to printf() as
> done originally?
> 
ok, will use the printf.
> > +		cur_len = 0;
> >   	}
> > +	return;
> > +error:
> > +	TESTPMD_LOG(INFO, "%s the output was truncated ...\n", print_buf);
> 
> What do you think having something shorter to notify the truncation, I think
> some special chars can work better, something like "...", "@@", "-->", "???" ?
> 
ok, I will use simple chars  for truncated case like below:
		if (cur_len >= buf_size)
			printf("%s ...\n", print_buf);
	
> >   }
> >
> >   uint16_t
> >

Thanks for your comments, I will do the changes and send V3 patch.

Thanks.
Jonny
  
Ferruh Yigit Nov. 19, 2020, 10:30 a.m. UTC | #3
On 11/18/2020 6:09 PM, Jiawei(Jonny) Wang wrote:
> Hi Ferruh,
> 
>> -----Original Message-----
>> From: Ferruh Yigit <ferruh.yigit@intel.com>
>> Sent: Tuesday, November 17, 2020 8:07 PM
>> To: Jiawei(Jonny) Wang <jiaweiw@nvidia.com>; wenzhuo.lu@intel.com;
>> beilei.xing@intel.com; bernard.iremonger@intel.com; Ori Kam
>> <orika@nvidia.com>; NBU-Contact-Thomas Monjalon
>> <thomas@monjalon.net>; Raslan Darawsheh <rasland@nvidia.com>
>> Cc: dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH v2] app/testpmd: fix testpmd packets dump
>> overlapping
>>
>> On 11/14/2020 12:01 PM, Jiawei Wang wrote:
>>> When testpmd enabled the verbosity for the received packets, if two
>>> packets was received at the same time, for example, sampling packet
>>> and normal packet, the dump output of these packets may be overlapping
>>> due to multiple core handled the multiple queues simultaneously.
>>>
>>> The patch uses one string buffer that collects all the packet dump
>>> output into this buffer and then printout it at last, that guarantee
>>> to printout separately the dump output per packet.
>>>
>>> Fixes: d862c45 ("app/testpmd: move dumping packets to a separate
>>> function")
>>>
>>> Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
>>> ---
>>> v2:
>>> * Print dump output of per packet instead of per burst.
>>> * Add the checking for return value of 'snprintf' and exit if required size
>> exceed the print buffer size.
>>> * Update the log messages.
>>> ---
>>>    app/test-pmd/util.c | 378
>> ++++++++++++++++++++++++++++++++++++++++------------
>>>    1 file changed, 295 insertions(+), 83 deletions(-)
>>>
>>> diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c index
>>> 649bf8f..ffae590 100644
>>> --- a/app/test-pmd/util.c
>>> +++ b/app/test-pmd/util.c
>>> @@ -12,15 +12,20 @@
>>>    #include <rte_vxlan.h>
>>>    #include <rte_ethdev.h>
>>>    #include <rte_flow.h>
>>> +#include <rte_log.h>
>>>
>>>    #include "testpmd.h"
>>>
>>> -static inline void
>>> -print_ether_addr(const char *what, const struct rte_ether_addr
>>> *eth_addr)
>>> +#define MAX_STRING_LEN 8192
>>
>> Isn't '8192' too large for a single packet, what do you think for '2048'?
>>
> 2K is ok for the normal case, here consider the case that registered mbuf dynamic flags names,
> Then total maximum length can reach to   64* RTE_MBUF_DYN_NAMESIZE = 4096
>   // char dynf_names[64][RTE_MBUF_DYN_NAMESIZE];
> So 2048 is not enough if all dynf_names be configured as maximum length of dyn_names.
> 
> How about the 5K? I think should be enough for now.

OK, and no need to be tight, if there are cases requesting longer string perhaps 
can keep the size as it is.

>> <...>
>>
>>> @@ -93,95 +103,269 @@
>>>    		is_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);
>>>    		ret = rte_flow_get_restore_info(port_id, mb, &info, &error);
>>>    		if (!ret) {
>>> -			printf("restore info:");
>>> +			cur_len += snprintf(print_buf + cur_len,
>>> +					    buf_size - cur_len,
>>> +					    "restore info:");
>>
>> What do you think having a macro like below to simplfy the code:
>>
>>    #define FOO(buf, buf_size, cur_len, ...) \
>>    do { \
>>           if (cur_len >= buf_size) break; \
>>           cur_len += snprintf(buf + cur_len, buf_size - cur_len, __VA_ARGS__); \
>>    } while (0)
>>
>> It can be used as:
>>    FOO(print_buf, buf_size, cur_len, "restore info:");
>>
> Agree, will move these common code into a MARCO,
> I will use the  "MKDUMPSTR" as MARCO name,  means that  making a dump string buffer.
> 

Ack

>>> +			if (cur_len >= buf_size)
>>> +				goto error;
>>
>> This 'goto' goes out of the loop, not sure about breking the loop and not
>> processing all packets if buffer is out of space for one of the packets.
>> Anyway if you switch to macro above, the 'goto' is removed completely.
>>
> Use 'break' only break the do{} while and continue to following processing, but won't filled anymore into printbuf since it will break firstly in the MARCO checking.
> Or could use 'goto lable' instead 'break' in the marco?

I think cleaner to not have the 'goto', yes processing will continue but no 
space left case expected to happen very rare.
  

Patch

diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c
index 649bf8f..ffae590 100644
--- a/app/test-pmd/util.c
+++ b/app/test-pmd/util.c
@@ -12,15 +12,20 @@ 
 #include <rte_vxlan.h>
 #include <rte_ethdev.h>
 #include <rte_flow.h>
+#include <rte_log.h>
 
 #include "testpmd.h"
 
-static inline void
-print_ether_addr(const char *what, const struct rte_ether_addr *eth_addr)
+#define MAX_STRING_LEN 8192
+
+static inline int
+print_ether_addr(const char *what, const struct rte_ether_addr *eth_addr,
+		 char print_buf[], int buf_size)
 {
 	char buf[RTE_ETHER_ADDR_FMT_SIZE];
+
 	rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr);
-	printf("%s%s", what, buf);
+	return snprintf(print_buf, buf_size, "%s%s", what, buf);
 }
 
 static inline bool
@@ -74,13 +79,18 @@ 
 	uint32_t vx_vni;
 	const char *reason;
 	int dynf_index;
+	int buf_size = MAX_STRING_LEN;
+	char print_buf[buf_size];
+	int cur_len = 0;
 
+	memset(print_buf, 0, sizeof(print_buf));
 	if (!nb_pkts)
 		return;
-	printf("port %u/queue %u: %s %u packets\n",
-		port_id, queue,
-	       is_rx ? "received" : "sent",
-	       (unsigned int) nb_pkts);
+	cur_len += snprintf(print_buf + cur_len, buf_size - cur_len,
+			    "port %u/queue %u: %s %u packets\n",
+			    port_id, queue,
+			    is_rx ? "received" : "sent",
+			    (unsigned int) nb_pkts);
 	for (i = 0; i < nb_pkts; i++) {
 		int ret;
 		struct rte_flow_error error;
@@ -93,95 +103,269 @@ 
 		is_encapsulation = RTE_ETH_IS_TUNNEL_PKT(packet_type);
 		ret = rte_flow_get_restore_info(port_id, mb, &info, &error);
 		if (!ret) {
-			printf("restore info:");
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    "restore info:");
+			if (cur_len >= buf_size)
+				goto error;
 			if (info.flags & RTE_FLOW_RESTORE_INFO_TUNNEL) {
 				struct port_flow_tunnel *port_tunnel;
 
 				port_tunnel = port_flow_locate_tunnel
 					      (port_id, &info.tunnel);
-				printf(" - tunnel");
-				if (port_tunnel)
-					printf(" #%u", port_tunnel->id);
-				else
-					printf(" %s", "-none-");
-				printf(" type %s",
-					port_flow_tunnel_type(&info.tunnel));
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    " - tunnel");
+				if (cur_len >= buf_size)
+					goto error;
+				if (port_tunnel) {
+					cur_len += snprintf(print_buf + cur_len,
+							    buf_size-cur_len,
+							    " #%u",
+							    port_tunnel->id);
+					if (cur_len >= buf_size)
+						goto error;
+				} else {
+					cur_len += snprintf(print_buf + cur_len,
+							    buf_size - cur_len,
+							    " %s",
+							    "-none-");
+					if (cur_len >= buf_size)
+						goto error;
+				}
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    " type %s",
+						    port_flow_tunnel_type
+						    (&info.tunnel));
+				if (cur_len >= buf_size)
+					goto error;
 			} else {
-				printf(" - no tunnel info");
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    " - no tunnel info");
+				if (cur_len >= buf_size)
+					goto error;
 			}
-			if (info.flags & RTE_FLOW_RESTORE_INFO_ENCAPSULATED)
-				printf(" - outer header present");
-			else
-				printf(" - no outer header");
-			if (info.flags & RTE_FLOW_RESTORE_INFO_GROUP_ID)
-				printf(" - miss group %u", info.group_id);
-			else
-				printf(" - no miss group");
-			printf("\n");
+			if (info.flags & RTE_FLOW_RESTORE_INFO_ENCAPSULATED) {
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    " - outer header present");
+				if (cur_len >= buf_size)
+					goto error;
+			} else {
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    " - no outer header");
+				if (cur_len >= buf_size)
+					goto error;
+			}
+			if (info.flags & RTE_FLOW_RESTORE_INFO_GROUP_ID) {
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    " - miss group %u",
+						    info.group_id);
+				if (cur_len >= buf_size)
+					goto error;
+			} else {
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    " - no miss group");
+				if (cur_len >= buf_size)
+					goto error;
+			}
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len, "\n");
+			if (cur_len >= buf_size)
+				goto error;
 		}
-		print_ether_addr("  src=", &eth_hdr->s_addr);
-		print_ether_addr(" - dst=", &eth_hdr->d_addr);
-		printf(" - type=0x%04x - length=%u - nb_segs=%d",
-		       eth_type, (unsigned int) mb->pkt_len,
-		       (int)mb->nb_segs);
+		cur_len += print_ether_addr("  src=", &eth_hdr->s_addr,
+					    print_buf + cur_len,
+					    buf_size);
+		if (cur_len >= buf_size)
+			goto error;
+		cur_len += print_ether_addr(" - dst=", &eth_hdr->d_addr,
+					    print_buf + cur_len,
+					    buf_size);
+		if (cur_len >= buf_size)
+			goto error;
+		cur_len += snprintf(print_buf + cur_len, buf_size - cur_len,
+				    " - type=0x%04x - length=%u - nb_segs=%d",
+				    eth_type, (unsigned int) mb->pkt_len,
+				    (int)mb->nb_segs);
+		if (cur_len >= buf_size)
+			goto error;
 		ol_flags = mb->ol_flags;
 		if (ol_flags & PKT_RX_RSS_HASH) {
-			printf(" - RSS hash=0x%x", (unsigned int) mb->hash.rss);
-			printf(" - RSS queue=0x%x", (unsigned int) queue);
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - RSS hash=0x%x",
+					    (unsigned int) mb->hash.rss);
+			if (cur_len >= buf_size)
+				goto error;
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - RSS queue=0x%x",
+					    (unsigned int) queue);
+			if (cur_len >= buf_size)
+				goto error;
 		}
 		if (ol_flags & PKT_RX_FDIR) {
-			printf(" - FDIR matched ");
-			if (ol_flags & PKT_RX_FDIR_ID)
-				printf("ID=0x%x",
-				       mb->hash.fdir.hi);
-			else if (ol_flags & PKT_RX_FDIR_FLX)
-				printf("flex bytes=0x%08x %08x",
-				       mb->hash.fdir.hi, mb->hash.fdir.lo);
-			else
-				printf("hash=0x%x ID=0x%x ",
-				       mb->hash.fdir.hash, mb->hash.fdir.id);
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - FDIR matched ");
+			if (cur_len >= buf_size)
+				goto error;
+			if (ol_flags & PKT_RX_FDIR_ID) {
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    "ID=0x%x",
+						    mb->hash.fdir.hi);
+				if (cur_len >= buf_size)
+					goto error;
+			} else if (ol_flags & PKT_RX_FDIR_FLX) {
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    "flex bytes=0x%08x %08x",
+						    mb->hash.fdir.hi,
+						    mb->hash.fdir.lo);
+				if (cur_len >= buf_size)
+					goto error;
+			} else {
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    "hash=0x%x ID=0x%x ",
+						    mb->hash.fdir.hash,
+						    mb->hash.fdir.id);
+				if (cur_len >= buf_size)
+					goto error;
+			}
+		}
+		if (is_timestamp_enabled(mb)) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - timestamp %"PRIu64" ",
+					    get_timestamp(mb));
+			if (cur_len >= buf_size)
+				goto error;
+		}
+		if (ol_flags & PKT_RX_QINQ) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - QinQ VLAN tci=0x%x, "
+					    "VLAN tci outer=0x%x",
+					    mb->vlan_tci,
+					    mb->vlan_tci_outer);
+			if (cur_len >= buf_size)
+				goto error;
+		} else if (ol_flags & PKT_RX_VLAN) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - VLAN tci=0x%x",
+					    mb->vlan_tci);
+			if (cur_len >= buf_size)
+				goto error;
+		}
+		if (!is_rx && (ol_flags & PKT_TX_DYNF_METADATA)) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - Tx metadata: 0x%x",
+					    *RTE_FLOW_DYNF_METADATA(mb));
+			if (cur_len >= buf_size)
+				goto error;
+		}
+		if (is_rx && (ol_flags & PKT_RX_DYNF_METADATA)) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - Rx metadata: 0x%x",
+					    *RTE_FLOW_DYNF_METADATA(mb));
+			if (cur_len >= buf_size)
+				goto error;
 		}
-		if (is_timestamp_enabled(mb))
-			printf(" - timestamp %"PRIu64" ", get_timestamp(mb));
-		if (ol_flags & PKT_RX_QINQ)
-			printf(" - QinQ VLAN tci=0x%x, VLAN tci outer=0x%x",
-			       mb->vlan_tci, mb->vlan_tci_outer);
-		else if (ol_flags & PKT_RX_VLAN)
-			printf(" - VLAN tci=0x%x", mb->vlan_tci);
-		if (!is_rx && (ol_flags & PKT_TX_DYNF_METADATA))
-			printf(" - Tx metadata: 0x%x",
-			       *RTE_FLOW_DYNF_METADATA(mb));
-		if (is_rx && (ol_flags & PKT_RX_DYNF_METADATA))
-			printf(" - Rx metadata: 0x%x",
-			       *RTE_FLOW_DYNF_METADATA(mb));
 		for (dynf_index = 0; dynf_index < 64; dynf_index++) {
-			if (dynf_names[dynf_index][0] != '\0')
-				printf(" - dynf %s: %d",
-				       dynf_names[dynf_index],
-				       !!(ol_flags & (1UL << dynf_index)));
+			if (dynf_names[dynf_index][0] != '\0') {
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    " - dynf %s: %d",
+						    dynf_names[dynf_index],
+						    !!(ol_flags &
+						    (1UL << dynf_index)));
+				if (cur_len >= buf_size)
+					goto error;
+			}
 		}
 		if (mb->packet_type) {
 			rte_get_ptype_name(mb->packet_type, buf, sizeof(buf));
-			printf(" - hw ptype: %s", buf);
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - hw ptype: %s", buf);
+			if (cur_len >= buf_size)
+				goto error;
 		}
 		sw_packet_type = rte_net_get_ptype(mb, &hdr_lens,
 					RTE_PTYPE_ALL_MASK);
 		rte_get_ptype_name(sw_packet_type, buf, sizeof(buf));
-		printf(" - sw ptype: %s", buf);
-		if (sw_packet_type & RTE_PTYPE_L2_MASK)
-			printf(" - l2_len=%d", hdr_lens.l2_len);
-		if (sw_packet_type & RTE_PTYPE_L3_MASK)
-			printf(" - l3_len=%d", hdr_lens.l3_len);
-		if (sw_packet_type & RTE_PTYPE_L4_MASK)
-			printf(" - l4_len=%d", hdr_lens.l4_len);
-		if (sw_packet_type & RTE_PTYPE_TUNNEL_MASK)
-			printf(" - tunnel_len=%d", hdr_lens.tunnel_len);
-		if (sw_packet_type & RTE_PTYPE_INNER_L2_MASK)
-			printf(" - inner_l2_len=%d", hdr_lens.inner_l2_len);
-		if (sw_packet_type & RTE_PTYPE_INNER_L3_MASK)
-			printf(" - inner_l3_len=%d", hdr_lens.inner_l3_len);
-		if (sw_packet_type & RTE_PTYPE_INNER_L4_MASK)
-			printf(" - inner_l4_len=%d", hdr_lens.inner_l4_len);
+		cur_len += snprintf(print_buf + cur_len,
+				    buf_size - cur_len,
+				    " - sw ptype: %s", buf);
+		if (cur_len >= buf_size)
+			goto error;
+		if (sw_packet_type & RTE_PTYPE_L2_MASK) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - l2_len=%d",
+					    hdr_lens.l2_len);
+			if (cur_len >= buf_size)
+				goto error;
+		}
+		if (sw_packet_type & RTE_PTYPE_L3_MASK) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - l3_len=%d",
+					    hdr_lens.l3_len);
+			if (cur_len >= buf_size)
+				goto error;
+		}
+		if (sw_packet_type & RTE_PTYPE_L4_MASK) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - l4_len=%d",
+					    hdr_lens.l4_len);
+			if (cur_len >= buf_size)
+				goto error;
+		}
+		if (sw_packet_type & RTE_PTYPE_TUNNEL_MASK) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - tunnel_len=%d",
+					    hdr_lens.tunnel_len);
+			if (cur_len >= buf_size)
+				goto error;
+		}
+		if (sw_packet_type & RTE_PTYPE_INNER_L2_MASK) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - inner_l2_len=%d",
+					    hdr_lens.inner_l2_len);
+			if (cur_len >= buf_size)
+				goto error;
+		}
+		if (sw_packet_type & RTE_PTYPE_INNER_L3_MASK) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - inner_l3_len=%d",
+					    hdr_lens.inner_l3_len);
+			if (cur_len >= buf_size)
+				goto error;
+		}
+		if (sw_packet_type & RTE_PTYPE_INNER_L4_MASK) {
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    " - inner_l4_len=%d",
+					    hdr_lens.inner_l4_len);
+			if (cur_len >= buf_size)
+				goto error;
+		}
 		if (is_encapsulation) {
 			struct rte_ipv4_hdr *ipv4_hdr;
 			struct rte_ipv6_hdr *ipv6_hdr;
@@ -218,19 +402,47 @@ 
 				l2_len + l3_len + l4_len);
 				udp_port = RTE_BE_TO_CPU_16(udp_hdr->dst_port);
 				vx_vni = rte_be_to_cpu_32(vxlan_hdr->vx_vni);
-				printf(" - VXLAN packet: packet type =%d, "
-				       "Destination UDP port =%d, VNI = %d",
-				       packet_type, udp_port, vx_vni >> 8);
+				cur_len += snprintf(print_buf + cur_len,
+						    buf_size - cur_len,
+						    " - VXLAN packet: packet "
+						    "type =%d, Destination UDP "
+						    "port =%d, VNI = %d",
+						    packet_type, udp_port,
+						    vx_vni >> 8);
+				if (cur_len >= buf_size)
+					goto error;
 			}
 		}
-		printf(" - %s queue=0x%x", is_rx ? "Receive" : "Send",
-			(unsigned int) queue);
-		printf("\n");
+		cur_len += snprintf(print_buf + cur_len,
+				    buf_size - cur_len,
+				    " - %s queue=0x%x",
+				    is_rx ? "Receive" : "Send",
+				    (unsigned int) queue);
+		if (cur_len >= buf_size)
+			goto error;
+		cur_len += snprintf(print_buf + cur_len,
+				    buf_size - cur_len, "\n");
+		if (cur_len >= buf_size)
+			goto error;
 		rte_get_rx_ol_flag_list(mb->ol_flags, buf, sizeof(buf));
-		printf("  ol_flags: %s\n", buf);
+		cur_len += snprintf(print_buf + cur_len,
+				    buf_size - cur_len,
+				    "  ol_flags: %s\n", buf);
+		if (cur_len >= buf_size)
+			goto error;
 		if (rte_mbuf_check(mb, 1, &reason) < 0)
-			printf("INVALID mbuf: %s\n", reason);
+			cur_len += snprintf(print_buf + cur_len,
+					    buf_size - cur_len,
+					    "INVALID mbuf: %s\n",
+					    reason);
+		if (cur_len >= buf_size)
+			goto error;
+		TESTPMD_LOG(INFO, "%s", print_buf);
+		cur_len = 0;
 	}
+	return;
+error:
+	TESTPMD_LOG(INFO, "%s the output was truncated ...\n", print_buf);
 }
 
 uint16_t