New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpf: dynamic-width static data inlining #25195
Conversation
e1bb7f2
to
0e37422
Compare
pkg/datapath/loader/template.go
Outdated
result["LXC_IP_3"] = sliceToBe32(ipv6[8:12]) | ||
result["LXC_IP_4"] = sliceToBe32(ipv6[12:16]) | ||
result["LXC_IP_1"] = sliceToBe32(ipv6[0:8]) | ||
result["LXC_IP_2"] = sliceToBe32(ipv6[8:16]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why Be32 if it's 64-bit now? This won't work, will it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, was a little rushed writing this. This made me realize the ELF substitution code also needed 64-bit support added.
pkg/datapath/loader/template.go
Outdated
result["LXC_IP_2"] = sliceToBe32(ipv6[4:8]) | ||
result["LXC_IP_3"] = sliceToBe32(ipv6[8:12]) | ||
result["LXC_IP_4"] = sliceToBe32(ipv6[12:16]) | ||
result["LXC_IP_1"] = sliceToBe32(ipv6[0:8]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General question: why isn't the same mechanism used for NAT_46X64_PREFIX? Can we still optimize NAT_46X64_PREFIX as well to use two 64-bits instead of four 32-bits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, the way it's implemented looks a bit strange to me. Instead of assigning individual bytes, why don't we write a single value to v6addr->p1
, which is a u32? @borkmann
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figure it might be related to endianness and making sure the same byte goes into the same slot in the address. The way sliceToBe32
and friends functions is quite subtle, and the ELF rewriter also potentially byte-swaps when converting u16/32/64 to []byte, which bit me a few times while working on this PR. Some of it will go away when we remove ELF rewriting, though, I'll revisit it then.
/test Job 'Cilium-PR-K8s-1.25-kernel-4.19' failed: Click to show.Test Name
Failure Output
Jenkins URL: https://jenkins.cilium.io/job/Cilium-PR-K8s-1.25-kernel-4.19/1947/ If it is a flake and a GitHub issue doesn't already exist to track it, comment Then please upload the Jenkins artifacts to that issue. |
Missing bpf_cpu_to_be64 for follow-up commit. Signed-off-by: Timo Beckers <timo@isovalent.com>
This patch adds support for 64-bit wide ELF substitutions, to be used in a follow-up patch. Signed-off-by: Timo Beckers <timo@isovalent.com>
/test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks for the nice commit history!
Historically, the largest data type used for declaring global data was uint32. Cilium's iproute2 fork had patches that made the assumption all values are 32 bits, so this behaviour was replicated when it was ported to Go. This only works well if the largest variable emitted to .data is 32 bits wide. Any smaller and the section's alignment would drop, causing the inliner to read part of the next variable. Any larger and only part of a u64 would be read. Since we now no longer rely on iproute2 for loading any ELFs, we can start changing the way this works. In Go, we have access to .data's BTF Datasec, so we can be a bit smarter about it and detect how wide each variable is, so we can accurately copy out the bits needed. This patch introduces a uint64 global data macro, DEFINE_U64, and updates DEFINE_IPV6 to use it. This cuts down on the amount of instructions needed to carry ipv6 values in the instruction stream from 8 to 4. Signed-off-by: Timo Beckers <timo@isovalent.com>
checkpatch failure can be ignored, it returns non-zero even if there are only suggestions left. Not addressing those since they're about copied kernel headers, and false-positive. Pushed a small doc change and touched a self-contained unit test. This is ready to 🚢. |
/test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API codeowners changes are trivial, approving on their behalf.
CI is green, ready to merge.
Hello! I think this broke IPv6 (at least with our configuration) in Cilium 1.14 and up, which we confirmed with a bisect (and also this touches some macros / functions used by that logic, see #27898). We tried to revert this but it's in a very load bearing file so that did not go very well. Does anyone more familiar with what this PR have any insight about what might be wrong? |
Closes: #7123