Skip to content
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

Merged
merged 3 commits into from May 5, 2023

Conversation

ti-mo
Copy link
Contributor

@ti-mo ti-mo commented Apr 28, 2023

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.

Closes: #7123

Reduce amount of bpf instructions needed for handling ipv6 addresses

@ti-mo ti-mo added kind/enhancement This would improve or streamline existing functionality. release-note/misc This PR makes changes that have no direct user impact. labels Apr 28, 2023
@ti-mo ti-mo requested a review from a team as a code owner April 28, 2023 13:04
@ti-mo ti-mo requested review from gentoo-root and lmb April 28, 2023 13:04
@ti-mo ti-mo requested a review from a team as a code owner April 28, 2023 13:42
pkg/datapath/linux/config/config_test.go Outdated Show resolved Hide resolved
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])
Copy link
Contributor

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?

Copy link
Contributor Author

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.

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])
Copy link
Contributor

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?

Copy link
Contributor Author

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

Copy link
Contributor Author

@ti-mo ti-mo May 2, 2023

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.

@ti-mo ti-mo requested a review from a team as a code owner May 2, 2023 13:40
@ti-mo ti-mo requested a review from nathanjsweet May 2, 2023 13:40
@ti-mo
Copy link
Contributor Author

ti-mo commented May 2, 2023

/test

Job 'Cilium-PR-K8s-1.25-kernel-4.19' failed:

Click to show.

Test Name

K8sDatapathConfig Host firewall With native routing and endpoint routes

Failure Output

FAIL: Failed to reach 192.168.56.11:80 from testclient-host-8d6b6

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 /mlh new-flake Cilium-PR-K8s-1.25-kernel-4.19 so I can create one.

Then please upload the Jenkins artifacts to that issue.

@nathanjsweet nathanjsweet removed their request for review May 2, 2023 19:17
ti-mo added 2 commits May 3, 2023 09:47
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>
@ti-mo
Copy link
Contributor Author

ti-mo commented May 3, 2023

/test

@ti-mo ti-mo requested a review from dylandreimerink May 3, 2023 13:48
Copy link
Member

@pchaigno pchaigno left a 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!

pkg/bpf/collection.go Show resolved Hide resolved
pkg/bpf/collection_test.go Show resolved Hide resolved
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>
@ti-mo ti-mo added the ready-to-merge This PR has passed all tests and received consensus from code owners to merge. label May 4, 2023
@ti-mo
Copy link
Contributor Author

ti-mo commented May 4, 2023

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 🚢.

@joestringer
Copy link
Member

/test

@joestringer joestringer added ready-to-merge This PR has passed all tests and received consensus from code owners to merge. and removed ready-to-merge This PR has passed all tests and received consensus from code owners to merge. labels May 4, 2023
Copy link
Member

@joestringer joestringer left a 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.

@joestringer joestringer merged commit d10e8eb into cilium:main May 5, 2023
55 of 57 checks passed
@joestringer joestringer added the ready-to-merge This PR has passed all tests and received consensus from code owners to merge. label May 5, 2023
@maintainer-s-little-helper maintainer-s-little-helper bot removed the ready-to-merge This PR has passed all tests and received consensus from code owners to merge. label May 5, 2023
@ti-mo ti-mo deleted the tb/dynamic-globals branch May 5, 2023 08:38
@nikhiljha
Copy link
Contributor

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/enhancement This would improve or streamline existing functionality. release-note/misc This PR makes changes that have no direct user impact.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve static data load support
7 participants