__rte_raw_cksum() crash with misaligned pointer
https://bugs.dpdk.org/show_bug.cgi?id=1035
Bug ID: 1035
Summary: __rte_raw_cksum() crash with misaligned pointer
Product: DPDK
Version: 21.11
Hardware: All
OS: All
Status: UNCONFIRMED
Severity: normal
Priority: Normal
Component: ethdev
Assignee: [email protected]
Reporter: [email protected]Target Milestone: ---
See rte_raw_cksum() in rte_ip.h, which is part of the public API. See also the subfunction __rte_raw_cksum().
_rte_raw_cksum assumes that the buffer over which the checksum is calculated is an even address (divisible by two). See for example this stack overflow post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-strict-aliasing-rule-or-incorrect-alignment
The post explains that there is undefined behavior in C11 when "conversion between two pointer types produces a result that is incorrectly aligned". When the buf argument starts on an odd address we thus have undefined behavior, since a pointer is cast from void* to uint16_t*.
In most cases (at least on x86) that isn't a problem, but with higher optimization levels it may break due to vector instructions. This new function seems to be easier to optimize by the compiler, resulting in a crash when the buf argument is odd. Please note that the undefined behavior is present in earlier versions of dpdk as well.
Now you're probably thinking: "Just align your buffers". The problem is that we have a packet buffer which is aligned. The checksum is calculated on a subset of that aligned packet buffer, and that sometimes lies on odd addresses.
The question remains if this is an issue with dpdk or not. Maybe you do the assumption that odd addresses are never passed in when calculating the checksum, and that's all right. But perhaps a public API comment should be added in that case. Or perhaps you use it incorrectly as well, and in that case something should be done about it.
Triggering this bug seems to require high optimization levels as well as odd values of buf.
Of interest may be that in older version of dpdk you added the a comment: /* workaround gcc strict-aliasing warning */ showing that you willfully ignored the warning.
Signature · 2 lines
You are receiving this mail because: You are the assignee for the bug.
Quoted 47 lines
From: [email protected] [mailto:[email protected]]
Sent: Wednesday, 15 June 2022 09.16https://bugs.dpdk.org/show_bug.cgi?id=1035
Bug ID: 1035 Summary: __rte_raw_cksum() crash with misaligned pointer Product: DPDK Version: 21.11 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: Normal Component: ethdev Assignee: [email protected] Reporter: [email protected]Target Milestone: ---
See
rte_raw_cksum()inrte_ip.h, which is part of the public API. See also the
subfunction__rte_raw_cksum().
_rte_raw_cksumassumes that the buffer over which the checksum is calculated is
an even address (divisible by two). See for example this stack overflow post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-
strict-aliasing-rule-or-incorrect-alignmentThe post explains that there is undefined behavior in C11 when "conversion
between two pointer types produces a result that is incorrectly aligned". When
the buf argument starts on an odd address we thus have undefined behavior,
since a pointer is cast from void* to uint16_t*.In most cases (at least on x86) that isn't a problem, but with higher optimization levels it may break due to vector instructions. This new function
seems to be easier to optimize by the compiler, resulting in a crash when the
buf argument is odd. Please note that the undefined behavior is present in
earlier versions of dpdk as well.
Quoted 8 lines
Now you're probably thinking: "Just align your buffers". The problem is that we
have a packet buffer which is aligned. The checksum is calculated on a subset
of that aligned packet buffer, and that sometimes lies on odd addresses.The question remains if this is an issue with dpdk or not.
I can imagine other systems doing what you describe too. So it needs to be addressed.
Off the top of my head, an easy fix would be updating __rte_raw_cksum() like this:
static inline uint32_t__rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
{
if (likely((buf & 1) == 0)) {
/* The buffer is 16 bit aligned. */
Keep the existing, optimized implementation here.
} else {
/* The buffer is not 16 bit aligned. */
Add a new odd-buf tolerant implementation here.
}
}However, I'm not sure that it covers your scenario!
The checksum is 16 bit wide, so if you calculate the checksum of e.g. 4 bytes of memory starting at offset 1 in a 6 byte packet buffer, the memory block can be treated as either 4 or 6 bytes relative to the data covered by the checksum, i.e.:
A: XX [01 02] [03 04] XX --> cksum = [04 06]
B: [XX 01] [02 03] [04 XX] --> cksum = [06 04]
Which one do you need?
Perhaps an additional function is required to support your use case, and the documentation for rte_raw_cksum() and __rte_raw_cksum() needs to reflect that the buffer must be 16 bit aligned.
Or the rte_raw_cksum() function can be modified to support an odd buffer pointer as outlined above, with documentation added about alignment of the running checksum.
+CC Olivier Matz <[email protected]>, Network Headers maintainer
Quoted 95 lines
From: Morten Brørup <[email protected]>
Sent: den 15 juni 2022 16:41Quoted 4 lines
From: [email protected] [mailto:[email protected]]
Sent: Wednesday, 15 June 2022 09.16https://protect2.fireeye.com/v1/url?k=31323334-501d5122-313273af-
45444
Quoted 1 line
5555731-2e92ae6bf759c0c5&q=1&e=b3fc70af-5d37-4ffb-b34d-
9a51927f5f6d&u=
Quoted 14 lines
https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%3D1035
Bug ID: 1035 Summary: __rte_raw_cksum() crash with misaligned pointer Product: DPDK Version: 21.11 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: Normal Component: ethdev Assignee: [email protected] Reporter: [email protected]Quoted 7 lines
Target Milestone: ---
See
rte_raw_cksum()inrte_ip.h, which is part of the public API. See also the subfunction__rte_raw_cksum().
_rte_raw_cksumassumes that the buffer over which the checksum is calculated is an even address (divisible by two). See for examplethis
Quoted 9 lines
stack overflow
post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-
strict-aliasing-rule-or-incorrect-alignmentThe post explains that there is undefined behavior in C11 when "conversion between two pointer types produces a result that is incorrectly aligned". When the buf argument starts on an odd address we thus have undefined behavior, since a pointer is cast from void*
to
Quoted 8 lines
uint16_t*.
In most cases (at least on x86) that isn't a problem, but with higher optimization levels it may break due to vector instructions. This new function seems to be easier to optimize by the compiler, resulting in a crash when the buf argument is odd. Please note that the undefined behavior is present in earlier versions of dpdk as well.
Quoted 6 lines
Now you're probably thinking: "Just align your buffers". The problem is that we have a packet buffer which is aligned. The checksum is calculated on a subset of that aligned packet buffer, and that sometimes lies on odd addresses.
The question remains if this is an issue with dpdk or not.
I can imagine other systems doing what you describe too. So it needs to be addressed.
Off the top of my head, an easy fix would be updating
__rte_raw_cksum()like this:static inline
uint32_t__rte_raw_cksum(const void *buf, size_t len, uint32_t sum) { if (likely((buf & 1) == 0)) { /* The buffer is 16 bit aligned. */ Keep the existing, optimized implementation here. } else { /* The buffer is not 16 bit aligned. */ Add a new odd-buf tolerant implementation here. } }However, I'm not sure that it covers your scenario!
The checksum is 16 bit wide, so if you calculate the checksum of e.g. 4 bytes of memory starting at offset 1 in a 6 byte packet buffer, the memory block can be treated as either 4 or 6 bytes relative to the data covered by the checksum, i.e.:
A: XX [01 02] [03 04] XX --> cksum = [04 06]
B: [XX 01] [02 03] [04 XX] --> cksum = [06 04]
Which one do you need?
Perhaps an additional function is required to support your use case, and the documentation for
rte_raw_cksum()and__rte_raw_cksum()needs to reflect that the buffer must be 16 bit aligned.Or the
rte_raw_cksum()function can be modified to support an odd buffer pointer as outlined above, with documentation added about alignment of the running checksum.
Quoted 8 lines
-----Original Message-----
From: Emil Berg [mailto:[email protected]]
Sent: Thursday, 16 June 2022 07.45Hi!
We want the B option, i.e. the 6 bytes option. Perhaps adding alignment detection to
__rte_raw_cksum()is a good idea.
With option B, the invariant that the running checksum is being calculated on a 16 bit aligned packet buffer remains unchanged. So I think that support for option B is appropriate to add to __rte_raw_cksum(), rather than adding a separate function.
Quoted 7 lines
A minor comment but I think buf & 1 won't work since buf isn't an integral type, but something along that way.
I'm starting to think about an efficient way to do this.
Thank you!
Sounds good. Please CC me on your patch, when ready for review. :-)
+CC Olivier Matz <[email protected]>, Network Headers maintainer
Quoted 132 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 15 juni 2022 16:41
To: Emil Berg <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misaligned pointerQuoted 4 lines
From: [email protected] [mailto:[email protected]]
Sent: Wednesday, 15 June 2022 09.16https://protect2.fireeye.com/v1/url?k=31323334-501d5122-313273af-
45444
Quoted 1 line
5555731-2e92ae6bf759c0c5&q=1&e=b3fc70af-5d37-4ffb-b34d-
9a51927f5f6d&u=
Quoted 14 lines
https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%3D1035
Bug ID: 1035 Summary: __rte_raw_cksum() crash with misaligned pointer Product: DPDK Version: 21.11 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: Normal Component: ethdev Assignee: [email protected] Reporter: [email protected]Quoted 7 lines
Target Milestone: ---
See
rte_raw_cksum()inrte_ip.h, which is part of the public API. See also the subfunction__rte_raw_cksum().
_rte_raw_cksumassumes that the buffer over which the checksum is calculated is an even address (divisible by two). See for examplethis
Quoted 9 lines
stack overflow
post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-
strict-aliasing-rule-or-incorrect-alignmentThe post explains that there is undefined behavior in C11 when "conversion between two pointer types produces a result that is incorrectly aligned". When the buf argument starts on an odd address we thus have undefined behavior, since a pointer is cast from void*
to
Quoted 8 lines
uint16_t*.
In most cases (at least on x86) that isn't a problem, but with higher optimization levels it may break due to vector instructions. This new function seems to be easier to optimize by the compiler, resulting in a crash when the buf argument is odd. Please note that the undefined behavior is present in earlier versions of dpdk as well.
Quoted 6 lines
Now you're probably thinking: "Just align your buffers". The problem is that we have a packet buffer which is aligned. The checksum is calculated on a subset of that aligned packet buffer, and that sometimes lies on odd addresses.
The question remains if this is an issue with dpdk or not.
I can imagine other systems doing what you describe too. So it needs to be addressed.
Off the top of my head, an easy fix would be updating
__rte_raw_cksum()like this:static inline
uint32_t__rte_raw_cksum(const void *buf, size_t len, uint32_t sum) { if (likely((buf & 1) == 0)) { /* The buffer is 16 bit aligned. */ Keep the existing, optimized implementation here. } else { /* The buffer is not 16 bit aligned. */ Add a new odd-buf tolerant implementation here. } }However, I'm not sure that it covers your scenario!
The checksum is 16 bit wide, so if you calculate the checksum of e.g. 4 bytes of memory starting at offset 1 in a 6 byte packet buffer, the memory block can be treated as either 4 or 6 bytes relative to the data covered by the checksum, i.e.:
A: XX [01 02] [03 04] XX --> cksum = [04 06]
B: [XX 01] [02 03] [04 XX] --> cksum = [06 04]
Which one do you need?
Perhaps an additional function is required to support your use case, and the documentation for
rte_raw_cksum()and__rte_raw_cksum()needs to reflect that the buffer must be 16 bit aligned.Or the
rte_raw_cksum()function can be modified to support an odd buffer pointer as outlined above, with documentation added about alignment of the running checksum.-----Original Message-----
From: Emil Berg
Sent: den 16 juni 2022 07:45
To: Morten Brørup <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misaligned pointerHi!
We want the B option, i.e. the 6 bytes option. Perhaps adding alignment detection to
__rte_raw_cksum()is a good idea.A minor comment but I think buf & 1 won't work since buf isn't an integral type, but something along that way.
I'm starting to think about an efficient way to do this.
Thank you!
-----Original Message-----
From: Emil Berg [mailto:[email protected]]
Sent: Thursday, 16 June 2022 08.32
To: Morten Brørup; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misaligned pointerI've been sketching on an efficient solution to this. What about something along the way below? I've run it with the combinations of:
even buf, even len
even buf, odd len
odd buf, even len
odd buf, odd len
Quoted 4 lines
and it seems to give the same results as the older version of
__rte_raw_cksum, before 21.03. I ran it without optimizations and such to ensure the compiler didn't insert vector instructions and such so the results were comparable.
The performance, when using an aligned buffer, needs to be comparable with full compiler optimization, or the patch will not be accepted.
Quoted 12 lines
static inline
uint32_t__rte_raw_cksum_newest(const void *buf, size_t len, uint32_t sum){ const uint8_t *end = buf + len; uint32_t sum_even = 0; for (const uint8_t *p = buf + 1; p < end; p += 2) { sum_even += *p; } sum += sum_even << 8;
Quoted 8 lines
uint32_t sum_odd = 0;
for (const uint8_t *p = buf; p < end; p += 2) {
sum_odd += *p;
}
sum += sum_odd;
return sum;
}This function does not work on both little and big endian, when mixed with other checksum functions.
The checksum functions read the buffer in CPU native endian and stores the checksum in CPU native endian; and magically it becomes correct in network endian. Please refer to RFC 1071 for the details. Perhaps you can also find some inspiration in RFC 1141.
PS: Please don't top post.
Hi!
We want the B option, i.e. the 6 bytes option. Perhaps adding alignment detection to __rte_raw_cksum() is a good idea.
A minor comment but I think buf & 1 won't work since buf isn't an integral type, but something along that way.
I'm starting to think about an efficient way to do this.
Thank you!
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 15 juni 2022 16:41
To: Emil Berg <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035] __rte_raw_cksum() crash with misaligned pointer
Quoted 43 lines
From: [email protected] [mailto:[email protected]]
Sent: Wednesday, 15 June 2022 09.16https://protect2.fireeye.com/v1/url?k=31323334-501d5122-313273af-45444
5555731-2e92ae6bf759c0c5&q=1&e=b3fc70af-5d37-4ffb-b34d-9a51927f5f6d&u= https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%3D1035Bug ID: 1035 Summary: __rte_raw_cksum() crash with misaligned pointer Product: DPDK Version: 21.11 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: Normal Component: ethdev Assignee: [email protected] Reporter: [email protected]Target Milestone: ---
See
rte_raw_cksum()inrte_ip.h, which is part of the public API. See also the subfunction__rte_raw_cksum().
_rte_raw_cksumassumes that the buffer over which the checksum is calculated is an even address (divisible by two). See for example this stack overflow
post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-
strict-aliasing-rule-or-incorrect-alignmentThe post explains that there is undefined behavior in C11 when "conversion between two pointer types produces a result that is incorrectly aligned". When the buf argument starts on an odd address we thus have undefined behavior, since a pointer is cast from void* to uint16_t*.
In most cases (at least on x86) that isn't a problem, but with higher optimization levels it may break due to vector instructions. This new function seems to be easier to optimize by the compiler, resulting in a crash when the buf argument is odd. Please note that the undefined behavior is present in earlier versions of dpdk as well.
Quoted 6 lines
Now you're probably thinking: "Just align your buffers". The problem is that we have a packet buffer which is aligned. The checksum is calculated on a subset of that aligned packet buffer, and that sometimes lies on odd addresses.
The question remains if this is an issue with dpdk or not.
I can imagine other systems doing what you describe too. So it needs to be addressed.
Off the top of my head, an easy fix would be updating __rte_raw_cksum() like this:
static inline uint32_t
__rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {
if (likely((buf & 1) == 0)) {
/* The buffer is 16 bit aligned. */
Keep the existing, optimized implementation here.
} else {
/* The buffer is not 16 bit aligned. */
Add a new odd-buf tolerant implementation here.
}
}However, I'm not sure that it covers your scenario!
The checksum is 16 bit wide, so if you calculate the checksum of e.g. 4 bytes of memory starting at offset 1 in a 6 byte packet buffer, the memory block can be treated as either 4 or 6 bytes relative to the data covered by the checksum, i.e.:
A: XX [01 02] [03 04] XX --> cksum = [04 06]
B: [XX 01] [02 03] [04 XX] --> cksum = [06 04]
Which one do you need?
Perhaps an additional function is required to support your use case, and the documentation for rte_raw_cksum() and __rte_raw_cksum() needs to reflect that the buffer must be 16 bit aligned.
Or the rte_raw_cksum() function can be modified to support an odd buffer pointer as outlined above, with documentation added about alignment of the running checksum.
I've been sketching on an efficient solution to this. What about something along the way below? I've run it with the combinations of:
even buf, even len
even buf, odd len
odd buf, even len
odd buf, odd len
and it seems to give the same results as the older version of __rte_raw_cksum, before 21.03. I ran it without optimizations and such to ensure the compiler didn't insert vector instructions and such so the results were comparable.
static inline uint32_t__rte_raw_cksum_newest(const void *buf, size_t len, uint32_t sum)
{
const uint8_t *end = buf + len;
uint32_t sum_even = 0;
for (const uint8_t *p = buf + 1; p < end; p += 2) {
sum_even += *p;
}
sum += sum_even << 8;
uint32_t sum_odd = 0;
for (const uint8_t *p = buf; p < end; p += 2) {
sum_odd += *p;
}
sum += sum_odd;
return sum;
}/Emil
-----Original Message-----
From: Emil Berg
Sent: den 16 juni 2022 07:45
To: Morten Brørup <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035] __rte_raw_cksum() crash with misaligned pointer
Hi!
We want the B option, i.e. the 6 bytes option. Perhaps adding alignment detection to __rte_raw_cksum() is a good idea.
A minor comment but I think buf & 1 won't work since buf isn't an integral type, but something along that way.
I'm starting to think about an efficient way to do this.
Thank you!
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 15 juni 2022 16:41
To: Emil Berg <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035] __rte_raw_cksum() crash with misaligned pointer
Quoted 43 lines
From: [email protected] [mailto:[email protected]]
Sent: Wednesday, 15 June 2022 09.16https://protect2.fireeye.com/v1/url?k=31323334-501d5122-313273af-45444
5555731-2e92ae6bf759c0c5&q=1&e=b3fc70af-5d37-4ffb-b34d-9a51927f5f6d&u= https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%3D1035Bug ID: 1035 Summary: __rte_raw_cksum() crash with misaligned pointer Product: DPDK Version: 21.11 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: Normal Component: ethdev Assignee: [email protected] Reporter: [email protected]Target Milestone: ---
See
rte_raw_cksum()inrte_ip.h, which is part of the public API. See also the subfunction__rte_raw_cksum().
_rte_raw_cksumassumes that the buffer over which the checksum is calculated is an even address (divisible by two). See for example this stack overflow
post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-
strict-aliasing-rule-or-incorrect-alignmentThe post explains that there is undefined behavior in C11 when "conversion between two pointer types produces a result that is incorrectly aligned". When the buf argument starts on an odd address we thus have undefined behavior, since a pointer is cast from void* to uint16_t*.
In most cases (at least on x86) that isn't a problem, but with higher optimization levels it may break due to vector instructions. This new function seems to be easier to optimize by the compiler, resulting in a crash when the buf argument is odd. Please note that the undefined behavior is present in earlier versions of dpdk as well.
Quoted 6 lines
Now you're probably thinking: "Just align your buffers". The problem is that we have a packet buffer which is aligned. The checksum is calculated on a subset of that aligned packet buffer, and that sometimes lies on odd addresses.
The question remains if this is an issue with dpdk or not.
I can imagine other systems doing what you describe too. So it needs to be addressed.
Off the top of my head, an easy fix would be updating __rte_raw_cksum() like this:
static inline uint32_t
__rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {
if (likely((buf & 1) == 0)) {
/* The buffer is 16 bit aligned. */
Keep the existing, optimized implementation here.
} else {
/* The buffer is not 16 bit aligned. */
Add a new odd-buf tolerant implementation here.
}
}However, I'm not sure that it covers your scenario!
The checksum is 16 bit wide, so if you calculate the checksum of e.g. 4 bytes of memory starting at offset 1 in a 6 byte packet buffer, the memory block can be treated as either 4 or 6 bytes relative to the data covered by the checksum, i.e.:
A: XX [01 02] [03 04] XX --> cksum = [04 06]
B: [XX 01] [02 03] [04 XX] --> cksum = [06 04]
Which one do you need?
Perhaps an additional function is required to support your use case, and the documentation for rte_raw_cksum() and __rte_raw_cksum() needs to reflect that the buffer must be 16 bit aligned.
Or the rte_raw_cksum() function can be modified to support an odd buffer pointer as outlined above, with documentation added about alignment of the running checksum.
Quoted 134 lines · Morten Brørup
+CC Olivier Matz <[email protected]>, Network Headers maintainer
Quoted 132 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 15 juni 2022 16:41
To: Emil Berg <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misaligned pointerQuoted 4 lines
From: [email protected] [mailto:[email protected]]
Sent: Wednesday, 15 June 2022 09.16https://protect2.fireeye.com/v1/url?k=31323334-501d5122-313273af-
45444
Quoted 1 line
5555731-2e92ae6bf759c0c5&q=1&e=b3fc70af-5d37-4ffb-b34d-
9a51927f5f6d&u=
Quoted 14 lines
https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%3D1035
Bug ID: 1035 Summary: __rte_raw_cksum() crash with misaligned pointer Product: DPDK Version: 21.11 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: Normal Component: ethdev Assignee: [email protected] Reporter: [email protected]Quoted 7 lines
Target Milestone: ---
See
rte_raw_cksum()inrte_ip.h, which is part of the public API. See also the subfunction__rte_raw_cksum().
_rte_raw_cksumassumes that the buffer over which the checksum is calculated is an even address (divisible by two). See for examplethis
Quoted 9 lines
stack overflow
post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-
strict-aliasing-rule-or-incorrect-alignmentThe post explains that there is undefined behavior in C11 when "conversion between two pointer types produces a result that is incorrectly aligned". When the buf argument starts on an odd address we thus have undefined behavior, since a pointer is cast from void*
to
Quoted 8 lines
uint16_t*.
In most cases (at least on x86) that isn't a problem, but with higher optimization levels it may break due to vector instructions. This new function seems to be easier to optimize by the compiler, resulting in a crash when the buf argument is odd. Please note that the undefined behavior is present in earlier versions of dpdk as well.
Quoted 6 lines
Now you're probably thinking: "Just align your buffers". The problem is that we have a packet buffer which is aligned. The checksum is calculated on a subset of that aligned packet buffer, and that sometimes lies on odd addresses.
The question remains if this is an issue with dpdk or not.
I can imagine other systems doing what you describe too. So it needs to be addressed.
Off the top of my head, an easy fix would be updating
__rte_raw_cksum()like this:static inline
uint32_t__rte_raw_cksum(const void *buf, size_t len, uint32_t sum) { if (likely((buf & 1) == 0)) { /* The buffer is 16 bit aligned. */ Keep the existing, optimized implementation here. } else { /* The buffer is not 16 bit aligned. */ Add a new odd-buf tolerant implementation here. } }However, I'm not sure that it covers your scenario!
The checksum is 16 bit wide, so if you calculate the checksum of e.g. 4 bytes of memory starting at offset 1 in a 6 byte packet buffer, the memory block can be treated as either 4 or 6 bytes relative to the data covered by the checksum, i.e.:
A: XX [01 02] [03 04] XX --> cksum = [04 06]
B: [XX 01] [02 03] [04 XX] --> cksum = [06 04]
Which one do you need?
Perhaps an additional function is required to support your use case, and the documentation for
rte_raw_cksum()and__rte_raw_cksum()needs to reflect that the buffer must be 16 bit aligned.Or the
rte_raw_cksum()function can be modified to support an odd buffer pointer as outlined above, with documentation added about alignment of the running checksum.-----Original Message-----
From: Emil Berg
Sent: den 16 juni 2022 07:45
To: Morten Brørup <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misaligned pointerHi!
We want the B option, i.e. the 6 bytes option. Perhaps adding alignment detection to
__rte_raw_cksum()is a good idea.A minor comment but I think buf & 1 won't work since buf isn't an integral type, but something along that way.
I'm starting to think about an efficient way to do this.
Thank you!
-----Original Message-----
From: Emil Berg [mailto:[email protected]]
Sent: Thursday, 16 June 2022 08.32
To: Morten Brørup; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misaligned pointerI've been sketching on an efficient solution to this. What about something along the way below? I've run it with the combinations of:
even buf, even len
even buf, odd len
odd buf, even len
odd buf, odd len
Quoted 7 lines
Quoted 4 lines
and it seems to give the same results as the older version of
__rte_raw_cksum, before 21.03. I ran it without optimizations and such to ensure the compiler didn't insert vector instructions and such so the results were comparable.The performance, when using an aligned buffer, needs to be comparable with full compiler optimization, or the patch will not be accepted.
I think the question is: does rte_raw_cksum() have any alignment requirements, from an API contract point of view? The documentation says nothing about any such. In that case, it seems reasonable to me to assume that there are none.
Quoted 27 lines
Quoted 12 lines
static inline
uint32_t__rte_raw_cksum_newest(const void *buf, size_t len, uint32_t sum){ const uint8_t *end = buf + len; uint32_t sum_even = 0; for (const uint8_t *p = buf + 1; p < end; p += 2) { sum_even += *p; } sum += sum_even << 8;Quoted 8 lines
uint32_t sum_odd = 0; for (const uint8_t *p = buf; p < end; p += 2) { sum_odd += *p; } sum += sum_odd; return sum; }This function does not work on both little and big endian, when mixed with other checksum functions.
The checksum functions read the buffer in CPU native endian and stores the checksum in CPU native endian; and magically it becomes correct in network endian. Please refer to RFC 1071 for the details. Perhaps you can also find some inspiration in RFC 1141.
PS: Please don't top post.
Quoted 8 lines · Emil Berg
I've been sketching on an efficient solution to this. What about something along the way below? I've run it with the combinations of:
even buf, even len
even buf, odd len
odd buf, even len
odd buf, odd lenand it seems to give the same results as the older version of
__rte_raw_cksum, before 21.03. I ran it without optimizations and such to ensure the compiler didn't insert vector instructions and such so the results were comparable.
...but you *want* the compiler to vectorize this code. There's much to gain, and it can likely be done also in the non-aligned case. What you don't want is for the compiler to assume the data is 16-bit aligned (and output SIMD load/store instructions which require alignment).
I don't see why you just can't take the current implementation, and replace the direct assignment ("*u16_buf") with a temporary variable, and a memcpy(). This also eliminates the need for the may_alias attribute (at least on the u16_buf pointer).
Quoted 125 lines
static inline
uint32_t__rte_raw_cksum_newest(const void *buf, size_t len, uint32_t sum){ const uint8_t *end = buf + len; uint32_t sum_even = 0; for (const uint8_t *p = buf + 1; p < end; p += 2) { sum_even += *p; } sum += sum_even << 8; uint32_t sum_odd = 0; for (const uint8_t *p = buf; p < end; p += 2) { sum_odd += *p; } sum += sum_odd; return sum; }/Emil
-----Original Message-----
From: Emil Berg
Sent: den 16 juni 2022 07:45
To: Morten Brørup <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misaligned pointerHi!
We want the B option, i.e. the 6 bytes option. Perhaps adding alignment detection to
__rte_raw_cksum()is a good idea.A minor comment but I think buf & 1 won't work since buf isn't an integral type, but something along that way.
I'm starting to think about an efficient way to do this.
Thank you!
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 15 juni 2022 16:41
To: Emil Berg <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misaligned pointerQuoted 43 lines
From: [email protected] [mailto:[email protected]]
Sent: Wednesday, 15 June 2022 09.16https://protect2.fireeye.com/v1/url?k=31323334-501d5122-313273af-45444
5555731-2e92ae6bf759c0c5&q=1&e=b3fc70af-5d37-4ffb-b34d-9a51927f5f6d&u= https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%3D1035Bug ID: 1035 Summary: __rte_raw_cksum() crash with misaligned pointer Product: DPDK Version: 21.11 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: Normal Component: ethdev Assignee: [email protected] Reporter: [email protected]Target Milestone: ---
See
rte_raw_cksum()inrte_ip.h, which is part of the public API. See also the subfunction__rte_raw_cksum().
_rte_raw_cksumassumes that the buffer over which the checksum is calculated is an even address (divisible by two). See for example this stack overflow
post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-
strict-aliasing-rule-or-incorrect-alignmentThe post explains that there is undefined behavior in C11 when "conversion between two pointer types produces a result that is incorrectly aligned". When the buf argument starts on an odd address we thus have undefined behavior, since a pointer is cast from void* to uint16_t*.
In most cases (at least on x86) that isn't a problem, but with higher optimization levels it may break due to vector instructions. This new function seems to be easier to optimize by the compiler, resulting in a crash when the buf argument is odd. Please note that the undefined behavior is present in earlier versions of dpdk as well.
Quoted 6 lines
Now you're probably thinking: "Just align your buffers". The problem is that we have a packet buffer which is aligned. The checksum is calculated on a subset of that aligned packet buffer, and that sometimes lies on odd addresses.
The question remains if this is an issue with dpdk or not.
I can imagine other systems doing what you describe too. So it needs to be addressed.
Off the top of my head, an easy fix would be updating
__rte_raw_cksum()like this:static inline
uint32_t__rte_raw_cksum(const void *buf, size_t len, uint32_t sum) { if (likely((buf & 1) == 0)) { /* The buffer is 16 bit aligned. */ Keep the existing, optimized implementation here. } else { /* The buffer is not 16 bit aligned. */ Add a new odd-buf tolerant implementation here. } }However, I'm not sure that it covers your scenario!
The checksum is 16 bit wide, so if you calculate the checksum of e.g. 4 bytes of memory starting at offset 1 in a 6 byte packet buffer, the memory block can be treated as either 4 or 6 bytes relative to the data covered by the checksum, i.e.:
A: XX [01 02] [03 04] XX --> cksum = [04 06]
B: [XX 01] [02 03] [04 XX] --> cksum = [06 04]
Which one do you need?
Perhaps an additional function is required to support your use case, and the documentation for
rte_raw_cksum()and__rte_raw_cksum()needs to reflect that the buffer must be 16 bit aligned.Or the
rte_raw_cksum()function can be modified to support an odd buffer pointer as outlined above, with documentation added about alignment of the running checksum.
Quoted 161 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Thursday, 16 June 2022 15.58Quoted 8 lines · Morten Brørup
+CC Olivier Matz <[email protected]>, Network Headers maintainer
Quoted 6 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 15 juni 2022 16:41
To: Emil Berg <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misalignedpointer
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
From: [email protected] [mailto:[email protected]]
Sent: Wednesday, 15 June 2022 09.16Quoted 8 lines
Quoted 8 lines
45444
Quoted 1 line
5555731-2e92ae6bf759c0c5&q=1&e=b3fc70af-5d37-4ffb-b34d-
9a51927f5f6d&u=
Quoted 4 lines
https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%3D1035
Bug ID: 1035
Summary:__rte_raw_cksum()crash with misalignedpointer
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Product: DPDK Version: 21.11 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: Normal Component: ethdev Assignee: [email protected] Reporter: [email protected]Target Milestone: ---
Quoted 1 line
Quoted 1 line
Quoted 1 line
See
rte_raw_cksum()inrte_ip.h, which is part of the public API.See
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
also the subfunction
__rte_raw_cksum().
_rte_raw_cksumassumes that the buffer over which the checksum is calculated is an even address (divisible by two). See for examplethis
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
stack overflow
post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-
strict-aliasing-rule-or-incorrect-alignmentThe post explains that there is undefined behavior in C11 when "conversion between two pointer types produces a result that is incorrectly aligned". When the buf argument starts on an odd
address
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
we thus have undefined behavior, since a pointer is cast from void*
to
Quoted 3 lines
uint16_t*.
In most cases (at least on x86) that isn't a problem, but with
higher
Quoted 1 line
Quoted 1 line
Quoted 1 line
optimization levels it may break due to vector instructions. This
new
Quoted 1 line
Quoted 1 line
Quoted 1 line
function seems to be easier to optimize by the compiler, resulting
in
Quoted 1 line
Quoted 1 line
Quoted 1 line
a crash when the buf argument is odd. Please note that the
undefined
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
behavior is present in earlier versions of dpdk as well.
Now you're probably thinking: "Just align your buffers". The
problem
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
is that we have a packet buffer which is aligned. The checksum is calculated on a subset of that aligned packet buffer, and that sometimes lies on odd addresses.
The question remains if this is an issue with dpdk or not.
I can imagine other systems doing what you describe too. So it needs
to
Quoted 3 lines
Quoted 3 lines
be addressed.
Off the top of my head, an easy fix would be updating
__rte_raw_cksum()Quoted 13 lines
Quoted 13 lines
like this:
static inline
uint32_t__rte_raw_cksum(const void *buf, size_t len, uint32_t sum) { if (likely((buf & 1) == 0)) { /* The buffer is 16 bit aligned. */ Keep the existing, optimized implementation here. } else { /* The buffer is not 16 bit aligned. */ Add a new odd-buf tolerant implementation here. } }Quoted 3 lines
Quoted 3 lines
However, I'm not sure that it covers your scenario!
The checksum is 16 bit wide, so if you calculate the checksum of
e.g. 4
Quoted 2 lines
Quoted 2 lines
bytes of memory starting at offset 1 in a 6 byte packet buffer, the memory block can be treated as either 4 or 6 bytes relative to the
data
Quoted 10 lines
Quoted 10 lines
covered by the checksum, i.e.:
A: XX [01 02] [03 04] XX --> cksum = [04 06]
B: [XX 01] [02 03] [04 XX] --> cksum = [06 04]
Which one do you need?
Perhaps an additional function is required to support your use case, and the documentation for
rte_raw_cksum()and__rte_raw_cksum()needs
Quoted 6 lines
Quoted 5 lines
to reflect that the buffer must be 16 bit aligned.
Or the
rte_raw_cksum()function can be modified to support an odd buffer pointer as outlined above, with documentation added about alignment of the running checksum.Quoted 6 lines
Quoted 6 lines
-----Original Message-----
From: Emil Berg
Sent: den 16 juni 2022 07:45
To: Morten Brørup <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misalignedpointer
Quoted 4 lines
Quoted 4 lines
Hi!
We want the B option, i.e. the 6 bytes option. Perhaps adding
alignment
Quoted 7 lines
Quoted 7 lines
detection to
__rte_raw_cksum()is a good idea.A minor comment but I think buf & 1 won't work since buf isn't an integral type, but something along that way.
I'm starting to think about an efficient way to do this.
Quoted 8 lines
Quoted 8 lines
Thank you!
-----Original Message-----
From: Emil Berg [mailto:[email protected]]
Sent: Thursday, 16 June 2022 08.32
To: Morten Brørup; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misalignedpointer
Quoted 10 lines
Quoted 10 lines
I've been sketching on an efficient solution to this. What about something along the way below? I've run it with the combinations of:
even buf, even len
even buf, odd len
odd buf, even len
odd buf, odd lenand it seems to give the same results as the older version of
__rte_raw_cksum, before 21.03. I ran it without optimizations andsuch
Quoted 3 lines
Quoted 2 lines
to ensure the compiler didn't insert vector instructions and such so the results were comparable.
Quoted 8 lines
Quoted 1 line
The performance, when using an aligned buffer, needs to be comparable
with full compiler optimization, or the patch will not be accepted.
Quoted 1 line
I think the question is: does
rte_raw_cksum()have any alignment requirements, from an API contract point of view? The documentation says
nothing about any such. In that case, it seems reasonable to me to assume that there are none.
The packet buffer must be 16 bit aligned. Many structures in DPDK are designed with this invariant, e.g. the Ethernet header (struct rte_ether_hdr) [1].
I agree that the documentation could mention this invariant in more places.
When calculating the checksum of a part of packet buffer, it should allow that part of the buffer to start at a non-16 bit aligned address, which is what Emil needs, and this is what I suggest adding support for in this function.
Regarding any implementation suggestions, please refer to my examples A and B above: The running checksum for a partial buffer of 4 bytes differs, depending on how you calculate it. The checksum calculation must see the buffer as part of the packet buffer, i.e. aligned with the (16 bit aligned) packet buffer and the (16 bit aligned) running checksum, as described by example B.
[1] https://elixir.bootlin.com/dpdk/latest/source/lib/net/rte_ether.h#L273
Quoted 202 lines
From: Morten Brørup
Sent: Thursday, 16 June 2022 16.36Quoted 5 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Thursday, 16 June 2022 15.58Quoted 1 line · Morten Brørup
+CC Olivier Matz <[email protected]>, Network Headers
maintainer
Quoted 33 lines
Quoted 7 lines
Quoted 7 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 15 juni 2022 16:41
To: Emil Berg <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misalignedpointer
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
From: [email protected] [mailto:[email protected]]
Sent: Wednesday, 15 June 2022 09.16Quoted 8 lines
Quoted 8 lines
45444
Quoted 1 line
5555731-2e92ae6bf759c0c5&q=1&e=b3fc70af-5d37-4ffb-b34d-
9a51927f5f6d&u=
Quoted 4 lines
https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%3D1035
Bug ID: 1035
Summary:__rte_raw_cksum()crash with misalignedpointer
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Product: DPDK Version: 21.11 Hardware: All OS: All Status: UNCONFIRMED Severity: normal Priority: Normal Component: ethdev Assignee: [email protected] Reporter: [email protected]Target Milestone: ---
Quoted 10 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
See
rte_raw_cksum()inrte_ip.h, which is part of the public API.See
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
also the subfunction
__rte_raw_cksum().
_rte_raw_cksumassumes that the buffer over which the checksum is calculated is an even address (divisible by two). See for examplethis
Quoted 3 lines
stack overflow
post:
https://stackoverflow.com/questions/46790550/c-undefined-behavior-
Quoted 7 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
strict-aliasing-rule-or-incorrect-alignment
The post explains that there is undefined behavior in C11 when "conversion between two pointer types produces a result that is incorrectly aligned". When the buf argument starts on an odd
address
Quoted 1 line
Quoted 1 line
Quoted 1 line
we thus have undefined behavior, since a pointer is cast from
void*
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
to
Quoted 3 lines
uint16_t*.
In most cases (at least on x86) that isn't a problem, but with
higher
Quoted 1 line
Quoted 1 line
Quoted 1 line
optimization levels it may break due to vector instructions. This
new
Quoted 1 line
Quoted 1 line
Quoted 1 line
function seems to be easier to optimize by the compiler,
resulting
Quoted 14 lines
in
Quoted 1 line
Quoted 1 line
Quoted 1 line
a crash when the buf argument is odd. Please note that the
undefined
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
behavior is present in earlier versions of dpdk as well.
Now you're probably thinking: "Just align your buffers". The
problem
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
is that we have a packet buffer which is aligned. The checksum is calculated on a subset of that aligned packet buffer, and that sometimes lies on odd addresses.
The question remains if this is an issue with dpdk or not.
I can imagine other systems doing what you describe too. So it
needs
Quoted 18 lines
to
Quoted 3 lines
Quoted 3 lines
be addressed.
Off the top of my head, an easy fix would be updating
__rte_raw_cksum()Quoted 13 lines
Quoted 13 lines
like this:
static inline
uint32_t__rte_raw_cksum(const void *buf, size_t len, uint32_t sum) { if (likely((buf & 1) == 0)) { /* The buffer is 16 bit aligned. */ Keep the existing, optimized implementation here. } else { /* The buffer is not 16 bit aligned. */ Add a new odd-buf tolerant implementation here. } }Quoted 5 lines
Quoted 3 lines
Quoted 3 lines
However, I'm not sure that it covers your scenario!
The checksum is 16 bit wide, so if you calculate the checksum of
e.g. 4
Quoted 1 line
Quoted 1 line
bytes of memory starting at offset 1 in a 6 byte packet buffer,
the
Quoted 11 lines
Quoted 1 line
Quoted 1 line
memory block can be treated as either 4 or 6 bytes relative to the
data
Quoted 9 lines
Quoted 9 lines
covered by the checksum, i.e.:
A: XX [01 02] [03 04] XX --> cksum = [04 06]
B: [XX 01] [02 03] [04 XX] --> cksum = [06 04]
Which one do you need?
Perhaps an additional function is required to support your use
case,
Quoted 29 lines
Quoted 1 line
Quoted 1 line
and the documentation for
rte_raw_cksum()and__rte_raw_cksum()needs
Quoted 6 lines
Quoted 5 lines
to reflect that the buffer must be 16 bit aligned.
Or the
rte_raw_cksum()function can be modified to support an odd buffer pointer as outlined above, with documentation added about alignment of the running checksum.Quoted 6 lines
Quoted 6 lines
-----Original Message-----
From: Emil Berg
Sent: den 16 juni 2022 07:45
To: Morten Brørup <[email protected]>; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misalignedpointer
Quoted 4 lines
Quoted 4 lines
Hi!
We want the B option, i.e. the 6 bytes option. Perhaps adding
alignment
Quoted 9 lines
Quoted 8 lines
detection to
__rte_raw_cksum()is a good idea.A minor comment but I think buf & 1 won't work since buf isn't an integral type, but something along that way.
I'm starting to think about an efficient way to do this.
Thank you!
Quoted 10 lines
Quoted 6 lines
Quoted 6 lines
-----Original Message-----
From: Emil Berg [mailto:[email protected]]
Sent: Thursday, 16 June 2022 08.32
To: Morten Brørup; [email protected]
Cc: [email protected]
Subject: RE: [Bug 1035]__rte_raw_cksum()crash with misalignedpointer
Quoted 3 lines
Quoted 3 lines
I've been sketching on an efficient solution to this. What about something along the way below? I've run it with the combinations
of:
Quoted 9 lines
Quoted 7 lines
Quoted 7 lines
even buf, even len
even buf, odd len
odd buf, even len
odd buf, odd lenand it seems to give the same results as the older version of
__rte_raw_cksum, before 21.03. I ran it without optimizations andsuch
Quoted 1 line
Quoted 1 line
to ensure the compiler didn't insert vector instructions and such
so
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
the results were comparable.
The performance, when using an aligned buffer, needs to be
comparable
Quoted 7 lines
with full compiler optimization, or the patch will not be accepted.
Quoted 1 line
I think the question is: does
rte_raw_cksum()have any alignment requirements, from an API contract point of view? The documentation says
nothing about any such. In that case, it seems reasonable to me to assume that there are none.The packet buffer must be 16 bit aligned. Many structures in DPDK are designed with this invariant, e.g. the Ethernet header (struct
rte_ether_hdr) [1].I agree that the documentation could mention this invariant in more places.
When calculating the checksum of a part of packet buffer, it should allow that part of the buffer to start at a non-16 bit aligned address, which is what Emil needs, and this is what I suggest adding support for in this function.
Regarding any implementation suggestions, please refer to my examples A and B above: The running checksum for a partial buffer of 4 bytes differs, depending on how you calculate it. The checksum calculation must see the buffer as part of the packet buffer, i.e. aligned with the (16 bit aligned) packet buffer and the (16 bit aligned) running checksum, as described by example B.
I tried a few things in Godbolt, and will submit a patch shortly.
Please hang on...
PATCH 1/1 net: fix checksum with unaligned buffer
With this patch, the checksum can be calculated on an unligned part of a packet buffer.
I.e. the buf parameter is no longer required to be 16 bit aligned.
The DPDK invariant that packet buffers must be 16 bit aligned remains unchanged.
This invariant also defines how to calculate the 16 bit checksum on an unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]
--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
lib/net/rte_ip.h +15 -2
@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1 ] = *(const unsigned char *)buf; + sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;
Signature · 1 line
2.17.1
RE: [PATCH] net: fix checksum with unaligned buffer
Quoted 51 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an unligned part of a packet buffer.
I.e. the buf parameter is no longer required to be 16 bit aligned.The DPDK invariant that packet buffers must be 16 bit aligned remains unchanged.
This invariant also defines how to calculate the 16 bit checksum on an unaligned part of a packet buffer.Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)lib/net/rte_ip.h +15
-3@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1 ] = *(const unsigned char *)buf; + sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf; --
Quoted 1 line
2.17.1
@Emil, can you please test this patch with an unaligned buffer on your application to confirm that it produces the expected result.
RE: [PATCH] net: fix checksum with unaligned buffer
Quoted 58 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07
To: Emil Berg <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH] net: fix checksum with unaligned bufferQuoted 29 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an unligned part of a packet buffer.
I.e. the buf parameter is no longer required to be 16 bit aligned.The DPDK invariant that packet buffers must be 16 bit aligned remains unchanged.
This invariant also defines how to calculate the 16 bit checksum on an unaligned part of a packet buffer.Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-1@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf;lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, · line 173
Quoted 10 lines
lib/net/rte_ip.h +9
-1-const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 10 lines
lib/net/rte_ip.h +6
-0+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;
Quoted 5 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an unaligned buffer on your application to confirm that it produces the expected result.
All right. I'll test, perhaps on Monday.
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Emil BergQuoted 66 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 7 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an unligned part
of
Quoted 4 lines
Quoted 4 lines
a packet buffer.
I.e. the buf parameter is no longer required to be 16 bit aligned.The DPDK invariant that packet buffers must be 16 bit aligned
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the 16 bit checksum onan
Quoted 40 lines
Quoted 19 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-1@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf;lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, · line 173
Quoted 10 lines
lib/net/rte_ip.h +9
-1-const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 10 lines
lib/net/rte_ip.h +6
-0+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;Quoted 4 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an unaligned buffer on
your
Quoted 1 line
application to confirm that it produces the expected result.
Quoted 7 lines
Hi!
I tested the patch. It doesn't seem to produce the same results. I think the problem is that it always starts summing from an even address, the sum should always start from the first byte according to the checksum specification. Can I instead propose something Mattias Rönnblom sent me?
I assume that it produces the same result when the "buf" parameter is aligned?
And when the "buf" parameter is unaligned, I don't expect it to produce the same results as the simple algorithm!
This was the whole point of the patch: I expect the overall packet buffer to be 16 bit aligned, and the checksum to be a partial checksum of such a 16 bit aligned packet buffer. When calling this function, I assume that the "buf" and "len" parameters point to a part of such a packet buffer. If these expectations are correct, the simple algorithm will produce incorrect results when "buf" is unaligned.
I was asking you to test if the checksum on the packet is correct when your application modifies an unaligned part of the packet and uses this function to update the checksum.
Quoted 54 lines
-----------------------------------------------------------------------
---------------------------------------
const void *end =RTE_PTR_ADD(buf, (len / sizeof(uint16_t)) * sizeof(uint16_t));for (; buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) { uint16_t v; memcpy(&v, buf, sizeof(uint16_t)); sum += v; }/* if length is odd, keeping it byte order independent */
if (unlikely(len % 2)) { uint16_t left = 0; *(unsigned char *)&left = *(const unsigned char *)end; sum += left; }-----------------------------------------------------------------------
---------------------------------------
Note that the last block is the same as before. Amazingly I see no measurable performance hit from this compared to the previous one (-O3, march=native). Looking at the previous the loop body may compile to (x86):
-----------------------------------------------------------------------
---------------------------------------
vmovdqa (%rdx),%xmm1
vpmovzxwd %xmm1,%xmm0
vpsrldq $0x8,%xmm1,%xmm1
vpmovzxwd %xmm1,%xmm1
vpaddd %xmm1,%xmm0,%xmm0
cmp $0xf,%rax
jbe0x7ff7a0dfb1a9
-----------------------------------------------------------------------
---------------------------------------
while Mattias' memcpy solution:
-----------------------------------------------------------------------
---------------------------------------
vmovdqu (%rcx),%ymm0
add $0x20,%rcx
vpmovzxwd %xmm0,%ymm1
vextracti128 $0x1,%ymm0,%xmm0
vpmovzxwd %xmm0,%ymm0
vpaddd %ymm0,%ymm1,%ymm0
vpaddd %ymm0,%ymm2,%ymm2
cmp %r9,%rcx
jne0x555555556380
-----------------------------------------------------------------------
---------------------------------------
Thus two extra instructions in the loop, but I suspect it may be memory bound, leading to no measurable performance difference.Any comments?
/Emil
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Emil Berg+TO: @Bruce and @Stephen: You signed off on the 16 bit alignment requirement. We need background info on this.
Quoted 119 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 17 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 14 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 5 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an unligned part
of
Quoted 2 lines
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer required to be 16 bitaligned.
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
Quoted 2 lines
The DPDK invariant that packet buffers must be 16 bit aligned
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the 16 bitchecksum
Quoted 12 lines
Quoted 12 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 10 lines
Quoted 10 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t
Quoted 5 lines
lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-0@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf, size_tlen,
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 9 lines
lib/net/rte_ip.h +4
-2uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */
Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 11 lines
lib/net/rte_ip.h +6
-1+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf; --Quoted 1 line
2.17.1
@Emil, can you please test this patch with an unaligned buffer on
Quoted 8 lines
Quoted 8 lines
your
Quoted 1 line
application to confirm that it produces the expected result.
Hi!
I tested the patch. It doesn't seem to produce the same results. I think the problem is that it always starts summing from an even address, the sum should always start from the first byte according
to
Quoted 7 lines
Quoted 2 lines
the checksum specification. Can I instead propose something Mattias Rönnblom sent me?
I assume that it produces the same result when the "buf" parameter is aligned?
And when the "buf" parameter is unaligned, I don't expect it to
produce the
Quoted 3 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall packet
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial checksum of such
a 16 bit
Quoted 1 line
aligned packet buffer. When calling this function, I assume that the
"buf" and
Quoted 2 lines
"len" parameters point to a part of such a packet buffer. If these expectations are correct, the simple algorithm will produce incorrect
results
Quoted 3 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet is correct
when your
Quoted 1 line
application modifies an unaligned part of the packet and uses this
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be about partial checksums, of which some partial checksums may start on unaligned addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a nested packet. That nested packet may start on unaligned addresses.
Quoted 6 lines
The difference is basically if we want to sum over aligned addresses or not, handling the heading and trailing bytes appropriately.
Your method does not work in our case since we want to treat the first two bytes as the first word in our case. But I do understand that both methods are useful.
Yes, that certainly are two different use cases, requiring two different ways of calculating the 16 bit checksum.
Quoted 6 lines
Note that your method breaks the API. Previously (assuming no crashing due to low optimization levels, more accepting hardware, or a different compiler (version)) the current method would calculate the checksum assuming the first two bytes is the first word.
Depending on the point of view, my patch either fixes a bug (where the checksum was calculated incorrectly when the buf pointer was unaligned) or breaks the API (by calculating the differently when the buffer is unaligned).
I cannot say with certainty which one is correct, but perhaps some of the people with a deeper DPDK track record can...
@Bruce and @Stephen, in 2019 you signed off on a patch [1] introducing a 16 bit alignment requirement to the Ethernet address structure.
It is my understanding that DPDK has an invariant requiring packets to be 16 bit aligned, which that patch supports. Is this invariant documented anywhere, or am I completely wrong? If I'm wrong, then the alignment requirement introduced in that patch needs to be removed, as well as any similar alignment requirements elsewhere in DPDK.
@Emil, we should wait for a conclusion about the alignment invariant before we proceed.
If there is no such invariant, my patch is wrong, and we need to provide a v2 of the patch, which will then fit your use case. If there is such an invariant, my patch is correct, and another function must be added for your use case.
Re: [PATCH] net: fix checksum with unaligned buffer
Quoted 137 lines · Morten Brørup
+TO: @Bruce and @Stephen: You signed off on the 16 bit alignment requirement. We need background info on this.
Quoted 119 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 17 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 14 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 5 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an unligned part
of
Quoted 2 lines
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer required to be 16 bitaligned.
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
Quoted 2 lines
The DPDK invariant that packet buffers must be 16 bit aligned
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the 16 bitchecksum
Quoted 12 lines
Quoted 12 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 10 lines
Quoted 10 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t
Quoted 5 lines
lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-0@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf, size_tlen,
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 9 lines
lib/net/rte_ip.h +4
-2uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */
Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 11 lines
lib/net/rte_ip.h +6
-1+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf; --Quoted 1 line
2.17.1
@Emil, can you please test this patch with an unaligned buffer on
Quoted 8 lines
Quoted 8 lines
your
Quoted 1 line
application to confirm that it produces the expected result.
Hi!
I tested the patch. It doesn't seem to produce the same results. I think the problem is that it always starts summing from an even address, the sum should always start from the first byte according
to
Quoted 7 lines
Quoted 2 lines
the checksum specification. Can I instead propose something Mattias Rönnblom sent me?
I assume that it produces the same result when the "buf" parameter is aligned?
And when the "buf" parameter is unaligned, I don't expect it to
produce the
Quoted 3 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall packet
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial checksum of such
a 16 bit
Quoted 1 line
aligned packet buffer. When calling this function, I assume that the
"buf" and
Quoted 2 lines
"len" parameters point to a part of such a packet buffer. If these expectations are correct, the simple algorithm will produce incorrect
results
Quoted 3 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet is correct
when your
Quoted 1 line
application modifies an unaligned part of the packet and uses this
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be about partial checksums, of which some partial checksums may start on unaligned addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a nested packet. That nested packet may start on unaligned addresses.
Quoted 6 lines
The difference is basically if we want to sum over aligned addresses or not, handling the heading and trailing bytes appropriately.
Your method does not work in our case since we want to treat the first two bytes as the first word in our case. But I do understand that both methods are useful.
Yes, that certainly are two different use cases, requiring two different ways of calculating the 16 bit checksum.
Quoted 6 lines
Note that your method breaks the API. Previously (assuming no crashing due to low optimization levels, more accepting hardware, or a different compiler (version)) the current method would calculate the checksum assuming the first two bytes is the first word.
Quoted 7 lines
Depending on the point of view, my patch either fixes a bug (where the checksum was calculated incorrectly when the buf pointer was unaligned) or breaks the API (by calculating the differently when the buffer is unaligned).
I cannot say with certainty which one is correct, but perhaps some of the people with a deeper DPDK track record can...
@Bruce and @Stephen, in 2019 you signed off on a patch [1] introducing a 16 bit alignment requirement to the Ethernet address structure.
It is my understanding that DPDK has an invariant requiring packets to be 16 bit aligned, which that patch supports. Is this invariant documented anywhere, or am I completely wrong? If I'm wrong, then the alignment requirement introduced in that patch needs to be removed, as well as any similar alignment requirements elsewhere in DPDK.
I don't believe it is explicitly documented as a global invariant, but I think it should be unless there is a definite case where we need to allow packets to be completely unaligned. Across all packet headers we looked at, there was no tunneling protocol where the resulting packet was left unaligned.
That said, if there are real use cases where we need to allow packets to start at an unaligned address, then I agree with you that we need to roll back the patch and work to ensure everything works with unaligned addresses.
/Bruce
Quoted 8 lines
@Emil, we should wait for a conclusion about the alignment invariant before we proceed.
If there is no such invariant, my patch is wrong, and we need to provide a v2 of the patch, which will then fit your use case. If there is such an invariant, my patch is correct, and another function must be added for your use case.
RE: [PATCH] net: fix checksum with unaligned buffer
Quoted 192 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 10.23Quoted 1 line · Morten Brørup
+TO: @Bruce and @Stephen: You signed off on the 16 bit alignment
requirement. We need background info on this.
Quoted 10 lines
Quoted 10 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 6 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 3 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an
unligned
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
part
of
Quoted 2 lines
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer required to be 16 bitaligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The DPDK invariant that packet buffers must be 16 bit
aligned
Quoted 16 lines
Quoted 16 lines
Quoted 3 lines
Quoted 3 lines
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the 16 bitchecksum
Quoted 12 lines
Quoted 12 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 10 lines
Quoted 10 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf,
Quoted 5 lines
lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-0@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
lib/net/rte_ip.h +0
-0uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__))
u16_p;Quoted 23 lines
Quoted 23 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, · line 168
Quoted 6 lines
lib/net/rte_ip.h +4
-2-const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, · line 173
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 10 lines
lib/net/rte_ip.h +6
-0+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an unaligned
buffer on
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
your
Quoted 1 line
application to confirm that it produces the expected result.
Hi!
I tested the patch. It doesn't seem to produce the same
results. I
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
think the problem is that it always starts summing from an even address, the sum should always start from the first byte
according
Quoted 2 lines
Quoted 2 lines
to
Quoted 1 line
Quoted 1 line
the checksum specification. Can I instead propose something
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the "buf"
parameter is
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't expect it to
produce the
Quoted 3 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall
packet
Quoted 2 lines
Quoted 2 lines
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial checksum of
such
Quoted 2 lines
Quoted 2 lines
a 16 bit
Quoted 1 line
aligned packet buffer. When calling this function, I assume that
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet buffer. If
these
Quoted 1 line
Quoted 1 line
Quoted 1 line
expectations are correct, the simple algorithm will produce
incorrect
Quoted 6 lines
Quoted 6 lines
results
Quoted 3 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet is correct
when your
Quoted 1 line
application modifies an unaligned part of the packet and uses
this
Quoted 5 lines
Quoted 5 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be about
partial
Quoted 4 lines
Quoted 4 lines
checksums, of which some partial checksums may start on unaligned addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a nested
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over aligned
addresses or
Quoted 3 lines
Quoted 3 lines
not, handling the heading and trailing bytes appropriately.
Your method does not work in our case since we want to treat the
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do understand that
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases, requiring two
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously (assuming no
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting hardware, or a
different
Quoted 5 lines
Quoted 3 lines
compiler (version)) the current method would calculate the checksum assuming the first two bytes is the first word.
Depending on the point of view, my patch either fixes a bug (where
the checksum was calculated incorrectly when the buf pointer was unaligned) or breaks the API (by calculating the differently when the buffer is unaligned).
Quoted 2 lines
I cannot say with certainty which one is correct, but perhaps some of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch [1]
introducing a 16 bit alignment requirement to the Ethernet address structure.
Quoted 2 lines
It is my understanding that DPDK has an invariant requiring packets
to be 16 bit aligned, which that patch supports. Is this invariant documented anywhere, or am I completely wrong? If I'm wrong, then the alignment requirement introduced in that patch needs to be removed, as well as any similar alignment requirements elsewhere in DPDK.
I don't believe it is explicitly documented as a global invariant, but I
think it should be unless there is a definite case where we need to allow
packets to be completely unaligned. Across all packet headers we looked at,
there was no tunneling protocol where the resulting packet was left unaligned.
Quoted 9 lines
That said, if there are real use cases where we need to allow packets to
start at an unaligned address, then I agree with you that we need to roll
back the patch and work to ensure everything works with unaligned addresses./Bruce
@Emil, can you please describe or refer to which tunneling protocol you are using, where the nested packet can be unaligned?
I am asking to determine if your use case is exotic (maybe some Ericsson proprietary protocol), or more generic (rooted in some standard protocol). This information affects the DPDK community's opinion about how it should be supported by DPDK.
If possible, please provide more details about the tunneling protocol and nested packets... E.g. do the nested packets also contain Layer 2 (Ethernet, VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP, etc.)? And how about ARP packets and Layer 2 control protocol packets (STP, LACP, etc.)?
Quoted 13 lines
Quoted 2 lines
[1]
http://git.dpdk.org/dpdk/commit/lib/librte_net/rte_ether.h?id=da5350ef2
9afd35c1adabe76f60832f3092269adQuoted 2 lines
@Emil, we should wait for a conclusion about the alignment invariant
before we proceed.
Quoted 2 lines
If there is no such invariant, my patch is wrong, and we need to
provide a v2 of the patch, which will then fit your use case.
Quoted 1 line
If there is such an invariant, my patch is correct, and another
function must be added for your use case.
Quoted 1 line
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 58 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07
To: Emil Berg <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH] net: fix checksum with unaligned bufferQuoted 29 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an unligned part of a packet buffer.
I.e. the buf parameter is no longer required to be 16 bit aligned.The DPDK invariant that packet buffers must be 16 bit aligned remains unchanged.
This invariant also defines how to calculate the 16 bit checksum on an unaligned part of a packet buffer.Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-1@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf;lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, · line 173
Quoted 10 lines
lib/net/rte_ip.h +9
-1-const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 10 lines
lib/net/rte_ip.h +6
-0+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;
Quoted 5 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an unaligned buffer on your application to confirm that it produces the expected result.
Hi!
I tested the patch. It doesn't seem to produce the same results. I think the problem is that it always starts summing from an even address, the sum should always start from the first byte according to the checksum specification. Can I instead propose something Mattias Rönnblom sent me?
--------------------------------------------------------------------------------------------------------------
const void *end = RTE_PTR_ADD(buf, (len / sizeof(uint16_t)) * sizeof(uint16_t));
for (; buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) {
uint16_t v;
memcpy(&v, buf, sizeof(uint16_t));
sum += v;
}/* if length is odd, keeping it byte order independent */
if (unlikely(len % 2)) {
uint16_t left = 0;
*(unsigned char *)&left = *(const unsigned char *)end;
sum += left;
}--------------------------------------------------------------------------------------------------------------
Note that the last block is the same as before. Amazingly I see no measurable performance hit from this compared to the previous one (-O3, march=native). Looking at the previous the loop body may compile to (x86):
--------------------------------------------------------------------------------------------------------------
vmovdqa (%rdx),%xmm1
vpmovzxwd %xmm1,%xmm0
vpsrldq $0x8,%xmm1,%xmm1
vpmovzxwd %xmm1,%xmm1
vpaddd %xmm1,%xmm0,%xmm0
cmp $0xf,%rax
jbe 0x7ff7a0dfb1a9
--------------------------------------------------------------------------------------------------------------
while Mattias' memcpy solution:
--------------------------------------------------------------------------------------------------------------
vmovdqu (%rcx),%ymm0
add $0x20,%rcx
vpmovzxwd %xmm0,%ymm1
vextracti128 $0x1,%ymm0,%xmm0
vpmovzxwd %xmm0,%ymm0
vpaddd %ymm0,%ymm1,%ymm0
vpaddd %ymm0,%ymm2,%ymm2
cmp %r9,%rcx
jne 0x555555556380
--------------------------------------------------------------------------------------------------------------
Thus two extra instructions in the loop, but I suspect it may be memory bound, leading to no measurable performance difference.
Any comments?
/Emil
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 99 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58
To: Emil Berg <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH] net: fix checksum with unaligned bufferQuoted 68 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 5 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an unligned part
of
Quoted 4 lines
Quoted 4 lines
a packet buffer.
I.e. the buf parameter is no longer required to be 16 bit aligned.The DPDK invariant that packet buffers must be 16 bit aligned
remains
Quoted 3 lines
Quoted 3 lines
unchanged.
This invariant also defines how to calculate the 16 bit checksum onan
Quoted 40 lines
Quoted 19 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-1@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf;lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, · line 173
Quoted 10 lines
lib/net/rte_ip.h +9
-1-const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 10 lines
lib/net/rte_ip.h +6
-0+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;Quoted 4 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an unaligned buffer on
your
Quoted 1 line
application to confirm that it produces the expected result.
Quoted 7 lines
Hi!
I tested the patch. It doesn't seem to produce the same results. I think the problem is that it always starts summing from an even address, the sum should always start from the first byte according to the checksum specification. Can I instead propose something Mattias Rönnblom sent me?
I assume that it produces the same result when the "buf" parameter is aligned?
And when the "buf" parameter is unaligned, I don't expect it to produce the same results as the simple algorithm!
This was the whole point of the patch: I expect the overall packet buffer to be 16 bit aligned, and the checksum to be a partial checksum of such a 16 bit aligned packet buffer. When calling this function, I assume that the "buf" and "len" parameters point to a part of such a packet buffer. If these expectations are correct, the simple algorithm will produce incorrect results when "buf" is unaligned.
Quoted 4 lines
I was asking you to test if the checksum on the packet is correct when your application modifies an unaligned part of the packet and uses this function to update the checksum.
Now I understand your use case. Your use case seems to be about partial checksums, of which some partial checksums may start on unaligned addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a nested packet. That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over aligned addresses or not, handling the heading and trailing bytes appropriately.
Your method does not work in our case since we want to treat the first two bytes as the first word in our case. But I do understand that both methods are useful.
Note that your method breaks the API. Previously (assuming no crashing due to low optimization levels, more accepting hardware, or a different compiler (version)) the current method would calculate the checksum assuming the first two bytes is the first word.
Quoted 62 lines
Quoted 62 lines
----------------------------------------------------------------------
-
---------------------------------------
const void *end =RTE_PTR_ADD(buf, (len / sizeof(uint16_t)) * sizeof(uint16_t));for (; buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) { uint16_t v; memcpy(&v, buf, sizeof(uint16_t)); sum += v; }/* if length is odd, keeping it byte order independent */ if
(unlikely(len % 2)) { uint16_t left = 0; *(unsigned char *)&left = *(const unsigned char *)end; sum += left; }----------------------------------------------------------------------
-
---------------------------------------
Note that the last block is the same as before. Amazingly I see no measurable performance hit from this compared to the previous one (-O3, march=native). Looking at the previous the loop body may compile to
(x86):
----------------------------------------------------------------------
-
---------------------------------------
vmovdqa (%rdx),%xmm1
vpmovzxwd %xmm1,%xmm0
vpsrldq $0x8,%xmm1,%xmm1
vpmovzxwd %xmm1,%xmm1
vpaddd %xmm1,%xmm0,%xmm0
cmp $0xf,%rax
jbe0x7ff7a0dfb1a9
----------------------------------------------------------------------
-
---------------------------------------
while Mattias' memcpy solution:
----------------------------------------------------------------------
-
---------------------------------------
vmovdqu (%rcx),%ymm0
add $0x20,%rcx
vpmovzxwd %xmm0,%ymm1
vextracti128 $0x1,%ymm0,%xmm0
vpmovzxwd %xmm0,%ymm0
vpaddd %ymm0,%ymm1,%ymm0
vpaddd %ymm0,%ymm2,%ymm2
cmp %r9,%rcx
jne0x555555556380
----------------------------------------------------------------------
-
---------------------------------------
Thus two extra instructions in the loop, but I suspect it may be memory bound, leading to no measurable performance difference.Any comments?
/Emil
Re: [PATCH] net: fix checksum with unaligned buffer
In reply to Emil BergQuoted 218 lines · Emil Berg
Quoted 218 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35
To: Emil Berg <[email protected]>
Cc: Bruce Richardson <[email protected]>; Stephen Hemminger <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH] net: fix checksum with unaligned bufferQuoted 191 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 10.23Quoted 1 line · Morten Brørup
+TO: @Bruce and @Stephen: You signed off on the 16 bit alignment
requirement. We need background info on this.
Quoted 10 lines
Quoted 10 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 6 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 3 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an
unligned
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
part
of
Quoted 2 lines
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer required to be 16 bitaligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The DPDK invariant that packet buffers must be 16 bit
aligned
Quoted 16 lines
Quoted 16 lines
Quoted 3 lines
Quoted 3 lines
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the 16 bitchecksum
Quoted 12 lines
Quoted 12 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 10 lines
Quoted 10 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf,
Quoted 5 lines
lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-0@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
lib/net/rte_ip.h +0
-0uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__))
u16_p;Quoted 23 lines
Quoted 23 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, · line 168
Quoted 6 lines
lib/net/rte_ip.h +4
-2-const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, · line 173
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 10 lines
lib/net/rte_ip.h +6
-0+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an unaligned
buffer on
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
your
Quoted 1 line
application to confirm that it produces the expected result.
Hi!
I tested the patch. It doesn't seem to produce the same
results. I
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
think the problem is that it always starts summing from an even address, the sum should always start from the first byte
according
Quoted 2 lines
Quoted 2 lines
to
Quoted 1 line
Quoted 1 line
the checksum specification. Can I instead propose something
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the "buf"
parameter is
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't expect it to
produce the
Quoted 3 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall
packet
Quoted 2 lines
Quoted 2 lines
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial checksum of
such
Quoted 2 lines
Quoted 2 lines
a 16 bit
Quoted 1 line
aligned packet buffer. When calling this function, I assume that
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet buffer. If
these
Quoted 1 line
Quoted 1 line
Quoted 1 line
expectations are correct, the simple algorithm will produce
incorrect
Quoted 7 lines
Quoted 7 lines
results
Quoted 4 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet is correct
when your
Quoted 1 line
application modifies an unaligned part of the packet and uses
this
Quoted 5 lines
Quoted 5 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be about
partial
Quoted 4 lines
Quoted 4 lines
checksums, of which some partial checksums may start on unaligned addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a nested
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over aligned
addresses or
Quoted 3 lines
Quoted 3 lines
not, handling the heading and trailing bytes appropriately.
Your method does not work in our case since we want to treat the
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do understand that
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases, requiring two
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously (assuming no
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting hardware, or a
different
Quoted 5 lines
Quoted 3 lines
compiler (version)) the current method would calculate the checksum assuming the first two bytes is the first word.
Depending on the point of view, my patch either fixes a bug (where
the checksum was calculated incorrectly when the buf pointer was unaligned) or breaks the API (by calculating the differently when the buffer is unaligned).
Quoted 3 lines
I cannot say with certainty which one is correct, but perhaps some of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch [1]
introducing a 16 bit alignment requirement to the Ethernet address structure.
Quoted 2 lines
It is my understanding that DPDK has an invariant requiring packets
to be 16 bit aligned, which that patch supports. Is this invariant documented anywhere, or am I completely wrong? If I'm wrong, then the alignment requirement introduced in that patch needs to be removed, as well as any similar alignment requirements elsewhere in DPDK.
I don't believe it is explicitly documented as a global invariant, but I think it should be unless there is a definite case where we need to allow packets to be completely unaligned. Across all packet headers we looked at, there was no tunneling protocol where the resulting packet was left unaligned.
Quoted 7 lines
That said, if there are real use cases where we need to allow packets to start at an unaligned address, then I agree with you that we need to roll back the patch and work to ensure everything works with unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which tunneling protocol you are using, where the nested packet can be unaligned?
I am asking to determine if your use case is exotic (maybe some Ericsson proprietary protocol), or more generic (rooted in some standard protocol). This information affects the DPDK community's opinion about how it should be supported by DPDK.
Quoted 8 lines
Quoted 5 lines
If possible, please provide more details about the tunneling protocol and nested packets... E.g. do the nested packets also contain Layer 2 (Ethernet, VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP, etc.)? And how about ARP packets and Layer 2 control protocol packets (STP, LACP, etc.)?
Well, if you append or adjust an odd number of bytes (e.g. a PDCP header) from a previously aligned payload the entire packet will then be unaligned.
If PDCP headers can leave the rest of the packet field unaligned, then we had better remove the alignment restrictions through all of DPDK.
/Bruce
RE: [PATCH] net: fix checksum with unaligned buffer
Quoted 270 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 11.18Quoted 9 lines · Emil Berg
Quoted 9 lines
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35Quoted 5 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 10.23Quoted 1 line · Morten Brørup
+TO: @Bruce and @Stephen: You signed off on the 16 bit
alignment
Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
requirement. We need background info on this.
Quoted 16 lines
Quoted 16 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 12 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 9 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 6 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 3 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
With this patch, the checksum can be calculated on an
unligned
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
part
of
Quoted 2 lines
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer required to be 16bit
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
Quoted 3 lines
aligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The DPDK invariant that packet buffers must be 16 bit
aligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the 16bit
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
checksum
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 6 lines
Quoted 6 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten BrørupQuoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h
Quoted 5 lines
--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)lib/net/rte_ip.h +0
-0index
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf,
Quoted 4 lines
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-0@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf,
size_tQuoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
lib/net/rte_ip.h +0
-0uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__))
u16_p;Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, · line 166
Quoted 2 lines
lib/net/rte_ip.h +0
-2-const u16_p *u16_buf = (const u16_p *)buf; - const u16_p *end = u16_buf + len /
sizeof(*u16_buf);Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, · line 168
Quoted 4 lines
lib/net/rte_ip.h +4
-0+const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
independent */
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, · line 173
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(constunsigned
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
char *)buf;
Quoted 10 lines
lib/net/rte_ip.h +6
-0+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an unaligned
buffer on
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
your
Quoted 1 line
application to confirm that it produces the expected
result.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Hi!
I tested the patch. It doesn't seem to produce the same
results. I
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
think the problem is that it always starts summing from
an
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
even address, the sum should always start from the first
byte
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
according
Quoted 2 lines
Quoted 2 lines
to
Quoted 1 line
Quoted 1 line
the checksum specification. Can I instead propose
something
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the "buf"
parameter is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't expect
it to
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
Quoted 4 lines
produce the
Quoted 3 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall
packet
Quoted 2 lines
Quoted 2 lines
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial
checksum of
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
such
Quoted 2 lines
Quoted 2 lines
a 16 bit
Quoted 1 line
aligned packet buffer. When calling this function, I assume
that
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet buffer.
If
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
these
Quoted 1 line
Quoted 1 line
Quoted 1 line
expectations are correct, the simple algorithm will produce
incorrect
Quoted 7 lines
Quoted 7 lines
results
Quoted 4 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet is correct
when your
Quoted 1 line
application modifies an unaligned part of the packet and
uses
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
this
Quoted 5 lines
Quoted 5 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be
about
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
partial
Quoted 1 line
Quoted 1 line
checksums, of which some partial checksums may start on
unaligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a
nested
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over aligned
addresses or
Quoted 3 lines
Quoted 3 lines
not, handling the heading and trailing bytes appropriately.
Your method does not work in our case since we want to treat
the
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do understand
that
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases, requiring two
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously (assuming no
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting hardware, or a
different
Quoted 5 lines
Quoted 3 lines
compiler (version)) the current method would calculate the checksum assuming the first two bytes is the first word.
Depending on the point of view, my patch either fixes a bug
(where
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
the checksum was calculated incorrectly when the buf pointer was unaligned) or breaks the API (by calculating the differently when
the
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
buffer is unaligned).
Quoted 2 lines
I cannot say with certainty which one is correct, but perhaps
some
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch [1]
introducing a 16 bit alignment requirement to the Ethernet
address
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
structure.
Quoted 2 lines
It is my understanding that DPDK has an invariant requiring
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to be 16 bit aligned, which that patch supports. Is this
invariant
Quoted 1 line
Quoted 1 line
Quoted 1 line
documented anywhere, or am I completely wrong? If I'm wrong, then
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
alignment requirement introduced in that patch needs to be
removed, as
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
well as any similar alignment requirements elsewhere in DPDK.
I don't believe it is explicitly documented as a global
invariant, but
Quoted 1 line
Quoted 1 line
Quoted 1 line
I think it should be unless there is a definite case where we
need to
Quoted 1 line
Quoted 1 line
Quoted 1 line
allow packets to be completely unaligned. Across all packet
headers we
Quoted 1 line
Quoted 1 line
Quoted 1 line
looked at, there was no tunneling protocol where the resulting
packet
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
was left unaligned.
That said, if there are real use cases where we need to allow
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to start at an unaligned address, then I agree with you that we
need
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
to roll back the patch and work to ensure everything works with unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which tunneling protocol
you are
Quoted 3 lines
Quoted 3 lines
using, where the nested packet can be unaligned?
I am asking to determine if your use case is exotic (maybe some
Ericsson
Quoted 1 line
Quoted 1 line
proprietary protocol), or more generic (rooted in some standard
protocol).
Quoted 1 line
Quoted 1 line
This information affects the DPDK community's opinion about how it
should
Quoted 3 lines
Quoted 3 lines
be supported by DPDK.
If possible, please provide more details about the tunneling
protocol and
Quoted 1 line
Quoted 1 line
nested packets... E.g. do the nested packets also contain Layer 2
(Ethernet,
Quoted 1 line
Quoted 1 line
VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP,
etc.)? And how
Quoted 1 line
Quoted 1 line
about ARP packets and Layer 2 control protocol packets (STP, LACP,
etc.)?
Quoted 3 lines
Quoted 1 line
Well, if you append or adjust an odd number of bytes (e.g. a PDCP
header) from a previously aligned payload the entire packet will then be unaligned.
Quoted 1 line
Quoted 5 lines
If PDCP headers can leave the rest of the packet field unaligned, then we
had better remove the alignment restrictions through all of DPDK./Bruce
Re-reading the details regarding unaligned pointers in C11, as posted by Emil in Bugzilla [2], I interpret it as follows: Any 16 bit or wider pointer type a must point to data aligned with that type, i.e. a pointer of the type "uint16_t *" must point to 16 bit aligned data, and a pointer of the type "uint64_t *" must point to 64 bit aligned data. Please, someone tell me I got this wrong, and wake me up from my nightmare!
Updating DPDK's packet structures to fully support this C11 limitation with unaligned access would be a nightmare, as we would need to use byte arrays for all structure fields. Functions would also be unable to use other pointer types than "void *" and "char *", which seems to be the actual problem in the __rte_raw_cksum() function. I guess that it also would prevent the compiler from auto-vectorizing the functions.
I am usually a big proponent of academically correct solutions, but such a change would be too wide ranging, so I would like to narrow it down to the actual use case, and perhaps extrapolate a bit from there.
@Emil: Do you only need to calculate the checksum of the (potentially unaligned) embedded packet? Or do you also need to use other DPDK functions with the embedded packet, potentially accessing it at an unaligned address?
I'm trying to determine the scope of this C11 pointer alignment limitation for your use case, i.e. whether or not other DPDK functions need to be updated to support unaligned packet access too.
PATCH v2 1/1 net: fix checksum with unaligned buffer
In reply to Morten BrørupWith this patch, the checksum can be calculated on an unligned buffer. I.e. the buf parameter is no longer required to be 16 bit aligned.
The checksum is still calculated using a 16 bit aligned pointer, so the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Futhermore, the calculated checksum of the buffer is byte shifted before being added to the initial checksum, to compensate for the checksum having been calculated on the buffer shifted by one byte.
v2:
* Do not assume that the buffer is part of an aligned packet buffer.
Bugzilla ID: 1035
Cc: [email protected]
--- lib/net/rte_ip.h | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-)
lib/net/rte_ip.h +26 -5
@@ -162,20 +162,41 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; +uint32_t bsum =0 ; +const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1 ] = *(const unsigned char *)buf; + bsum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + bsum += *u16_buf;/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; *(unsigned char *)&left = *(const unsigned char *)end; - sum += left; + bsum += left; + } + +/* if buffer is unaligned, swap the checksum bytes */ +if (unlikely (unaligned)) { + bsum = (bsum &0xFF00FF00 ) >>8 | (bsum &0x00FF00FF ) <<8 ; } -return sum; +return sum + bsum; }/**
Signature · 1 line
2.17.1
PATCH v3 1/1 net: fix checksum with unaligned buffer
In reply to Morten BrørupWith this patch, the checksum can be calculated on an unligned buffer. I.e. the buf parameter is no longer required to be 16 bit aligned.
The checksum is still calculated using a 16 bit aligned pointer, so the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial checksum, to compensate for the checksum having been calculated on the buffer shifted by one byte.
v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packet buffer.
Bugzilla ID: 1035
Cc: [email protected]
--- lib/net/rte_ip.h | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-)
lib/net/rte_ip.h +25 -5
@@ -162,20 +162,40 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; +uint32_t bsum =0 ; +const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1 ] = *(const unsigned char *)buf; + bsum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + bsum += *u16_buf;/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; *(unsigned char *)&left = *(const unsigned char *)end; - sum += left; + bsum += left; } -return sum; +/* if buffer is unaligned, swap the checksum bytes */ +if (unlikely (unaligned)) + bsum = (bsum &0xFF00FF00 ) >>8 | (bsum &0x00FF00FF ) <<8 ; + +return sum + bsum; }/**
Signature · 1 line
2.17.1
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Emil BergQuoted 381 lines
From: Emil Berg [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 14.25Quoted 15 lines
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 13:26Quoted 12 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 11.18Quoted 8 lines · Emil Berg
Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35Quoted 4 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 10.23On Tue, Jun 21, 2022 at 10:05:15AM +0200, Morten Brørup
Quoted 13 lines · wrote:
Quoted 13 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
+TO: @Bruce and @Stephen: You signed off on the 16 bit
alignment
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
requirement. We need background info on this.
Quoted 10 lines
Quoted 10 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 6 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 3 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 5 lines
From: Morten Brørup
[mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated
on
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
an
unligned
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
part
of
Quoted 2 lines
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer required tobe
Quoted 10 lines
Quoted 10 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
16
bit
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
aligned.
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
The DPDK invariant that packet buffers must be 16
bitaligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the16
Quoted 44 lines
Quoted 9 lines
bit
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
checksum
Quoted 7 lines
Quoted 7 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 5 lines
Quoted 5 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Quoted 18 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Signed-off-by Morten BrørupQuoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h
Quoted 5 lines
--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)lib/net/rte_ip.h +0
-0index
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void · line 162
Quoted 5 lines
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-0@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
lib/net/rte_ip.h +0
-0uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t__attribute__((__may_alias__))
Quoted 9 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
u16_p;Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
lib/net/rte_ip.h __rte_raw_cksum(const void · line 167
Quoted 2 lines
lib/net/rte_ip.h +0
-2-const u16_p *u16_buf = (const u16_p *)buf; - const u16_p *end = u16_buf + len /
sizeof(*u16_buf);Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
lib/net/rte_ip.h __rte_raw_cksum(const void · line 169
Quoted 4 lines
lib/net/rte_ip.h +4
-0+const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
independent */
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void · line 174
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] =*(const
Quoted 21 lines
Quoted 4 lines
unsigned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
char *)buf;
lib/net/rte_ip.h __rte_raw_cksum(const void · line 176
Quoted 2 lines
lib/net/rte_ip.h +2
-0+ sum += first; + buf = (const void *)((uintptr_t)buf+ 1);
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
lib/net/rte_ip.h +4
-0+ len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an
unalignedbuffer on
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
your
Quoted 1 line
application to confirm that it produces the
expected
Quoted 5 lines
Quoted 5 lines
result.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Hi!
I tested the patch. It doesn't seem to produce the
same
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
results. I
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
think the problem is that it always starts summing
from
Quoted 2 lines
Quoted 2 lines
an
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
even address, the sum should always start from the
first
Quoted 9 lines
Quoted 9 lines
byte
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
according
Quoted 2 lines
Quoted 2 lines
to
Quoted 1 line
Quoted 1 line
the checksum specification. Can I instead propose
something
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the
"buf"
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
parameter is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't
expect
Quoted 10 lines
Quoted 10 lines
it to
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
produce the
Quoted 4 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall
packet
Quoted 2 lines
Quoted 2 lines
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial
checksum of
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
such
Quoted 3 lines
Quoted 3 lines
a 16 bit
Quoted 2 lines
aligned packet buffer. When calling this function, I assume
that
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet
buffer.
Quoted 9 lines
Quoted 9 lines
If
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
these
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
expectations are correct, the simple algorithm will produce
incorrect
Quoted 4 lines
Quoted 4 lines
results
Quoted 3 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet
is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
correct
when your
Quoted 1 line
application modifies an unaligned part of the packet
and
Quoted 11 lines
Quoted 11 lines
uses
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
this
Quoted 5 lines
Quoted 5 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be
about
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
partial
Quoted 1 line
Quoted 1 line
checksums, of which some partial checksums may start on
unaligned
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a
nested
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over
aligned
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
addresses or
Quoted 1 line
Quoted 1 line
not, handling the heading and trailing bytes
appropriately.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Your method does not work in our case since we want to
treat
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do
understand
Quoted 5 lines
Quoted 5 lines
that
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases, requiring
two
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously
(assuming
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
no
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting hardware,
or
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
a
different
Quoted 1 line
Quoted 1 line
compiler (version)) the current method would calculate
the
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
checksum assuming the first two bytes is the first word.
Depending on the point of view, my patch either fixes a bug
(where
Quoted 1 line
Quoted 1 line
Quoted 1 line
the checksum was calculated incorrectly when the buf pointer
was
Quoted 6 lines
Quoted 6 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
unaligned) or breaks the API (by calculating the differently when
the
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
buffer is unaligned).
Quoted 2 lines
I cannot say with certainty which one is correct, but
perhaps
Quoted 20 lines
Quoted 20 lines
some
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch [1]
introducing a 16 bit alignment requirement to the Ethernet
address
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
structure.
Quoted 2 lines
It is my understanding that DPDK has an invariant requiring
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to be 16 bit aligned, which that patch supports. Is this
invariant
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
documented anywhere, or am I completely wrong? If I'm wrong, then
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
alignment requirement introduced in that patch needs to be
removed, as
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
well as any similar alignment requirements elsewhere in DPDK.
Quoted 7 lines
Quoted 7 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
I don't believe it is explicitly documented as a global
invariant, but
Quoted 1 line
Quoted 1 line
Quoted 1 line
I think it should be unless there is a definite case where we
need to
Quoted 1 line
Quoted 1 line
Quoted 1 line
allow packets to be completely unaligned. Across all packet
headers we
Quoted 1 line
Quoted 1 line
Quoted 1 line
looked at, there was no tunneling protocol where the
resulting
Quoted 6 lines
Quoted 6 lines
packet
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
was left unaligned.
That said, if there are real use cases where we need to allow
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to start at an unaligned address, then I agree with you that
we
Quoted 2 lines
Quoted 2 lines
need
Quoted 1 line
Quoted 1 line
Quoted 1 line
to roll back the patch and work to ensure everything works
with
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which tunneling protocol
Quoted 8 lines
Quoted 8 lines
you are
Quoted 3 lines
Quoted 3 lines
using, where the nested packet can be unaligned?
I am asking to determine if your use case is exotic (maybe some
Ericsson
Quoted 1 line
Quoted 1 line
proprietary protocol), or more generic (rooted in some standard
protocol).
Quoted 1 line
Quoted 1 line
This information affects the DPDK community's opinion about how
it
Quoted 6 lines
Quoted 6 lines
should
Quoted 3 lines
Quoted 3 lines
be supported by DPDK.
If possible, please provide more details about the tunneling
protocol and
Quoted 1 line
Quoted 1 line
nested packets... E.g. do the nested packets also contain Layer
2
Quoted 4 lines
Quoted 4 lines
(Ethernet,
Quoted 1 line
Quoted 1 line
VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP,
etc.)? And how
Quoted 1 line
Quoted 1 line
about ARP packets and Layer 2 control protocol packets (STP,
LACP,
Quoted 5 lines
Quoted 5 lines
etc.)?
Quoted 3 lines
Quoted 1 line
Well, if you append or adjust an odd number of bytes (e.g. a PDCP
header) from a previously aligned payload the entire packet will
then
Quoted 4 lines
Quoted 4 lines
be unaligned.
Quoted 1 line
If PDCP headers can leave the rest of the packet field unaligned,
then
Quoted 1 line
Quoted 1 line
we had better remove the alignment restrictions through all of
DPDK.
Quoted 4 lines
Quoted 2 lines
/Bruce
Re-reading the details regarding unaligned pointers in C11, as posted
by Emil
Quoted 1 line
in Bugzilla [2], I interpret it as follows: Any 16 bit or wider
pointer type a must
Quoted 1 line
point to data aligned with that type, i.e. a pointer of the type
"
uint16_t*"Quoted 1 line
must point to 16 bit aligned data, and a pointer of the type
"
uint64_t*" mustQuoted 1 line
point to 64 bit aligned data. Please, someone tell me I got this
wrong, and
Quoted 3 lines
wake me up from my nightmare!
Updating DPDK's packet structures to fully support this C11
limitation with
Quoted 1 line
unaligned access would be a nightmare, as we would need to use byte
arrays
Quoted 1 line
for all structure fields. Functions would also be unable to use other
pointer
Quoted 1 line
types than "void *" and "char *", which seems to be the actual
problem in
Quoted 1 line
the
__rte_raw_cksum()function. I guess that it also would preventthe
Quoted 3 lines
compiler from auto-vectorizing the functions.
I am usually a big proponent of academically correct solutions, but
such a
Quoted 1 line
change would be too wide ranging, so I would like to narrow it down
to the
Quoted 5 lines
actual use case, and perhaps extrapolate a bit from there.
@Emil: Do you only need to calculate the checksum of the (potentially unaligned) embedded packet? Or do you also need to use other DPDK functions with the embedded packet, potentially accessing it at an
unaligned
Quoted 3 lines
address?
I'm trying to determine the scope of this C11 pointer alignment
limitation for
Quoted 1 line
your use case, i.e. whether or not other DPDK functions need to be
updated
Quoted 6 lines
to support unaligned packet access too.
[2] https://protect2.fireeye.com/v1/url?k=31323334-501cfaf3-313273af-
454445554331-2ffe58e5caaeb74e&q=1&e=3f0544d3-8a71-4676-b4f9- 27e0952f7de0&u=https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid% 3D1035That's my interpretation of the standard as well; For example an uint16_t* must be on even addresses. If not it is undefined behavior. I think this is a bigger problem on ARM for example.
Quoted 5 lines
Without being that invested in dpdk, adding unaligned support for everything seems like a steep step, but I'm not sure what it entails in practice.
We are actually only interested in the checksumming.
Great! Then we can cancel the panic about rewriting DPDK Core completely. Although it might still need some review for similar alignment bugs, where we have been forcing the compiler shut up when trying to warn us. :-)
I have provided v3 of the patch, which should do as requested - and still allow the compiler to auto-vectorize.
@Emil, will you please test v3 of the patch?
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Emil BergQuoted 466 lines
From: Emil Berg [mailto:[email protected]]
Sent: Thursday, 23 June 2022 07.22Quoted 18 lines
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 16:02Quoted 15 lines
From: Emil Berg [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 14.25Quoted 12 lines
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 13:26Quoted 9 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 11.18Quoted 5 lines · Emil Berg
Quoted 5 lines
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35Quoted 1 line
From: Bruce Richardson
[mailto:[email protected]]
Quoted 17 lines
Quoted 17 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Sent: Tuesday, 21 June 2022 10.23
On Tue, Jun 21, 2022 at 10:05:15AM +0200, Morten Brørup
Quoted 13 lines · wrote:
Quoted 13 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
+TO: @Bruce and @Stephen: You signed off on the 16 bit
alignment
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
requirement. We need background info on this.
Quoted 10 lines
Quoted 10 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 6 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 3 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07From: Morten Brørup
[mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be
calculated
Quoted 7 lines
Quoted 7 lines
on
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
an
unligned
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
part
of
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer requiredto
Quoted 6 lines
Quoted 6 lines
be
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
16
bit
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The DPDK invariant that packet buffers must
be
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
16 bit
aligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
remains
Quoted 2 lines
unchanged.
This invariant also defines how to calculatethe
Quoted 10 lines
Quoted 10 lines
16
Quoted 9 lines
Quoted 9 lines
bit
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
checksum
Quoted 7 lines
Quoted 7 lines
Quoted 1 line
on
an
Quoted 5 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Signed-off-by: Morten Brørup
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
---
lib/net/rte_ip.h | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2
deletions(-)diff --git a/lib/net/rte_ip.h
b/lib/net/rte_ip.hQuoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
index
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
b502481670..8e301d9c26 100644
--- a/lib/net/rte_ip.h
+++ b/lib/net/rte_ip.h
@@ -162,9 +162,22 @@ __rte_raw_cksum(constvoid
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
*buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
uint32_t sum) {
/* extend strict-aliasing rules */
typedef uint16_t__attribute__((__may_alias__))
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
u16_p;Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
- const u16_p *u16_buf = (const u16_p
*)buf;
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
- const u16_p *end = u16_buf + len /
sizeof(*u16_buf);Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
+ const u16_p *u16_buf;
+ const u16_p *end;
+
+ /* if buffer is unaligned, keeping itbyte
Quoted 27 lines
Quoted 27 lines
Quoted 27 lines
Quoted 7 lines
order
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
independent */
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
+ if (unlikely((uintptr_t)buf & 1)) {
+ uint16_t first = 0;
+ if (unlikely(len == 0))
+ return 0;
+ ((unsigned char *)&first)[1] =*(const
Quoted 4 lines
unsigned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
char *)buf;
+ sum += first;
+ buf = (const void *)((uintptr_t)buf+ 1);
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
+ len--;
+ }+ u16_buf = (const u16_p *)buf;
+ end = u16_buf + len / sizeof(*u16_buf);
for (; u16_buf != end; ++u16_buf)
sum += *u16_buf;Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
--
2.17.1@Emil, can you please test this patch with an
unalignedbuffer on
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
your
Quoted 1 line
application to confirm that it produces the
expected
Quoted 5 lines
Quoted 5 lines
result.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Hi!
I tested the patch. It doesn't seem to produce
the
Quoted 3 lines
Quoted 3 lines
same
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
results. I
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
think the problem is that it always starts
summing
Quoted 3 lines
Quoted 3 lines
from
Quoted 2 lines
Quoted 2 lines
an
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
even address, the sum should always start from
the
Quoted 22 lines
Quoted 22 lines
first
Quoted 9 lines
Quoted 9 lines
byte
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
according
Quoted 2 lines
Quoted 2 lines
to
Quoted 1 line
Quoted 1 line
the checksum specification. Can I instead propose
something
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the
"buf"
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
parameter is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't
expect
Quoted 6 lines
Quoted 6 lines
it to
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
produce the
Quoted 4 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
packet
Quoted 2 lines
Quoted 2 lines
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial
checksum of
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
such
Quoted 2 lines
Quoted 2 lines
a 16 bit
Quoted 1 line
aligned packet buffer. When calling this function,
I
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
assume
that
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet
buffer.
Quoted 1 line
Quoted 1 line
If
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
these
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
expectations are correct, the simple algorithm will produce
incorrect
Quoted 4 lines
Quoted 4 lines
results
Quoted 3 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the
packet
Quoted 4 lines
Quoted 4 lines
is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
correct
when your
Quoted 1 line
application modifies an unaligned part of the
packet
Quoted 8 lines
Quoted 8 lines
and
Quoted 7 lines
Quoted 7 lines
uses
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
this
Quoted 5 lines
Quoted 5 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems
to
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
be
about
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
partial
Quoted 1 line
Quoted 1 line
checksums, of which some partial checksums may start
on
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
unaligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum
on a
Quoted 11 lines
Quoted 11 lines
Quoted 5 lines
Quoted 5 lines
nested
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over
aligned
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
addresses or
Quoted 1 line
Quoted 1 line
not, handling the heading and trailing bytes
appropriately.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Your method does not work in our case since we want
to
Quoted 10 lines
Quoted 10 lines
treat
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do
understand
Quoted 5 lines
Quoted 5 lines
that
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases,
requiring
Quoted 9 lines
Quoted 9 lines
two
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously
(assuming
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
no
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting
hardware,
Quoted 4 lines
Quoted 4 lines
or
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
a
different
Quoted 1 line
Quoted 1 line
compiler (version)) the current method would
calculate
Quoted 2 lines
Quoted 2 lines
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
checksum assuming the first two bytes is the first
word.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Depending on the point of view, my patch either fixes a bug
(where
Quoted 1 line
Quoted 1 line
Quoted 1 line
the checksum was calculated incorrectly when the buf
pointer
Quoted 2 lines
Quoted 2 lines
was
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
unaligned) or breaks the API (by calculating the
differently
Quoted 11 lines
Quoted 11 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
when
the
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
buffer is unaligned).
Quoted 2 lines
I cannot say with certainty which one is correct, but
perhaps
Quoted 5 lines
Quoted 5 lines
some
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch
[1]
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
introducing a 16 bit alignment requirement to the
Ethernet
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
address
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
structure.
Quoted 3 lines
It is my understanding that DPDK has an invariant
requiringpackets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to be 16 bit aligned, which that patch supports. Is this
invariant
Quoted 1 line
Quoted 1 line
Quoted 1 line
documented anywhere, or am I completely wrong? If I'm
wrong,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
then
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
alignment requirement introduced in that patch needs to
be
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
removed, as
Quoted 1 line
Quoted 1 line
Quoted 1 line
well as any similar alignment requirements elsewhere in
DPDK.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
I don't believe it is explicitly documented as a global
invariant, but
Quoted 1 line
Quoted 1 line
Quoted 1 line
I think it should be unless there is a definite case
where
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
we
need to
Quoted 1 line
Quoted 1 line
Quoted 1 line
allow packets to be completely unaligned. Across all
packet
Quoted 10 lines
Quoted 10 lines
Quoted 2 lines
Quoted 2 lines
headers we
Quoted 1 line
Quoted 1 line
Quoted 1 line
looked at, there was no tunneling protocol where the
resulting
Quoted 7 lines
Quoted 7 lines
packet
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
was left unaligned.
That said, if there are real use cases where we need to allow
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to start at an unaligned address, then I agree with you
that
Quoted 3 lines
Quoted 3 lines
we
Quoted 2 lines
Quoted 2 lines
need
Quoted 1 line
Quoted 1 line
Quoted 1 line
to roll back the patch and work to ensure everything
works
Quoted 16 lines
Quoted 16 lines
with
Quoted 15 lines
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which tunneling protocol
you are
Quoted 4 lines
Quoted 4 lines
using, where the nested packet can be unaligned?
I am asking to determine if your use case is exotic (maybe some
Ericsson
Quoted 2 lines
Quoted 2 lines
proprietary protocol), or more generic (rooted in some standard
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
protocol).
Quoted 2 lines
Quoted 2 lines
This information affects the DPDK community's opinion about how
it
Quoted 4 lines
Quoted 4 lines
should
Quoted 3 lines
Quoted 3 lines
be supported by DPDK.
If possible, please provide more details about the
tunneling
Quoted 9 lines
Quoted 9 lines
Quoted 3 lines
Quoted 3 lines
protocol and
Quoted 2 lines
Quoted 2 lines
nested packets... E.g. do the nested packets also contain Layer
2
Quoted 5 lines
Quoted 5 lines
(Ethernet,
Quoted 2 lines
Quoted 2 lines
VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP,
etc.)? And how
Quoted 1 line
Quoted 1 line
about ARP packets and Layer 2 control protocol packets
(STP,
Quoted 7 lines
Quoted 7 lines
LACP,
Quoted 6 lines
Quoted 6 lines
etc.)?
Quoted 4 lines
Quoted 1 line
Well, if you append or adjust an odd number of bytes (e.g. a PDCP
header) from a previously aligned payload the entire packet
will
Quoted 5 lines
Quoted 5 lines
then
Quoted 4 lines
Quoted 4 lines
be unaligned.
Quoted 1 line
If PDCP headers can leave the rest of the packet field
unaligned,
Quoted 14 lines
Quoted 14 lines
then
Quoted 1 line
Quoted 1 line
we had better remove the alignment restrictions through all of
DPDK.
Quoted 5 lines
Quoted 2 lines
/Bruce
Re-reading the details regarding unaligned pointers in C11, as posted
by Emil
Quoted 1 line
in Bugzilla [2], I interpret it as follows: Any 16 bit or wider
pointer type a must
Quoted 1 line
point to data aligned with that type, i.e. a pointer of the type
"
uint16_t*"Quoted 1 line
must point to 16 bit aligned data, and a pointer of the type
Quoted 8 lines
Quoted 8 lines
"
uint64_t*" mustQuoted 1 line
point to 64 bit aligned data. Please, someone tell me I got this
wrong, and
Quoted 3 lines
wake me up from my nightmare!
Updating DPDK's packet structures to fully support this C11
limitation with
Quoted 1 line
unaligned access would be a nightmare, as we would need to use
byte
Quoted 7 lines
Quoted 7 lines
arrays
Quoted 2 lines
for all structure fields. Functions would also be unable to use other
pointer
Quoted 1 line
types than "void *" and "char *", which seems to be the actual
problem in
Quoted 1 line
the
__rte_raw_cksum()function. I guess that it also wouldprevent
Quoted 4 lines
Quoted 4 lines
the
Quoted 3 lines
compiler from auto-vectorizing the functions.
I am usually a big proponent of academically correct solutions,
but
Quoted 2 lines
Quoted 2 lines
such a
Quoted 1 line
change would be too wide ranging, so I would like to narrow it
down
Quoted 7 lines
Quoted 7 lines
to the
Quoted 6 lines
actual use case, and perhaps extrapolate a bit from there.
@Emil: Do you only need to calculate the checksum of the (potentially
unaligned) embedded packet? Or do you also need to use other DPDK functions with the embedded packet, potentially accessing it atan
Quoted 6 lines
Quoted 6 lines
unaligned
Quoted 3 lines
address?
I'm trying to determine the scope of this C11 pointer alignment
limitation for
Quoted 1 line
your use case, i.e. whether or not other DPDK functions need to
be
Quoted 12 lines
Quoted 7 lines
updated
Quoted 6 lines
to support unaligned packet access too.
[2]
https://protect2.fireeye.com/v1/url?k=31323334-501cfaf3-313273af-
454445554331-2ffe58e5caaeb74e&q=1&e=3f0544d3-8a71-4676-b4f9-27e0952f7de0&u=https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%
Quoted 4 lines
Quoted 1 line
3D1035
That's my interpretation of the standard as well; For example an uint16_t* must be on even addresses. If not it is undefined
behavior.
Quoted 4 lines
Quoted 4 lines
I think this is a bigger problem on ARM for example.
Without being that invested in dpdk, adding unaligned support for everything seems like a steep step, but I'm not sure what it
entails
Quoted 5 lines
Quoted 3 lines
in practice.
We are actually only interested in the checksumming.
Great! Then we can cancel the panic about rewriting DPDK Core
completely.
Quoted 1 line
Although it might still need some review for similar alignment bugs,
where
Quoted 3 lines
we have been forcing the compiler shut up when trying to warn us. :-)
I have provided v3 of the patch, which should do as requested - and
still allow
Quoted 2 lines
the compiler to auto-vectorize.
Quoted 8 lines
Quoted 1 line
@Emil, will you please test v3 of the patch?
It seems to work in these two cases:
* Even address, even length
* Even address, odd length
But it breaks in these two cases:
* Odd address, even length (although it works for small buffers, probably when the sum fits inside auint16_tinteger or something)
Interesting observation, good analysis.
Quoted 1 line
* Odd address, odd length
Does this also work for small buffers?
Quoted 2 lines
I get (and like) the main idea of the algorithm but haven't yet figured out what the problem is with odd addresses.
I wonder if I messed up the algorithm for swapping back the bytes in bsum after the calculation... Is the checksum also wrong when compiling without optimization?
And just to be sure: The algorithm requires that __rte_raw_cksum_reduce() is also applied to the sum. Please confirm that you call rte_raw_cksum() (or __rte_raw_cksum() followed by __rte_raw_cksum_reduce())?
Quoted 2 lines
/Emil
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 218 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35
To: Emil Berg <[email protected]>
Cc: Bruce Richardson <[email protected]>; Stephen Hemminger <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH] net: fix checksum with unaligned bufferQuoted 191 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 10.23Quoted 1 line · Morten Brørup
+TO: @Bruce and @Stephen: You signed off on the 16 bit alignment
requirement. We need background info on this.
Quoted 10 lines
Quoted 10 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 6 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 3 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated on an
unligned
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
part
of
Quoted 2 lines
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer required to be 16 bitaligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The DPDK invariant that packet buffers must be 16 bit
aligned
Quoted 16 lines
Quoted 16 lines
Quoted 3 lines
Quoted 3 lines
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the 16 bitchecksum
Quoted 12 lines
Quoted 12 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 10 lines
Quoted 10 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf,
Quoted 5 lines
lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-0@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
lib/net/rte_ip.h +0
-0uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__))
u16_p;Quoted 23 lines
Quoted 23 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, · line 168
Quoted 6 lines
lib/net/rte_ip.h +4
-2-const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order independent */
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, · line 173
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 10 lines
lib/net/rte_ip.h +6
-0+ sum += first; + buf = (const void *)((uintptr_t )buf +1 ); + len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an unaligned
buffer on
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
your
Quoted 1 line
application to confirm that it produces the expected result.
Hi!
I tested the patch. It doesn't seem to produce the same
results. I
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
think the problem is that it always starts summing from an even address, the sum should always start from the first byte
according
Quoted 2 lines
Quoted 2 lines
to
Quoted 1 line
Quoted 1 line
the checksum specification. Can I instead propose something
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the "buf"
parameter is
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't expect it to
produce the
Quoted 3 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall
packet
Quoted 2 lines
Quoted 2 lines
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial checksum of
such
Quoted 2 lines
Quoted 2 lines
a 16 bit
Quoted 1 line
aligned packet buffer. When calling this function, I assume that
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet buffer. If
these
Quoted 1 line
Quoted 1 line
Quoted 1 line
expectations are correct, the simple algorithm will produce
incorrect
Quoted 7 lines
Quoted 7 lines
results
Quoted 4 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet is correct
when your
Quoted 1 line
application modifies an unaligned part of the packet and uses
this
Quoted 5 lines
Quoted 5 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be about
partial
Quoted 4 lines
Quoted 4 lines
checksums, of which some partial checksums may start on unaligned addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a nested
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over aligned
addresses or
Quoted 3 lines
Quoted 3 lines
not, handling the heading and trailing bytes appropriately.
Your method does not work in our case since we want to treat the
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do understand that
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases, requiring two
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously (assuming no
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting hardware, or a
different
Quoted 5 lines
Quoted 3 lines
compiler (version)) the current method would calculate the checksum assuming the first two bytes is the first word.
Depending on the point of view, my patch either fixes a bug (where
the checksum was calculated incorrectly when the buf pointer was unaligned) or breaks the API (by calculating the differently when the buffer is unaligned).
Quoted 3 lines
I cannot say with certainty which one is correct, but perhaps some of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch [1]
introducing a 16 bit alignment requirement to the Ethernet address structure.
Quoted 2 lines
It is my understanding that DPDK has an invariant requiring packets
to be 16 bit aligned, which that patch supports. Is this invariant documented anywhere, or am I completely wrong? If I'm wrong, then the alignment requirement introduced in that patch needs to be removed, as well as any similar alignment requirements elsewhere in DPDK.
I don't believe it is explicitly documented as a global invariant, but I think it should be unless there is a definite case where we need to allow packets to be completely unaligned. Across all packet headers we looked at, there was no tunneling protocol where the resulting packet was left unaligned.
Quoted 7 lines
That said, if there are real use cases where we need to allow packets to start at an unaligned address, then I agree with you that we need to roll back the patch and work to ensure everything works with unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which tunneling protocol you are using, where the nested packet can be unaligned?
I am asking to determine if your use case is exotic (maybe some Ericsson proprietary protocol), or more generic (rooted in some standard protocol). This information affects the DPDK community's opinion about how it should be supported by DPDK.
Quoted 5 lines
If possible, please provide more details about the tunneling protocol and nested packets... E.g. do the nested packets also contain Layer 2 (Ethernet, VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP, etc.)? And how about ARP packets and Layer 2 control protocol packets (STP, LACP, etc.)?
Well, if you append or adjust an odd number of bytes (e.g. a PDCP header) from a previously aligned payload the entire packet will then be unaligned.
Quoted 19 lines
Quoted 4 lines
Quoted 2 lines
[1]
https://protect2.fireeye.com/v1/url?k=31323334-501d5122-313273af-45444
5555731-713e91ae28ea4a95&q=1&e=91f8f355-4366-43bd-ac93-4c2f375f8d25&u=
Quoted 1 line
http%3A%2F%2Fgit.dpdk.org%2Fdpdk%2Fcommit%2Flib%2Flibrte_net%2Frt
e_ethQuoted 11 lines
er.h%3Fid%3Dda5350ef2
9afd35c1adabe76f60832f3092269adQuoted 2 lines
@Emil, we should wait for a conclusion about the alignment invariant
before we proceed.
Quoted 2 lines
If there is no such invariant, my patch is wrong, and we need to
provide a v2 of the patch, which will then fit your use case.
Quoted 1 line
If there is such an invariant, my patch is correct, and another
function must be added for your use case.
Quoted 1 line
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 327 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 13:26
To: Bruce Richardson <[email protected]>; Emil Berg <[email protected]>
Cc: Stephen Hemminger <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH] net: fix checksum with unaligned bufferQuoted 58 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 11.18Quoted 9 lines · Emil Berg
Quoted 9 lines
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35Quoted 5 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 10.23Quoted 1 line · Morten Brørup
+TO: @Bruce and @Stephen: You signed off on the 16 bit
alignment
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
requirement. We need background info on this.
Quoted 17 lines
Quoted 17 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 13 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 10 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 7 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 4 lines
From: Morten Brørup
[mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
With this patch, the checksum can be calculated on an
unligned
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
part
of
Quoted 3 lines
Quoted 3 lines
a packet buffer.
I.e. the buf parameter is no longer required to be 16bit
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
aligned.
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
The DPDK invariant that packet buffers must be 16
bitaligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the 16bit
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
checksum
Quoted 7 lines
Quoted 7 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 5 lines
Quoted 5 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Quoted 18 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Signed-off-by Morten BrørupQuoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h
Quoted 5 lines
--- lib/net/rte_ip.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)lib/net/rte_ip.h +0
-0index
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void · line 162
Quoted 5 lines
b502481670..8e301d9c26100644lib/net/rte_ip.h +0
-0@@ -162,9 +162,22 @@ __rte_raw_cksum(const void *buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
lib/net/rte_ip.h +0
-0uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t__attribute__((__may_alias__))
Quoted 9 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
u16_p;Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
lib/net/rte_ip.h __rte_raw_cksum(const void · line 167
Quoted 2 lines
lib/net/rte_ip.h +0
-2-const u16_p *u16_buf = (const u16_p *)buf; - const u16_p *end = u16_buf + len /
sizeof(*u16_buf);Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
lib/net/rte_ip.h __rte_raw_cksum(const void · line 169
Quoted 4 lines
lib/net/rte_ip.h +4
-0+const u16_p *u16_buf; +const u16_p *end; + +/* if buffer is unaligned, keeping it byte order
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
independent */
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void · line 174
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely ((uintptr_t )buf &1 )) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] =*(const
Quoted 4 lines
unsigned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
char *)buf;
lib/net/rte_ip.h __rte_raw_cksum(const void · line 176
Quoted 2 lines
lib/net/rte_ip.h +2
-0+ sum += first; + buf = (const void *)((uintptr_t)buf+ 1);
Quoted 185 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
lib/net/rte_ip.h +4
-0+ len--; + } + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) sum += *u16_buf;Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an
unalignedbuffer on
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
your
Quoted 1 line
application to confirm that it produces the expected
result.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Hi!
I tested the patch. It doesn't seem to produce the same
results. I
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
think the problem is that it always starts summing from
an
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
even address, the sum should always start from the first
byte
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
according
Quoted 2 lines
Quoted 2 lines
to
Quoted 1 line
Quoted 1 line
the checksum specification. Can I instead propose
something
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the "buf"
parameter is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't expect
it to
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
produce the
Quoted 4 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall
packet
Quoted 2 lines
Quoted 2 lines
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial
checksum of
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
such
Quoted 3 lines
Quoted 3 lines
a 16 bit
Quoted 2 lines
aligned packet buffer. When calling this function, I assume
that
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet buffer.
If
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
these
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
expectations are correct, the simple algorithm will produce
incorrect
Quoted 7 lines
Quoted 7 lines
results
Quoted 4 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet is correct
when your
Quoted 1 line
application modifies an unaligned part of the packet and
uses
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
this
Quoted 5 lines
Quoted 5 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be
about
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
partial
Quoted 1 line
Quoted 1 line
checksums, of which some partial checksums may start on
unaligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a
nested
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over aligned
addresses or
Quoted 3 lines
Quoted 3 lines
not, handling the heading and trailing bytes appropriately.
Your method does not work in our case since we want to treat
the
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do understand
that
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases, requiring two
different ways of calculating the 16 bit checksum.
Quoted 4 lines
Quoted 4 lines
Note that your method breaks the API. Previously (assuming no
crashing
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
due to low optimization levels, more accepting hardware, or a
different
Quoted 5 lines
Quoted 3 lines
compiler (version)) the current method would calculate the checksum assuming the first two bytes is the first word.
Depending on the point of view, my patch either fixes a bug
(where
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
the checksum was calculated incorrectly when the buf pointer was unaligned) or breaks the API (by calculating the differently when
the
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
buffer is unaligned).
Quoted 2 lines
I cannot say with certainty which one is correct, but perhaps
some
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch [1]
introducing a 16 bit alignment requirement to the Ethernet
address
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
structure.
Quoted 2 lines
It is my understanding that DPDK has an invariant requiring
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to be 16 bit aligned, which that patch supports. Is this
invariant
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
documented anywhere, or am I completely wrong? If I'm wrong, then
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
alignment requirement introduced in that patch needs to be
removed, as
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
well as any similar alignment requirements elsewhere in DPDK.
I don't believe it is explicitly documented as a global
invariant, but
Quoted 1 line
Quoted 1 line
Quoted 1 line
I think it should be unless there is a definite case where we
need to
Quoted 1 line
Quoted 1 line
Quoted 1 line
allow packets to be completely unaligned. Across all packet
headers we
Quoted 1 line
Quoted 1 line
Quoted 1 line
looked at, there was no tunneling protocol where the resulting
packet
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
was left unaligned.
That said, if there are real use cases where we need to allow
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to start at an unaligned address, then I agree with you that we
need
Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
to roll back the patch and work to ensure everything works with unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which tunneling protocol
you are
Quoted 3 lines
Quoted 3 lines
using, where the nested packet can be unaligned?
I am asking to determine if your use case is exotic (maybe some
Ericsson
Quoted 1 line
Quoted 1 line
proprietary protocol), or more generic (rooted in some standard
protocol).
Quoted 1 line
Quoted 1 line
This information affects the DPDK community's opinion about how it
should
Quoted 3 lines
Quoted 3 lines
be supported by DPDK.
If possible, please provide more details about the tunneling
protocol and
Quoted 1 line
Quoted 1 line
nested packets... E.g. do the nested packets also contain Layer 2
(Ethernet,
Quoted 1 line
Quoted 1 line
VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP,
etc.)? And how
Quoted 1 line
Quoted 1 line
about ARP packets and Layer 2 control protocol packets (STP, LACP,
etc.)?
Quoted 3 lines
Quoted 1 line
Well, if you append or adjust an odd number of bytes (e.g. a PDCP
Quoted 8 lines
header) from a previously aligned payload the entire packet will then be unaligned.
Quoted 1 line
If PDCP headers can leave the rest of the packet field unaligned, then we had better remove the alignment restrictions through all of DPDK.
/Bruce
Re-reading the details regarding unaligned pointers in C11, as posted by Emil in Bugzilla [2], I interpret it as follows: Any 16 bit or wider pointer type a must point to data aligned with that type, i.e. a pointer of the type "
uint16_t*" must point to 16 bit aligned data, and a pointer of the type "uint64_t*" must point to 64 bit aligned data. Please, someone tell me I got this wrong, and wake me up from my nightmare!Updating DPDK's packet structures to fully support this C11 limitation with unaligned access would be a nightmare, as we would need to use byte arrays for all structure fields. Functions would also be unable to use other pointer types than "void *" and "char *", which seems to be the actual problem in the
__rte_raw_cksum()function. I guess that it also would prevent the compiler from auto-vectorizing the functions.I am usually a big proponent of academically correct solutions, but such a change would be too wide ranging, so I would like to narrow it down to the actual use case, and perhaps extrapolate a bit from there.
@Emil: Do you only need to calculate the checksum of the (potentially unaligned) embedded packet? Or do you also need to use other DPDK functions with the embedded packet, potentially accessing it at an unaligned address?
Quoted 8 lines
I'm trying to determine the scope of this C11 pointer alignment limitation for your use case, i.e. whether or not other DPDK functions need to be updated to support unaligned packet access too.
[2] https://protect2.fireeye.com/v1/url?k=31323334-501cfaf3-313273af-
454445554331-2ffe58e5caaeb74e&q=1&e=3f0544d3-8a71-4676-b4f9- 27e0952f7de0&u=https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid% 3D1035
That's my interpretation of the standard as well; For example an uint16_t* must be on even addresses. If not it is undefined behavior. I think this is a bigger problem on ARM for example.
Without being that invested in dpdk, adding unaligned support for everything seems like a steep step, but I'm not sure what it entails in practice.
We are actually only interested in the checksumming.
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 414 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 16:02
To: Emil Berg <[email protected]>; Bruce Richardson <[email protected]>
Cc: Stephen Hemminger <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH] net: fix checksum with unaligned bufferQuoted 378 lines
From: Emil Berg [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 14.25Quoted 15 lines
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 13:26Quoted 12 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 11.18Quoted 8 lines · Emil Berg
Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35Quoted 4 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 10.23On Tue, Jun 21, 2022 at 10:05:15AM +0200, Morten Brørup
Quoted 13 lines · wrote:
Quoted 13 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
+TO: @Bruce and @Stephen: You signed off on the 16 bit
alignment
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
requirement. We need background info on this.
Quoted 10 lines
Quoted 10 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 6 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 3 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 5 lines
From: Morten Brørup
[mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated
on
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
an
unligned
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
part
of
Quoted 2 lines
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer required tobe
Quoted 10 lines
Quoted 10 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
16
bit
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
aligned.
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
The DPDK invariant that packet buffers must be
16 bitaligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the16
Quoted 45 lines
Quoted 10 lines
bit
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
checksum
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 6 lines
Quoted 6 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by: Morten Brørup
Quoted 18 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
---
lib/net/rte_ip.h | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2
deletions(-)diff --git a/lib/net/rte_ip.h b/lib/net/rte_ip.h
index
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
b502481670..8e301d9c26 100644
--- a/lib/net/rte_ip.h
+++ b/lib/net/rte_ip.h
@@ -162,9 +162,22 @@ __rte_raw_cksum(const void
*buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
uint32_t sum) {
/* extend strict-aliasing rules */
typedef uint16_t__attribute__((__may_alias__))
Quoted 9 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
u16_p;Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
- const u16_p *u16_buf = (const u16_p *)buf;
- const u16_p *end = u16_buf + len /
sizeof(*u16_buf);Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
+ const u16_p *u16_buf;
+ const u16_p *end;
+
+ /* if buffer is unaligned, keeping it byteorder
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
independent */
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
+ if (unlikely((uintptr_t)buf & 1)) {
+ uint16_t first = 0;
+ if (unlikely(len == 0))
+ return 0;
+ ((unsigned char *)&first)[1] =*(const
Quoted 21 lines
Quoted 4 lines
unsigned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
char *)buf;
Quoted 2 lines
+ sum += first;
+ buf = (const void *)((uintptr_t)buf+ 1);
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
+ len--;
+ }+ u16_buf = (const u16_p *)buf;
+ end = u16_buf + len / sizeof(*u16_buf);
for (; u16_buf != end; ++u16_buf)
sum += *u16_buf;Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an
unalignedbuffer on
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
your
Quoted 1 line
application to confirm that it produces the
expected
Quoted 5 lines
Quoted 5 lines
result.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Hi!
I tested the patch. It doesn't seem to produce the
same
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
results. I
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
think the problem is that it always starts summing
from
Quoted 2 lines
Quoted 2 lines
an
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
even address, the sum should always start from the
first
Quoted 9 lines
Quoted 9 lines
byte
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
according
Quoted 2 lines
Quoted 2 lines
to
Quoted 1 line
Quoted 1 line
the checksum specification. Can I instead propose
something
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the
"buf"
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
parameter is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't
expect
Quoted 10 lines
Quoted 10 lines
it to
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
produce the
Quoted 4 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall
packet
Quoted 2 lines
Quoted 2 lines
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial
checksum of
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
such
Quoted 3 lines
Quoted 3 lines
a 16 bit
Quoted 2 lines
aligned packet buffer. When calling this function, I assume
that
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet
buffer.
Quoted 9 lines
Quoted 9 lines
If
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
these
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
expectations are correct, the simple algorithm will produce
incorrect
Quoted 4 lines
Quoted 4 lines
results
Quoted 3 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet
is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
correct
when your
Quoted 1 line
application modifies an unaligned part of the packet
and
Quoted 12 lines
Quoted 12 lines
uses
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
this
Quoted 6 lines
Quoted 6 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be
about
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
partial
Quoted 1 line
Quoted 1 line
checksums, of which some partial checksums may start on
unaligned
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a
nested
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over
aligned
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
addresses or
Quoted 1 line
Quoted 1 line
not, handling the heading and trailing bytes
appropriately.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Your method does not work in our case since we want to
treat
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do
understand
Quoted 5 lines
Quoted 5 lines
that
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases, requiring
two
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously
(assuming
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
no
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting hardware,
or
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
a
different
Quoted 1 line
Quoted 1 line
compiler (version)) the current method would calculate
the
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
checksum assuming the first two bytes is the first word.
Depending on the point of view, my patch either fixes a bug
(where
Quoted 1 line
Quoted 1 line
Quoted 1 line
the checksum was calculated incorrectly when the buf pointer
was
Quoted 6 lines
Quoted 6 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
unaligned) or breaks the API (by calculating the differently when
the
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
buffer is unaligned).
Quoted 2 lines
I cannot say with certainty which one is correct, but
perhaps
Quoted 21 lines
Quoted 21 lines
some
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch [1]
introducing a 16 bit alignment requirement to the Ethernet
address
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
structure.
Quoted 3 lines
It is my understanding that DPDK has an invariant
requiringpackets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to be 16 bit aligned, which that patch supports. Is this
invariant
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
documented anywhere, or am I completely wrong? If I'm wrong, then
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
alignment requirement introduced in that patch needs to be
removed, as
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
well as any similar alignment requirements elsewhere in DPDK.
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
I don't believe it is explicitly documented as a global
invariant, but
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
I think it should be unless there is a definite case where we
need to
Quoted 1 line
Quoted 1 line
Quoted 1 line
allow packets to be completely unaligned. Across all packet
headers we
Quoted 1 line
Quoted 1 line
Quoted 1 line
looked at, there was no tunneling protocol where the
resulting
Quoted 7 lines
Quoted 7 lines
packet
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
was left unaligned.
That said, if there are real use cases where we need to allow
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to start at an unaligned address, then I agree with you that
we
Quoted 2 lines
Quoted 2 lines
need
Quoted 1 line
Quoted 1 line
Quoted 1 line
to roll back the patch and work to ensure everything works
with
Quoted 10 lines
Quoted 10 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which tunneling protocol
you are
Quoted 2 lines
Quoted 2 lines
using, where the nested packet can be unaligned?
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
I am asking to determine if your use case is exotic (maybe some
Ericsson
Quoted 2 lines
Quoted 2 lines
proprietary protocol), or more generic (rooted in some standard
protocol).
Quoted 2 lines
Quoted 2 lines
This information affects the DPDK community's opinion about how
it
Quoted 7 lines
Quoted 7 lines
should
Quoted 3 lines
Quoted 3 lines
be supported by DPDK.
If possible, please provide more details about the tunneling
protocol and
Quoted 2 lines
Quoted 2 lines
nested packets... E.g. do the nested packets also contain Layer
2
Quoted 5 lines
Quoted 5 lines
(Ethernet,
Quoted 2 lines
Quoted 2 lines
VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP,
etc.)? And how
Quoted 1 line
Quoted 1 line
about ARP packets and Layer 2 control protocol packets (STP,
LACP,
Quoted 6 lines
Quoted 6 lines
etc.)?
Quoted 4 lines
Quoted 1 line
Well, if you append or adjust an odd number of bytes (e.g. a PDCP
header) from a previously aligned payload the entire packet will
then
Quoted 4 lines
Quoted 4 lines
be unaligned.
Quoted 1 line
If PDCP headers can leave the rest of the packet field unaligned,
then
Quoted 1 line
Quoted 1 line
we had better remove the alignment restrictions through all of
DPDK.
Quoted 5 lines
Quoted 2 lines
/Bruce
Re-reading the details regarding unaligned pointers in C11, as posted
by Emil
Quoted 1 line
in Bugzilla [2], I interpret it as follows: Any 16 bit or wider
pointer type a must
Quoted 1 line
point to data aligned with that type, i.e. a pointer of the type
"
uint16_t*"Quoted 1 line
must point to 16 bit aligned data, and a pointer of the type
"
uint64_t*" mustQuoted 1 line
point to 64 bit aligned data. Please, someone tell me I got this
wrong, and
Quoted 3 lines
wake me up from my nightmare!
Updating DPDK's packet structures to fully support this C11
limitation with
Quoted 1 line
unaligned access would be a nightmare, as we would need to use byte
arrays
Quoted 2 lines
for all structure fields. Functions would also be unable to use other
pointer
Quoted 1 line
types than "void *" and "char *", which seems to be the actual
problem in
Quoted 1 line
the
__rte_raw_cksum()function. I guess that it also would preventthe
Quoted 3 lines
compiler from auto-vectorizing the functions.
I am usually a big proponent of academically correct solutions, but
such a
Quoted 1 line
change would be too wide ranging, so I would like to narrow it down
to the
Quoted 6 lines
actual use case, and perhaps extrapolate a bit from there.
@Emil: Do you only need to calculate the checksum of the (potentially
unaligned) embedded packet? Or do you also need to use other DPDK functions with the embedded packet, potentially accessing it at anQuoted 13 lines
unaligned
Quoted 3 lines
address?
I'm trying to determine the scope of this C11 pointer alignment
limitation for
Quoted 1 line
your use case, i.e. whether or not other DPDK functions need to be
updated
Quoted 6 lines
to support unaligned packet access too.
[2]
https://protect2.fireeye.com/v1/url?k=31323334-501cfaf3-313273af-
454445554331-2ffe58e5caaeb74e&q=1&e=3f0544d3-8a71-4676-b4f9-27e0952f7de0&u=https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%
Quoted 11 lines
Quoted 1 line
3D1035
That's my interpretation of the standard as well; For example an uint16_t* must be on even addresses. If not it is undefined behavior. I think this is a bigger problem on ARM for example.
Without being that invested in dpdk, adding unaligned support for everything seems like a steep step, but I'm not sure what it entails in practice.
We are actually only interested in the checksumming.
Quoted 8 lines
Great! Then we can cancel the panic about rewriting DPDK Core completely. Although it might still need some review for similar alignment bugs, where we have been forcing the compiler shut up when trying to warn us. :-)
I have provided v3 of the patch, which should do as requested - and still allow the compiler to auto-vectorize.
@Emil, will you please test v3 of the patch?
I will test the patch tomorrow.
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 416 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 16:02
To: Emil Berg <[email protected]>; Bruce Richardson <[email protected]>
Cc: Stephen Hemminger <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH] net: fix checksum with unaligned bufferQuoted 378 lines
From: Emil Berg [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 14.25Quoted 15 lines
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 13:26Quoted 12 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 11.18Quoted 8 lines · Emil Berg
Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35Quoted 4 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 10.23On Tue, Jun 21, 2022 at 10:05:15AM +0200, Morten Brørup
Quoted 13 lines · wrote:
Quoted 13 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
+TO: @Bruce and @Stephen: You signed off on the 16 bit
alignment
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
requirement. We need background info on this.
Quoted 10 lines
Quoted 10 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 6 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 3 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
From: Morten Brørup <[email protected]>
Sent: den 17 juni 2022 11:07Quoted 5 lines
From: Morten Brørup
[mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be calculated
on
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
an
unligned
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
part
of
Quoted 2 lines
Quoted 2 lines
a packet buffer.
I.e. the buf parameter is no longer required tobe
Quoted 10 lines
Quoted 10 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
16
bit
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
aligned.
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
The DPDK invariant that packet buffers must be
16 bitaligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
remains
Quoted 2 lines
Quoted 2 lines
unchanged.
This invariant also defines how to calculate the16
Quoted 45 lines
Quoted 10 lines
bit
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
checksum
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
on
an
Quoted 6 lines
Quoted 6 lines
unaligned part of a packet buffer.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by: Morten Brørup
Quoted 18 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
---
lib/net/rte_ip.h | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2
deletions(-)diff --git a/lib/net/rte_ip.h b/lib/net/rte_ip.h
index
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
b502481670..8e301d9c26 100644
--- a/lib/net/rte_ip.h
+++ b/lib/net/rte_ip.h
@@ -162,9 +162,22 @@ __rte_raw_cksum(const void
*buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
uint32_t sum) {
/* extend strict-aliasing rules */
typedef uint16_t__attribute__((__may_alias__))
Quoted 9 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
u16_p;Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
- const u16_p *u16_buf = (const u16_p *)buf;
- const u16_p *end = u16_buf + len /
sizeof(*u16_buf);Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
+ const u16_p *u16_buf;
+ const u16_p *end;
+
+ /* if buffer is unaligned, keeping it byteorder
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
independent */
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
+ if (unlikely((uintptr_t)buf & 1)) {
+ uint16_t first = 0;
+ if (unlikely(len == 0))
+ return 0;
+ ((unsigned char *)&first)[1] =*(const
Quoted 21 lines
Quoted 4 lines
unsigned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
char *)buf;
Quoted 2 lines
+ sum += first;
+ buf = (const void *)((uintptr_t)buf+ 1);
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
+ len--;
+ }+ u16_buf = (const u16_p *)buf;
+ end = u16_buf + len / sizeof(*u16_buf);
for (; u16_buf != end; ++u16_buf)
sum += *u16_buf;Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
--
2.17.1@Emil, can you please test this patch with an
unalignedbuffer on
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
your
Quoted 1 line
application to confirm that it produces the
expected
Quoted 5 lines
Quoted 5 lines
result.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Hi!
I tested the patch. It doesn't seem to produce the
same
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
results. I
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
think the problem is that it always starts summing
from
Quoted 2 lines
Quoted 2 lines
an
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
even address, the sum should always start from the
first
Quoted 9 lines
Quoted 9 lines
byte
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
according
Quoted 2 lines
Quoted 2 lines
to
Quoted 1 line
Quoted 1 line
the checksum specification. Can I instead propose
something
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the
"buf"
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
parameter is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't
expect
Quoted 10 lines
Quoted 10 lines
it to
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
produce the
Quoted 4 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect the overall
packet
Quoted 2 lines
Quoted 2 lines
buffer to
Quoted 1 line
be 16 bit aligned, and the checksum to be a partial
checksum of
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
such
Quoted 3 lines
Quoted 3 lines
a 16 bit
Quoted 2 lines
aligned packet buffer. When calling this function, I assume
that
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet
buffer.
Quoted 9 lines
Quoted 9 lines
If
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
these
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
expectations are correct, the simple algorithm will produce
incorrect
Quoted 4 lines
Quoted 4 lines
results
Quoted 3 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the packet
is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
correct
when your
Quoted 1 line
application modifies an unaligned part of the packet
and
Quoted 12 lines
Quoted 12 lines
uses
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
this
Quoted 6 lines
Quoted 6 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems to be
about
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
partial
Quoted 1 line
Quoted 1 line
checksums, of which some partial checksums may start on
unaligned
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum on a
nested
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over
aligned
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
addresses or
Quoted 1 line
Quoted 1 line
not, handling the heading and trailing bytes
appropriately.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Your method does not work in our case since we want to
treat
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do
understand
Quoted 5 lines
Quoted 5 lines
that
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases, requiring
two
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously
(assuming
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
no
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting hardware,
or
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
a
different
Quoted 1 line
Quoted 1 line
compiler (version)) the current method would calculate
the
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
checksum assuming the first two bytes is the first word.
Depending on the point of view, my patch either fixes a bug
(where
Quoted 1 line
Quoted 1 line
Quoted 1 line
the checksum was calculated incorrectly when the buf pointer
was
Quoted 6 lines
Quoted 6 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
unaligned) or breaks the API (by calculating the differently when
the
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
buffer is unaligned).
Quoted 2 lines
I cannot say with certainty which one is correct, but
perhaps
Quoted 21 lines
Quoted 21 lines
some
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch [1]
introducing a 16 bit alignment requirement to the Ethernet
address
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
structure.
Quoted 3 lines
It is my understanding that DPDK has an invariant
requiringpackets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to be 16 bit aligned, which that patch supports. Is this
invariant
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
documented anywhere, or am I completely wrong? If I'm wrong, then
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
alignment requirement introduced in that patch needs to be
removed, as
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
well as any similar alignment requirements elsewhere in DPDK.
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
I don't believe it is explicitly documented as a global
invariant, but
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
I think it should be unless there is a definite case where we
need to
Quoted 1 line
Quoted 1 line
Quoted 1 line
allow packets to be completely unaligned. Across all packet
headers we
Quoted 1 line
Quoted 1 line
Quoted 1 line
looked at, there was no tunneling protocol where the
resulting
Quoted 7 lines
Quoted 7 lines
packet
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
was left unaligned.
That said, if there are real use cases where we need to allow
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to start at an unaligned address, then I agree with you that
we
Quoted 2 lines
Quoted 2 lines
need
Quoted 1 line
Quoted 1 line
Quoted 1 line
to roll back the patch and work to ensure everything works
with
Quoted 10 lines
Quoted 10 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which tunneling protocol
you are
Quoted 2 lines
Quoted 2 lines
using, where the nested packet can be unaligned?
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
I am asking to determine if your use case is exotic (maybe some
Ericsson
Quoted 2 lines
Quoted 2 lines
proprietary protocol), or more generic (rooted in some standard
protocol).
Quoted 2 lines
Quoted 2 lines
This information affects the DPDK community's opinion about how
it
Quoted 7 lines
Quoted 7 lines
should
Quoted 3 lines
Quoted 3 lines
be supported by DPDK.
If possible, please provide more details about the tunneling
protocol and
Quoted 2 lines
Quoted 2 lines
nested packets... E.g. do the nested packets also contain Layer
2
Quoted 5 lines
Quoted 5 lines
(Ethernet,
Quoted 2 lines
Quoted 2 lines
VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP,
etc.)? And how
Quoted 1 line
Quoted 1 line
about ARP packets and Layer 2 control protocol packets (STP,
LACP,
Quoted 6 lines
Quoted 6 lines
etc.)?
Quoted 4 lines
Quoted 1 line
Well, if you append or adjust an odd number of bytes (e.g. a PDCP
header) from a previously aligned payload the entire packet will
then
Quoted 4 lines
Quoted 4 lines
be unaligned.
Quoted 1 line
If PDCP headers can leave the rest of the packet field unaligned,
then
Quoted 1 line
Quoted 1 line
we had better remove the alignment restrictions through all of
DPDK.
Quoted 5 lines
Quoted 2 lines
/Bruce
Re-reading the details regarding unaligned pointers in C11, as posted
by Emil
Quoted 1 line
in Bugzilla [2], I interpret it as follows: Any 16 bit or wider
pointer type a must
Quoted 1 line
point to data aligned with that type, i.e. a pointer of the type
"
uint16_t*"Quoted 1 line
must point to 16 bit aligned data, and a pointer of the type
"
uint64_t*" mustQuoted 1 line
point to 64 bit aligned data. Please, someone tell me I got this
wrong, and
Quoted 3 lines
wake me up from my nightmare!
Updating DPDK's packet structures to fully support this C11
limitation with
Quoted 1 line
unaligned access would be a nightmare, as we would need to use byte
arrays
Quoted 2 lines
for all structure fields. Functions would also be unable to use other
pointer
Quoted 1 line
types than "void *" and "char *", which seems to be the actual
problem in
Quoted 1 line
the
__rte_raw_cksum()function. I guess that it also would preventthe
Quoted 3 lines
compiler from auto-vectorizing the functions.
I am usually a big proponent of academically correct solutions, but
such a
Quoted 1 line
change would be too wide ranging, so I would like to narrow it down
to the
Quoted 6 lines
actual use case, and perhaps extrapolate a bit from there.
@Emil: Do you only need to calculate the checksum of the (potentially
unaligned) embedded packet? Or do you also need to use other DPDK functions with the embedded packet, potentially accessing it at anQuoted 13 lines
unaligned
Quoted 3 lines
address?
I'm trying to determine the scope of this C11 pointer alignment
limitation for
Quoted 1 line
your use case, i.e. whether or not other DPDK functions need to be
updated
Quoted 6 lines
to support unaligned packet access too.
[2]
https://protect2.fireeye.com/v1/url?k=31323334-501cfaf3-313273af-
454445554331-2ffe58e5caaeb74e&q=1&e=3f0544d3-8a71-4676-b4f9-27e0952f7de0&u=https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%
Quoted 11 lines
Quoted 1 line
3D1035
That's my interpretation of the standard as well; For example an uint16_t* must be on even addresses. If not it is undefined behavior. I think this is a bigger problem on ARM for example.
Without being that invested in dpdk, adding unaligned support for everything seems like a steep step, but I'm not sure what it entails in practice.
We are actually only interested in the checksumming.
Quoted 8 lines
Great! Then we can cancel the panic about rewriting DPDK Core completely. Although it might still need some review for similar alignment bugs, where we have been forcing the compiler shut up when trying to warn us. :-)
I have provided v3 of the patch, which should do as requested - and still allow the compiler to auto-vectorize.
@Emil, will you please test v3 of the patch?
It seems to work in these two cases:
* Even address, even length
* Even address, odd length
But it breaks in these two cases:
* Odd address, even length (although it works for small buffers, probably when the sum fits inside a uint16_t integer or something)
* Odd address, odd length
I get (and like) the main idea of the algorithm but haven't yet figured out what the problem is with odd addresses.
/Emil
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Emil BergQuoted 561 lines
From: Emil Berg [mailto:[email protected]]
Sent: Thursday, 23 June 2022 13.39Quoted 28 lines
From: Morten Brørup <[email protected]>
Sent: den 23 juni 2022 09:01Quoted 25 lines
From: Emil Berg [mailto:[email protected]]
Sent: Thursday, 23 June 2022 07.22Quoted 18 lines
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 16:02Quoted 15 lines
From: Emil Berg [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 14.25Quoted 12 lines
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 13:26Quoted 9 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 11.18Quoted 5 lines · Emil Berg
Quoted 5 lines
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35Quoted 1 line
From: Bruce Richardson
[mailto:[email protected]]
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Sent: Tuesday, 21 June 2022 10.23
On Tue, Jun 21, 2022 at 10:05:15AM +0200, Morten
Brørup
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 1 line · wrote:
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
+TO: @Bruce and @Stephen: You signed off on the 16
bit
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
alignment
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
requirement. We need background info on this.
Quoted 8 lines
Quoted 8 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 4 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58From: Emil Berg
[mailto:[email protected]]
Quoted 19 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Sent: Monday, 20 June 2022 12.38
From: Morten Brørup
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Sent: den 17 juni 2022 11:07
From: Morten Brørup
[mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be
calculated
Quoted 7 lines
Quoted 7 lines
on
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
an
unligned
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
part
of
a packet buffer.
I.e. the buf parameter is no longerrequired
Quoted 7 lines
Quoted 7 lines
to
Quoted 6 lines
Quoted 6 lines
be
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
16
bit
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned.
Quoted 2 lines
The DPDK invariant that packet buffers
must
Quoted 6 lines
Quoted 6 lines
be
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
16 bit
aligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
remains
unchanged.
This invariant also defines how tocalculate
Quoted 18 lines
Quoted 18 lines
the
Quoted 17 lines
Quoted 17 lines
16
Quoted 16 lines
Quoted 16 lines
bit
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
checksum
Quoted 8 lines
on
an
unaligned part of a packet buffer.Bugzilla ID: 1035
Cc: [email protected]Signed-off-by: Morten Brørup
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
---
lib/net/rte_ip.h | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2
deletions(-)Quoted 7 lines
Quoted 7 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
diff --git a/lib/net/rte_ip.h
b/lib/net/rte_ip.hQuoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
index
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
b502481670..8e301d9c26 100644
--- a/lib/net/rte_ip.h
+++ b/lib/net/rte_ip.h
@@ -162,9 +162,22 @@__rte_raw_cksum(const
Quoted 9 lines
Quoted 9 lines
void
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
*buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
uint32_t sum) {
/* extend strict-aliasing rules */
typedef uint16_t__attribute__((__may_alias__))
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
u16_p;Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
- const u16_p *u16_buf = (const u16_p
*)buf;
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
- const u16_p *end = u16_buf + len /
sizeof(*u16_buf);Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
+ const u16_p *u16_buf;
+ const u16_p *end;
+
+ /* if buffer is unaligned, keepingit
Quoted 8 lines
Quoted 8 lines
byte
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
order
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
independent */
Quoted 5 lines
+ if (unlikely((uintptr_t)buf & 1)) {
+ uint16_t first = 0;
+ if (unlikely(len == 0))
+ return 0;
+ ((unsigned char *)&first)[1]=
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
*(const
Quoted 4 lines
unsigned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
char *)buf;
+ sum += first;
+ buf = (const void*)((uintptr_t)buf
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
+ 1);
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
+ len--;
+ }+ u16_buf = (const u16_p *)buf;
+ end = u16_buf + len /
sizeof(*u16_buf);Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
for (; u16_buf != end; ++u16_buf)
sum += *u16_buf;--
2.17.1@Emil, can you please test this patch with
an
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
unaligned
buffer on
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
your
application to confirm that it produces theexpected
Quoted 5 lines
Quoted 5 lines
result.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Hi!
I tested the patch. It doesn't seem to
produce
Quoted 8 lines
Quoted 8 lines
the
Quoted 3 lines
Quoted 3 lines
same
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
results. I
Quoted 1 line
Quoted 1 line
Quoted 1 line
think the problem is that it always starts
summing
Quoted 3 lines
Quoted 3 lines
from
Quoted 2 lines
Quoted 2 lines
an
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
even address, the sum should always start
from
Quoted 4 lines
Quoted 4 lines
the
Quoted 3 lines
Quoted 3 lines
first
Quoted 2 lines
Quoted 2 lines
byte
Quoted 1 line
Quoted 1 line
Quoted 1 line
according
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
to
Quoted 2 lines
the checksum specification. Can I instead
proposesomething
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Rönnblom sent me?
I assume that it produces the same result when
the
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
"buf"
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
parameter is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I
don't
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
expect
Quoted 6 lines
Quoted 6 lines
it to
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
produce the
Quoted 4 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect
the overallQuoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
packet
Quoted 3 lines
Quoted 3 lines
buffer to
Quoted 2 lines
be 16 bit aligned, and the checksum to be a
partialchecksum of
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
such
Quoted 2 lines
Quoted 2 lines
a 16 bit
Quoted 1 line
aligned packet buffer. When calling this
function,
Quoted 6 lines
Quoted 6 lines
I
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
assume
that
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a
packet
Quoted 16 lines
Quoted 16 lines
Quoted 10 lines
Quoted 10 lines
buffer.
Quoted 9 lines
Quoted 9 lines
If
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
these
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
expectations are correct, the simple algorithm
will produceincorrect
Quoted 4 lines
Quoted 4 lines
results
Quoted 3 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the
packet
Quoted 4 lines
Quoted 4 lines
is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
correct
when your
Quoted 1 line
application modifies an unaligned part of the
packet
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
and
Quoted 7 lines
Quoted 7 lines
uses
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
this
Quoted 5 lines
Quoted 5 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case
seems
Quoted 5 lines
Quoted 5 lines
to
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
be
about
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
partial
Quoted 1 line
Quoted 1 line
checksums, of which some partial checksums may
start
Quoted 5 lines
Quoted 5 lines
on
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
unaligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
addresses in an otherwise aligned packet.
Our use case is about calculating the full
checksum
Quoted 4 lines
Quoted 4 lines
on a
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
nested
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
packet.
Quoted 1 line
Quoted 1 line
That nested packet may start on unaligned
addresses.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The difference is basically if we want to sum
over
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
aligned
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
addresses or
Quoted 1 line
Quoted 1 line
not, handling the heading and trailing bytes
appropriately.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Your method does not work in our case since we
want
Quoted 21 lines
Quoted 21 lines
to
Quoted 10 lines
Quoted 10 lines
treat
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do
understand
Quoted 5 lines
Quoted 5 lines
that
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases,
requiring
Quoted 9 lines
Quoted 9 lines
two
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously
(assuming
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
no
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting
Quoted 8 lines
Quoted 8 lines
hardware,
Quoted 4 lines
Quoted 4 lines
or
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
a
different
Quoted 1 line
Quoted 1 line
compiler (version)) the current method would
calculate
Quoted 2 lines
Quoted 2 lines
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
checksum assuming the first two bytes is the
first
Quoted 4 lines
Quoted 4 lines
word.
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Depending on the point of view, my patch either
fixes
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
a bug
(where
Quoted 1 line
Quoted 1 line
Quoted 1 line
the checksum was calculated incorrectly when the buf
pointer
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
was
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
unaligned) or breaks the API (by calculating the
differently
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
when
the
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
buffer is unaligned).
Quoted 2 lines
I cannot say with certainty which one is correct,
but
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
perhaps
Quoted 5 lines
Quoted 5 lines
some
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a
patch
Quoted 10 lines
Quoted 10 lines
[1]
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
introducing a 16 bit alignment requirement to the
Ethernet
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
address
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
structure.
Quoted 3 lines
It is my understanding that DPDK has an invariant
requiringpackets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to be 16 bit aligned, which that patch supports. Is
this
Quoted 6 lines
Quoted 6 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
invariant
Quoted 1 line
Quoted 1 line
Quoted 1 line
documented anywhere, or am I completely wrong? If I'm
wrong,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
then
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
alignment requirement introduced in that patch needs
to
Quoted 3 lines
Quoted 3 lines
be
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
removed, as
Quoted 1 line
Quoted 1 line
Quoted 1 line
well as any similar alignment requirements elsewhere
in
Quoted 3 lines
Quoted 3 lines
DPDK.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
I don't believe it is explicitly documented as a
global
Quoted 6 lines
Quoted 6 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
invariant, but
Quoted 1 line
Quoted 1 line
Quoted 1 line
I think it should be unless there is a definite case
where
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
we
need to
Quoted 1 line
Quoted 1 line
Quoted 1 line
allow packets to be completely unaligned. Across all
Quoted 8 lines
Quoted 8 lines
packet
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines
Quoted 2 lines
headers we
Quoted 1 line
Quoted 1 line
Quoted 1 line
looked at, there was no tunneling protocol where the
resulting
Quoted 4 lines
Quoted 4 lines
packet
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
was left unaligned.
That said, if there are real use cases where we need
to
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
allow
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to start at an unaligned address, then I agree with
you
Quoted 4 lines
Quoted 4 lines
that
Quoted 3 lines
Quoted 3 lines
we
Quoted 2 lines
Quoted 2 lines
need
Quoted 1 line
Quoted 1 line
Quoted 1 line
to roll back the patch and work to ensure everything
Quoted 8 lines
Quoted 8 lines
works
Quoted 7 lines
Quoted 7 lines
with
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines
unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which
tunneling
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
protocol
you are
Quoted 3 lines
Quoted 3 lines
using, where the nested packet can be unaligned?
I am asking to determine if your use case is exotic
(maybe
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 1 line
Quoted 1 line
some
Ericsson
Quoted 2 lines
Quoted 2 lines
proprietary protocol), or more generic (rooted in some standard
protocol).
Quoted 2 lines
Quoted 2 lines
This information affects the DPDK community's opinion about how
Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
it
Quoted 4 lines
Quoted 4 lines
should
Quoted 3 lines
Quoted 3 lines
be supported by DPDK.
If possible, please provide more details about the
tunneling
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
protocol and
Quoted 1 line
Quoted 1 line
nested packets... E.g. do the nested packets also
contain
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Layer
2
Quoted 2 lines
Quoted 2 lines
(Ethernet,
Quoted 1 line
Quoted 1 line
VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4
(TCP,
Quoted 9 lines
Quoted 9 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
UDP,
etc.)? And how
Quoted 1 line
Quoted 1 line
about ARP packets and Layer 2 control protocol packets
(STP,
Quoted 5 lines
Quoted 5 lines
LACP,
Quoted 4 lines
Quoted 4 lines
etc.)?
Quoted 3 lines
Quoted 1 line
Well, if you append or adjust an odd number of bytes
(e.g. a
Quoted 11 lines
Quoted 11 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 1 line
PDCP
header) from a previously aligned payload the entire packet
will
Quoted 5 lines
Quoted 5 lines
then
Quoted 4 lines
Quoted 4 lines
be unaligned.
Quoted 1 line
If PDCP headers can leave the rest of the packet field
unaligned,
Quoted 2 lines
Quoted 2 lines
then
Quoted 1 line
Quoted 1 line
we had better remove the alignment restrictions through all
of
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
DPDK.
Quoted 4 lines
Quoted 2 lines
/Bruce
Re-reading the details regarding unaligned pointers in C11,
as
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
posted
by Emil
Quoted 1 line
in Bugzilla [2], I interpret it as follows: Any 16 bit or
wider
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
pointer type a must
Quoted 1 line
point to data aligned with that type, i.e. a pointer of the
type
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
"
uint16_t*"Quoted 1 line
must point to 16 bit aligned data, and a pointer of the type
"
uint64_t*" mustQuoted 1 line
point to 64 bit aligned data. Please, someone tell me I got
this
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
wrong, and
Quoted 3 lines
wake me up from my nightmare!
Updating DPDK's packet structures to fully support this C11
limitation with
Quoted 1 line
unaligned access would be a nightmare, as we would need to
use
Quoted 3 lines
Quoted 3 lines
byte
Quoted 2 lines
Quoted 2 lines
arrays
Quoted 1 line
for all structure fields. Functions would also be unable to
use
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
other
pointer
Quoted 1 line
types than "void *" and "char *", which seems to be the
actual
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines
Quoted 2 lines
problem in
Quoted 1 line
the
__rte_raw_cksum()function. I guess that it also wouldprevent
Quoted 4 lines
Quoted 4 lines
the
Quoted 3 lines
compiler from auto-vectorizing the functions.
I am usually a big proponent of academically correct
solutions,
Quoted 3 lines
Quoted 3 lines
but
Quoted 2 lines
Quoted 2 lines
such a
Quoted 1 line
change would be too wide ranging, so I would like to narrow
it
Quoted 8 lines
Quoted 8 lines
down
Quoted 7 lines
Quoted 7 lines
to the
Quoted 6 lines
actual use case, and perhaps extrapolate a bit from there.
@Emil: Do you only need to calculate the checksum of the (potentially
unaligned) embedded packet? Or do you also need to use other DPDK functions with the embedded packet, potentiallyaccessing
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
it at
an
Quoted 4 lines
Quoted 4 lines
unaligned
Quoted 3 lines
address?
I'm trying to determine the scope of this C11 pointer
alignment
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
limitation for
Quoted 1 line
your use case, i.e. whether or not other DPDK functions need
to
Quoted 6 lines
Quoted 6 lines
be
Quoted 5 lines
Quoted 5 lines
updated
Quoted 4 lines
to support unaligned packet access too.
313273afQuoted 8 lines
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
Quoted 3 lines
- 454445554331-2ffe58e5caaeb74e&q=1&e=3f0544d3-8a71-4676-b4f9-
27e0952f7de0&u=https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
3D1035
That's my interpretation of the standard as well; For example
an
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
uint16_t* must be on even addresses. If not it is undefined
behavior.
Quoted 3 lines
Quoted 3 lines
I think this is a bigger problem on ARM for example.
Without being that invested in dpdk, adding unaligned support
for
Quoted 9 lines
Quoted 9 lines
Quoted 1 line
Quoted 1 line
everything seems like a steep step, but I'm not sure what it
entails
Quoted 5 lines
Quoted 3 lines
in practice.
We are actually only interested in the checksumming.
Great! Then we can cancel the panic about rewriting DPDK Core
completely.
Quoted 1 line
Although it might still need some review for similar alignment
bugs,
Quoted 5 lines
Quoted 5 lines
where
Quoted 4 lines
we have been forcing the compiler shut up when trying to warn us. :-)
I have provided v3 of the patch, which should do as requested -
and
Quoted 14 lines
Quoted 11 lines
still allow
Quoted 3 lines
the compiler to auto-vectorize.
@Emil, will you please test v3 of the patch?
It seems to work in these two cases:
* Even address, even length
* Even address, odd length
But it breaks in these two cases:
* Odd address, even length (although it works for small buffers, probably when the sum fits inside auint16_tinteger or something)Interesting observation, good analysis.
Quoted 8 lines
Quoted 1 line
* Odd address, odd length
Does this also work for small buffers?
Quoted 2 lines
I get (and like) the main idea of the algorithm but haven't yet figured out what the problem is with odd addresses.
I wonder if I messed up the algorithm for swapping back the bytes in
bsum
Quoted 1 line
after the calculation... Is the checksum also wrong when compiling
without
Quoted 3 lines
optimization?
And just to be sure: The algorithm requires that
Quoted 8 lines
__rte_raw_cksum_reduce()Quoted 1 line
is also applied to the sum. Please confirm that you call
rte_raw_cksum()(orQuoted 2 lines
__rte_raw_cksum()followed by__rte_raw_cksum_reduce())?Yes, I messed up. I didn't run the reduction part. When I do the output seems to be the same.
I'm really happy to hear that! Thank you for informing me quickly.
Quoted 6 lines
It seems to be about as fast as the previous algorithm, obviously. Both valgrind and fsanitize=undefined are happy.
Some minor improvements:
* #include <stdbool.h>?
Some include it, some don't.
Looking at other header files, I can't see any pattern, but I agree that it should be included here.
Quoted 1 line
* Use
RTE_PTR_ADDto make the casts cleaner?
Yes. Will do.
Quoted 2 lines
* I guess you could skip using 'bsum' and add to 'sum' instead, but that's a matter of preference
No, because we want to keep the byte order of the initial sum intact, and only swap the bytes of the buffer's sum (when the buffer is unaligned).
Quoted 2 lines
* Can't you just do bsum += *(const unsigned char *)buf; to avoid 'first', making it a bit more readable?
No, because on little endian CPUs, the second byte is the MSB of the uint16_t. It would only work on big endian CPUs.
I considered doing it differently. But for consistency, I reused the 'left' block's method; only I'm putting the spare byte in the second byte of the 16 bit word, whereas the 'first' block puts the spare byte in the first byte of the 16 bit word.
PS: A lot of smart tricks are available for IP checksumming... RFC 1071 is worth a read. :-)
PATCH v4 1/1 net: fix checksum with unaligned buffer
In reply to Morten BrørupWith this patch, the checksum can be calculated on an unaligned buffer. I.e. the buf parameter is no longer required to be 16 bit aligned.
The checksum is still calculated using a 16 bit aligned pointer, so the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial checksum, to compensate for the checksum having been calculated on the buffer shifted by one byte.
v4:
* Add copyright notice.
* Include stdbool.h (Emil Berg).
* Use RTE_PTR_ADD (Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even a word? v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packet buffer.
Bugzilla ID: 1035
Cc: [email protected]
--- lib/net/rte_ip.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)
lib/net/rte_ip.h +27 -5
@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */
@@ -15,6 +16,7 @@* IP-related defines */ +#include <stdbool.h> #include <stdint.h> #ifdef RTE_EXEC_ENV_WINDOWS
@@ -162,20 +164,40 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; +uint32_t bsum =0 ; +const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1 ] = *(const unsigned char *)buf; + bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + bsum += *u16_buf;/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; *(unsigned char *)&left = *(const unsigned char *)end; - sum += left; + bsum += left; } -return sum; +/* if buffer is unaligned, swap the checksum bytes */ +if (unlikely (unaligned)) + bsum = (bsum &0xFF00FF00 ) >>8 | (bsum &0x00FF00FF ) <<8 ; + +return sum + bsum; }/**
Signature · 1 line
2.17.1
RE: [PATCH v4] net: fix checksum with unaligned buffer
Quoted 100 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned buffer. I.e. the buf parameter is no longer required to be 16 bit aligned.
The checksum is still calculated using a 16 bit aligned pointer, so the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial checksum, to compensate for the
checksum having been calculated on the buffer shifted by one byte.v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even a word? v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packet buffer.Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)lib/net/rte_ip.h +27
-5@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */ @@ -15,6 +16,7 @@* IP-related defines */ +#include <stdbool.h> #include <stdint.h> #ifdef RTE_EXEC_ENV_WINDOWS @@ -162,20 +164,40 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; +uint32_t bsum =0 ; +const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1 ] = *(const unsigned char *)buf; + bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ + u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + bsum += *u16_buf;/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; *(unsigned char *)&left = *(const unsigned char *)end; - sum += left; + bsum += left; } -return sum; +/* if buffer is unaligned, swap the checksum bytes */ +if (unlikely (unaligned)) + bsum = (bsum &0xFF00FF00 ) >>8 | (bsum &0x00FF00FF ) <<8 ; + +return sum + bsum; }
Quoted 3 lines
/**
--
2.17.1
@Emil, thank you for thoroughly reviewing the previous versions.
If your test succeeds and you are satisfied with the patch, remember to reply with a "Tested-by" tag for patchwork.
RE: [PATCH] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 503 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 23 juni 2022 09:01
To: Emil Berg <[email protected]>; Bruce Richardson <[email protected]>
Cc: Stephen Hemminger <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH] net: fix checksum with unaligned bufferQuoted 15 lines
From: Emil Berg [mailto:[email protected]]
Sent: Thursday, 23 June 2022 07.22Quoted 12 lines
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 16:02Quoted 9 lines
From: Emil Berg [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 14.25Quoted 6 lines
From: Morten Brørup <[email protected]>
Sent: den 22 juni 2022 13:26Quoted 3 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Wednesday, 22 June 2022 11.18Quoted 25 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines · Emil Berg
Quoted 5 lines
Quoted 5 lines
From: Morten Brørup <[email protected]>
Sent: den 21 juni 2022 11:35Quoted 1 line
From: Bruce Richardson
[mailto:[email protected]]
Quoted 18 lines
Quoted 18 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Sent: Tuesday, 21 June 2022 10.23
On Tue, Jun 21, 2022 at 10:05:15AM +0200, Morten Brørup
Quoted 14 lines · wrote:
Quoted 14 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
+TO: @Bruce and @Stephen: You signed off on the 16 bit
alignment
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
requirement. We need background info on this.
Quoted 11 lines
Quoted 11 lines
From: Emil Berg [mailto:[email protected]]
Sent: Tuesday, 21 June 2022 09.17Quoted 7 lines
From: Morten Brørup <[email protected]>
Sent: den 20 juni 2022 12:58Quoted 4 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 20 June 2022 12.38From: Morten Brørup
Quoted 389 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Sent: den 17 juni 2022 11:07
From: Morten Brørup
[mailto:[email protected]]
Sent: Friday, 17 June 2022 10.45With this patch, the checksum can be
calculated
Quoted 7 lines
Quoted 7 lines
on
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
an
unligned
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
part
of
a packet buffer.
I.e. the buf parameter is no longer requiredto
Quoted 6 lines
Quoted 6 lines
be
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
16
bit
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned.
Quoted 2 lines
Quoted 2 lines
The DPDK invariant that packet buffers must
be
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
16 bit
aligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
remains
unchanged.
This invariant also defines how to calculatethe
Quoted 10 lines
Quoted 10 lines
16
Quoted 9 lines
Quoted 9 lines
bit
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
checksum
Quoted 7 lines
Quoted 7 lines
on
an
unaligned part of a packet buffer.Bugzilla ID: 1035
Cc: [email protected]Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Signed-off-by: Morten Brørup
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
---
lib/net/rte_ip.h | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2
deletions(-)diff --git a/lib/net/rte_ip.h
b/lib/net/rte_ip.hQuoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
index
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
b502481670..8e301d9c26 100644
--- a/lib/net/rte_ip.h
+++ b/lib/net/rte_ip.h
@@ -162,9 +162,22 @@ __rte_raw_cksum(constvoid
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
*buf,
size_tQuoted 4 lines
Quoted 4 lines
len,
Quoted 3 lines
Quoted 3 lines
uint32_t sum) {
/* extend strict-aliasing rules */
typedef uint16_t__attribute__((__may_alias__))
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
u16_p;Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
- const u16_p *u16_buf = (const u16_p
*)buf;
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
- const u16_p *end = u16_buf + len /
sizeof(*u16_buf);Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
+ const u16_p *u16_buf;
+ const u16_p *end;
+
+ /* if buffer is unaligned, keeping itbyte
Quoted 27 lines
Quoted 27 lines
Quoted 27 lines
Quoted 7 lines
order
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
independent */
Quoted 5 lines
Quoted 5 lines
+ if (unlikely((uintptr_t)buf & 1)) {
+ uint16_t first = 0;
+ if (unlikely(len == 0))
+ return 0;
+ ((unsigned char *)&first)[1] =*(const
Quoted 4 lines
unsigned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
char *)buf;
+ sum += first;
+ buf = (const void *)((uintptr_t)buf+ 1);
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
+ len--;
+ }+ u16_buf = (const u16_p *)buf;
+ end = u16_buf + len / sizeof(*u16_buf);
for (; u16_buf != end; ++u16_buf)
sum += *u16_buf;Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
--
2.17.1@Emil, can you please test this patch with an
unalignedbuffer on
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
your
application to confirm that it produces theexpected
Quoted 5 lines
Quoted 5 lines
result.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Hi!
I tested the patch. It doesn't seem to produce
the
Quoted 3 lines
Quoted 3 lines
same
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
results. I
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
think the problem is that it always starts
summing
Quoted 3 lines
Quoted 3 lines
from
Quoted 2 lines
Quoted 2 lines
an
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
even address, the sum should always start from
the
Quoted 23 lines
Quoted 23 lines
first
Quoted 10 lines
Quoted 10 lines
byte
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
according
Quoted 3 lines
Quoted 3 lines
to
Quoted 2 lines
Quoted 2 lines
the checksum specification. Can I instead
proposesomething
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Mattias
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Rönnblom sent me?
I assume that it produces the same result when the
"buf"
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
parameter is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
aligned?
And when the "buf" parameter is unaligned, I don't
expect
Quoted 6 lines
Quoted 6 lines
it to
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
produce the
Quoted 4 lines
same results as the simple algorithm!
This was the whole point of the patch: I expect
the overallQuoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
packet
Quoted 3 lines
Quoted 3 lines
buffer to
Quoted 2 lines
be 16 bit aligned, and the checksum to be a
partialchecksum of
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
such
Quoted 2 lines
Quoted 2 lines
a 16 bit
Quoted 1 line
aligned packet buffer. When calling this function,
I
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
assume
that
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
"buf" and
Quoted 1 line
"len" parameters point to a part of such a packet
buffer.
Quoted 1 line
Quoted 1 line
If
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
these
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
expectations are correct, the simple algorithm
will produceincorrect
Quoted 4 lines
Quoted 4 lines
results
Quoted 3 lines
when "buf" is unaligned.
I was asking you to test if the checksum on the
packet
Quoted 4 lines
Quoted 4 lines
is
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
correct
when your
Quoted 1 line
application modifies an unaligned part of the
packet
Quoted 8 lines
Quoted 8 lines
and
Quoted 7 lines
Quoted 7 lines
uses
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
this
Quoted 5 lines
Quoted 5 lines
function to
Quoted 2 lines
update the checksum.
Now I understand your use case. Your use case seems
to
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
be
about
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
partial
Quoted 1 line
Quoted 1 line
checksums, of which some partial checksums may start
on
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
unaligned
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
addresses in an otherwise aligned packet.
Our use case is about calculating the full checksum
on a
Quoted 11 lines
Quoted 11 lines
Quoted 5 lines
Quoted 5 lines
nested
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
packet.
Quoted 3 lines
Quoted 3 lines
That nested packet may start on unaligned addresses.
The difference is basically if we want to sum over
aligned
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
addresses or
Quoted 1 line
Quoted 1 line
not, handling the heading and trailing bytes
appropriately.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Your method does not work in our case since we want
to
Quoted 10 lines
Quoted 10 lines
treat
Quoted 3 lines
Quoted 3 lines
the
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
first
Quoted 1 line
Quoted 1 line
two bytes as the first word in our case. But I do
understand
Quoted 5 lines
Quoted 5 lines
that
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
both
Quoted 3 lines
Quoted 1 line
methods are useful.
Yes, that certainly are two different use cases,
requiring
Quoted 9 lines
Quoted 9 lines
two
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
different ways of calculating the 16 bit checksum.
Quoted 3 lines
Quoted 3 lines
Note that your method breaks the API. Previously
(assuming
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
no
crashing
Quoted 1 line
Quoted 1 line
due to low optimization levels, more accepting
hardware,
Quoted 4 lines
Quoted 4 lines
or
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
a
different
Quoted 1 line
Quoted 1 line
compiler (version)) the current method would
calculate
Quoted 2 lines
Quoted 2 lines
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
checksum assuming the first two bytes is the first
word.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
Depending on the point of view, my patch either fixes a bug
(where
Quoted 1 line
Quoted 1 line
Quoted 1 line
the checksum was calculated incorrectly when the buf
pointer
Quoted 2 lines
Quoted 2 lines
was
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
unaligned) or breaks the API (by calculating the
differently
Quoted 11 lines
Quoted 11 lines
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
when
the
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
buffer is unaligned).
Quoted 2 lines
I cannot say with certainty which one is correct, but
perhaps
Quoted 5 lines
Quoted 5 lines
some
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
of
the people with a deeper DPDK track record can...
Quoted 2 lines
@Bruce and @Stephen, in 2019 you signed off on a patch
[1]
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
introducing a 16 bit alignment requirement to the
Ethernet
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
address
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
structure.
Quoted 3 lines
It is my understanding that DPDK has an invariant
requiringpackets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to be 16 bit aligned, which that patch supports. Is this
invariant
Quoted 1 line
Quoted 1 line
Quoted 1 line
documented anywhere, or am I completely wrong? If I'm
wrong,
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
then
the
Quoted 1 line
Quoted 1 line
Quoted 1 line
alignment requirement introduced in that patch needs to
be
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
removed, as
Quoted 1 line
Quoted 1 line
Quoted 1 line
well as any similar alignment requirements elsewhere in
DPDK.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
I don't believe it is explicitly documented as a global
invariant, but
Quoted 1 line
Quoted 1 line
Quoted 1 line
I think it should be unless there is a definite case
where
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
we
need to
Quoted 1 line
Quoted 1 line
Quoted 1 line
allow packets to be completely unaligned. Across all
packet
Quoted 10 lines
Quoted 10 lines
Quoted 2 lines
Quoted 2 lines
headers we
Quoted 1 line
Quoted 1 line
Quoted 1 line
looked at, there was no tunneling protocol where the
resulting
Quoted 7 lines
Quoted 7 lines
packet
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
was left unaligned.
That said, if there are real use cases where we need to allow
packets
Quoted 1 line
Quoted 1 line
Quoted 1 line
to start at an unaligned address, then I agree with you
that
Quoted 3 lines
Quoted 3 lines
we
Quoted 2 lines
Quoted 2 lines
need
Quoted 1 line
Quoted 1 line
Quoted 1 line
to roll back the patch and work to ensure everything
works
Quoted 16 lines
Quoted 16 lines
with
Quoted 15 lines
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
unaligned addresses.
/Bruce
@Emil, can you please describe or refer to which tunneling protocol
you are
Quoted 4 lines
Quoted 4 lines
using, where the nested packet can be unaligned?
I am asking to determine if your use case is exotic (maybe some
Ericsson
Quoted 2 lines
Quoted 2 lines
proprietary protocol), or more generic (rooted in some standard
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
protocol).
Quoted 2 lines
Quoted 2 lines
This information affects the DPDK community's opinion about how
it
Quoted 4 lines
Quoted 4 lines
should
Quoted 3 lines
Quoted 3 lines
be supported by DPDK.
If possible, please provide more details about the
tunneling
Quoted 9 lines
Quoted 9 lines
Quoted 3 lines
Quoted 3 lines
protocol and
Quoted 2 lines
Quoted 2 lines
nested packets... E.g. do the nested packets also contain Layer
2
Quoted 5 lines
Quoted 5 lines
(Ethernet,
Quoted 2 lines
Quoted 2 lines
VLAN, etc.) headers, or only Layer 3 (IP) or Layer 4 (TCP, UDP,
etc.)? And how
Quoted 1 line
Quoted 1 line
about ARP packets and Layer 2 control protocol packets
(STP,
Quoted 7 lines
Quoted 7 lines
LACP,
Quoted 6 lines
Quoted 6 lines
etc.)?
Quoted 4 lines
Quoted 1 line
Well, if you append or adjust an odd number of bytes (e.g. a PDCP
header) from a previously aligned payload the entire packet
will
Quoted 5 lines
Quoted 5 lines
then
Quoted 4 lines
Quoted 4 lines
be unaligned.
Quoted 1 line
If PDCP headers can leave the rest of the packet field
unaligned,
Quoted 14 lines
Quoted 14 lines
then
Quoted 1 line
Quoted 1 line
we had better remove the alignment restrictions through all of
DPDK.
Quoted 5 lines
Quoted 2 lines
/Bruce
Re-reading the details regarding unaligned pointers in C11, as posted
by Emil
Quoted 1 line
in Bugzilla [2], I interpret it as follows: Any 16 bit or wider
pointer type a must
Quoted 1 line
point to data aligned with that type, i.e. a pointer of the type
"
uint16_t*"Quoted 1 line
must point to 16 bit aligned data, and a pointer of the type
Quoted 8 lines
Quoted 8 lines
"
uint64_t*" mustQuoted 1 line
point to 64 bit aligned data. Please, someone tell me I got this
wrong, and
Quoted 3 lines
wake me up from my nightmare!
Updating DPDK's packet structures to fully support this C11
limitation with
Quoted 1 line
unaligned access would be a nightmare, as we would need to use
byte
Quoted 7 lines
Quoted 7 lines
arrays
Quoted 2 lines
for all structure fields. Functions would also be unable to use other
pointer
Quoted 1 line
types than "void *" and "char *", which seems to be the actual
problem in
Quoted 1 line
the
__rte_raw_cksum()function. I guess that it also wouldprevent
Quoted 4 lines
Quoted 4 lines
the
Quoted 3 lines
compiler from auto-vectorizing the functions.
I am usually a big proponent of academically correct solutions,
but
Quoted 2 lines
Quoted 2 lines
such a
Quoted 1 line
change would be too wide ranging, so I would like to narrow it
down
Quoted 8 lines
Quoted 8 lines
to the
Quoted 7 lines
actual use case, and perhaps extrapolate a bit from there.
@Emil: Do you only need to calculate the checksum of the (potentially
unaligned) embedded packet? Or do you also need to use other DPDK functions with the embedded packet, potentially accessing it atQuoted 17 lines
an
Quoted 6 lines
Quoted 6 lines
unaligned
Quoted 3 lines
address?
I'm trying to determine the scope of this C11 pointer alignment
limitation for
Quoted 1 line
your use case, i.e. whether or not other DPDK functions need to
be
Quoted 9 lines
Quoted 8 lines
updated
Quoted 7 lines
to support unaligned packet access too.
[2]
https://protect2.fireeye.com/v1/url?k=31323334-501cfaf3-313273af
- 454445554331-2ffe58e5caaeb74e&q=1&e=3f0544d3-8a71-4676-b4f9-27e0952f7de0&u=https%3A%2F%2Fbugs.dpdk.org%2Fshow_bug.cgi%3Fid%
Quoted 25 lines
Quoted 4 lines
Quoted 4 lines
Quoted 1 line
3D1035
That's my interpretation of the standard as well; For example an uint16_t* must be on even addresses. If not it is undefined
behavior.
Quoted 4 lines
Quoted 4 lines
I think this is a bigger problem on ARM for example.
Without being that invested in dpdk, adding unaligned support for everything seems like a steep step, but I'm not sure what it
entails
Quoted 5 lines
Quoted 3 lines
in practice.
We are actually only interested in the checksumming.
Great! Then we can cancel the panic about rewriting DPDK Core
completely.
Quoted 1 line
Although it might still need some review for similar alignment bugs,
where
Quoted 4 lines
we have been forcing the compiler shut up when trying to warn us. :-)
I have provided v3 of the patch, which should do as requested - and
still allow
Quoted 2 lines
the compiler to auto-vectorize.
Quoted 8 lines
Quoted 1 line
@Emil, will you please test v3 of the patch?
It seems to work in these two cases:
* Even address, even length
* Even address, odd length
But it breaks in these two cases:
* Odd address, even length (although it works for small buffers, probably when the sum fits inside auint16_tinteger or something)Interesting observation, good analysis.
Quoted 1 line
* Odd address, odd length
Does this also work for small buffers?
Quoted 2 lines
I get (and like) the main idea of the algorithm but haven't yet figured out what the problem is with odd addresses.
Quoted 8 lines
I wonder if I messed up the algorithm for swapping back the bytes in bsum after the calculation... Is the checksum also wrong when compiling without optimization?
And just to be sure: The algorithm requires that
__rte_raw_cksum_reduce()is also applied to the sum. Please confirm that you callrte_raw_cksum()(or__rte_raw_cksum()followed by__rte_raw_cksum_reduce())?
Yes, I messed up. I didn't run the reduction part. When I do the output seems to be the same.
It seems to be about as fast as the previous algorithm, obviously. Both valgrind and fsanitize=undefined are happy.
Some minor improvements:
* #include <stdbool.h>?
* Use RTE_PTR_ADD to make the casts cleaner?
* I guess you could skip using 'bsum' and add to 'sum' instead, but that's a matter of preference
* Can't you just do bsum += *(const unsigned char *)buf; to avoid 'first', making it a bit more readable?
Quoted 2 lines
Quoted 2 lines
/Emil
Morten Brørup
Tested-by Emil BergRE: [PATCH v4] net: fix checksum with unaligned buffer
In reply to Emil BergQuoted 120 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 27 June 2022 09.57Quoted 7 lines
From: Morten Brørup <[email protected]>
Sent: den 23 juni 2022 14:51Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned
buffer.
Quoted 6 lines
Quoted 6 lines
I.e. the buf parameter is no longer required to be 16 bit aligned.
The checksum is still calculated using a 16 bit aligned pointer, so the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is
handled
Quoted 1 line
Quoted 1 line
separately. Furthermore, the calculated checksum of the buffer is
byte
Quoted 1 line
Quoted 1 line
shifted before being added to the initial checksum, to compensate
for
Quoted 1 line
Quoted 1 line
the checksum having been calculated on the buffer shifted by one
byte.
Quoted 11 lines
Quoted 11 lines
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even a word? v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packetbuffer.
Quoted 84 lines
Quoted 37 lines
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>Tested-by Emil Berg <[email protected]>--- lib/net/rte_ip.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..738d643da0100644lib/net/rte_ip.h +3
-2@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */ @@ -15,6 +16,7 @@* IP-related defines */ +#include <stdbool.h> #include <stdint.h> #ifdef RTE_EXEC_ENV_WINDOWS @@ -162,20 +164,40 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf;lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, · line 177
Quoted 10 lines
lib/net/rte_ip.h +10
-0+const u16_p *end; +uint32_t bsum =0 ; +const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 6 lines
lib/net/rte_ip.h +5
-0+ bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 10 lines
lib/net/rte_ip.h +3
-1+ u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + bsum += *u16_buf;/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; *(unsigned char *)&left = *(const unsigned char*)end;
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 8 lines
lib/net/rte_ip.h +4
-2- sum += left; + bsum += left; } -return sum; +/* if buffer is unaligned, swap the checksum bytes */ +if (unlikely (unaligned)) + bsum = (bsum & 0xFF00FF00) >> 8 | (bsum &
0x00FF00FF) << 8;Quoted 7 lines
lib/net/rte_ip.h +2
-1+ +return sum + bsum; }/** -- 2.17.1
@Emil, thank you for thoroughly reviewing the previous versions.
Quoted 7 lines
Quoted 1 line
If your test succeeds and you are satisfied with the patch, remember
to reply
Quoted 1 line
with a "Tested-by" tag for patchwork.
The test succeeded and I'm satisfied with the patch. I added 'Tested-
by: Emil Berg <[email protected]>' to the patch above, hopefully as you intended.
Thank you for testing! You don't need to put the tag inside the patch. Next time, just put the tag in your reply, like here, and Patchwork will catch it.
The same goes for other tags, like Acked-by, Reviewed-by, etc..
-Morten
Re: [PATCH v4] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 77 lines · Morten Brørup
Quoted 77 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned buffer. I.e. the buf parameter is no longer required to be 16 bit aligned.
The checksum is still calculated using a 16 bit aligned pointer, so the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial checksum, to compensate for the
checksum having been calculated on the buffer shifted by one byte.v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even a word? v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packet buffer.Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)lib/net/rte_ip.h +17
-2@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */ @@ -15,6 +16,7 @@* IP-related defines */ +#include <stdbool.h> #include <stdint.h> #ifdef RTE_EXEC_ENV_WINDOWS @@ -162,20 +164,40 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; +uint32_t bsum =0 ; +const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1 ] = *(const unsigned char *)buf; + bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + }
Quoted 1 line
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 183
Quoted 1 line
lib/net/rte_ip.h +1
-0+/* aligned access for compiler auto-vectorization */
The compiler will be able to auto vectorize even unaligned accesses, just with different instructions. From what I can tell, there's no performance impact, at least not on the x86_64 systems I tried on.
I think you should remove the first special case conditional and use memcpy() instead of the cumbersome __may_alias__ construct to retrieve the data.
Quoted 30 lines
Quoted 22 lines
lib/net/rte_ip.h +9
-3+ u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + bsum += *u16_buf;/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; *(unsigned char *)&left = *(const unsigned char *)end; - sum += left; + bsum += left; } -return sum; +/* if buffer is unaligned, swap the checksum bytes */ +if (unlikely (unaligned)) + bsum = (bsum &0xFF00FF00 ) >>8 | (bsum &0x00FF00FF ) <<8 ; + +return sum + bsum; }Quoted 3 lines
/**
--
2.17.1@Emil, thank you for thoroughly reviewing the previous versions.
If your test succeeds and you are satisfied with the patch, remember to reply with a "Tested-by" tag for patchwork.
RE: [PATCH v4] net: fix checksum with unaligned buffer
In reply to Emil BergQuoted 117 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 27 June 2022 14.51Quoted 11 lines
From: Emil Berg
Sent: den 27 juni 2022 14:46Quoted 8 lines
From: Mattias Rönnblom <[email protected]>
Sent: den 27 juni 2022 14:28Quoted 4 lines · Morten Brørup
Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned
buffer.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
I.e. the buf parameter is no longer required to be 16 bit
aligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The checksum is still calculated using a 16 bit aligned pointer,
so
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial
checksum,
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
to compensate for the checksum having been calculated on the
buffer
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
shifted by one byte.
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even aword?
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packetbuffer.
Quoted 25 lines
Quoted 25 lines
Quoted 25 lines
Quoted 25 lines
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..738d643da0100644lib/net/rte_ip.h +1
-0@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */ @@ -15,6 +16,7 @@* IP-related defines */ Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t
Quoted 5 lines
lib/net/rte_ip.h +1
-0+#include <stdbool.h> #include <stdint.h> #ifdef RTE_EXEC_ENV_WINDOWS @@ -162,20 +164,40 @@ __rte_raw_cksum(const void *buf, size_tlen,
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
lib/net/rte_ip.h +0
-0uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p;Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 8 lines
lib/net/rte_ip.h +6
-2-const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; +uint32_t bsum =0 ; +const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 183
Quoted 6 lines
lib/net/rte_ip.h +5
-0+ bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ The compiler will be able to auto vectorize even unaligned
accesses,
Quoted 4 lines
Quoted 4 lines
just with different instructions. From what I can tell, there's no performance impact, at least not on the
x86_64systems I tried on.I think you should remove the first special case conditional and
use
Quoted 1 line
Quoted 1 line
memcpy()instead of the cumbersome__may_alias__construct toretrieve
Quoted 6 lines
Quoted 2 lines
the data.
Here:
https://www.agner.org/optimize/instruction_tables.pdf
it lists the latency of vmovdqa (aligned) as 6 cycles and the latencyfor
Quoted 1 line
vmovdqu (unaligned) as 7 cycles. So I guess there can be some
difference.
Quoted 9 lines
Quoted 1 line
Although in practice I'm not sure what difference it makes. I've not
seen any
Quoted 2 lines
difference in runtime between the two versions.
Correction to my comment:
Those stats are for some older CPU. For some newer CPUs such as Tiger Lake the stats seem to be the same regardless of aligned or unaligned.
I agree that the memcpy method is more elegant and easy to read.
However, we would need to performance test the modified checksum function with a large number of CPUs to prove that we don't introduce a performance regression on any CPU architecture still supported by DPDK. And Emil already found a CPU where it costs 1 extra cycle per 16 bytes, which adds up to a total of ca. 91 extra cycles on a 1460 byte TCP packet.
So I opted for a solution with zero changes to the inner loop, so no performance retesting is required (for the previously supported use cases, where the buffer is aligned).
I have previously submitted a couple of patches to fix some minor bugs in the mempool cache functions [1] and [2], while also refactoring the functions for readability. But after having incorporated various feedback, nobody wants to proceed with the patches, probably due to fear of performance regressions. I didn't want to risk the same with this patch.
[1] http://inbox.dpdk.org/dev/[email protected]/
[2] http://inbox.dpdk.org/dev/[email protected]/
Re: [PATCH v4] net: fix checksum with unaligned buffer
Quoted 122 lines · Morten Brørup
Quoted 122 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 27 June 2022 14.51Quoted 11 lines
From: Emil Berg
Sent: den 27 juni 2022 14:46Quoted 8 lines
From: Mattias Rönnblom <[email protected]>
Sent: den 27 juni 2022 14:28Quoted 4 lines · Morten Brørup
Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned
buffer.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
I.e. the buf parameter is no longer required to be 16 bit
aligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The checksum is still calculated using a 16 bit aligned pointer,
so
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial
checksum,
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
to compensate for the checksum having been calculated on the
buffer
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
shifted by one byte.
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even aword?
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packetbuffer.
Quoted 25 lines
Quoted 25 lines
Quoted 25 lines
Quoted 25 lines
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..738d643da0100644lib/net/rte_ip.h +1
-0@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */ @@ -15,6 +16,7 @@* IP-related defines */ Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t
Quoted 5 lines
lib/net/rte_ip.h +1
-0+#include <stdbool.h> #include <stdint.h> #ifdef RTE_EXEC_ENV_WINDOWS @@ -162,20 +164,40 @@ __rte_raw_cksum(const void *buf, size_tlen,
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
lib/net/rte_ip.h +0
-0uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p;Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 8 lines
lib/net/rte_ip.h +6
-2-const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; +uint32_t bsum =0 ; +const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */
Quoted 6 lines
Quoted 6 lines
Quoted 5 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 5 lines
lib/net/rte_ip.h +5
-0+if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 183
Quoted 6 lines
lib/net/rte_ip.h +5
-0+ bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ The compiler will be able to auto vectorize even unaligned
accesses,
Quoted 4 lines
Quoted 4 lines
just with different instructions. From what I can tell, there's no performance impact, at least not on the
x86_64systems I tried on.I think you should remove the first special case conditional and
use
Quoted 1 line
Quoted 1 line
memcpy()instead of the cumbersome__may_alias__construct toretrieve
Quoted 6 lines
Quoted 2 lines
the data.
Here:
https://www.agner.org/optimize/instruction_tables.pdf
it lists the latency of vmovdqa (aligned) as 6 cycles and the latencyfor
Quoted 1 line
vmovdqu (unaligned) as 7 cycles. So I guess there can be some
difference.
Quoted 1 line
Although in practice I'm not sure what difference it makes. I've not
seen any
Quoted 2 lines
difference in runtime between the two versions.
Quoted 9 lines
Quoted 4 lines
Correction to my comment:
Those stats are for some older CPU. For some newer CPUs such as Tiger Lake the stats seem to be the same regardless of aligned or unaligned.I agree that the memcpy method is more elegant and easy to read.
However, we would need to performance test the modified checksum function with a large number of CPUs to prove that we don't introduce a performance regression on any CPU architecture still supported by DPDK. And Emil already found a CPU where it costs 1 extra cycle per 16 bytes, which adds up to a total of ca. 91 extra cycles on a 1460 byte TCP packet.
I think you've misunderstood what latency means in such tables. It's a data dependency thing, not a measure of throughput. The throughput is *much* higher. My guess would be two such instruction per clock.
For your 1460 bytes example, my Zen3 AMD needs performs identical with both the current DPDK implementation, your patch, and a memcpy()-ified version of the current implementation. They all need ~130 clock cycles/packet, with warm caches. IPC is 3 instructions per cycle, but obvious not all instructions are SIMD.
The main issue with checksumming on the CPU is, in my experience, not that you don't have enough compute, but that you trash the caches.
Quoted 2 lines
So I opted for a solution with zero changes to the inner loop, so no performance retesting is required (for the previously supported use cases, where the buffer is aligned).
You will see performance degradation with this solution as well, under certain conditions. For unaligned 100 bytes of data, the current DPDK implementation and the memcpy()-fied version needs ~21 cc/packet. Your patch needs 54 cc/packet.
But the old version didn't support unaligned accesses? In many compiler flag/machine combinations it did.
Quoted 5 lines
I have previously submitted a couple of patches to fix some minor bugs in the mempool cache functions [1] and [2], while also refactoring the functions for readability. But after having incorporated various feedback, nobody wants to proceed with the patches, probably due to fear of performance regressions. I didn't want to risk the same with this patch.
[1] http://inbox.dpdk.org/dev/[email protected]/
[2] http://inbox.dpdk.org/dev/[email protected]/
RE: [PATCH v4] net: fix checksum with unaligned buffer
Quoted 51 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Monday, 27 June 2022 19.23Quoted 47 lines · Morten Brørup
Quoted 47 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 27 June 2022 14.51Quoted 11 lines
From: Emil Berg
Sent: den 27 juni 2022 14:46Quoted 8 lines
From: Mattias Rönnblom <[email protected]>
Sent: den 27 juni 2022 14:28Quoted 4 lines · Morten Brørup
Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned
buffer.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
I.e. the buf parameter is no longer required to be 16 bit
aligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The checksum is still calculated using a 16 bit aligned pointer,
so
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial
checksum,
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
to compensate for the checksum having been calculated on the
buffer
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
shifted by one byte.
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even aword?
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packetbuffer.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>
[...]
Quoted 47 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
The compiler will be able to auto vectorize even unaligned
accesses,
Quoted 4 lines
Quoted 4 lines
just with different instructions. From what I can tell, there's no performance impact, at least not on the
x86_64systems I tried on.I think you should remove the first special case conditional and
use
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
memcpy()instead of the cumbersome__may_alias__construct toretrieve
Quoted 6 lines
Quoted 2 lines
the data.
Here:
https://www.agner.org/optimize/instruction_tables.pdf
it lists the latency of vmovdqa (aligned) as 6 cycles and thelatency
Quoted 4 lines
Quoted 4 lines
for
Quoted 1 line
vmovdqu (unaligned) as 7 cycles. So I guess there can be some
difference.
Quoted 1 line
Although in practice I'm not sure what difference it makes. I've
not
Quoted 6 lines
Quoted 6 lines
seen any
Quoted 2 lines
difference in runtime between the two versions.
Correction to my comment:
Those stats are for some older CPU. For some newer CPUs such asTiger
Quoted 1 line
Quoted 1 line
Lake the stats seem to be the same regardless of aligned or
unaligned.
Quoted 5 lines
Quoted 1 line
I agree that the memcpy method is more elegant and easy to read.
However, we would need to performance test the modified checksum
function with a large number of CPUs to prove that we don't introduce a performance regression on any CPU architecture still supported by DPDK. And Emil already found a CPU where it costs 1 extra cycle per 16 bytes, which adds up to a total of ca. 91 extra cycles on a 1460 byte TCP packet.
Quoted 1 line
I think you've misunderstood what latency means in such tables. It's a data dependency thing, not a measure of throughput. The throughput is *much* higher. My guess would be two such instruction per clock.
Quoted 5 lines
For your 1460 bytes example, my Zen3 AMD needs performs identical with both the current DPDK implementation, your patch, and a memcpy()-ified version of the current implementation. They all need ~130 clock cycles/packet, with warm caches. IPC is 3 instructions per cycle, but obvious not all instructions are SIMD.
You're right, I wasn't thinking deeper about it before extrapolating.
Great to see some real numbers! I wish someone would do the same testing on an old ARM CPU, so we could also see the other end of the scale.
Quoted 2 lines
The main issue with checksumming on the CPU is, in my experience, not that you don't have enough compute, but that you trash the caches.
Agree. I have noticed that x86 has "non-temporal" instruction variants to load/store data without trashing the cache entirely.
A variant of the checksum function using such instructions might be handy.
Variants of the memcpy function using such instructions might also be handy for some purposes, e.g. copying the contents of packets, where the original and/or copy will not accessed shortly thereafter.
Quoted 9 lines
Quoted 1 line
So I opted for a solution with zero changes to the inner loop, so no
performance retesting is required (for the previously supported use cases, where the buffer is aligned).
Quoted 1 line
You will see performance degradation with this solution as well, under certain conditions. For unaligned 100 bytes of data, the current DPDK implementation and the memcpy()-fied version needs ~21 cc/packet. Your patch needs 54 cc/packet.
Yes, it's a tradeoff. I exclusively aimed at maintaining performance for the case with aligned buffers (under all circumstances, with all CPUs etc.), and ignored how it affects the performance for the case with unaligned buffers.
Unlike this patch, the memcpy() variant has no additional branches for the unaligned case, so its performance should be generally unaffected by the buffer being aligned or not. However, I don't have sufficient in-depth CPU knowledge to say if this also applies to RISCV and older ARM CPUs still supported by DPDK.
I don't have strong feelings for this patch, so you can provide a memcpy() based alternative patch, and we will let the community decide which one they prefer.
Quoted 2 lines
But the old version didn't support unaligned accesses? In many compiler flag/machine combinations it did.
It crashed in some cases. That was the point of the bug report [1], and the reason to provide a patch.
Re: [PATCH v4] net: fix checksum with unaligned buffer
Quoted 107 lines · Morten Brørup
Quoted 51 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Monday, 27 June 2022 19.23Quoted 47 lines · Morten Brørup
Quoted 47 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 27 June 2022 14.51Quoted 11 lines
From: Emil Berg
Sent: den 27 juni 2022 14:46Quoted 8 lines
From: Mattias Rönnblom <[email protected]>
Sent: den 27 juni 2022 14:28Quoted 4 lines · Morten Brørup
Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned
buffer.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
I.e. the buf parameter is no longer required to be 16 bit
aligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The checksum is still calculated using a 16 bit aligned pointer,
so
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial
checksum,
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
to compensate for the checksum having been calculated on the
buffer
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
shifted by one byte.
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even aword?
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packetbuffer.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>[...]
Quoted 47 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
The compiler will be able to auto vectorize even unaligned
accesses,
Quoted 4 lines
Quoted 4 lines
just with different instructions. From what I can tell, there's no performance impact, at least not on the
x86_64systems I tried on.I think you should remove the first special case conditional and
use
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
memcpy()instead of the cumbersome__may_alias__construct toretrieve
Quoted 6 lines
Quoted 2 lines
the data.
Here:
https://www.agner.org/optimize/instruction_tables.pdf
it lists the latency of vmovdqa (aligned) as 6 cycles and thelatency
Quoted 4 lines
Quoted 4 lines
for
Quoted 1 line
vmovdqu (unaligned) as 7 cycles. So I guess there can be some
difference.
Quoted 1 line
Although in practice I'm not sure what difference it makes. I've
not
Quoted 6 lines
Quoted 6 lines
seen any
Quoted 2 lines
difference in runtime between the two versions.
Correction to my comment:
Those stats are for some older CPU. For some newer CPUs such asTiger
Quoted 1 line
Quoted 1 line
Lake the stats seem to be the same regardless of aligned or
unaligned.
Quoted 5 lines
Quoted 1 line
I agree that the memcpy method is more elegant and easy to read.
However, we would need to performance test the modified checksum
function with a large number of CPUs to prove that we don't introduce a performance regression on any CPU architecture still supported by DPDK. And Emil already found a CPU where it costs 1 extra cycle per 16 bytes, which adds up to a total of ca. 91 extra cycles on a 1460 byte TCP packet.
Quoted 1 line
I think you've misunderstood what latency means in such tables. It's a data dependency thing, not a measure of throughput. The throughput is *much* higher. My guess would be two such instruction per clock.
Quoted 5 lines
For your 1460 bytes example, my Zen3 AMD needs performs identical with both the current DPDK implementation, your patch, and a memcpy()-ified version of the current implementation. They all need ~130 clock cycles/packet, with warm caches. IPC is 3 instructions per cycle, but obvious not all instructions are SIMD.
Quoted 4 lines
You're right, I wasn't thinking deeper about it before extrapolating.
Great to see some real numbers! I wish someone would do the same testing on an old ARM CPU, so we could also see the other end of the scale.
I've ran it on an ARM A72. For the aligned 1460 bytes case I got: Current DPDK ~572 cc. Your patch: ~578 cc. Memcpy-fied: ~573 cc. They performed about the same for all unaligned/aligned and sizes I tested. This platform (or could be GCC version as well) doesn't suffer from the unaligned performance degradation your patch showed on my AMD machine.
Quoted 7 lines
Quoted 2 lines
The main issue with checksumming on the CPU is, in my experience, not that you don't have enough compute, but that you trash the caches.
Agree. I have noticed that x86 has "non-temporal" instruction variants to load/store data without trashing the cache entirely.
A variant of the checksum function using such instructions might be handy.
Yes, although you may need to prefetch the payload for good performance.
Quoted 2 lines
Variants of the memcpy function using such instructions might also be handy for some purposes, e.g. copying the contents of packets, where the original and/or copy will not accessed shortly thereafter.
Indeed and I think it's been discussed on the list. There's some work to get it right, since alignment requirement and the fact a different memory model is used for those SIMD instructions causes trouble for a generic implementation. (For x86_64.)
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
So I opted for a solution with zero changes to the inner loop, so no
performance retesting is required (for the previously supported use cases, where the buffer is aligned).
Quoted 1 line
Quoted 9 lines
Quoted 4 lines
You will see performance degradation with this solution as well, under certain conditions. For unaligned 100 bytes of data, the current DPDK implementation and the memcpy()-fied version needs ~21 cc/packet. Your patch needs 54 cc/packet.
Yes, it's a tradeoff. I exclusively aimed at maintaining performance for the case with aligned buffers (under all circumstances, with all CPUs etc.), and ignored how it affects the performance for the case with unaligned buffers.
Unlike this patch, the
memcpy()variant has no additional branches for the unaligned case, so its performance should be generally unaffected by the buffer being aligned or not. However, I don't have sufficient in-depth CPU knowledge to say if this also applies to RISCV and older ARM CPUs still supported by DPDK.
I don't think avoiding RISCV non-catastrophic regressions triumphs improving performance on mainstream CPUs and avoiding code quality regressions.
Quoted 2 lines
I don't have strong feelings for this patch, so you can provide a
memcpy()based alternative patch, and we will let the community decide which one they prefer.
This is what my conversion looks like:
static inline uint32_t__rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
{
const void *end;
for (end = RTE_PTR_ADD(buf, (len/sizeof(uint16_t)) * sizeof(uint16_t));
buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) {
uint16_t v;
memcpy(&v, buf, sizeof(uint16_t));
sum += v;
}
/* if length is odd, keeping it byte order independent */
if (unlikely(len % 2)) {
uint8_t last;
uint16_t left = 0;
memcpy(&last, end, 1);
*(unsigned char *)&left = last;
sum += left;
}
return sum;
}Maybe the maintainer can have an opinion, before I provide a real patch, to save me some work. I would really like to contribute some performance autotests in that case. I mean, you could be right and the performance could be totally off on some platform.
Quoted 7 lines
Quoted 2 lines
But the old version didn't support unaligned accesses? In many compiler flag/machine combinations it did.
It crashed in some cases. That was the point of the bug report [1], and the reason to provide a patch.
RE: [PATCH v4] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 113 lines
-----Original Message-----
From: Morten Brørup <[email protected]>
Sent: den 23 juni 2022 14:51
To: Emil Berg <[email protected]>; [email protected]; [email protected]
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH v4] net: fix checksum with unaligned bufferQuoted 61 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned buffer. I.e. the buf parameter is no longer required to be 16 bit aligned.
The checksum is still calculated using a 16 bit aligned pointer, so the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial checksum, to compensate for the checksum having been calculated on the buffer shifted by one byte.
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even a word? v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packet buffer.Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>Tested-by Emil Berg <[email protected]>--- lib/net/rte_ip.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..738d643da0100644lib/net/rte_ip.h +3
-2@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */ @@ -15,6 +16,7 @@* IP-related defines */ +#include <stdbool.h> #include <stdint.h> #ifdef RTE_EXEC_ENV_WINDOWS @@ -162,20 +164,40 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf;lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, · line 177
Quoted 10 lines
lib/net/rte_ip.h +10
-0+const u16_p *end; +uint32_t bsum =0 ; +const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 6 lines
lib/net/rte_ip.h +5
-0+ bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 10 lines
lib/net/rte_ip.h +3
-1+ u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + bsum += *u16_buf;/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; *(unsigned char *)&left = *(const unsigned char*)end;
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 8 lines
lib/net/rte_ip.h +4
-2- sum += left; + bsum += left; } -return sum; +/* if buffer is unaligned, swap the checksum bytes */ +if (unlikely (unaligned)) + bsum = (bsum & 0xFF00FF00) >> 8 | (bsum &
0x00FF00FF) << 8;Quoted 4 lines
lib/net/rte_ip.h +2
-0+ +return sum + bsum; }
Quoted 8 lines
Quoted 3 lines
lib/net/rte_ip.h +0
-1/** -- 2.17.1
@Emil, thank you for thoroughly reviewing the previous versions.
If your test succeeds and you are satisfied with the patch, remember to reply with a "Tested-by" tag for patchwork.
The test succeeded and I'm satisfied with the patch. I added 'Tested-by: Emil Berg <[email protected]>' to the patch above, hopefully as you intended.
RE: [PATCH v4] net: fix checksum with unaligned buffer
In reply to Mattias RönnblomQuoted 96 lines
-----Original Message-----
From: Mattias Rönnblom <[email protected]>
Sent: den 27 juni 2022 14:28
To: Morten Brørup <[email protected]>; Emil Berg <[email protected]>; [email protected]; [email protected]
Cc: [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH v4] net: fix checksum with unaligned bufferQuoted 64 lines · Morten Brørup
Quoted 64 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned buffer. I.e. the buf parameter is no longer required to be 16 bit aligned.
The checksum is still calculated using a 16 bit aligned pointer, so the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial checksum, to compensate for the checksum having been calculated on the buffer shifted by one byte.
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even a word? v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packet buffer.Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..738d643da0100644lib/net/rte_ip.h +5
-2@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */ @@ -15,6 +16,7 @@* IP-related defines */ +#include <stdbool.h> #include <stdint.h> #ifdef RTE_EXEC_ENV_WINDOWS @@ -162,20 +164,40 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; +uint32_t bsum =0 ;Quoted 8 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 8 lines
lib/net/rte_ip.h +8
-0+const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 6 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 183
Quoted 6 lines
lib/net/rte_ip.h +5
-0+ bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ The compiler will be able to auto vectorize even unaligned accesses, just with different instructions. From what I can tell, there's no performance impact, at least not on the
x86_64systems I tried on.
Quoted 4 lines
I think you should remove the first special case conditional and use
memcpy()instead of the cumbersome__may_alias__construct to retrieve the data.
Here:
https://www.agner.org/optimize/instruction_tables.pdf
it lists the latency of vmovdqa (aligned) as 6 cycles and the latency for vmovdqu (unaligned) as 7 cycles. So I guess there can be some difference. Although in practice I'm not sure what difference it makes. I've not seen any difference in runtime between the two versions.
Quoted 33 lines
Quoted 10 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 10 lines
lib/net/rte_ip.h +3
-1+ u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + bsum += *u16_buf;/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; *(unsigned char *)&left = *(const unsigned char*)end;
Quoted 8 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 8 lines
lib/net/rte_ip.h +4
-2- sum += left; + bsum += left; } -return sum; +/* if buffer is unaligned, swap the checksum bytes */ +if (unlikely (unaligned)) + bsum = (bsum & 0xFF00FF00) >> 8 | (bsum &
0x00FF00FF) << 8;Quoted 11 lines
Quoted 7 lines
lib/net/rte_ip.h +2
-0+ +return sum + bsum; }/**
--
2.17.1@Emil, thank you for thoroughly reviewing the previous versions.
If your test succeeds and you are satisfied with the patch, remember to
reply with a "Tested-by" tag for patchwork.
Quoted 1 line
RE: [PATCH v4] net: fix checksum with unaligned buffer
Quoted 113 lines
-----Original Message-----
From: Emil Berg
Sent: den 27 juni 2022 14:46
To: Mattias Rönnblom <[email protected]>; Morten Brørup <[email protected]>; [email protected]; [email protected]
Cc: [email protected]; [email protected]; [email protected]; [email protected]
Subject: RE: [PATCH v4] net: fix checksum with unaligned bufferQuoted 94 lines
-----Original Message-----
From: Mattias Rönnblom <[email protected]>
Sent: den 27 juni 2022 14:28
To: Morten Brørup <[email protected]>; Emil Berg <[email protected]>; [email protected]; [email protected]
Cc: [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH v4] net: fix checksum with unaligned bufferQuoted 64 lines · Morten Brørup
Quoted 64 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an unaligned buffer. I.e. the buf parameter is no longer required to be 16 bit aligned.
The checksum is still calculated using a 16 bit aligned pointer, so the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of the buffer is byte shifted before being added to the initial checksum, to compensate for the checksum having been calculated on the buffer shifted by one byte.
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even a word? v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packet buffer.Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Morten Brørup <[email protected]>--- lib/net/rte_ip.h | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)lib/net/rte_ip.h index renamed from lib/net/rte_ip.h +0
-0
b502481670..738d643da0100644lib/net/rte_ip.h +5
-2@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */ @@ -15,6 +16,7 @@* IP-related defines */ +#include <stdbool.h> #include <stdint.h> #ifdef RTE_EXEC_ENV_WINDOWS @@ -162,20 +164,40 @@ __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {/* extend strict-aliasing rules */ typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const u16_p *u16_buf; +const u16_p *end; +uint32_t bsum =0 ;Quoted 8 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 8 lines
lib/net/rte_ip.h +8
-0+const bool unaligned = (uintptr_t )buf &1 ; + +/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ; + ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Quoted 6 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 183
Quoted 6 lines
lib/net/rte_ip.h +5
-0+ bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + } +/* aligned access for compiler auto-vectorization */ The compiler will be able to auto vectorize even unaligned accesses, just with different instructions. From what I can tell, there's no performance impact, at least not on the
x86_64systems I tried on.Quoted 4 lines
I think you should remove the first special case conditional and use
memcpy()instead of the cumbersome__may_alias__construct to retrieve the data.
Quoted 7 lines
Here:
https://www.agner.org/optimize/instruction_tables.pdf
it lists the latency of vmovdqa (aligned) as 6 cycles and the latency for vmovdqu (unaligned) as 7 cycles. So I guess there can be some difference. Although in practice I'm not sure what difference it makes. I've not seen any difference in runtime between the two versions.
Correction to my comment:
Those stats are for some older CPU. For some newer CPUs such as Tiger Lake the stats seem to be the same regardless of aligned or unaligned.
Quoted 34 lines
Quoted 34 lines
Quoted 10 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 10 lines
lib/net/rte_ip.h +3
-1+ u16_buf = (const u16_p *)buf; + end = u16_buf + len /sizeof (*u16_buf);for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + bsum += *u16_buf;/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; *(unsigned char *)&left = *(const unsigned char*)end;
Quoted 8 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum)
Quoted 8 lines
lib/net/rte_ip.h +4
-2- sum += left; + bsum += left; } -return sum; +/* if buffer is unaligned, swap the checksum bytes */ +if (unlikely (unaligned)) + bsum = (bsum & 0xFF00FF00) >> 8 | (bsum &
0x00FF00FF) << 8;Quoted 4 lines
Quoted 4 lines
lib/net/rte_ip.h +2
-0+ +return sum + bsum; }Quoted 8 lines
Quoted 3 lines
/**
--
2.17.1@Emil, thank you for thoroughly reviewing the previous versions.
If your test succeeds and you are satisfied with the patch, remember to
reply with a "Tested-by" tag for patchwork.
Quoted 1 line
RE: [PATCH v4] net: fix checksum with unaligned buffer
In reply to Mattias RönnblomQuoted 156 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Tuesday, 28 June 2022 08.28Quoted 10 lines · Morten Brørup
Quoted 10 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Monday, 27 June 2022 19.23Quoted 6 lines · Morten Brørup
Quoted 6 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 27 June 2022 14.51Quoted 3 lines
From: Emil Berg
Sent: den 27 juni 2022 14:46Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
From: Mattias Rönnblom <[email protected]>
Sent: den 27 juni 2022 14:28Quoted 4 lines · Morten Brørup
Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an
unaligned
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
buffer.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
I.e. the buf parameter is no longer required to be 16 bit
aligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The checksum is still calculated using a 16 bit aligned
pointer,
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
so
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of
the
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
buffer is byte shifted before being added to the initial
checksum,
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
to compensate for the checksum having been calculated on the
buffer
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
shifted by one byte.
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even aword?
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packetbuffer.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Bugzilla ID: 1035
Cc: [email protected]Quoted 8 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Signed-off-by Morten Brørup <[email protected]>[...]
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
Quoted 2 lines
The compiler will be able to auto vectorize even unaligned
accesses,
Quoted 1 line
Quoted 1 line
just with different instructions. From what I can tell, there's
no
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
performance impact, at least not on the
x86_64systems I triedon.
Quoted 24 lines
Quoted 24 lines
Quoted 11 lines
Quoted 11 lines
Quoted 2 lines
Quoted 2 lines
I think you should remove the first special case conditional and
use
Quoted 1 line
Quoted 1 line
memcpy()instead of the cumbersome__may_alias__construct toretrieve
Quoted 6 lines
Quoted 2 lines
the data.
Here:
https://www.agner.org/optimize/instruction_tables.pdf
it lists the latency of vmovdqa (aligned) as 6 cycles and thelatency
Quoted 4 lines
Quoted 4 lines
for
Quoted 1 line
vmovdqu (unaligned) as 7 cycles. So I guess there can be some
difference.
Quoted 1 line
Although in practice I'm not sure what difference it makes. I've
not
Quoted 6 lines
Quoted 6 lines
seen any
Quoted 2 lines
difference in runtime between the two versions.
Correction to my comment:
Those stats are for some older CPU. For some newer CPUs such asTiger
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Lake the stats seem to be the same regardless of aligned or
unaligned.
Quoted 5 lines
Quoted 1 line
I agree that the memcpy method is more elegant and easy to read.
However, we would need to performance test the modified checksum
function with a large number of CPUs to prove that we don't
introduce a
Quoted 1 line
Quoted 1 line
performance regression on any CPU architecture still supported by
DPDK.
Quoted 1 line
Quoted 1 line
And Emil already found a CPU where it costs 1 extra cycle per 16
bytes,
Quoted 5 lines
Quoted 5 lines
which adds up to a total of ca. 91 extra cycles on a 1460 byte TCP packet.
Quoted 1 line
I think you've misunderstood what latency means in such tables. It's
a
Quoted 1 line
Quoted 1 line
data dependency thing, not a measure of throughput. The throughput
is
Quoted 3 lines
Quoted 3 lines
*much* higher. My guess would be two such instruction per clock.
For your 1460 bytes example, my Zen3 AMD needs performs identical
with
Quoted 1 line
Quoted 1 line
both the current DPDK implementation, your patch, and a memcpy()-
ified
Quoted 2 lines
Quoted 2 lines
version of the current implementation. They all need ~130 clock cycles/packet, with warm caches. IPC is 3 instructions per cycle,
but
Quoted 5 lines
Quoted 1 line
obvious not all instructions are SIMD.
You're right, I wasn't thinking deeper about it before extrapolating.
Great to see some real numbers! I wish someone would do the same
testing on an old ARM CPU, so we could also see the other end of the scale.
Quoted 1 line
I've ran it on an ARM A72. For the aligned 1460 bytes case I got:
Current DPDK ~572 cc. Your patch: ~578 cc. Memcpy-fied: ~573 cc. They performed about the same for all unaligned/aligned and sizes I tested. This platform (or could be GCC version as well) doesn't suffer from the unaligned performance degradation your patch showed on my AMD machine.Quoted 1 line
Quoted 1 line
The main issue with checksumming on the CPU is, in my experience,
not
Quoted 3 lines
Quoted 1 line
that you don't have enough compute, but that you trash the caches.
Agree. I have noticed that x86 has "non-temporal" instruction
variants to load/store data without trashing the cache entirely.
Quoted 2 lines
A variant of the checksum function using such instructions might be
handy.
Quoted 1 line
Yes, although you may need to prefetch the payload for good performance.
Quoted 1 line
Variants of the memcpy function using such instructions might also be
handy for some purposes, e.g. copying the contents of packets, where the original and/or copy will not accessed shortly thereafter.
Quoted 1 line
Quoted 5 lines
Indeed and I think it's been discussed on the list. There's some work to
get it right, since alignment requirement and the fact a different memory model is used for those SIMD instructions causes trouble for a generic implementation. (Forx86_64.)
I just posted an RFC [1] for such memcpy() and memset() functions, so let's see how it fans out.
[1] http://inbox.dpdk.org/dev/[email protected]/T/#u
Quoted 27 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
So I opted for a solution with zero changes to the inner loop, so
no
Quoted 5 lines
Quoted 5 lines
performance retesting is required (for the previously supported use cases, where the buffer is aligned).
Quoted 1 line
You will see performance degradation with this solution as well,
under
Quoted 1 line
Quoted 1 line
certain conditions. For unaligned 100 bytes of data, the current
DPDK
Quoted 1 line
Quoted 1 line
implementation and the memcpy()-fied version needs ~21 cc/packet.
Your
Quoted 3 lines
Quoted 1 line
patch needs 54 cc/packet.
Yes, it's a tradeoff. I exclusively aimed at maintaining performance
for the case with aligned buffers (under all circumstances, with all CPUs etc.), and ignored how it affects the performance for the case with unaligned buffers.
Quoted 2 lines
Unlike this patch, the
memcpy()variant has no additional branchesfor the unaligned case, so its performance should be generally unaffected by the buffer being aligned or not. However, I don't have sufficient in-depth CPU knowledge to say if this also applies to RISCV and older ARM CPUs still supported by DPDK.
Quoted 1 line
Quoted 3 lines
I don't think avoiding RISCV non-catastrophic regressions triumphs improving performance on mainstream CPUs and avoiding code quality regressions.
+1
Quoted 35 lines
Quoted 2 lines
I don't have strong feelings for this patch, so you can provide a
memcpy()based alternative patch, and we will let the community decide which one they prefer.Quoted 1 line
This is what my conversion looks like:
static inline
uint32_t__rte_raw_cksum(const void *buf, size_t len, uint32_t sum){ const void *end; for (end = RTE_PTR_ADD(buf, (len/sizeof(uint16_t)) * sizeof(uint16_t)); buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) { uint16_t v; memcpy(&v, buf, sizeof(uint16_t)); sum += v; } /* if length is odd, keeping it byte order independent */ if (unlikely(len % 2)) { uint8_t last; uint16_t left = 0; memcpy(&last, end, 1); *(unsigned char *)&left = last; sum += left; } return sum; }
Quoted 6 lines
Maybe the maintainer can have an opinion, before I provide a real patch,
to save me some work. I would really like to contribute some performance
autotests in that case. I mean, you could be right and the performance could be totally off on some platform.
Looking at the meson files, A72 seems to be the weakest type of CPU actively supported by DPDK. So your testing shows better performance for your solution than mine under all conditions.
If you post a patch, I'll close this one as superseded.
Quoted 10 lines
Quoted 2 lines
Quoted 2 lines
But the old version didn't support unaligned accesses? In many
compiler
Quoted 3 lines
Quoted 1 line
flag/machine combinations it did.
It crashed in some cases. That was the point of the bug report [1],
and the reason to provide a patch.
Quoted 3 lines
Re: [PATCH v4] net: fix checksum with unaligned buffer
In reply to Morten Brøruplib/net/rte_ip.h line 8
Quoted 11 lines · On Thu, 23 Jun 2022 14:39:00 +0200 Morten Brørup <[email protected]>…
lib/net/rte_ip.h +1
-0@@ -3,6 +3,7 @@* The Regents of the University of California. * Copyright(c) 2010-2014 Intel Corporation. * Copyright(c) 2014 6WIND S.A. +* Copyright(c) 2022 SmartShare Systems. * All rights reserved. */
NAK
Doing a small incremental fix should not change copyright.
Re: [PATCH v4] net: fix checksum with unaligned buffer
In reply to Morten Brøruplib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 176
Quoted 5 lines · On Thu, 23 Jun 2022 14:39:00 +0200 Morten Brørup <[email protected]>…
lib/net/rte_ip.h +5
-0+/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ;
Why is length == 0 unique to unaligned case?
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 177
Quoted 1 line
lib/net/rte_ip.h +1
-0+ ((unsigned char *)&first)[1 ] = *(const unsigned char *)buf;
Use a proper union instead of casting to avoid aliasing warnings.
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 181
Quoted 4 lines
lib/net/rte_ip.h +4
-0+ bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + }
Many CPU's (such as x86) won't care about alignment and therefore the extra code to handle this is not worth doing.
Perhaps DPDK needs a macro (like Linux kernel) for efficient unaligned access.
In Linux kernel it is CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
RE: [PATCH v4] net: fix checksum with unaligned buffer
Quoted 27 lines
-----Original Message-----
From: Stephen Hemminger <[email protected]>
Sent: den 30 juni 2022 19:46
To: Morten Brørup <[email protected]>
Cc: Emil Berg <[email protected]>; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: Re: [PATCH v4] net: fix checksum with unaligned bufferlib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 176
Quoted 5 lines · On Thu, 23 Jun 2022 14:39:00 +0200 Morten Brørup <[email protected]>…
lib/net/rte_ip.h +5
-0+/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ;Why is length == 0 unique to unaligned case?
Review
Quoted 1 line
(quoted diff) +1
-0+ ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Use a proper union instead of casting to avoid aliasing warnings.
Quoted 8 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 181
Quoted 4 lines
lib/net/rte_ip.h +4
-0+ bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + }Many CPU's (such as x86) won't care about alignment and therefore the extra code to handle this is not worth doing.
x86 does care about alignment. An example is the vmovdqa instruction, where 'a' stands for 'aligned'. The description in the link below says: "When the source or destination operand is a memory operand, the operand must be aligned on a 16-byte boundary or a general-protection exception (#GP) will be generated. "
https://www.felixcloutier.com/x86/movdqa:vmovdqa32:vmovdqa64
Quoted 4 lines
Perhaps DPDK needs a macro (like Linux kernel) for efficient unaligned access.
In Linux kernel it is
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
RE: [PATCH v4] net: fix checksum with unaligned buffer
Quoted 16 lines
From: Emil Berg [mailto:[email protected]]
Sent: Friday, 1 July 2022 06.11Quoted 13 lines
From: Stephen Hemminger <[email protected]>
Sent: den 30 juni 2022 19:46lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 176
Quoted 5 lines · On Thu, 23 Jun 2022 14:39:00 +0200 Morten Brørup <[email protected]>…
lib/net/rte_ip.h +5
-0+/* if buffer is unaligned, keeping it byte order independent */ +if (unlikely (unaligned)) { +uint16_t first =0 ; +if (unlikely (len ==0 )) +return 0 ;Why is length == 0 unique to unaligned case?
Because the aligned case handles it gracefully. The unaligned case subtracts one from 'len', which (being unsigned) would become a very large number, causing 'end' to become way off.
Quoted 5 lines
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +1
-0+ ((unsigned char *)&first)[1] = *(const unsignedchar *)buf;
Use a proper union instead of casting to avoid aliasing warnings.
I copied what is done by 'left', so it resembles the existing code in the function, making it easier to review.
It is part of the endian neutral checksum handling. Tricky stuff! :-)
Quoted 10 lines
Quoted 9 lines
lib/net/rte_ip.h __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) · line 181
Quoted 5 lines
lib/net/rte_ip.h +4
-0+ bsum += first; + buf =RTE_PTR_ADD (buf,1 ); + len--; + }Many CPU's (such as x86) won't care about alignment and therefore the extra code to handle this is not worth doing.
Quoted 8 lines
x86 does care about alignment. An example is the vmovdqa instruction, where 'a' stands for 'aligned'. The description in the link below says:
"When the source or destination operand is a memory operand, the operand must be aligned on a 16-byte boundary or a general-protection exception (#GP) will be generated. "https://www.felixcloutier.com/x86/movdqa:vmovdqa32:vmovdqa64
Also, this misconception is exactly the bug [1] this patch fixes.
[1] https://bugs.dpdk.org/show_bug.cgi?id=1035
Quoted 5 lines
Quoted 1 line
Perhaps DPDK needs a macro (like Linux kernel) for efficient
unaligned
Quoted 3 lines
access.
In Linux kernel it is
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
I recently stumbled across RTE_ARCH_STRICT_ALIGN in /lib/eal/include/rte_common.h.
But I guess it is something else.
Anyway, this function has ugly alignment problems (also before the patch), and has gone through a couple of iterations to silence warnings from the compiler. These warnings should have been addressed instead of silenced. Mattias has suggested a far better solution [2] than mine, which also correctly addresses the compiler alignment warnings, so we will probably end up with his solution instead.
Re: [PATCH v4] net: fix checksum with unaligned buffer
Quoted 6 lines · On Fri, 1 Jul 2022 18:50:34 +0200 Morten Brørup <[email protected]>…
But I guess it is something else.
Anyway, this function has ugly alignment problems (also before the patch), and has gone through a couple of iterations to silence warnings from the compiler. These warnings should have been addressed instead of silenced. Mattias has suggested a far better solution [2] than mine, which also correctly addresses the compiler alignment warnings, so we will probably end up with his solution instead.
Maybe some mix of the memcpy for unaligned and odd length and faster (unrolled?) version for the case of aligned and exact multiple? Or just take code from FreeBSD?
RE: [PATCH v4] net: fix checksum with unaligned buffer
Quoted 22 lines
From: Stephen Hemminger [mailto:[email protected]]
Sent: Friday, 1 July 2022 19.05Quoted 3 lines · On Fri, 1 Jul 2022 18:50:34 +0200 Morten Brørup <[email protected]>…
But I guess it is something else.
Anyway, this function has ugly alignment problems (also before the
patch), and has gone through a couple of iterations to silence warnings from the compiler. These warnings should have been addressed instead of silenced. Mattias has suggested a far better solution [2] than mine, which also correctly addresses the compiler alignment warnings, so we will probably end up with his solution instead.
Quoted 2 lines
[2]
http://inbox.dpdk.org/dev/AM8PR07MB7666AD7BF7B780CC5062C14598BD9@AM8PR0
7MB7666.eurprd07.prod.outlook.com/T/#m1a76490541fce4a85b12d9390f2f4fac5 a9f4660Quoted 1 line
Quoted 3 lines
Maybe some mix of the memcpy for unaligned and odd length and faster (unrolled?) version for the case of aligned and exact multiple? Or just take code from FreeBSD?
I just took a look at the BSD code, and it starts with the same "if ptr is unaligned" as my patch, and then does some manual loop unrolling, which we expect the compiler to do. Mattias has demonstrated that his solution has better performance, not only on modern X86 CPUs, also on an A72 CPU, so I prefer his solution. And the difference between using "vmovdqa" and "vmovdq" instructions here seem to be insignificant.
Re: [PATCH v4] net: fix checksum with unaligned buffer
In reply to Morten BrørupQuoted 195 lines · Morten Brørup
Quoted 157 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Tuesday, 28 June 2022 08.28Quoted 10 lines · Morten Brørup
Quoted 10 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Monday, 27 June 2022 19.23Quoted 6 lines · Morten Brørup
Quoted 6 lines
From: Emil Berg [mailto:[email protected]]
Sent: Monday, 27 June 2022 14.51Quoted 3 lines
From: Emil Berg
Sent: den 27 juni 2022 14:46Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
From: Mattias Rönnblom <[email protected]>
Sent: den 27 juni 2022 14:28Quoted 4 lines · Morten Brørup
Quoted 4 lines
From: Morten Brørup [mailto:[email protected]]
Sent: Thursday, 23 June 2022 14.39With this patch, the checksum can be calculated on an
unaligned
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
buffer.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
I.e. the buf parameter is no longer required to be 16 bit
aligned.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The checksum is still calculated using a 16 bit aligned
pointer,
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
so
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
the compiler can auto-vectorize the function's inner loop.
When the buffer is unaligned, the first byte of the buffer is handled separately. Furthermore, the calculated checksum of
the
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
buffer is byte shifted before being added to the initial
checksum,
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
to compensate for the checksum having been calculated on the
buffer
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
shifted by one byte.
v4:
* Add copyright notice.
* Includestdbool.h(Emil Berg).
* UseRTE_PTR_ADD(Emil Berg).
* Fix one more typo in commit message. Is 'unligned' even aword?
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
v3:
* Remove braces from single statement block.
* Fix typo in commit message.
v2:
* Do not assume that the buffer is part of an aligned packetbuffer.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Bugzilla ID: 1035
Cc: [email protected]Quoted 8 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Signed-off-by Morten Brørup <[email protected]>[...]
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 2 lines
Quoted 2 lines
The compiler will be able to auto vectorize even unaligned
accesses,
Quoted 1 line
Quoted 1 line
just with different instructions. From what I can tell, there's
no
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
performance impact, at least not on the
x86_64systems I triedon.
Quoted 24 lines
Quoted 24 lines
Quoted 11 lines
Quoted 11 lines
Quoted 2 lines
Quoted 2 lines
I think you should remove the first special case conditional and
use
Quoted 1 line
Quoted 1 line
memcpy()instead of the cumbersome__may_alias__construct toretrieve
Quoted 6 lines
Quoted 2 lines
the data.
Here:
https://www.agner.org/optimize/instruction_tables.pdf
it lists the latency of vmovdqa (aligned) as 6 cycles and thelatency
Quoted 4 lines
Quoted 4 lines
for
Quoted 1 line
vmovdqu (unaligned) as 7 cycles. So I guess there can be some
difference.
Quoted 1 line
Although in practice I'm not sure what difference it makes. I've
not
Quoted 6 lines
Quoted 6 lines
seen any
Quoted 2 lines
difference in runtime between the two versions.
Correction to my comment:
Those stats are for some older CPU. For some newer CPUs such asTiger
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
Quoted 1 line
Lake the stats seem to be the same regardless of aligned or
unaligned.
Quoted 5 lines
Quoted 1 line
I agree that the memcpy method is more elegant and easy to read.
However, we would need to performance test the modified checksum
function with a large number of CPUs to prove that we don't
introduce a
Quoted 1 line
Quoted 1 line
performance regression on any CPU architecture still supported by
DPDK.
Quoted 1 line
Quoted 1 line
And Emil already found a CPU where it costs 1 extra cycle per 16
bytes,
Quoted 5 lines
Quoted 5 lines
which adds up to a total of ca. 91 extra cycles on a 1460 byte TCP packet.
Quoted 1 line
I think you've misunderstood what latency means in such tables. It's
a
Quoted 1 line
Quoted 1 line
data dependency thing, not a measure of throughput. The throughput
is
Quoted 3 lines
Quoted 3 lines
*much* higher. My guess would be two such instruction per clock.
For your 1460 bytes example, my Zen3 AMD needs performs identical
with
Quoted 1 line
Quoted 1 line
both the current DPDK implementation, your patch, and a memcpy()-
ified
Quoted 2 lines
Quoted 2 lines
version of the current implementation. They all need ~130 clock cycles/packet, with warm caches. IPC is 3 instructions per cycle,
but
Quoted 5 lines
Quoted 1 line
obvious not all instructions are SIMD.
You're right, I wasn't thinking deeper about it before extrapolating.
Great to see some real numbers! I wish someone would do the same
testing on an old ARM CPU, so we could also see the other end of the scale.
Quoted 1 line
I've ran it on an ARM A72. For the aligned 1460 bytes case I got:
Current DPDK ~572 cc. Your patch: ~578 cc. Memcpy-fied: ~573 cc. They performed about the same for all unaligned/aligned and sizes I tested. This platform (or could be GCC version as well) doesn't suffer from the unaligned performance degradation your patch showed on my AMD machine.Quoted 1 line
Quoted 1 line
The main issue with checksumming on the CPU is, in my experience,
not
Quoted 3 lines
Quoted 1 line
that you don't have enough compute, but that you trash the caches.
Agree. I have noticed that x86 has "non-temporal" instruction
variants to load/store data without trashing the cache entirely.
Quoted 2 lines
A variant of the checksum function using such instructions might be
handy.
Quoted 1 line
Yes, although you may need to prefetch the payload for good performance.
Quoted 1 line
Variants of the memcpy function using such instructions might also be
handy for some purposes, e.g. copying the contents of packets, where the original and/or copy will not accessed shortly thereafter.
Quoted 1 line
Quoted 5 lines
Indeed and I think it's been discussed on the list. There's some work to
get it right, since alignment requirement and the fact a different memory model is used for those SIMD instructions causes trouble for a generic implementation. (Forx86_64.)I just posted an RFC [1] for such
memcpy()andmemset()functions, so let's see how it fans out.[1] http://inbox.dpdk.org/dev/[email protected]/T/#u
Quoted 27 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
So I opted for a solution with zero changes to the inner loop, so
no
Quoted 5 lines
Quoted 5 lines
performance retesting is required (for the previously supported use cases, where the buffer is aligned).
Quoted 1 line
You will see performance degradation with this solution as well,
under
Quoted 1 line
Quoted 1 line
certain conditions. For unaligned 100 bytes of data, the current
DPDK
Quoted 1 line
Quoted 1 line
implementation and the memcpy()-fied version needs ~21 cc/packet.
Your
Quoted 3 lines
Quoted 1 line
patch needs 54 cc/packet.
Yes, it's a tradeoff. I exclusively aimed at maintaining performance
for the case with aligned buffers (under all circumstances, with all CPUs etc.), and ignored how it affects the performance for the case with unaligned buffers.
Quoted 2 lines
Unlike this patch, the
memcpy()variant has no additional branchesfor the unaligned case, so its performance should be generally unaffected by the buffer being aligned or not. However, I don't have sufficient in-depth CPU knowledge to say if this also applies to RISCV and older ARM CPUs still supported by DPDK.
Quoted 1 line
Quoted 4 lines
Quoted 3 lines
I don't think avoiding RISCV non-catastrophic regressions triumphs improving performance on mainstream CPUs and avoiding code quality regressions.
+1
+1. In general RISC-V spec leaves the unaligned load/store handling to implementation (it might fault, it might not). The U74 core that I have at hand allows unaligned reads/writes. Though it's not a platform for performance evaluation (time measurement causes a trap to firmware), so I won't say anything on that.
--
Best Regards,
Stanisław Kardach
PATCH 1/2 app/test: add cksum performance test
In reply to Morten BrørupFrom: Mattias Rönnblom <[email protected]>
Add performance test for the rte_raw_cksum() function, which delegates the actual work to __rte_raw_cksum(), which in turn is used by other functions in need of Internet checksum calculation.
--- MAINTAINERS | 1 + app/test/meson.build | 1 + app/test/test_cksum_perf.c | 118 +++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 app/test/test_cksum_perf.c
MAINTAINERS +1 -0
@@ -1414,6 +1414,7 @@ Network headers M: Olivier Matz <[email protected]> F: lib/net/ F: app/test/test_cksum.c +F: app/test/test_cksum_perf.c Packet CRC M: Jasvinder Singh <[email protected]>
app/test/meson.build +1 -0
@@ -18,6 +18,7 @@ test_sources = files( 'test_bpf.c', 'test_byteorder.c', 'test_cksum.c', + 'test_cksum_perf.c', 'test_cmdline.c', 'test_cmdline_cirbuf.c', 'test_cmdline_etheraddr.c',
app/test/test_cksum_perf.c new file +118 -0
118 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH 2/2 net: have checksum routines accept unaligned data
From: Mattias Rönnblom <[email protected]>
__rte_raw_cksum() (used by rte_raw_cksum() among others) accessed its data through an uint16_t pointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.
This patch keeps the old algorithm, but data is read using memcpy() instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The __may_alias__ GCC attribute is no longer needed.
The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]
--- lib/net/rte_ip.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
lib/net/rte_ip.h +12 -7
@@ -160,18 +160,23 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum) { -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end; -for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; +for (end =RTE_PTR_ADD (buf, (len/sizeof (uint16_t )) *sizeof (uint16_t )); + buf != end; buf =RTE_PTR_ADD (buf,sizeof (uint16_t ))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v; + }/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) { +uint8_t last;uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&last, end,1 ); + *(unsigned char *)&left = last; sum += left; }
Signature · 1 line
2.25.1
RE: [PATCH 2/2] net: have checksum routines accept unaligned data
Quoted 36 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Thursday, 7 July 2022 20.35From: Mattias Rönnblom <[email protected]>
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessed its data through anuint16_tpointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Mattias Rönnblom <[email protected]>--- lib/net/rte_ip.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)lib/net/rte_ip.h +0
-0
lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr · line 164
Quoted 9 lines
lib/net/rte_ip.h +1
-4@@ -160,18 +160,23 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum) { -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end;
I would set "end" here instead, possibly making the pointer const too. And add spaces around '/'. const void * const end = RTE_PTR_ADD(buf, (len / sizeof(uint16_t)) * sizeof(uint16_t));
Quoted 10 lines
lib/net/rte_ip.h +6
-2-for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; +for (end =RTE_PTR_ADD (buf, (len/sizeof (uint16_t )) *sizeof (uint16_t )); + buf != end; buf =RTE_PTR_ADD (buf,sizeof (uint16_t ))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v;
lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) · line 179
Quoted 10 lines
lib/net/rte_ip.h +5
-1+ }/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) { +uint8_t last;uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&last, end,1 ); + *(unsigned char *)&left = last;
Couldn't you just memcpy(&left, end, 1), and omit the temporary variable "last"?
Quoted 6 lines
lib/net/rte_ip.h +0
-1sum += left; } --2.25.1
With our without my suggested changes, it looks good.
Re: [PATCH 2/2] net: have checksum routines accept unaligned data
Quoted 40 lines · Morten Brørup
Quoted 40 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Thursday, 7 July 2022 20.35From: Mattias Rönnblom <[email protected]>
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessed its data through anuint16_tpointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Mattias Rönnblom <[email protected]>--- lib/net/rte_ip.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)lib/net/rte_ip.h +0
-0@@ -160,18 +160,23 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum) {
Quoted 9 lines
lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) · line 163
Quoted 5 lines
lib/net/rte_ip.h +1
-4-/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end;I would set "end" here instead, possibly making the pointer const too. And add spaces around '/'. const void * const end =
RTE_PTR_ADD(buf, (len / sizeof(uint16_t)) * sizeof(uint16_t));
I don't think that makes the code more readable.
Quoted 12 lines
Quoted 12 lines
lib/net/rte_ip.h +7
-2-for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; +for (end =RTE_PTR_ADD (buf, (len/sizeof (uint16_t )) *sizeof (uint16_t )); + buf != end; buf =RTE_PTR_ADD (buf,sizeof (uint16_t ))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v; + }
Quoted 11 lines
lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) · line 179
Quoted 8 lines
lib/net/rte_ip.h +4
-1/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) { +uint8_t last;uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&last, end,1 ); + *(unsigned char *)&left = last;Couldn't you just
memcpy(&left, end, 1), and omit the temporary variable "last"?
Good point.
I don't like how this code is clever vis-à-vis byte order, but then I also don't have a better suggestion.
Quoted 11 lines
Quoted 6 lines
lib/net/rte_ip.h +0
-1sum += left; } --2.25.1
With our without my suggested changes, it looks good.
Reviewed-by Morten Brørup <[email protected]>
Thanks!
PATCH v2 2/2 net: have checksum routines accept unaligned data
In reply to Mattias Rönnblom__rte_raw_cksum() (used by rte_raw_cksum() among others) accessed its data through an uint16_t pointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.
This patch keeps the old algorithm, but data is read using memcpy() instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The __may_alias__ GCC attribute is no longer needed.
The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]
---
v2:
* Simplified the odd-length conditional (Morten Brørup).
--- lib/net/rte_ip.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
lib/net/rte_ip.h +10 -7
@@ -160,18 +160,21 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum) { -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end; -for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; +for (end =RTE_PTR_ADD (buf, (len/sizeof (uint16_t )) *sizeof (uint16_t )); + buf != end; buf =RTE_PTR_ADD (buf,sizeof (uint16_t ))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v; + }/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&left, end,1 ); sum += left; }
Signature · 1 line
2.25.1
PATCH v2 1/2 app/test: add cksum performance test
In reply to Mattias RönnblomAdd performance test for the rte_raw_cksum() function, which delegates the actual work to __rte_raw_cksum(), which in turn is used by other functions in need of Internet checksum calculation.
---
v2:
* Added __rte_unused to unused volatile variable, to keep the Intel compiler happy.
--- MAINTAINERS | 1 + app/test/meson.build | 1 + app/test/test_cksum_perf.c | 118 +++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 app/test/test_cksum_perf.c
MAINTAINERS +1 -0
@@ -1414,6 +1414,7 @@ Network headers M: Olivier Matz <[email protected]> F: lib/net/ F: app/test/test_cksum.c +F: app/test/test_cksum_perf.c Packet CRC M: Jasvinder Singh <[email protected]>
app/test/meson.build +1 -0
@@ -18,6 +18,7 @@ test_sources = files( 'test_bpf.c', 'test_byteorder.c', 'test_cksum.c', + 'test_cksum_perf.c', 'test_cmdline.c', 'test_cmdline_cirbuf.c', 'test_cmdline_etheraddr.c',
app/test/test_cksum_perf.c new file +118 -0
118 lines not on this page · raw message
Signature · 1 line
2.25.1
RE: [PATCH 2/2] net: have checksum routines accept unaligned data
In reply to Mattias RönnblomQuoted 55 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Friday, 8 July 2022 14.44Quoted 6 lines · Morten Brørup
Quoted 6 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Thursday, 7 July 2022 20.35From: Mattias Rönnblom <[email protected]>
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessedits
Quoted 1 line
Quoted 1 line
data through an
uint16_tpointer, which allowed the compiler toassume
Quoted 2 lines
Quoted 2 lines
the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with
SIMD
Quoted 8 lines
Quoted 8 lines
load or store instructions with restrictions on data alignment.
This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are
almost
Quoted 14 lines
Quoted 14 lines
always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Mattias Rönnblom <[email protected]>--- lib/net/rte_ip.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)Quoted 16 lines
Quoted 5 lines
lib/net/rte_ip.h +0
-0lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr · line 164
Quoted 9 lines
lib/net/rte_ip.h +1
-4@@ -160,18 +160,23 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum) { -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end;I would set "end" here instead, possibly making the pointer const
Quoted 6 lines
too. And add spaces around '/'.
Quoted 1 line
const void * const end = RTE_PTR_ADD(buf, (len /
sizeof(uint16_t)) *
sizeof(uint16_t));Quoted 1 line
I don't think that makes the code more readable.
It's only a matter of taste... Your code, your decision. :-)
I think the spaces are required by the coding standard; not sure, though.
Quoted 23 lines
Quoted 13 lines
Quoted 13 lines
lib/net/rte_ip.h +7
-2-for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; +for (end =RTE_PTR_ADD (buf, (len/sizeof (uint16_t )) *sizeof (uint16_t )); + buf != end; buf =RTE_PTR_ADD (buf,sizeof (uint16_t ))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v; + }Quoted 10 lines
lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) · line 179
Quoted 8 lines
lib/net/rte_ip.h +4
-1/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) { +uint8_t last;uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&last, end,1 ); + *(unsigned char *)&left = last;Couldn't you just
memcpy(&left, end, 1), and omit the temporary
Quoted 7 lines
variable "last"?
Quoted 1 line
Good point.
I don't like how this code is clever vis-à-vis byte order, but then I also don't have a better suggestion.
The byte ordering cleverness has its roots in RFC 1071.
Stephen suggested using a union, although in a slightly different context. I'm not sure it will be more readable here, because it will require #ifdef to support byte ordering. Just thought I'd mention it, for your consideration.
Your patch v2 just reached my inbox, and it looks good. No further response to this email is expected.
Re: [PATCH 2/2] net: have checksum routines accept unaligned data
Quoted 57 lines · Morten Brørup
Quoted 57 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Friday, 8 July 2022 14.44Quoted 6 lines · Morten Brørup
Quoted 6 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Thursday, 7 July 2022 20.35From: Mattias Rönnblom <[email protected]>
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessedits
Quoted 1 line
Quoted 1 line
data through an
uint16_tpointer, which allowed the compiler toassume
Quoted 2 lines
Quoted 2 lines
the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with
SIMD
Quoted 8 lines
Quoted 8 lines
load or store instructions with restrictions on data alignment.
This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are
almost
Quoted 14 lines
Quoted 14 lines
always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Mattias Rönnblom <[email protected]>--- lib/net/rte_ip.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)Quoted 16 lines
Quoted 5 lines
lib/net/rte_ip.h +0
-0lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr · line 164
Quoted 9 lines
lib/net/rte_ip.h +1
-4@@ -160,18 +160,23 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum) { -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end;I would set "end" here instead, possibly making the pointer const
too. And add spaces around '/'.
Quoted 1 line
const void * const end = RTE_PTR_ADD(buf, (len /
sizeof(uint16_t)) *
Quoted 9 lines
Quoted 4 lines
sizeof(uint16_t));Quoted 1 line
I don't think that makes the code more readable.
It's only a matter of taste... Your code, your decision. :-)
I think the spaces are required by the coding standard; not sure, though.
If it isn't in the coding standard, it should be. But if you add spaces, you have to break the line, to fit into 80 characters. A net loss, IMO.
Quoted 37 lines
Quoted 23 lines
Quoted 13 lines
Quoted 13 lines
lib/net/rte_ip.h +7
-2-for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; +for (end =RTE_PTR_ADD (buf, (len/sizeof (uint16_t )) *sizeof (uint16_t )); + buf != end; buf =RTE_PTR_ADD (buf,sizeof (uint16_t ))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v; + }Quoted 10 lines
lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) · line 179
Quoted 8 lines
lib/net/rte_ip.h +4
-1/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) { +uint8_t last;uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&last, end,1 ); + *(unsigned char *)&left = last;Couldn't you just
memcpy(&left, end, 1), and omit the temporaryQuoted 7 lines
variable "last"?
Quoted 1 line
Good point.
I don't like how this code is clever vis-à-vis byte order, but then I also don't have a better suggestion.
The byte ordering cleverness has its roots in RFC 1071.
Stephen suggested using a union, although in a slightly different context. I'm not sure it will be more readable here, because it will require #ifdef to support byte ordering. Just thought I'd mention it, for your consideration.
Your patch v2 just reached my inbox, and it looks good. No further response to this email is expected.
Re: [PATCH 2/2] net: have checksum routines accept unaligned data
Quoted 63 lines · Mattias Rönnblom
Quoted 62 lines · Morten Brørup
Quoted 61 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Friday, 8 July 2022 14.44Quoted 6 lines · Morten Brørup
Quoted 6 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Thursday, 7 July 2022 20.35From: Mattias Rönnblom <[email protected]>
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessedits
Quoted 1 line
Quoted 1 line
data through an
uint16_tpointer, which allowed the compiler toassume
Quoted 2 lines
Quoted 2 lines
the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with
SIMD
Quoted 8 lines
Quoted 8 lines
load or store instructions with restrictions on data alignment.
This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are
almost
Quoted 14 lines
Quoted 14 lines
always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]Signed-off-by Mattias Rönnblom <[email protected]>--- lib/net/rte_ip.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)Quoted 16 lines
Quoted 5 lines
lib/net/rte_ip.h +0
-0lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr · line 164
Quoted 9 lines
lib/net/rte_ip.h +1
-4@@ -160,18 +160,23 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum) { -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end;I would set "end" here instead, possibly making the pointer const
too. And add spaces around '/'.
Quoted 1 line
const void * const end = RTE_PTR_ADD(buf, (len /
sizeof(uint16_t)) *
sizeof(uint16_t));Quoted 1 line
I don't think that makes the code more readable.
Quoted 8 lines
Quoted 4 lines
It's only a matter of taste... Your code, your decision. :-)
I think the spaces are required by the coding standard; not sure, though.
If it isn't in the coding standard, it should be. But if you add spaces, you have to break the line, to fit into 80 characters. A net loss, IMO.
Just FYI, lines up to 100 chars are ok now. Automated checkpatch checks as shown in patchwork only flag lines longer than that.
/Bruce
RE: [PATCH 2/2] net: have checksum routines accept unaligned data
Quoted 12 lines
From: Bruce Richardson [mailto:[email protected]]
Sent: Friday, 8 July 2022 16.10Quoted 8 lines · Mattias Rönnblom
Quoted 7 lines · Morten Brørup
Quoted 7 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Friday, 8 July 2022 14.44Quoted 3 lines · Morten Brørup
Quoted 3 lines
From: Mattias Rönnblom [mailto:[email protected]]
Sent: Thursday, 7 July 2022 20.35
[...]
Quoted 27 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) · line 163
Quoted 8 lines
static inline uint32_t __rte_raw_cksum(const void *buf, size_t len, uint32_t sum) {lib/net/rte_ip.h +1
-4-/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end;I would set "end" here instead, possibly making the pointer const
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
too. And add spaces around '/'.
Quoted 1 line
const void * const end = RTE_PTR_ADD(buf, (len /
sizeof(uint16_t)) *Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
sizeof(uint16_t));Quoted 1 line
I don't think that makes the code more readable.
It's only a matter of taste... Your code, your decision. :-)
I think the spaces are required by the coding standard; not sure,
though.
Quoted 3 lines
Quoted 1 line
If it isn't in the coding standard, it should be. But if you add
spaces,
Quoted 1 line
you have to break the line, to fit into 80 characters. A net loss,
Quoted 8 lines
IMO.
Quoted 1 line
Just FYI, lines up to 100 chars are ok now. Automated checkpatch checks as
shown in patchwork only flag lines longer than that./Bruce
The coding style [1] recommends max 80 characters, with an (easy to miss) note below, saying that up to 100 characters are acceptable. I think it should be simplified, replacing the 80 characters recommendation by a 100 characters limit, so the additional note can be removed. Why still recommend 80, when we really mean 100?
[1] https://doc.dpdk.org/guides/contributing/coding_style.html
Re: [PATCH v2 2/2] net: have checksum routines accept unaligned data
In reply to Mattias RönnblomQuoted 56 lines · Mattias Rönnblom
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessed its data through anuint16_tpointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]---
v2:
* Simplified the odd-length conditional (Morten Brørup).Reviewed-by Morten Brørup <[email protected]>Signed-off-by Mattias Rönnblom <[email protected]>--- lib/net/rte_ip.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)lib/net/rte_ip.h +8
-6@@ -160,18 +160,21 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum) { -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end; -for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; +for (end =RTE_PTR_ADD (buf, (len/sizeof (uint16_t )) *sizeof (uint16_t )); + buf != end; buf =RTE_PTR_ADD (buf,sizeof (uint16_t ))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v; + }
lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) · line 180
Quoted 10 lines
lib/net/rte_ip.h +2
-1/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&left, end,1 ); sum += left; }
Hi Mattias,
I got following result [1] with patches on [2].
Can you shed light to some questions I have,
1) For 1500 why 'Unaligned' access gives better performance than 'Aligned' access?
2) Why 21/101 bytes almost doubles 20/100 bytes perf?
3) Why 1501 bytes perf better than 1500 bytes perf?
Btw, I don't see any noticeable performance difference between with and without patch.
[1]
RTE>>cksum_perf_autotest
### rte_raw_cksum() performance ###
Alignment Block size TSC cycles/block TSC cycles/byte
Aligned 20 25.1 1.25 Unaligned 20 25.1 1.25 Aligned 21 51.5 2.45 Unaligned 21 51.5 2.45 Aligned 100 28.2 0.28 Unaligned 100 28.2 0.28 Aligned 101 54.5 0.54 Unaligned 101 54.5 0.54 Aligned 1500 188.9 0.13 Unaligned 1500 138.7 0.09 Aligned 1501 114.1 0.08 Unaligned 1501 110.1 0.07
Test OK
RTE>>
[2]
AMD EPYC 7543P
Re: [PATCH v2 1/2] app/test: add cksum performance test
In reply to Mattias RönnblomHi Mattias,
Please see few comments below.
Quoted 54 lines · Mattias Rönnblom
Add performance test for the
rte_raw_cksum()function, which delegates the actual work to__rte_raw_cksum(), which in turn is used by other functions in need of Internet checksum calculation.Signed-off-by Mattias Rönnblom <[email protected]>---
v2:
* Added__rte_unusedto unused volatile variable, to keep the Intel compiler happy.--- MAINTAINERS | 1 + app/test/meson.build | 1 + app/test/test_cksum_perf.c | 118 +++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 app/test/test_cksum_perf.cMAINTAINERS +1
-0@@ -1414,6 +1414,7 @@ Network headers M: Olivier Matz <[email protected]> F: lib/net/ F: app/test/test_cksum.c +F: app/test/test_cksum_perf.c Packet CRC M: Jasvinder Singh <[email protected]>app/test/meson.build +1
-0@@ -18,6 +18,7 @@ test_sources = files( 'test_bpf.c', 'test_byteorder.c', 'test_cksum.c', + 'test_cksum_perf.c', 'test_cmdline.c', 'test_cmdline_cirbuf.c', 'test_cmdline_etheraddr.c',app/test/test_cksum_perf.c new file +6
-0@@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2022 Ericsson AB +*/ + +#include <stdio.h> +
app/test/test_cksum_perf.c line 16
Quoted 10 lines
app/test/test_cksum_perf.c new file +10
-0+#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_ip.h> +#include <rte_malloc.h> +#include <rte_random.h> + +#include "test.h" + +#define NUM_BLOCKS (10) +#define ITERATIONS (1000000)
Parenthesis can be safely removed
app/test/test_cksum_perf.c line 24
Quoted 8 lines
app/test/test_cksum_perf.c new file +8
-0+ +static const size_t data_sizes[] = {20 ,21 ,100 ,101 ,1500 ,1501 }; + +static __rte_noinline uint16_t +do_rte_raw_cksum (const void *buf,size_t len) +{ +return rte_raw_cksum (buf, len); +}
I don't understand the need to have this wrapper, especially marked __rte_noinline. What is the objective?
Note that when I remove the __rte_noinline, the performance is better for size 20 and 21.
app/test/test_cksum_perf.c line 27
Quoted 3 lines
app/test/test_cksum_perf.c new file +3
-0+ +static void +init_block (void *buf,size_t len)
Can buf be a (char *) instead?
It would avoid a cast below.
Quoted 38 lines
app/test/test_cksum_perf.c new file +38
-0+{ +size_t i; + +for (i =0 ; i < len; i++) + ((char *)buf)[i] = (uint8_t )rte_rand (); +} + +static int +test_cksum_perf_size_alignment (size_t block_size,bool aligned) +{ +char *data[NUM_BLOCKS ]; +char *blocks[NUM_BLOCKS ]; +unsigned int i; +uint64_t start; +uint64_t end; +/* Floating point to handle low (pseudo-)TSC frequencies */ +double block_latency; +double byte_latency; + volatile __rte_unused uint64_t sum = 0; + +for (i =0 ; i <NUM_BLOCKS ; i++) { + data[i] =rte_malloc (NULL , block_size +1 ,0 ); + +if (data[i] ==NULL ) { +printf ("Failed to allocate memory for block\n" ); +return TEST_FAILED ; + } + +init_block (data[i], block_size +1 ); + + blocks[i] = aligned ? data[i] : data[i] +1 ; + } + + start =rte_rdtsc (); + +for (i =0 ; i <ITERATIONS ; i++) { +unsigned int j; +for (j =0 ; j <NUM_BLOCKS ; j++)
app/test/test_cksum_perf.c line 75
Quoted 10 lines
app/test/test_cksum_perf.c new file +10
-0+ sum +=do_rte_raw_cksum (blocks[j], block_size); + } + + end =rte_rdtsc (); + + block_latency = (end - start) / (double )(ITERATIONS *NUM_BLOCKS ); + byte_latency = block_latency / block_size; + +printf ("%-9s %10zd %19.1f %16.2f\n" , aligned ?"Aligned" :"Unaligned" , + block_size, block_latency, byte_latency);
When I run the test on my dev machine, I get the following results, which are quite reproductible:
Aligned 20 10.4 0.52 (range is 0.48 - 0.52) Unaligned 20 7.9 0.39 (range is 0.39 - 0.40)
...
If I increase the number of iterations, the first results change significantly:
Aligned 20 8.2 0.42 (range is 0.41 - 0.42) Unaligned 20 8.0 0.40 (always this value)
To have more precise tests with small size, would it make sense to target a test time instead of an iteration count? Something like this:
#define ITERATIONS 1000000
uint64_t iterations = 0;
...
do {
for (i = 0; i < ITERATIONS; i++) {
unsigned int j;
for (j = 0; j < NUM_BLOCKS; j++)
sum += do_rte_raw_cksum(blocks[j], block_size);
}
iterations += ITERATIONS;
end = rte_rdtsc();
} while ((end - start) < rte_get_tsc_hz());
block_latency = (end - start) / (double)(iterations * NUM_BLOCKS);After this change, the aligned and unaligned cases have the same performance on my machine.
Quoted 33 lines
app/test/test_cksum_perf.c new file +33
-0+ +for (i =0 ; i <NUM_BLOCKS ; i++) +rte_free (data[i]); + +return TEST_SUCCESS ; +} + +static int +test_cksum_perf_size (size_t block_size) +{ +int rc; + + rc =test_cksum_perf_size_alignment (block_size, true); +if (rc !=TEST_SUCCESS ) +return rc; + + rc =test_cksum_perf_size_alignment (block_size, false); + +return rc; +} + +static int +test_cksum_perf (void ) +{ +uint16_t i; + +printf ("### rte_raw_cksum() performance ###\n" ); +printf ("Alignment Block size TSC cycles/block TSC cycles/byte\n" ); + +for (i =0 ; i <RTE_DIM (data_sizes); i++) { +int rc; + + rc =test_cksum_perf_size (data_sizes[i]);
app/test/test_cksum_perf.c line 118
Quoted 10 lines
app/test/test_cksum_perf.c new file +10
-0+if (rc !=TEST_SUCCESS ) +return rc; + } + +return TEST_SUCCESS ; +} + + +REGISTER_TEST_COMMAND (cksum_perf_autotest, test_cksum_perf); +
The last empty line can be removed.
Quoted 3 lines
Signature · 1 line
2.25.1
Re: [PATCH v2 2/2] net: have checksum routines accept unaligned data
In reply to Mattias RönnblomHi,
Quoted 15 lines · Mattias Rönnblom
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessed its data through anuint16_tpointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Quoted 7 lines
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]---
Using memcpy() looks to be a good solution fix the issue, while avoiding a branch and the __may_alias__.
I just have one minor comment below.
Quoted 18 lines
v2:
* Simplified the odd-length conditional (Morten Brørup).Reviewed-by Morten Brørup <[email protected]>Signed-off-by Mattias Rönnblom <[email protected]>--- lib/net/rte_ip.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)lib/net/rte_ip.h +0
-0@@ -160,18 +160,21 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum)
lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) · line 165
Quoted 10 lines
lib/net/rte_ip.h +2
-6{ -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end; -for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + for (end = RTE_PTR_ADD(buf, (len/sizeof(uint16_t)) * sizeof(uint16_t));
What do you think about this form:
for (end = RTE_PTR_ADD(buf, RTE_ALIGN_FLOOR(len, sizeof(uint16_t)));
This also has the good property to solve the debate about the spaces around the '/' :)
Quoted 19 lines
lib/net/rte_ip.h +8
-1+ buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v; + }/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&left, end,1 ); sum += left; }Signature · 1 line
2.25.1
Re: [PATCH v2 1/2] app/test: add cksum performance test
In reply to Olivier MatzQuoted 72 lines · Olivier Matz
Hi Mattias,
Please see few comments below.
Quoted 54 lines · Mattias Rönnblom
Add performance test for the
rte_raw_cksum()function, which delegates the actual work to__rte_raw_cksum(), which in turn is used by other functions in need of Internet checksum calculation.Signed-off-by Mattias Rönnblom <[email protected]>---
v2:
* Added__rte_unusedto unused volatile variable, to keep the Intel compiler happy.--- MAINTAINERS | 1 + app/test/meson.build | 1 + app/test/test_cksum_perf.c | 118 +++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+)create mode 100644
app/test/test_cksum_perf.cMAINTAINERS +1
-0@@ -1414,6 +1414,7 @@ Network headers M: Olivier Matz <[email protected]> F: lib/net/ F: app/test/test_cksum.c +F: app/test/test_cksum_perf.c Packet CRC M: Jasvinder Singh <[email protected]>app/test/meson.build +1
-0@@ -18,6 +18,7 @@ test_sources = files( 'test_bpf.c', 'test_byteorder.c', 'test_cksum.c', + 'test_cksum_perf.c', 'test_cmdline.c', 'test_cmdline_cirbuf.c', 'test_cmdline_etheraddr.c',app/test/test_cksum_perf.c new file +6
-0@@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2022 Ericsson AB +*/ + +#include <stdio.h> +app/test/test_cksum_perf.c line 16
Quoted 10 lines
app/test/test_cksum_perf.c new file +10
-0+#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_ip.h> +#include <rte_malloc.h> +#include <rte_random.h> + +#include "test.h" + +#define NUM_BLOCKS (10) +#define ITERATIONS (1000000)Parenthesis can be safely removed
Quoted 12 lines
app/test/test_cksum_perf.c line 24
Quoted 8 lines
app/test/test_cksum_perf.c new file +8
-0+ +static const size_t data_sizes[] = {20 ,21 ,100 ,101 ,1500 ,1501 }; + +static __rte_noinline uint16_t +do_rte_raw_cksum (const void *buf,size_t len) +{ +return rte_raw_cksum (buf, len); +}I don't understand the need to have this wrapper, especially marked
__rte_noinline. What is the objective?
The intention is to disallow the compiler to perform unrolling and integrating/interleave one cksum operating with the next buffer's in a way that wouldn't be feasable in a real application.
It will result in an overestimation of the cost for small cksums, so it's still misleading, but in another direction. :)
Quoted 10 lines
Note that when I remove the
__rte_noinline, the performance is better for size 20 and 21.app/test/test_cksum_perf.c line 27
Quoted 3 lines
app/test/test_cksum_perf.c new file +3
-0+ +static void +init_block (void *buf,size_t len)Can buf be a (char *) instead?
It would avoid a cast below.
Yes.
Quoted 54 lines
Quoted 38 lines
app/test/test_cksum_perf.c new file +38
-0+{ +size_t i; + +for (i =0 ; i < len; i++) + ((char *)buf)[i] = (uint8_t )rte_rand (); +} + +static int +test_cksum_perf_size_alignment (size_t block_size,bool aligned) +{ +char *data[NUM_BLOCKS ]; +char *blocks[NUM_BLOCKS ]; +unsigned int i; +uint64_t start; +uint64_t end; +/* Floating point to handle low (pseudo-)TSC frequencies */ +double block_latency; +double byte_latency; + volatile __rte_unused uint64_t sum = 0; + +for (i =0 ; i <NUM_BLOCKS ; i++) { + data[i] =rte_malloc (NULL , block_size +1 ,0 ); + +if (data[i] ==NULL ) { +printf ("Failed to allocate memory for block\n" ); +return TEST_FAILED ; + } + +init_block (data[i], block_size +1 ); + + blocks[i] = aligned ? data[i] : data[i] +1 ; + } + + start =rte_rdtsc (); + +for (i =0 ; i <ITERATIONS ; i++) { +unsigned int j; +for (j =0 ; j <NUM_BLOCKS ; j++)app/test/test_cksum_perf.c line 75
Quoted 10 lines
app/test/test_cksum_perf.c new file +10
-0+ sum +=do_rte_raw_cksum (blocks[j], block_size); + } + + end =rte_rdtsc (); + + block_latency = (end - start) / (double )(ITERATIONS *NUM_BLOCKS ); + byte_latency = block_latency / block_size; + +printf ("%-9s %10zd %19.1f %16.2f\n" , aligned ?"Aligned" :"Unaligned" , + block_size, block_latency, byte_latency);When I run the test on my dev machine, I get the following results, which are quite reproductible:
Aligned 20 10.4 0.52 (range is 0.48 - 0.52) Unaligned 20 7.9 0.39 (range is 0.39 - 0.40)
Quoted 7 lines
...
If I increase the number of iterations, the first results change significantly:
Aligned 20 8.2 0.42 (range is 0.41 - 0.42) Unaligned 20 8.0 0.40 (always this value)
I suspect you have frequency scaling enabled on your system. This is generally not advisable, you want to some level of determinism in when benchmarking. Especially on short runs like this is (and must be).
I thought about doing something about this, but it seemed like an issue that should be addressed on a framework level, rather than on a per-perf autotest level.
If you want your CPU core to scale up, you can just insert
rte_delay_block_us(100000);
before the actual test is run.
Should I add this? I *think* 100 ms should be enough, but maybe someone with more in-depth knowledge of the frequency governors can comment on this.
Quoted 5 lines
To have more precise tests with small size, would it make sense to target a test time instead of an iteration count? Something like this:
The time lost when running on a lower frequency (plus the hiccups when the frequency is changed) will be amortized as you add to the length of the test run, which will partly solved the problem. A better solution is to not start the test before the core runs on the max frequency.
Again, this is assuming DVFS is what you suffer from here. I guess in theory it could be TLB miss as well.
Quoted 18 lines
#define ITERATIONS 1000000
uint64_t iterations = 0;
...
do {
for (i = 0; i < ITERATIONS; i++) {
unsigned int j;
for (j = 0; j < NUM_BLOCKS; j++)
sum += do_rte_raw_cksum(blocks[j], block_size);
}
iterations += ITERATIONS;
end = rte_rdtsc();
} while ((end - start) < rte_get_tsc_hz());
block_latency = (end - start) / (double)(iterations * NUM_BLOCKS);Quoted 4 lines
After this change, the aligned and unaligned cases have the same performance on my machine.
RTE>>cksum_perf_autotest
### rte_raw_cksum() performance ###
Alignment Block size TSC cycles/block TSC cycles/byte
Aligned 20 16.1 0.81 Unaligned 20 16.1 0.81
... with the 100 ms busy-wait delay (and frequency scaling enabled) on my AMD machine.
Quoted 37 lines
Quoted 37 lines
app/test/test_cksum_perf.c new file +37
-0+ +for (i =0 ; i <NUM_BLOCKS ; i++) +rte_free (data[i]); + +return TEST_SUCCESS ; +} + +static int +test_cksum_perf_size (size_t block_size) +{ +int rc; + + rc =test_cksum_perf_size_alignment (block_size, true); +if (rc !=TEST_SUCCESS ) +return rc; + + rc =test_cksum_perf_size_alignment (block_size, false); + +return rc; +} + +static int +test_cksum_perf (void ) +{ +uint16_t i; + +printf ("### rte_raw_cksum() performance ###\n" ); +printf ("Alignment Block size TSC cycles/block TSC cycles/byte\n" ); + +for (i =0 ; i <RTE_DIM (data_sizes); i++) { +int rc; + + rc =test_cksum_perf_size (data_sizes[i]); +if (rc !=TEST_SUCCESS ) +return rc; + } +
Quoted 9 lines
app/test/test_cksum_perf.c line 118
Quoted 6 lines
app/test/test_cksum_perf.c new file +6
-0+return TEST_SUCCESS ; +} + + +REGISTER_TEST_COMMAND (cksum_perf_autotest, test_cksum_perf); +The last empty line can be removed.
OK.
Thanks for the review. I will send a v3 as soon as we've settled the DVFS issue.
Quoted 3 lines
Quoted 3 lines
Signature · 1 line
2.25.1
Re: [PATCH v2 2/2] net: have checksum routines accept unaligned data
In reply to Olivier MatzQuoted 62 lines · Olivier Matz
Hi,
Quoted 15 lines · Mattias Rönnblom
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessed its data through anuint16_tpointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Quoted 7 lines
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]---
Using
memcpy()looks to be a good solution fix the issue, while avoiding a branch and the__may_alias__.I just have one minor comment below.
Quoted 18 lines
v2:
* Simplified the odd-length conditional (Morten Brørup).Reviewed-by Morten Brørup <[email protected]>Signed-off-by Mattias Rönnblom <[email protected]>--- lib/net/rte_ip.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)lib/net/rte_ip.h +0
-0@@ -160,18 +160,21 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum)lib/net/rte_ip.h rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr) · line 165
Quoted 10 lines
lib/net/rte_ip.h +2
-6{ -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end; -for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; + for (end = RTE_PTR_ADD(buf, (len/sizeof(uint16_t)) * sizeof(uint16_t));What do you think about this form:
Quoted 5 lines
for (end = RTE_PTR_ADD(buf, RTE_ALIGN_FLOOR(len, sizeof(uint16_t)));This also has the good property to solve the debate about the spaces around the '/' :)
Shorter, more readable. Looks good to me.
Thanks.
Quoted 20 lines
Quoted 20 lines
lib/net/rte_ip.h +8
-1+ buf != end; buf = RTE_PTR_ADD(buf, sizeof(uint16_t))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v; + }/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&left, end,1 ); sum += left; }Signature · 1 line
2.25.1
Re: [PATCH v2 1/2] app/test: add cksum performance test
In reply to Mattias RönnblomQuoted 86 lines · Mattias Rönnblom
Quoted 72 lines · Olivier Matz
Hi Mattias,
Please see few comments below.
Quoted 54 lines · Mattias Rönnblom
Add performance test for the
rte_raw_cksum()function, which delegates the actual work to__rte_raw_cksum(), which in turn is used by other functions in need of Internet checksum calculation.Signed-off-by Mattias Rönnblom <[email protected]>---
v2:
* Added__rte_unusedto unused volatile variable, to keep the Intel compiler happy.--- MAINTAINERS | 1 + app/test/meson.build | 1 + app/test/test_cksum_perf.c | 118 +++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+)create mode 100644
app/test/test_cksum_perf.cMAINTAINERS +1
-0@@ -1414,6 +1414,7 @@ Network headers M: Olivier Matz <[email protected]> F: lib/net/ F: app/test/test_cksum.c +F: app/test/test_cksum_perf.c Packet CRC M: Jasvinder Singh <[email protected]>app/test/meson.build +1
-0@@ -18,6 +18,7 @@ test_sources = files( 'test_bpf.c', 'test_byteorder.c', 'test_cksum.c', + 'test_cksum_perf.c', 'test_cmdline.c', 'test_cmdline_cirbuf.c', 'test_cmdline_etheraddr.c',app/test/test_cksum_perf.c new file +6
-0@@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2022 Ericsson AB +*/ + +#include <stdio.h> +app/test/test_cksum_perf.c line 16
Quoted 10 lines
app/test/test_cksum_perf.c new file +10
-0+#include <rte_common.h> +#include <rte_cycles.h> +#include <rte_ip.h> +#include <rte_malloc.h> +#include <rte_random.h> + +#include "test.h" + +#define NUM_BLOCKS (10) +#define ITERATIONS (1000000)Parenthesis can be safely removed
Quoted 12 lines
app/test/test_cksum_perf.c line 24
Quoted 8 lines
app/test/test_cksum_perf.c new file +8
-0+ +static const size_t data_sizes[] = {20 ,21 ,100 ,101 ,1500 ,1501 }; + +static __rte_noinline uint16_t +do_rte_raw_cksum (const void *buf,size_t len) +{ +return rte_raw_cksum (buf, len); +}I don't understand the need to have this wrapper, especially marked
__rte_noinline. What is the objective?
Quoted 6 lines
The intention is to disallow the compiler to perform unrolling and integrating/interleave one cksum operating with the next buffer's in a way that wouldn't be feasable in a real application.
It will result in an overestimation of the cost for small cksums, so it's still misleading, but in another direction. :)
OK, got it. I think it's fine like you did then.
Quoted 85 lines
Quoted 11 lines
Note that when I remove the
__rte_noinline, the performance is better for size 20 and 21.app/test/test_cksum_perf.c line 27
Quoted 3 lines
app/test/test_cksum_perf.c new file +3
-0+ +static void +init_block (void *buf,size_t len)Can buf be a (char *) instead?
It would avoid a cast below.Yes.
Quoted 54 lines
Quoted 38 lines
app/test/test_cksum_perf.c new file +38
-0+{ +size_t i; + +for (i =0 ; i < len; i++) + ((char *)buf)[i] = (uint8_t )rte_rand (); +} + +static int +test_cksum_perf_size_alignment (size_t block_size,bool aligned) +{ +char *data[NUM_BLOCKS ]; +char *blocks[NUM_BLOCKS ]; +unsigned int i; +uint64_t start; +uint64_t end; +/* Floating point to handle low (pseudo-)TSC frequencies */ +double block_latency; +double byte_latency; + volatile __rte_unused uint64_t sum = 0; + +for (i =0 ; i <NUM_BLOCKS ; i++) { + data[i] =rte_malloc (NULL , block_size +1 ,0 ); + +if (data[i] ==NULL ) { +printf ("Failed to allocate memory for block\n" ); +return TEST_FAILED ; + } + +init_block (data[i], block_size +1 ); + + blocks[i] = aligned ? data[i] : data[i] +1 ; + } + + start =rte_rdtsc (); + +for (i =0 ; i <ITERATIONS ; i++) { +unsigned int j; +for (j =0 ; j <NUM_BLOCKS ; j++)app/test/test_cksum_perf.c line 75
Quoted 10 lines
app/test/test_cksum_perf.c new file +10
-0+ sum +=do_rte_raw_cksum (blocks[j], block_size); + } + + end =rte_rdtsc (); + + block_latency = (end - start) / (double )(ITERATIONS *NUM_BLOCKS ); + byte_latency = block_latency / block_size; + +printf ("%-9s %10zd %19.1f %16.2f\n" , aligned ?"Aligned" :"Unaligned" , + block_size, block_latency, byte_latency);When I run the test on my dev machine, I get the following results, which are quite reproductible:
Aligned 20 10.4 0.52 (range is 0.48 - 0.52) Unaligned 20 7.9 0.39 (range is 0.39 - 0.40)Quoted 7 lines
...
If I increase the number of iterations, the first results change significantly:
Aligned 20 8.2 0.42 (range is 0.41 - 0.42) Unaligned 20 8.0 0.40 (always this value)I suspect you have frequency scaling enabled on your system. This is generally not advisable, you want to some level of determinism in when benchmarking. Especially on short runs like this is (and must be).
I thought about doing something about this, but it seemed like an issue that should be addressed on a framework level, rather than on a per-perf autotest level.
Quoted 5 lines
If you want your CPU core to scale up, you can just insert
rte_delay_block_us(100000);before the actual test is run.
Your hypothesis is correct. When I disable frequency scaling, the results are now the same with 100K, 1M or 10M iterations.
However, adding a rte_delay_us_block() does not really solve the issue, probably because it calls rte_pause() in the loop.
Quoted 2 lines
Should I add this? I *think* 100 ms should be enough, but maybe someone with more in-depth knowledge of the frequency governors can comment on this.
Anyway, I think we don't need to add the blocking delay, we can legitimally expect that freq scaling is disabled when we run performance tests.
Quoted 103 lines
Quoted 6 lines
To have more precise tests with small size, would it make sense to target a test time instead of an iteration count? Something like this:
The time lost when running on a lower frequency (plus the hiccups when the frequency is changed) will be amortized as you add to the length of the test run, which will partly solved the problem. A better solution is to not start the test before the core runs on the max frequency.
Again, this is assuming DVFS is what you suffer from here. I guess in theory it could be TLB miss as well.
Quoted 18 lines
#define ITERATIONS 1000000 uint64_t iterations = 0; ... do { for (i = 0; i < ITERATIONS; i++) { unsigned int j; for (j = 0; j < NUM_BLOCKS; j++) sum += do_rte_raw_cksum(blocks[j], block_size); } iterations += ITERATIONS; end = rte_rdtsc(); } while ((end - start) < rte_get_tsc_hz()); block_latency = (end - start) / (double)(iterations * NUM_BLOCKS);Quoted 4 lines
After this change, the aligned and unaligned cases have the same performance on my machine.
RTE>>cksum_perf_autotest
###rte_raw_cksum()performance ###
Alignment Block size TSC cycles/block TSC cycles/byteAligned 20 16.1 0.81 Unaligned 20 16.1 0.81... with the 100 ms busy-wait delay (and frequency scaling enabled) on my AMD machine.
Quoted 37 lines
Quoted 37 lines
app/test/test_cksum_perf.c new file +37
-0+ +for (i =0 ; i <NUM_BLOCKS ; i++) +rte_free (data[i]); + +return TEST_SUCCESS ; +} + +static int +test_cksum_perf_size (size_t block_size) +{ +int rc; + + rc =test_cksum_perf_size_alignment (block_size, true); +if (rc !=TEST_SUCCESS ) +return rc; + + rc =test_cksum_perf_size_alignment (block_size, false); + +return rc; +} + +static int +test_cksum_perf (void ) +{ +uint16_t i; + +printf ("### rte_raw_cksum() performance ###\n" ); +printf ("Alignment Block size TSC cycles/block TSC cycles/byte\n" ); + +for (i =0 ; i <RTE_DIM (data_sizes); i++) { +int rc; + + rc =test_cksum_perf_size (data_sizes[i]); +if (rc !=TEST_SUCCESS ) +return rc; + } +Quoted 9 lines
app/test/test_cksum_perf.c line 118
Quoted 6 lines
app/test/test_cksum_perf.c new file +6
-0+return TEST_SUCCESS ; +} + + +REGISTER_TEST_COMMAND (cksum_perf_autotest, test_cksum_perf); +The last empty line can be removed.
OK.
Thanks for the review. I will send a v3 as soon as we've settled the DVFS issue.
Quoted 3 lines
Quoted 3 lines
Signature · 1 line
2.25.1
PATCH v3 2/2 net: have checksum routines accept unaligned data
In reply to Mattias Rönnblom__rte_raw_cksum() (used by rte_raw_cksum() among others) accessed its data through an uint16_t pointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.
This patch keeps the old algorithm, but data is read using memcpy() instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The __may_alias__ GCC attribute is no longer needed.
The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]
---
v3:
* Use RTE_ALIGN_FLOOR() in the pointer arithmetic (Olivier Matz).
v2:
* Simplified the odd-length conditional (Morten Brørup).
--- lib/net/rte_ip.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
lib/net/rte_ip.h +10 -7
@@ -160,18 +160,21 @@ rte_ipv4_hdr_len(const struct rte_ipv4_hdr *ipv4_hdr)static inline uint32_t __rte_raw_cksum (const void *buf,size_t len,uint32_t sum) { -/* extend strict-aliasing rules */ - typedef uint16_t __attribute__((__may_alias__)) u16_p; -const u16_p *u16_buf = (const u16_p *)buf; -const u16_p *end = u16_buf + len /sizeof (*u16_buf); +const void *end; -for (; u16_buf != end; ++u16_buf) - sum += *u16_buf; +for (end =RTE_PTR_ADD (buf,RTE_ALIGN_FLOOR (len,sizeof (uint16_t ))); + buf != end; buf =RTE_PTR_ADD (buf,sizeof (uint16_t ))) { +uint16_t v; + +memcpy (&v, buf,sizeof (uint16_t )); + sum += v; + }/* if length is odd, keeping it byte order independent */ if (unlikely (len %2 )) {uint16_t left =0 ; - *(unsigned char *)&left = *(const unsigned char *)end; + +memcpy (&left, end,1 ); sum += left; }
Signature · 1 line
2.25.1
PATCH v3 1/2 app/test: add cksum performance test
In reply to Olivier MatzAdd performance test for the rte_raw_cksum() function, which delegates the actual work to __rte_raw_cksum(), which in turn is used by other functions in need of Internet checksum calculation.
---
v3:
* Changed init function buffer parameter type, to avoid cast.
* Code formatting improved.
v2:
* Added __rte_unused to unused volatile variable, to keep the Intel compiler happy.
--- MAINTAINERS | 1 + app/test/meson.build | 1 + app/test/test_cksum_perf.c | 117 +++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 app/test/test_cksum_perf.c
MAINTAINERS +1 -0
@@ -1414,6 +1414,7 @@ Network headers M: Olivier Matz <[email protected]> F: lib/net/ F: app/test/test_cksum.c +F: app/test/test_cksum_perf.c Packet CRC M: Jasvinder Singh <[email protected]>
app/test/meson.build +1 -0
@@ -18,6 +18,7 @@ test_sources = files( 'test_bpf.c', 'test_byteorder.c', 'test_cksum.c', + 'test_cksum_perf.c', 'test_cmdline.c', 'test_cmdline_cirbuf.c', 'test_cmdline_etheraddr.c',
app/test/test_cksum_perf.c new file +117 -0
117 lines not on this page · raw message
Signature · 1 line
2.25.1
Re: [PATCH v3 1/2] app/test: add cksum performance test
Quoted 5 lines · Mattias Rönnblom
Add performance test for the
rte_raw_cksum()function, which delegates the actual work to__rte_raw_cksum(), which in turn is used by other functions in need of Internet checksum calculation.Signed-off-by Mattias Rönnblom <[email protected]>
Thank you!
Re: [PATCH v3 2/2] net: have checksum routines accept unaligned data
In reply to Mattias RönnblomQuoted 15 lines · Mattias Rönnblom
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessed its data through anuint16_tpointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Quoted 5 lines
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]
Quoted 10 lines
---
v3:
* UseRTE_ALIGN_FLOOR()in the pointer arithmetic (Olivier Matz).
v2:
* Simplified the odd-length conditional (Morten Brørup).Reviewed-by Morten Brørup <[email protected]>Signed-off-by Mattias Rönnblom <[email protected]>
Thank you!
Re: [PATCH v3 2/2] net: have checksum routines accept unaligned data
Quoted 31 lines · Olivier Matz
Quoted 15 lines · Mattias Rönnblom
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessed its data through anuint16_tpointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Quoted 5 lines
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]Fixes 6006818cfb26 ("net: new checksum functions")Quoted 7 lines
---
v3:
* UseRTE_ALIGN_FLOOR()in the pointer arithmetic (Olivier Matz).
v2:
* Simplified the odd-length conditional (Morten Brørup).
Quoted 7 lines
Quoted 3 lines
Reviewed-by Morten Brørup <[email protected]>Signed-off-by Mattias Rönnblom <[email protected]>Acked-by Olivier Matz <[email protected]>Thank you!
Will this be merged into 22.11? Into the stable branches?
Re: [PATCH v3 2/2] net: have checksum routines accept unaligned data
In reply to Olivier MatzQuoted 31 lines · Olivier Matz
Quoted 15 lines · Mattias Rönnblom
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessed its data through anuint16_tpointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Quoted 5 lines
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]Fixes 6006818cfb26 ("net: new checksum functions")Quoted 7 lines
---
v3:
* UseRTE_ALIGN_FLOOR()in the pointer arithmetic (Olivier Matz).
v2:
* Simplified the odd-length conditional (Morten Brørup).
Quoted 7 lines
Quoted 3 lines
Reviewed-by Morten Brørup <[email protected]>Signed-off-by Mattias Rönnblom <[email protected]>Acked-by Olivier Matz <[email protected]>Thank you!
Are there any plans to merge this patchset?
Thomas Monjalon
AppliedRe: [PATCH v3 2/2] net: have checksum routines accept unaligned data
20/09/2022 14:09, Mattias Rönnblom:
Quoted 34 lines · Olivier Matz
Quoted 33 lines · Mattias Rönnblom
Quoted 15 lines
__rte_raw_cksum()(used byrte_raw_cksum()among others) accessed its data through anuint16_tpointer, which allowed the compiler to assume the data was 16-bit aligned. This in turn would, with certain architectures and compiler flag combinations, result in code with SIMD load or store instructions with restrictions on data alignment.This patch keeps the old algorithm, but data is read using
memcpy()instead of direct pointer access, forcing the compiler to always generate code that handles unaligned input. The__may_alias__GCC attribute is no longer needed.The data on which the Internet checksum functions operates are almost always 16-bit aligned, but there are exceptions. In particular, the PDCP protocol header may (literally) have an odd size.
Quoted 5 lines
Performance impact seems to range from none to a very slight regression.
Bugzilla ID: 1035
Cc: [email protected]Fixes 6006818cfb26 ("net: new checksum functions")Quoted 9 lines
---
v3:
* UseRTE_ALIGN_FLOOR()in the pointer arithmetic (Olivier Matz).
v2:
* Simplified the odd-length conditional (Morten Brørup).Reviewed-by Morten Brørup <[email protected]>
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Signed-off-by Mattias Rönnblom <[email protected]>Acked-by Olivier Matz <[email protected]>Thank you!
Are there any plans to merge this patchset?
Applied, thanks.
Sorry for the delay.
https://bugs.dpdk.org/show_bug.cgi?id=1035
Thomas Monjalon ([email protected]) changed:
What |Removed |Added
----------------------------------------------------------------------------
Resolution|--- |FIXED
Status|UNCONFIRMED |RESOLVED--- Comment #3 from Thomas Monjalon ([email protected]) --- Resolved in http://git.dpdk.org/dpdk/commit/?id=1c9a7fba5c
Signature · 2 lines
You are receiving this mail because: You are the assignee for the bug.