Solved! :-) -- Re: How to calculate ICMPv6 checksum?

2025-08-14 Thread Gábor LENCSE

Dear Stephen,

On 8/13/2025 1:57 AM, Stephen Hemminger wrote:
[...]


Yes this is similar but in UDP/TCP case the UDP/TCP header is included in
the checksum. l4_hdr points to the UDP/TCP header. l4_len is the payload
length that is TCP/UDP header and the associated data.


Yes, when I tried using the rte_ipv6_udptcp_cksum() function, I supplied 
a pointer to the ICMPv6 header as the second argument. My code line was:


reply_icmpv6_hdr->checksum=rte_ipv6_udptcp_cksum(reply_ipv6_hdr,reply_icmpv6_hdr); 



And the internal function reads out the payload length from the IPv6 
header as follows:


    l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);

This is also correct.


The pseudo header is done by rte_ipv6_phdr_cksum().

For ICMPv6 you would need to point l4_hdr at ICMP header.
Even though ICMP is not really an L4 protocol.

https://en.wikipedia.org/wiki/ICMPv6#Checksum

Yes, I checked the drawing, this is the same as 
https://www.rfc-editor.org/rfc/rfc2460#section-8.1 and the code 
calculates exactly the same (with some trick, as I mentioned earlier).


*And the calculated checksum is CORRECT! :-)*

It turned out, that I had made a programming error. (My calculation of 
the address of the checksum field was incorrect, and thus I manipulated 
a wrong field.)


Anyway, thank you very much for all your help!

I learnt a lot from checking how ICMPv6 checksum is calculated. :-)

And I hope that it will be useful information for others that the 
rte_ipv6_udptcp_cksum() function is perfectly suitable for calculating 
ICMPv6 checksum, too. :-)


Best regards,

Gábor




Re: How to calculate ICMPv6 checksum?

2025-08-12 Thread Stephen Hemminger
On Fri, 8 Aug 2025 20:56:33 +0200
Gábor LENCSE  wrote:

> Dear Stephen,
> 
> Thank you very much for your answer. It helps me a lot, but I have 
> further questions. Please see my comments inline.
> > The pseudo-header part is different.  
> If I understand it correctly, then it means that I need to write the 
> ICMPv6 checksum function myself. To that end, I reviewed the source code 
> of the "rte_ipv6_udptcp_cksum()" function so that I can learn from it. 
> However, I did not find where it differs from the one that I need. I 
> took the below source code from here: 
> https://doc.dpdk.org/api/rte__ip6_8h_source.html#l00610 
> rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void 
> *l4_hdr) { uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr); 
> cksum = ~cksum; /* * Per RFC 768: If the computed checksum is zero for 
> UDP, * it is transmitted as all ones * (the equivalent in one's 
> complement arithmetic). */ if (cksum == 0 && ipv6_hdr->proto == 
> IPPROTO_UDP) cksum = 0x; return cksum; } It is the highest level. It 
> calls an internal function and at the end it considers the protocol 
> number (with other words, the next header field of the IPv6 header) when 
> it handles UDP specific things, thus I think that this time it does not 
> cause any problem in the case of ICMPv6.
> 
> This is the source code of the internal function:
> 
> static inline uint16_t
> __rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void 
> *l4_hdr)
> {
>      uint32_t cksum;
>      uint32_t l4_len;
> 
>      l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);
> 
>      cksum = rte_raw_cksum(l4_hdr, l4_len);
>      cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0);
> 
>      cksum = ((cksum & 0x) >> 16) + (cksum & 0x);
> 
>      return (uint16_t)cksum;
> }

Yes this is similar but in UDP/TCP case the UDP/TCP header is included in
the checksum. l4_hdr points to the UDP/TCP header. l4_len is the payload
length that is TCP/UDP header and the associated data.

The pseudo header is done by rte_ipv6_phdr_cksum().

For ICMPv6 you would need to point l4_hdr at ICMP header.
Even though ICMP is not really an L4 protocol.

https://en.wikipedia.org/wiki/ICMPv6#Checksum





Re: How to calculate ICMPv6 checksum?

2025-08-08 Thread Gábor LENCSE

Dear Stephen,

Thank you very much for your answer. It helps me a lot, but I have 
further questions. Please see my comments inline.

The pseudo-header part is different.
If I understand it correctly, then it means that I need to write the 
ICMPv6 checksum function myself. To that end, I reviewed the source code 
of the "rte_ipv6_udptcp_cksum()" function so that I can learn from it. 
However, I did not find where it differs from the one that I need. I 
took the below source code from here: 
https://doc.dpdk.org/api/rte__ip6_8h_source.html#l00610 
rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void 
*l4_hdr) { uint16_t cksum = __rte_ipv6_udptcp_cksum(ipv6_hdr, l4_hdr); 
cksum = ~cksum; /* * Per RFC 768: If the computed checksum is zero for 
UDP, * it is transmitted as all ones * (the equivalent in one's 
complement arithmetic). */ if (cksum == 0 && ipv6_hdr->proto == 
IPPROTO_UDP) cksum = 0x; return cksum; } It is the highest level. It 
calls an internal function and at the end it considers the protocol 
number (with other words, the next header field of the IPv6 header) when 
it handles UDP specific things, thus I think that this time it does not 
cause any problem in the case of ICMPv6.


This is the source code of the internal function:

static inline uint16_t
__rte_ipv6_udptcp_cksum(const struct rte_ipv6_hdr *ipv6_hdr, const void 
*l4_hdr)

{
    uint32_t cksum;
    uint32_t l4_len;

    l4_len = rte_be_to_cpu_16(ipv6_hdr->payload_len);

    cksum = rte_raw_cksum(l4_hdr, l4_len);
    cksum += rte_ipv6_phdr_cksum(ipv6_hdr, 0);

    cksum = ((cksum & 0x) >> 16) + (cksum & 0x);

    return (uint16_t)cksum;
}

It calculates the checksum for the L4 part and also for the 
pseudo-header separately. The latter could be different than what I need 
for ICMPv6.


I also checked the source code of  "rte_ipv6_phdr_cksum(ipv6_hdr, 0)", 
please see it below the figure from RFC 2460.



https://www.rfc-editor.org/rfc/rfc4443

2.3.  Message Checksum Calculation

The checksum is the 16-bit one's complement of the one's complement
sum of the entire ICMPv6 message, starting with the ICMPv6 message
type field, and prepended with a "pseudo-header" of IPv6 header
fields, as specified in [IPv6, Section 8.1].  The Next Header value
used in the pseudo-header is 58.  (The inclusion of a pseudo-header
in the ICMPv6 checksum is a change from IPv4; see [IPv6] for the
rationale for this change.)

For computing the checksum, the checksum field is first set to zero.

https://www.rfc-editor.org/rfc/rfc2460#section-8.1

8.1 Upper-Layer Checksums

Any transport or other upper-layer protocol that includes the
addresses from the IP header in its checksum computation must be
modified for use over IPv6, to include the 128-bit IPv6 addresses
instead of 32-bit IPv4 addresses.  In particular, the following
illustration shows the TCP and UDP "pseudo-header" for IPv6:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   |
+   +
|   |
+ Source Address+
|   |
+   +
|   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   |
+   +
|   |
+  Destination Address  +
|   |
+   +
|   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Upper-Layer Packet Length   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  zero |  Next Header  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


So this is what I need. And it seems to me, that the below source code 
does exactly the same:


static inline uint16_t
rte_ipv6_phdr_cksum(const struct rte_ipv6_hdr *ipv6_hdr, uint64_t ol_flags)
{
    uint32_t sum;
    struct {
    rte_be32_t len;   /* L4 length. */
    rte_be32_t proto; /* L4 protocol - top 3 bytes must be zero */
    } psd_hdr;

    psd_hdr.proto = (uint32_t)(ipv6_hdr->proto << 24);
    if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))
    psd_hdr.len = 0;
    else
    psd_hdr.len = ipv6_hdr->payload_len;

Re: How to calculate ICMPv6 checksum?

2025-08-07 Thread Stephen Hemminger
On Thu, 7 Aug 2025 17:32:02 +0200
Gábor LENCSE  wrote:

> Dear All,
> 
> I am working on adding ARP/NDP support to my SIIT / Stateful NAT64 
> benchmarking tool, siitperf [1]. (So far, the ARP / NDP table entries 
> had to be set manually at the device under test, as siitperf was not 
> able to reply to ARP / NDP requests).
> 
> The ARP reply functionality seems to work fine, but I have a problem 
> with NDP. As ICMPv6 messages contain checksum, I would need a function 
> that computes it. However, I only found  the rte_ipv6_udptcp_cksum() 
> function, but I did not find a similar one for calculating ICMPv6 checksum.
> 
> I have been checking the functions shown here: 
> https://doc.dpdk.org/api/rte__ip6_8h.html
> 
> Could you please advise me about the function to use for ICMPv6 checksum 
> calculation?
> 
> Best regards,
> 
> Gábor
> 
> [1] https://github.com/lencsegabor/siitperf

The pseudo-header part is different.


https://www.rfc-editor.org/rfc/rfc4443

2.3.  Message Checksum Calculation

   The checksum is the 16-bit one's complement of the one's complement
   sum of the entire ICMPv6 message, starting with the ICMPv6 message
   type field, and prepended with a "pseudo-header" of IPv6 header
   fields, as specified in [IPv6, Section 8.1].  The Next Header value
   used in the pseudo-header is 58.  (The inclusion of a pseudo-header
   in the ICMPv6 checksum is a change from IPv4; see [IPv6] for the
   rationale for this change.)

   For computing the checksum, the checksum field is first set to zero.

https://www.rfc-editor.org/rfc/rfc2460#section-8.1

8.1 Upper-Layer Checksums

   Any transport or other upper-layer protocol that includes the
   addresses from the IP header in its checksum computation must be
   modified for use over IPv6, to include the 128-bit IPv6 addresses
   instead of 32-bit IPv4 addresses.  In particular, the following
   illustration shows the TCP and UDP "pseudo-header" for IPv6:

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   |
   +   +
   |   |
   + Source Address+
   |   |
   +   +
   |   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   |
   +   +
   |   |
   +  Destination Address  +
   |   |
   +   +
   |   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Upper-Layer Packet Length   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  zero |  Next Header  |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  o  If the IPv6 packet contains a Routing header, the Destination
 Address used in the pseudo-header is that of the final
 destination.  At the originating node, that address will be in
 the last element of the Routing header; at the recipient(s),
 that address will be in the Destination Address field of the
 IPv6 header.

  o  The Next Header value in the pseudo-header identifies the
 upper-layer protocol (e.g., 6 for TCP, or 17 for UDP).  It will
 differ from the Next Header value in the IPv6 header if there
 are extension headers between the IPv6 header and the upper-
 layer header.

  o  The Upper-Layer Packet Length in the pseudo-header is the
 length of the upper-layer header and data (e.g., TCP header
 plus TCP data).  Some upper-layer protocols carry their own
 length information (e.g., the Length field in the UDP header);
 for such protocols, that is the length used in the pseudo-
 header.  Other protocols (such as TCP) do not carry their own
 length information, in which case the length used in the
 pseudo-header is the Payload Length from the IPv6 header, minus
 the length of any extension headers present between the IPv6
 header and the upper-layer header.

  o  Unlike IPv4, when UDP packets are originated by an IPv6 node,
 the UDP checksum is not optional.  That is, whenever
 originating a UDP packet, an IPv6 node must compute a UDP
 checksum over the packet and the pseudo-header, 

How to calculate ICMPv6 checksum?

2025-08-07 Thread Gábor LENCSE

Dear All,

I am working on adding ARP/NDP support to my SIIT / Stateful NAT64 
benchmarking tool, siitperf [1]. (So far, the ARP / NDP table entries 
had to be set manually at the device under test, as siitperf was not 
able to reply to ARP / NDP requests).


The ARP reply functionality seems to work fine, but I have a problem 
with NDP. As ICMPv6 messages contain checksum, I would need a function 
that computes it. However, I only found  the rte_ipv6_udptcp_cksum() 
function, but I did not find a similar one for calculating ICMPv6 checksum.


I have been checking the functions shown here: 
https://doc.dpdk.org/api/rte__ip6_8h.html


Could you please advise me about the function to use for ICMPv6 checksum 
calculation?


Best regards,

Gábor

[1] https://github.com/lencsegabor/siitperf