[V6,6/8] telemetry: support adding integer value as hexadecimal

Message ID 20221215103146.816-7-lihuisong@huawei.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers
Series telemetry: fix data truncation and conversion error and add hex integer API |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

lihuisong (C) Dec. 15, 2022, 10:31 a.m. UTC
  Sometimes displaying a unsigned integer value as hexadecimal encoded style
is more expected for human consumption, such as, offload capability and
device flag. This patch introduces two APIs to add unsigned integer value
as hexadecimal encoded string to array or dictionary. And user can choose
whether the stored value is padding to the specified width.

Signed-off-by: Huisong Li <lihuisong@huawei.com>
Acked-by: Morten Brørup <mb@smartsharesystems.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
 lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
 lib/telemetry/telemetry_data.c | 72 ++++++++++++++++++++++++++++++++++
 lib/telemetry/version.map      |  9 +++++
 3 files changed, 128 insertions(+)
  

Comments

Bruce Richardson Dec. 15, 2022, 10:46 a.m. UTC | #1
On Thu, Dec 15, 2022 at 06:31:44PM +0800, Huisong Li wrote:
> Sometimes displaying a unsigned integer value as hexadecimal encoded style
> is more expected for human consumption, such as, offload capability and
> device flag. This patch introduces two APIs to add unsigned integer value
> as hexadecimal encoded string to array or dictionary. And user can choose
> whether the stored value is padding to the specified width.
> 
> Signed-off-by: Huisong Li <lihuisong@huawei.com>
> Acked-by: Morten Brørup <mb@smartsharesystems.com>
> Acked-by: Chengwen Feng <fengchengwen@huawei.com>
> ---
>  lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
>  lib/telemetry/telemetry_data.c | 72 ++++++++++++++++++++++++++++++++++
>  lib/telemetry/version.map      |  9 +++++
>  3 files changed, 128 insertions(+)
> 
<snip>
> +/* To suppress compiler warning about format string. */
> +#if defined(RTE_TOOLCHAIN_GCC)
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
> +#elif defined(RTE_TOOLCHAIN_CLANG)
> +#pragma clang diagnostic push
> +#pragma clang diagnostic ignored "-Wformat-nonliteral"
> +#endif
> +
> +static int
> +rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len, uint64_t val,
> +				uint8_t display_bitwidth)
> +{
> +#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
> +
> +	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
> +	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
> +
> +	/* Buffer needs to have room to contain the prefix '0x' and '\0'. */
> +	if (len < spec_hex_width + 3)
> +		return -EINVAL;
> +

This check is not sufficient, as display_bitwidth could be 0 for example,
and the actual printed number have up to 16 characters.

> +	if (display_bitwidth != 0) {
> +		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
> +		sprintf(buf, format, val);
> +	} else {
> +		sprintf(buf, "0x%" PRIx64, val);
> +	}
> +

snprintf should always be used when printing to the buffer so as to avoid
overflow. The return value after snprintf should always be checked too.

Thanks,
/Bruce
  
lihuisong (C) Dec. 15, 2022, 11:27 a.m. UTC | #2
在 2022/12/15 18:46, Bruce Richardson 写道:
> On Thu, Dec 15, 2022 at 06:31:44PM +0800, Huisong Li wrote:
>> Sometimes displaying a unsigned integer value as hexadecimal encoded style
>> is more expected for human consumption, such as, offload capability and
>> device flag. This patch introduces two APIs to add unsigned integer value
>> as hexadecimal encoded string to array or dictionary. And user can choose
>> whether the stored value is padding to the specified width.
>>
>> Signed-off-by: Huisong Li <lihuisong@huawei.com>
>> Acked-by: Morten Brørup <mb@smartsharesystems.com>
>> Acked-by: Chengwen Feng <fengchengwen@huawei.com>
>> ---
>>   lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
>>   lib/telemetry/telemetry_data.c | 72 ++++++++++++++++++++++++++++++++++
>>   lib/telemetry/version.map      |  9 +++++
>>   3 files changed, 128 insertions(+)
>>
> <snip>
>> +/* To suppress compiler warning about format string. */
>> +#if defined(RTE_TOOLCHAIN_GCC)
>> +#pragma GCC diagnostic push
>> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
>> +#elif defined(RTE_TOOLCHAIN_CLANG)
>> +#pragma clang diagnostic push
>> +#pragma clang diagnostic ignored "-Wformat-nonliteral"
>> +#endif
>> +
>> +static int
>> +rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len, uint64_t val,
>> +				uint8_t display_bitwidth)
>> +{
>> +#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
>> +
>> +	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
>> +	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
>> +
>> +	/* Buffer needs to have room to contain the prefix '0x' and '\0'. */
>> +	if (len < spec_hex_width + 3)
>> +		return -EINVAL;
>> +
> This check is not sufficient, as display_bitwidth could be 0 for example,
> and the actual printed number have up to 16 characters.
Yes, you are right. What do you think of the following check?

max_hex_width = display_bitwidth == 0 ? (sizeof(uint64_t) * 2) : 
spec_hex_width;
if (len < max_hex_width + 3)
     return -EINVAL;
>
>> +	if (display_bitwidth != 0) {
>> +		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
>> +		sprintf(buf, format, val);
>> +	} else {
>> +		sprintf(buf, "0x%" PRIx64, val);
>> +	}
>> +
> snprintf should always be used when printing to the buffer so as to avoid
> overflow. The return value after snprintf should always be checked too.
If check for buffer is sufficient, can the return value of snprintf not 
be checked?
There are also many places in telemetry lib that are not checked for 
this return value.
Do you have any principles for this?
>
> Thanks,
> /Bruce
> .
  
Morten Brørup Dec. 15, 2022, noon UTC | #3
> From: lihuisong (C) [mailto:lihuisong@huawei.com]
> Sent: Thursday, 15 December 2022 12.28
> 
> 在 2022/12/15 18:46, Bruce Richardson 写道:
> > On Thu, Dec 15, 2022 at 06:31:44PM +0800, Huisong Li wrote:
> >> Sometimes displaying a unsigned integer value as hexadecimal encoded
> style
> >> is more expected for human consumption, such as, offload capability
> and
> >> device flag. This patch introduces two APIs to add unsigned integer
> value
> >> as hexadecimal encoded string to array or dictionary. And user can
> choose
> >> whether the stored value is padding to the specified width.
> >>
> >> Signed-off-by: Huisong Li <lihuisong@huawei.com>
> >> Acked-by: Morten Brørup <mb@smartsharesystems.com>
> >> Acked-by: Chengwen Feng <fengchengwen@huawei.com>
> >> ---
> >>   lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
> >>   lib/telemetry/telemetry_data.c | 72
> ++++++++++++++++++++++++++++++++++
> >>   lib/telemetry/version.map      |  9 +++++
> >>   3 files changed, 128 insertions(+)
> >>
> > <snip>
> >> +/* To suppress compiler warning about format string. */
> >> +#if defined(RTE_TOOLCHAIN_GCC)
> >> +#pragma GCC diagnostic push
> >> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
> >> +#elif defined(RTE_TOOLCHAIN_CLANG)
> >> +#pragma clang diagnostic push
> >> +#pragma clang diagnostic ignored "-Wformat-nonliteral"
> >> +#endif
> >> +
> >> +static int
> >> +rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len, uint64_t
> val,

The "len" parameter should be size_t or unsigned int, not uint16_t.

And as a personal preference, I would name it "buf_len" instead of "len".

> >> +				uint8_t display_bitwidth)
> >> +{
> >> +#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
> >> +
> >> +	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
> >> +	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
> >> +
> >> +	/* Buffer needs to have room to contain the prefix '0x' and '\0'.
> */
> >> +	if (len < spec_hex_width + 3)
> >> +		return -EINVAL;
> >> +
> > This check is not sufficient, as display_bitwidth could be 0 for
> example,
> > and the actual printed number have up to 16 characters.
> Yes, you are right. What do you think of the following check?
> 
> max_hex_width = display_bitwidth == 0 ? (sizeof(uint64_t) * 2) :
> spec_hex_width;
> if (len < max_hex_width + 3)
>      return -EINVAL;

LGTM.

> >
> >> +	if (display_bitwidth != 0) {
> >> +		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
> >> +		sprintf(buf, format, val);

snprintf(format, sizeof(format), "0x%%0%u" PRIx64, spec_hex_width);
snprintf(buf, len, format, val);

> >> +	} else {
> >> +		sprintf(buf, "0x%" PRIx64, val);

snprintf(buf, len, "0x%" PRIx64, val);

> >> +	}
> >> +
> > snprintf should always be used when printing to the buffer so as to
> avoid
> > overflow. The return value after snprintf should always be checked
> too.
> If check for buffer is sufficient, can the return value of snprintf not
> be checked?
> There are also many places in telemetry lib that are not checked for
> this return value.
> Do you have any principles for this?

You already check the buffer size before printf() into it, so I think it suffices. However, to keep automated code checkers happy, you could easily use snprintf() instead of printf(). (Sorry about not doing it in my example.)

I somewhat disagree with Bruce's suggestion to check the return value from snprintf() after checking that the buffer is large enough. It would be effectively dead code, which might cause some confusion. On the other hand, it might keep some automated code checkers happy. In this specific case here, I don't have a strong preference.

-Morten
  
Bruce Richardson Dec. 15, 2022, 12:15 p.m. UTC | #4
On Thu, Dec 15, 2022 at 01:00:40PM +0100, Morten Brørup wrote:
> > From: lihuisong (C) [mailto:lihuisong@huawei.com]
> > Sent: Thursday, 15 December 2022 12.28
> > 
> > 在 2022/12/15 18:46, Bruce Richardson 写道:
> > > On Thu, Dec 15, 2022 at 06:31:44PM +0800, Huisong Li wrote:
> > >> Sometimes displaying a unsigned integer value as hexadecimal encoded
> > style
> > >> is more expected for human consumption, such as, offload capability
> > and
> > >> device flag. This patch introduces two APIs to add unsigned integer
> > value
> > >> as hexadecimal encoded string to array or dictionary. And user can
> > choose
> > >> whether the stored value is padding to the specified width.
> > >>
> > >> Signed-off-by: Huisong Li <lihuisong@huawei.com>
> > >> Acked-by: Morten Brørup <mb@smartsharesystems.com>
> > >> Acked-by: Chengwen Feng <fengchengwen@huawei.com>
> > >> ---
> > >>   lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
> > >>   lib/telemetry/telemetry_data.c | 72
> > ++++++++++++++++++++++++++++++++++
> > >>   lib/telemetry/version.map      |  9 +++++
> > >>   3 files changed, 128 insertions(+)
> > >>
> > > <snip>
> > >> +/* To suppress compiler warning about format string. */
> > >> +#if defined(RTE_TOOLCHAIN_GCC)
> > >> +#pragma GCC diagnostic push
> > >> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
> > >> +#elif defined(RTE_TOOLCHAIN_CLANG)
> > >> +#pragma clang diagnostic push
> > >> +#pragma clang diagnostic ignored "-Wformat-nonliteral"
> > >> +#endif
> > >> +
> > >> +static int
> > >> +rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len, uint64_t
> > val,
> 
> The "len" parameter should be size_t or unsigned int, not uint16_t.
> 
> And as a personal preference, I would name it "buf_len" instead of "len".
> 
> > >> +				uint8_t display_bitwidth)
> > >> +{
> > >> +#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
> > >> +
> > >> +	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
> > >> +	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
> > >> +
> > >> +	/* Buffer needs to have room to contain the prefix '0x' and '\0'.
> > */
> > >> +	if (len < spec_hex_width + 3)
> > >> +		return -EINVAL;
> > >> +
> > > This check is not sufficient, as display_bitwidth could be 0 for
> > example,
> > > and the actual printed number have up to 16 characters.
> > Yes, you are right. What do you think of the following check?
> > 
> > max_hex_width = display_bitwidth == 0 ? (sizeof(uint64_t) * 2) :
> > spec_hex_width;
> > if (len < max_hex_width + 3)
> >      return -EINVAL;
> 
> LGTM.

That would work, but actually I think we should drop this check completely
- see comment below.

> 
> > >
> > >> +	if (display_bitwidth != 0) {
> > >> +		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
> > >> +		sprintf(buf, format, val);
> 
> snprintf(format, sizeof(format), "0x%%0%u" PRIx64, spec_hex_width);
> snprintf(buf, len, format, val);
> 
> > >> +	} else {
> > >> +		sprintf(buf, "0x%" PRIx64, val);
> 
> snprintf(buf, len, "0x%" PRIx64, val);
> 
> > >> +	}
> > >> +
> > > snprintf should always be used when printing to the buffer so as to
> > avoid
> > > overflow. The return value after snprintf should always be checked
> > too.
> > If check for buffer is sufficient, can the return value of snprintf not
> > be checked?
> > There are also many places in telemetry lib that are not checked for
> > this return value.
> > Do you have any principles for this?
> 
> You already check the buffer size before printf() into it, so I think it suffices. However, to keep automated code checkers happy, you could easily use snprintf() instead of printf(). (Sorry about not doing it in my example.)
> 
> I somewhat disagree with Bruce's suggestion to check the return value from snprintf() after checking that the buffer is large enough. It would be effectively dead code, which might cause some confusion. On the other hand, it might keep some automated code checkers happy. In this specific case here, I don't have a strong preference.
> 
Sure, you don't need 2 checks - we can either check the length at the
start, or else check the length by looking for the return value from
snprintf, but we don't need to do both.

Given the slight complexity in determining the correct length of the printf
for the initial size check, I think I would go with the approach of *not*
checking the buffer initially and just check the snprintf return value.
That would remove any possibility of us doing an incorrect length check, as
was the case originally with this patch.

/Bruce
  
Morten Brørup Dec. 15, 2022, 12:24 p.m. UTC | #5
> From: Bruce Richardson [mailto:bruce.richardson@intel.com]
> Sent: Thursday, 15 December 2022 13.16
> 
> On Thu, Dec 15, 2022 at 01:00:40PM +0100, Morten Brørup wrote:
> > > From: lihuisong (C) [mailto:lihuisong@huawei.com]
> > > Sent: Thursday, 15 December 2022 12.28
> > >
> > > 在 2022/12/15 18:46, Bruce Richardson 写道:
> > > > On Thu, Dec 15, 2022 at 06:31:44PM +0800, Huisong Li wrote:
> > > >> Sometimes displaying a unsigned integer value as hexadecimal
> encoded
> > > style
> > > >> is more expected for human consumption, such as, offload
> capability
> > > and
> > > >> device flag. This patch introduces two APIs to add unsigned
> integer
> > > value
> > > >> as hexadecimal encoded string to array or dictionary. And user
> can
> > > choose
> > > >> whether the stored value is padding to the specified width.
> > > >>
> > > >> Signed-off-by: Huisong Li <lihuisong@huawei.com>
> > > >> Acked-by: Morten Brørup <mb@smartsharesystems.com>
> > > >> Acked-by: Chengwen Feng <fengchengwen@huawei.com>
> > > >> ---
> > > >>   lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
> > > >>   lib/telemetry/telemetry_data.c | 72
> > > ++++++++++++++++++++++++++++++++++
> > > >>   lib/telemetry/version.map      |  9 +++++
> > > >>   3 files changed, 128 insertions(+)
> > > >>
> > > > <snip>
> > > >> +/* To suppress compiler warning about format string. */
> > > >> +#if defined(RTE_TOOLCHAIN_GCC)
> > > >> +#pragma GCC diagnostic push
> > > >> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
> > > >> +#elif defined(RTE_TOOLCHAIN_CLANG)
> > > >> +#pragma clang diagnostic push
> > > >> +#pragma clang diagnostic ignored "-Wformat-nonliteral"
> > > >> +#endif
> > > >> +
> > > >> +static int
> > > >> +rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len,
> uint64_t
> > > val,
> >
> > The "len" parameter should be size_t or unsigned int, not uint16_t.
> >
> > And as a personal preference, I would name it "buf_len" instead of
> "len".
> >
> > > >> +				uint8_t display_bitwidth)
> > > >> +{
> > > >> +#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
> > > >> +
> > > >> +	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
> > > >> +	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
> > > >> +
> > > >> +	/* Buffer needs to have room to contain the prefix '0x' and
> '\0'.
> > > */
> > > >> +	if (len < spec_hex_width + 3)
> > > >> +		return -EINVAL;
> > > >> +
> > > > This check is not sufficient, as display_bitwidth could be 0 for
> > > example,
> > > > and the actual printed number have up to 16 characters.
> > > Yes, you are right. What do you think of the following check?
> > >
> > > max_hex_width = display_bitwidth == 0 ? (sizeof(uint64_t) * 2) :
> > > spec_hex_width;
> > > if (len < max_hex_width + 3)
> > >      return -EINVAL;
> >
> > LGTM.
> 
> That would work, but actually I think we should drop this check
> completely
> - see comment below.
> 
> >
> > > >
> > > >> +	if (display_bitwidth != 0) {
> > > >> +		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
> > > >> +		sprintf(buf, format, val);
> >
> > snprintf(format, sizeof(format), "0x%%0%u" PRIx64, spec_hex_width);
> > snprintf(buf, len, format, val);
> >
> > > >> +	} else {
> > > >> +		sprintf(buf, "0x%" PRIx64, val);
> >
> > snprintf(buf, len, "0x%" PRIx64, val);
> >
> > > >> +	}
> > > >> +
> > > > snprintf should always be used when printing to the buffer so as
> to
> > > avoid
> > > > overflow. The return value after snprintf should always be
> checked
> > > too.
> > > If check for buffer is sufficient, can the return value of snprintf
> not
> > > be checked?
> > > There are also many places in telemetry lib that are not checked
> for
> > > this return value.
> > > Do you have any principles for this?
> >
> > You already check the buffer size before printf() into it, so I think
> it suffices. However, to keep automated code checkers happy, you could
> easily use snprintf() instead of printf(). (Sorry about not doing it in
> my example.)
> >
> > I somewhat disagree with Bruce's suggestion to check the return value
> from snprintf() after checking that the buffer is large enough. It
> would be effectively dead code, which might cause some confusion. On
> the other hand, it might keep some automated code checkers happy. In
> this specific case here, I don't have a strong preference.
> >
> Sure, you don't need 2 checks - we can either check the length at the
> start, or else check the length by looking for the return value from
> snprintf, but we don't need to do both.
> 
> Given the slight complexity in determining the correct length of the
> printf
> for the initial size check, I think I would go with the approach of
> *not*
> checking the buffer initially and just check the snprintf return value.
> That would remove any possibility of us doing an incorrect length
> check, as
> was the case originally with this patch.

That sounds reasonable to me. Please do that.

-Morten
  
lihuisong (C) Dec. 15, 2022, 12:45 p.m. UTC | #6
在 2022/12/15 20:24, Morten Brørup 写道:
>> From: Bruce Richardson [mailto:bruce.richardson@intel.com]
>> Sent: Thursday, 15 December 2022 13.16
>>
>> On Thu, Dec 15, 2022 at 01:00:40PM +0100, Morten Brørup wrote:
>>>> From: lihuisong (C) [mailto:lihuisong@huawei.com]
>>>> Sent: Thursday, 15 December 2022 12.28
>>>>
>>>> 在 2022/12/15 18:46, Bruce Richardson 写道:
>>>>> On Thu, Dec 15, 2022 at 06:31:44PM +0800, Huisong Li wrote:
>>>>>> Sometimes displaying a unsigned integer value as hexadecimal
>> encoded
>>>> style
>>>>>> is more expected for human consumption, such as, offload
>> capability
>>>> and
>>>>>> device flag. This patch introduces two APIs to add unsigned
>> integer
>>>> value
>>>>>> as hexadecimal encoded string to array or dictionary. And user
>> can
>>>> choose
>>>>>> whether the stored value is padding to the specified width.
>>>>>>
>>>>>> Signed-off-by: Huisong Li <lihuisong@huawei.com>
>>>>>> Acked-by: Morten Brørup <mb@smartsharesystems.com>
>>>>>> Acked-by: Chengwen Feng <fengchengwen@huawei.com>
>>>>>> ---
>>>>>>    lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
>>>>>>    lib/telemetry/telemetry_data.c | 72
>>>> ++++++++++++++++++++++++++++++++++
>>>>>>    lib/telemetry/version.map      |  9 +++++
>>>>>>    3 files changed, 128 insertions(+)
>>>>>>
>>>>> <snip>
>>>>>> +/* To suppress compiler warning about format string. */
>>>>>> +#if defined(RTE_TOOLCHAIN_GCC)
>>>>>> +#pragma GCC diagnostic push
>>>>>> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
>>>>>> +#elif defined(RTE_TOOLCHAIN_CLANG)
>>>>>> +#pragma clang diagnostic push
>>>>>> +#pragma clang diagnostic ignored "-Wformat-nonliteral"
>>>>>> +#endif
>>>>>> +
>>>>>> +static int
>>>>>> +rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len,
>> uint64_t
>>>> val,
>>> The "len" parameter should be size_t or unsigned int, not uint16_t.
>>>
>>> And as a personal preference, I would name it "buf_len" instead of
>> "len".
>>>>>> +				uint8_t display_bitwidth)
>>>>>> +{
>>>>>> +#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
>>>>>> +
>>>>>> +	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
>>>>>> +	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
>>>>>> +
>>>>>> +	/* Buffer needs to have room to contain the prefix '0x' and
>> '\0'.
>>>> */
>>>>>> +	if (len < spec_hex_width + 3)
>>>>>> +		return -EINVAL;
>>>>>> +
>>>>> This check is not sufficient, as display_bitwidth could be 0 for
>>>> example,
>>>>> and the actual printed number have up to 16 characters.
>>>> Yes, you are right. What do you think of the following check?
>>>>
>>>> max_hex_width = display_bitwidth == 0 ? (sizeof(uint64_t) * 2) :
>>>> spec_hex_width;
>>>> if (len < max_hex_width + 3)
>>>>       return -EINVAL;
>>> LGTM.
>> That would work, but actually I think we should drop this check
>> completely
>> - see comment below.
>>
>>>>>> +	if (display_bitwidth != 0) {
>>>>>> +		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
>>>>>> +		sprintf(buf, format, val);
>>> snprintf(format, sizeof(format), "0x%%0%u" PRIx64, spec_hex_width);
>>> snprintf(buf, len, format, val);
>>>
>>>>>> +	} else {
>>>>>> +		sprintf(buf, "0x%" PRIx64, val);
>>> snprintf(buf, len, "0x%" PRIx64, val);
>>>
>>>>>> +	}
>>>>>> +
>>>>> snprintf should always be used when printing to the buffer so as
>> to
>>>> avoid
>>>>> overflow. The return value after snprintf should always be
>> checked
>>>> too.
>>>> If check for buffer is sufficient, can the return value of snprintf
>> not
>>>> be checked?
>>>> There are also many places in telemetry lib that are not checked
>> for
>>>> this return value.
>>>> Do you have any principles for this?
>>> You already check the buffer size before printf() into it, so I think
>> it suffices. However, to keep automated code checkers happy, you could
>> easily use snprintf() instead of printf(). (Sorry about not doing it in
>> my example.)
>>> I somewhat disagree with Bruce's suggestion to check the return value
>> from snprintf() after checking that the buffer is large enough. It
>> would be effectively dead code, which might cause some confusion. On
>> the other hand, it might keep some automated code checkers happy. In
>> this specific case here, I don't have a strong preference.
>> Sure, you don't need 2 checks - we can either check the length at the
>> start, or else check the length by looking for the return value from
>> snprintf, but we don't need to do both.
>>
>> Given the slight complexity in determining the correct length of the
>> printf
>> for the initial size check, I think I would go with the approach of
>> *not*
>> checking the buffer initially and just check the snprintf return value.
>> That would remove any possibility of us doing an incorrect length
>> check, as
>> was the case originally with this patch.
> That sounds reasonable to me. Please do that.
I think above check is necessary. Because snprintf returns the total 
length of string
formated instead of negative when buffer size isn't sufficient. what do 
you think?

/Huisong
  
Morten Brørup Dec. 15, 2022, 12:52 p.m. UTC | #7
> From: lihuisong (C) [mailto:lihuisong@huawei.com]
> Sent: Thursday, 15 December 2022 13.46
> 
> 在 2022/12/15 20:24, Morten Brørup 写道:
> >> From: Bruce Richardson [mailto:bruce.richardson@intel.com]
> >> Sent: Thursday, 15 December 2022 13.16
> >>
> >> On Thu, Dec 15, 2022 at 01:00:40PM +0100, Morten Brørup wrote:
> >>>> From: lihuisong (C) [mailto:lihuisong@huawei.com]
> >>>> Sent: Thursday, 15 December 2022 12.28
> >>>>
> >>>> 在 2022/12/15 18:46, Bruce Richardson 写道:
> >>>>> On Thu, Dec 15, 2022 at 06:31:44PM +0800, Huisong Li wrote:
> >>>>>> Sometimes displaying a unsigned integer value as hexadecimal
> >> encoded
> >>>> style
> >>>>>> is more expected for human consumption, such as, offload
> >> capability
> >>>> and
> >>>>>> device flag. This patch introduces two APIs to add unsigned
> >> integer
> >>>> value
> >>>>>> as hexadecimal encoded string to array or dictionary. And user
> >> can
> >>>> choose
> >>>>>> whether the stored value is padding to the specified width.
> >>>>>>
> >>>>>> Signed-off-by: Huisong Li <lihuisong@huawei.com>
> >>>>>> Acked-by: Morten Brørup <mb@smartsharesystems.com>
> >>>>>> Acked-by: Chengwen Feng <fengchengwen@huawei.com>
> >>>>>> ---
> >>>>>>    lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
> >>>>>>    lib/telemetry/telemetry_data.c | 72
> >>>> ++++++++++++++++++++++++++++++++++
> >>>>>>    lib/telemetry/version.map      |  9 +++++
> >>>>>>    3 files changed, 128 insertions(+)
> >>>>>>
> >>>>> <snip>
> >>>>>> +/* To suppress compiler warning about format string. */
> >>>>>> +#if defined(RTE_TOOLCHAIN_GCC)
> >>>>>> +#pragma GCC diagnostic push
> >>>>>> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
> >>>>>> +#elif defined(RTE_TOOLCHAIN_CLANG)
> >>>>>> +#pragma clang diagnostic push
> >>>>>> +#pragma clang diagnostic ignored "-Wformat-nonliteral"
> >>>>>> +#endif
> >>>>>> +
> >>>>>> +static int
> >>>>>> +rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len,
> >> uint64_t
> >>>> val,
> >>> The "len" parameter should be size_t or unsigned int, not uint16_t.
> >>>
> >>> And as a personal preference, I would name it "buf_len" instead of
> >> "len".
> >>>>>> +				uint8_t display_bitwidth)
> >>>>>> +{
> >>>>>> +#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
> >>>>>> +
> >>>>>> +	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
> >>>>>> +	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
> >>>>>> +
> >>>>>> +	/* Buffer needs to have room to contain the prefix '0x' and
> >> '\0'.
> >>>> */
> >>>>>> +	if (len < spec_hex_width + 3)
> >>>>>> +		return -EINVAL;
> >>>>>> +
> >>>>> This check is not sufficient, as display_bitwidth could be 0 for
> >>>> example,
> >>>>> and the actual printed number have up to 16 characters.
> >>>> Yes, you are right. What do you think of the following check?
> >>>>
> >>>> max_hex_width = display_bitwidth == 0 ? (sizeof(uint64_t) * 2) :
> >>>> spec_hex_width;
> >>>> if (len < max_hex_width + 3)
> >>>>       return -EINVAL;
> >>> LGTM.
> >> That would work, but actually I think we should drop this check
> >> completely
> >> - see comment below.
> >>
> >>>>>> +	if (display_bitwidth != 0) {
> >>>>>> +		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
> >>>>>> +		sprintf(buf, format, val);
> >>> snprintf(format, sizeof(format), "0x%%0%u" PRIx64, spec_hex_width);
> >>> snprintf(buf, len, format, val);
> >>>
> >>>>>> +	} else {
> >>>>>> +		sprintf(buf, "0x%" PRIx64, val);
> >>> snprintf(buf, len, "0x%" PRIx64, val);
> >>>
> >>>>>> +	}
> >>>>>> +
> >>>>> snprintf should always be used when printing to the buffer so as
> >> to
> >>>> avoid
> >>>>> overflow. The return value after snprintf should always be
> >> checked
> >>>> too.
> >>>> If check for buffer is sufficient, can the return value of
> snprintf
> >> not
> >>>> be checked?
> >>>> There are also many places in telemetry lib that are not checked
> >> for
> >>>> this return value.
> >>>> Do you have any principles for this?
> >>> You already check the buffer size before printf() into it, so I
> think
> >> it suffices. However, to keep automated code checkers happy, you
> could
> >> easily use snprintf() instead of printf(). (Sorry about not doing it
> in
> >> my example.)
> >>> I somewhat disagree with Bruce's suggestion to check the return
> value
> >> from snprintf() after checking that the buffer is large enough. It
> >> would be effectively dead code, which might cause some confusion. On
> >> the other hand, it might keep some automated code checkers happy. In
> >> this specific case here, I don't have a strong preference.
> >> Sure, you don't need 2 checks - we can either check the length at
> the
> >> start, or else check the length by looking for the return value from
> >> snprintf, but we don't need to do both.
> >>
> >> Given the slight complexity in determining the correct length of the
> >> printf
> >> for the initial size check, I think I would go with the approach of
> >> *not*
> >> checking the buffer initially and just check the snprintf return
> value.
> >> That would remove any possibility of us doing an incorrect length
> >> check, as
> >> was the case originally with this patch.
> > That sounds reasonable to me. Please do that.
> I think above check is necessary. Because snprintf returns the total
> length of string
> formated instead of negative when buffer size isn't sufficient. what do
> you think?

I had the same concern, so I looked it up.

snprintf() returns the length that the string would have, regardless if it was truncated or not.

In other words:

If the string is truncated, snprintf() returns a value greater than the buffer length parameter given to it.

It can be checked like this:

if (snprintf(buf, len, "0x%" PRIx64, val) > len)
    return -EINVAL;

In my opinion, checking for negative return values from snprintf() is not necessary.
  
Bruce Richardson Dec. 15, 2022, 1:08 p.m. UTC | #8
On Thu, Dec 15, 2022 at 01:52:02PM +0100, Morten Brørup wrote:
> > From: lihuisong (C) [mailto:lihuisong@huawei.com]
> > Sent: Thursday, 15 December 2022 13.46
> > 
> > 在 2022/12/15 20:24, Morten Brørup 写道:
> > >> From: Bruce Richardson [mailto:bruce.richardson@intel.com]
> > >> Sent: Thursday, 15 December 2022 13.16
> > >>
> > >> On Thu, Dec 15, 2022 at 01:00:40PM +0100, Morten Brørup wrote:
> > >>>> From: lihuisong (C) [mailto:lihuisong@huawei.com]
> > >>>> Sent: Thursday, 15 December 2022 12.28
> > >>>>
> > >>>> 在 2022/12/15 18:46, Bruce Richardson 写道:
> > >>>>> On Thu, Dec 15, 2022 at 06:31:44PM +0800, Huisong Li wrote:
> > >>>>>> Sometimes displaying a unsigned integer value as hexadecimal
> > >> encoded
> > >>>> style
> > >>>>>> is more expected for human consumption, such as, offload
> > >> capability
> > >>>> and
> > >>>>>> device flag. This patch introduces two APIs to add unsigned
> > >> integer
> > >>>> value
> > >>>>>> as hexadecimal encoded string to array or dictionary. And user
> > >> can
> > >>>> choose
> > >>>>>> whether the stored value is padding to the specified width.
> > >>>>>>
> > >>>>>> Signed-off-by: Huisong Li <lihuisong@huawei.com>
> > >>>>>> Acked-by: Morten Brørup <mb@smartsharesystems.com>
> > >>>>>> Acked-by: Chengwen Feng <fengchengwen@huawei.com>
> > >>>>>> ---
> > >>>>>>    lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
> > >>>>>>    lib/telemetry/telemetry_data.c | 72
> > >>>> ++++++++++++++++++++++++++++++++++
> > >>>>>>    lib/telemetry/version.map      |  9 +++++
> > >>>>>>    3 files changed, 128 insertions(+)
> > >>>>>>
> > >>>>> <snip>
> > >>>>>> +/* To suppress compiler warning about format string. */
> > >>>>>> +#if defined(RTE_TOOLCHAIN_GCC)
> > >>>>>> +#pragma GCC diagnostic push
> > >>>>>> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
> > >>>>>> +#elif defined(RTE_TOOLCHAIN_CLANG)
> > >>>>>> +#pragma clang diagnostic push
> > >>>>>> +#pragma clang diagnostic ignored "-Wformat-nonliteral"
> > >>>>>> +#endif
> > >>>>>> +
> > >>>>>> +static int
> > >>>>>> +rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len,
> > >> uint64_t
> > >>>> val,
> > >>> The "len" parameter should be size_t or unsigned int, not uint16_t.
> > >>>
> > >>> And as a personal preference, I would name it "buf_len" instead of
> > >> "len".
> > >>>>>> +				uint8_t display_bitwidth)
> > >>>>>> +{
> > >>>>>> +#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
> > >>>>>> +
> > >>>>>> +	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
> > >>>>>> +	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
> > >>>>>> +
> > >>>>>> +	/* Buffer needs to have room to contain the prefix '0x' and
> > >> '\0'.
> > >>>> */
> > >>>>>> +	if (len < spec_hex_width + 3)
> > >>>>>> +		return -EINVAL;
> > >>>>>> +
> > >>>>> This check is not sufficient, as display_bitwidth could be 0 for
> > >>>> example,
> > >>>>> and the actual printed number have up to 16 characters.
> > >>>> Yes, you are right. What do you think of the following check?
> > >>>>
> > >>>> max_hex_width = display_bitwidth == 0 ? (sizeof(uint64_t) * 2) :
> > >>>> spec_hex_width;
> > >>>> if (len < max_hex_width + 3)
> > >>>>       return -EINVAL;
> > >>> LGTM.
> > >> That would work, but actually I think we should drop this check
> > >> completely
> > >> - see comment below.
> > >>
> > >>>>>> +	if (display_bitwidth != 0) {
> > >>>>>> +		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
> > >>>>>> +		sprintf(buf, format, val);
> > >>> snprintf(format, sizeof(format), "0x%%0%u" PRIx64, spec_hex_width);
> > >>> snprintf(buf, len, format, val);
> > >>>
> > >>>>>> +	} else {
> > >>>>>> +		sprintf(buf, "0x%" PRIx64, val);
> > >>> snprintf(buf, len, "0x%" PRIx64, val);
> > >>>
> > >>>>>> +	}
> > >>>>>> +
> > >>>>> snprintf should always be used when printing to the buffer so as
> > >> to
> > >>>> avoid
> > >>>>> overflow. The return value after snprintf should always be
> > >> checked
> > >>>> too.
> > >>>> If check for buffer is sufficient, can the return value of
> > snprintf
> > >> not
> > >>>> be checked?
> > >>>> There are also many places in telemetry lib that are not checked
> > >> for
> > >>>> this return value.
> > >>>> Do you have any principles for this?
> > >>> You already check the buffer size before printf() into it, so I
> > think
> > >> it suffices. However, to keep automated code checkers happy, you
> > could
> > >> easily use snprintf() instead of printf(). (Sorry about not doing it
> > in
> > >> my example.)
> > >>> I somewhat disagree with Bruce's suggestion to check the return
> > value
> > >> from snprintf() after checking that the buffer is large enough. It
> > >> would be effectively dead code, which might cause some confusion. On
> > >> the other hand, it might keep some automated code checkers happy. In
> > >> this specific case here, I don't have a strong preference.
> > >> Sure, you don't need 2 checks - we can either check the length at
> > the
> > >> start, or else check the length by looking for the return value from
> > >> snprintf, but we don't need to do both.
> > >>
> > >> Given the slight complexity in determining the correct length of the
> > >> printf
> > >> for the initial size check, I think I would go with the approach of
> > >> *not*
> > >> checking the buffer initially and just check the snprintf return
> > value.
> > >> That would remove any possibility of us doing an incorrect length
> > >> check, as
> > >> was the case originally with this patch.
> > > That sounds reasonable to me. Please do that.
> > I think above check is necessary. Because snprintf returns the total
> > length of string
> > formated instead of negative when buffer size isn't sufficient. what do
> > you think?
> 
> I had the same concern, so I looked it up.
> 
> snprintf() returns the length that the string would have, regardless if it was truncated or not.
> 
> In other words:
> 
> If the string is truncated, snprintf() returns a value greater than the buffer length parameter given to it.
> 
> It can be checked like this:
> 
> if (snprintf(buf, len, "0x%" PRIx64, val) > len)
>     return -EINVAL;
> 
> In my opinion, checking for negative return values from snprintf() is not necessary.
>
+1
One nit, because of the \0, we need to check for ">=" len since a return val
equal to length means the last character was truncated to make room for the
\0.

/Bruce
  
lihuisong (C) Dec. 16, 2022, 1:15 a.m. UTC | #9
在 2022/12/15 21:08, Bruce Richardson 写道:
> On Thu, Dec 15, 2022 at 01:52:02PM +0100, Morten Brørup wrote:
>>> From: lihuisong (C) [mailto:lihuisong@huawei.com]
>>> Sent: Thursday, 15 December 2022 13.46
>>>
>>> 在 2022/12/15 20:24, Morten Brørup 写道:
>>>>> From: Bruce Richardson [mailto:bruce.richardson@intel.com]
>>>>> Sent: Thursday, 15 December 2022 13.16
>>>>>
>>>>> On Thu, Dec 15, 2022 at 01:00:40PM +0100, Morten Brørup wrote:
>>>>>>> From: lihuisong (C) [mailto:lihuisong@huawei.com]
>>>>>>> Sent: Thursday, 15 December 2022 12.28
>>>>>>>
>>>>>>> 在 2022/12/15 18:46, Bruce Richardson 写道:
>>>>>>>> On Thu, Dec 15, 2022 at 06:31:44PM +0800, Huisong Li wrote:
>>>>>>>>> Sometimes displaying a unsigned integer value as hexadecimal
>>>>> encoded
>>>>>>> style
>>>>>>>>> is more expected for human consumption, such as, offload
>>>>> capability
>>>>>>> and
>>>>>>>>> device flag. This patch introduces two APIs to add unsigned
>>>>> integer
>>>>>>> value
>>>>>>>>> as hexadecimal encoded string to array or dictionary. And user
>>>>> can
>>>>>>> choose
>>>>>>>>> whether the stored value is padding to the specified width.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Huisong Li <lihuisong@huawei.com>
>>>>>>>>> Acked-by: Morten Brørup <mb@smartsharesystems.com>
>>>>>>>>> Acked-by: Chengwen Feng <fengchengwen@huawei.com>
>>>>>>>>> ---
>>>>>>>>>     lib/telemetry/rte_telemetry.h  | 47 ++++++++++++++++++++++
>>>>>>>>>     lib/telemetry/telemetry_data.c | 72
>>>>>>> ++++++++++++++++++++++++++++++++++
>>>>>>>>>     lib/telemetry/version.map      |  9 +++++
>>>>>>>>>     3 files changed, 128 insertions(+)
>>>>>>>>>
>>>>>>>> <snip>
>>>>>>>>> +/* To suppress compiler warning about format string. */
>>>>>>>>> +#if defined(RTE_TOOLCHAIN_GCC)
>>>>>>>>> +#pragma GCC diagnostic push
>>>>>>>>> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
>>>>>>>>> +#elif defined(RTE_TOOLCHAIN_CLANG)
>>>>>>>>> +#pragma clang diagnostic push
>>>>>>>>> +#pragma clang diagnostic ignored "-Wformat-nonliteral"
>>>>>>>>> +#endif
>>>>>>>>> +
>>>>>>>>> +static int
>>>>>>>>> +rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len,
>>>>> uint64_t
>>>>>>> val,
>>>>>> The "len" parameter should be size_t or unsigned int, not uint16_t.
>>>>>>
>>>>>> And as a personal preference, I would name it "buf_len" instead of
>>>>> "len".
>>>>>>>>> +				uint8_t display_bitwidth)
>>>>>>>>> +{
>>>>>>>>> +#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
>>>>>>>>> +
>>>>>>>>> +	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
>>>>>>>>> +	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
>>>>>>>>> +
>>>>>>>>> +	/* Buffer needs to have room to contain the prefix '0x' and
>>>>> '\0'.
>>>>>>> */
>>>>>>>>> +	if (len < spec_hex_width + 3)
>>>>>>>>> +		return -EINVAL;
>>>>>>>>> +
>>>>>>>> This check is not sufficient, as display_bitwidth could be 0 for
>>>>>>> example,
>>>>>>>> and the actual printed number have up to 16 characters.
>>>>>>> Yes, you are right. What do you think of the following check?
>>>>>>>
>>>>>>> max_hex_width = display_bitwidth == 0 ? (sizeof(uint64_t) * 2) :
>>>>>>> spec_hex_width;
>>>>>>> if (len < max_hex_width + 3)
>>>>>>>        return -EINVAL;
>>>>>> LGTM.
>>>>> That would work, but actually I think we should drop this check
>>>>> completely
>>>>> - see comment below.
>>>>>
>>>>>>>>> +	if (display_bitwidth != 0) {
>>>>>>>>> +		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
>>>>>>>>> +		sprintf(buf, format, val);
>>>>>> snprintf(format, sizeof(format), "0x%%0%u" PRIx64, spec_hex_width);
>>>>>> snprintf(buf, len, format, val);
>>>>>>
>>>>>>>>> +	} else {
>>>>>>>>> +		sprintf(buf, "0x%" PRIx64, val);
>>>>>> snprintf(buf, len, "0x%" PRIx64, val);
>>>>>>
>>>>>>>>> +	}
>>>>>>>>> +
>>>>>>>> snprintf should always be used when printing to the buffer so as
>>>>> to
>>>>>>> avoid
>>>>>>>> overflow. The return value after snprintf should always be
>>>>> checked
>>>>>>> too.
>>>>>>> If check for buffer is sufficient, can the return value of
>>> snprintf
>>>>> not
>>>>>>> be checked?
>>>>>>> There are also many places in telemetry lib that are not checked
>>>>> for
>>>>>>> this return value.
>>>>>>> Do you have any principles for this?
>>>>>> You already check the buffer size before printf() into it, so I
>>> think
>>>>> it suffices. However, to keep automated code checkers happy, you
>>> could
>>>>> easily use snprintf() instead of printf(). (Sorry about not doing it
>>> in
>>>>> my example.)
>>>>>> I somewhat disagree with Bruce's suggestion to check the return
>>> value
>>>>> from snprintf() after checking that the buffer is large enough. It
>>>>> would be effectively dead code, which might cause some confusion. On
>>>>> the other hand, it might keep some automated code checkers happy. In
>>>>> this specific case here, I don't have a strong preference.
>>>>> Sure, you don't need 2 checks - we can either check the length at
>>> the
>>>>> start, or else check the length by looking for the return value from
>>>>> snprintf, but we don't need to do both.
>>>>>
>>>>> Given the slight complexity in determining the correct length of the
>>>>> printf
>>>>> for the initial size check, I think I would go with the approach of
>>>>> *not*
>>>>> checking the buffer initially and just check the snprintf return
>>> value.
>>>>> That would remove any possibility of us doing an incorrect length
>>>>> check, as
>>>>> was the case originally with this patch.
>>>> That sounds reasonable to me. Please do that.
>>> I think above check is necessary. Because snprintf returns the total
>>> length of string
>>> formated instead of negative when buffer size isn't sufficient. what do
>>> you think?
>> I had the same concern, so I looked it up.
>>
>> snprintf() returns the length that the string would have, regardless if it was truncated or not.
>>
>> In other words:
>>
>> If the string is truncated, snprintf() returns a value greater than the buffer length parameter given to it.
>>
>> It can be checked like this:
>>
>> if (snprintf(buf, len, "0x%" PRIx64, val) > len)
>>      return -EINVAL;
>>
>> In my opinion, checking for negative return values from snprintf() is not necessary.
>>
> +1
> One nit, because of the \0, we need to check for ">=" len since a return val
> equal to length means the last character was truncated to make room for the
> \0.
ok, do this in this way.
  

Patch

diff --git a/lib/telemetry/rte_telemetry.h b/lib/telemetry/rte_telemetry.h
index 40e9a3bf9d..b24f0310ea 100644
--- a/lib/telemetry/rte_telemetry.h
+++ b/lib/telemetry/rte_telemetry.h
@@ -10,6 +10,7 @@  extern "C" {
 #endif
 
 #include <stdint.h>
+#include <rte_compat.h>
 
 /** Maximum length for string used in object. */
 #define RTE_TEL_MAX_STRING_LEN 128
@@ -153,6 +154,28 @@  int
 rte_tel_data_add_array_container(struct rte_tel_data *d,
 		struct rte_tel_data *val, int keep);
 
+/**
+ * Convert a unsigned integer to hexadecimal encoded strings and add this string
+ * to an array.
+ * The array must have been started by rte_tel_data_start_array() with
+ * RTE_TEL_STRING_VAL as the type parameter.
+ *
+ * @param d
+ *   The data structure passed to the callback
+ * @param val
+ *   The number to be returned in the array as a hexadecimal encoded strings.
+ * @param display_bitwidth
+ *   The display bit width of the 'val'. If 'display_bitwidth' is zero, the
+ *   value is stored in the array as no-padding zero hexadecimal encoded string,
+ *   or the value is stored as padding zero to specified hexadecimal width.
+ * @return
+ *   0 on success, negative errno on error
+ */
+__rte_experimental
+int
+rte_tel_data_add_array_uint_hex(struct rte_tel_data *d, uint64_t val,
+				uint8_t display_bitwidth);
+
 /**
  * Add a string value to a dictionary.
  * The dict must have been started by rte_tel_data_start_dict().
@@ -231,6 +254,30 @@  int
 rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name,
 		struct rte_tel_data *val, int keep);
 
+/**
+ * Convert a unsigned integer to hexadecimal encoded strings and add this string
+ * to an dictionary.
+ * The dict must have been started by rte_tel_data_start_dict().
+ *
+ * @param d
+ *   The data structure passed to the callback
+ * @param name
+ *   The name of the value is to be stored in the dict
+ *   Must contain only alphanumeric characters or the symbols: '_' or '/'
+ * @param val
+ *   The number to be stored in the dict as a hexadecimal encoded strings.
+ * @param display_bitwidth
+ *   The display bit width of the 'val'. If 'display_bitwidth' is zero, the
+ *   value is stored in the array as no-padding zero hexadecimal encoded string,
+ *   or the value is stored as padding zero to specified hexadecimal width.
+ * @return
+ *   0 on success, negative errno on error
+ */
+__rte_experimental
+int
+rte_tel_data_add_dict_uint_hex(struct rte_tel_data *d, const char *name,
+			       uint64_t val, uint8_t display_bitwidth);
+
 /**
  * This telemetry callback is used when registering a telemetry command.
  * It handles getting and formatting information to be returned to telemetry
diff --git a/lib/telemetry/telemetry_data.c b/lib/telemetry/telemetry_data.c
index 34366ecee3..2a4dcec30a 100644
--- a/lib/telemetry/telemetry_data.c
+++ b/lib/telemetry/telemetry_data.c
@@ -4,6 +4,7 @@ 
 
 #include <errno.h>
 #include <stdlib.h>
+#include <inttypes.h>
 
 #undef RTE_USE_LIBBSD
 #include <stdbool.h>
@@ -12,6 +13,8 @@ 
 
 #include "telemetry_data.h"
 
+#define RTE_TEL_UINT_HEX_STR_BUF_LEN 64
+
 int
 rte_tel_data_start_array(struct rte_tel_data *d, enum rte_tel_value_type type)
 {
@@ -97,6 +100,59 @@  rte_tel_data_add_array_container(struct rte_tel_data *d,
 	return 0;
 }
 
+/* To suppress compiler warning about format string. */
+#if defined(RTE_TOOLCHAIN_GCC)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#elif defined(RTE_TOOLCHAIN_CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-nonliteral"
+#endif
+
+static int
+rte_tel_uint_to_hex_encoded_str(char *buf, uint16_t len, uint64_t val,
+				uint8_t display_bitwidth)
+{
+#define RTE_TEL_UINT_HEX_FORMAT_LEN 16
+
+	uint8_t spec_hex_width = (display_bitwidth + 3) / 4;
+	char format[RTE_TEL_UINT_HEX_FORMAT_LEN];
+
+	/* Buffer needs to have room to contain the prefix '0x' and '\0'. */
+	if (len < spec_hex_width + 3)
+		return -EINVAL;
+
+	if (display_bitwidth != 0) {
+		sprintf(format, "0x%%0%u" PRIx64, spec_hex_width);
+		sprintf(buf, format, val);
+	} else {
+		sprintf(buf, "0x%" PRIx64, val);
+	}
+
+	return 0;
+}
+
+#if defined(RTE_TOOLCHAIN_GCC)
+#pragma GCC diagnostic pop
+#elif defined(RTE_TOOLCHAIN_CLANG)
+#pragma clang diagnostic pop
+#endif
+
+int
+rte_tel_data_add_array_uint_hex(struct rte_tel_data *d, uint64_t val,
+				uint8_t display_bitwidth)
+{
+	char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
+	int ret;
+
+	ret = rte_tel_uint_to_hex_encoded_str(hex_str,
+			RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
+	if (ret != 0)
+		return ret;
+
+	return rte_tel_data_add_array_string(d, hex_str);
+}
+
 static bool
 valid_name(const char *name)
 {
@@ -204,6 +260,22 @@  rte_tel_data_add_dict_container(struct rte_tel_data *d, const char *name,
 	return bytes < RTE_TEL_MAX_STRING_LEN ? 0 : E2BIG;
 }
 
+int
+rte_tel_data_add_dict_uint_hex(struct rte_tel_data *d, const char *name,
+			       uint64_t val, uint8_t display_bitwidth)
+{
+	char hex_str[RTE_TEL_UINT_HEX_STR_BUF_LEN];
+	int ret;
+
+	ret = rte_tel_uint_to_hex_encoded_str(hex_str,
+			RTE_TEL_UINT_HEX_STR_BUF_LEN, val, display_bitwidth);
+	if (ret != 0)
+		return ret;
+
+
+	return rte_tel_data_add_dict_string(d, name, hex_str);
+}
+
 struct rte_tel_data *
 rte_tel_data_alloc(void)
 {
diff --git a/lib/telemetry/version.map b/lib/telemetry/version.map
index 9794f9ea20..951bd63974 100644
--- a/lib/telemetry/version.map
+++ b/lib/telemetry/version.map
@@ -1,3 +1,12 @@ 
+EXPERIMENTAL {
+	global:
+
+	rte_tel_data_add_array_uint_hex;
+	rte_tel_data_add_dict_uint_hex;
+
+	local: *;
+};
+
 DPDK_23 {
 	global: