eBPF-based collection is mature on x86, but moving to Kunpeng, Phytium, or Loongson hits three hurdles: kernel BTF, cross-compilation, and capability permissions. This article explains how to assess feasibility, build and deploy, and validate under load.
eBPF-based collection for processes, networking, and performance data is mature on x86, but after moving to domestic ARM CPUs (Kunpeng, Phytium) and LoongArch (Loongson) many teams hit the same three walls: the kernel, the build, and permissions. This article works through each one and ends with an acceptance method.
eBPF's CO-RE mechanism depends on the kernel enabling CONFIG_DEBUG_INFO_BTF, which makes programs portable across kernel versions. Without it, a program compiled for one kernel revision will not load on another, which is a real problem on domestic distributions where the shipped kernel is often customized. Domestic distributions such as Kylin V10 and UOS do not always enable it by default. Confirm with two commands:
cat /proc/config.gz | gunzip | grep CONFIG_DEBUG_INFO_BTF
bpftool btf dump file /sys/kernel/btf/vmlinux format c > /dev/null && echo OK
Without BTF you are forced back to version-sensitive precompiled objects that are nearly unmaintainable. If the kernel is older than 5.4, which covers early LoongArch kernels, upgrade the kernel before adopting eBPF rather than fighting compatibility issues. Treat this check as the gate: no BTF, no eBPF, and move on to an SDK-based approach instead of sinking weeks into a dead end.
One practical nuance: some domestic distributions strip BTF from the running kernel even when the build config shows it enabled, or they ship a custom kernel where /proc/config.gz is unreadable. In that case fall back to checking for the file itself with ls /sys/kernel/btf/vmlinux; if it is absent, CO-RE is unavailable regardless of what the config claims.
Domestic platforms rarely ship a ready-made eBPF collector binary, so you compile it for the target architecture yourself. For a Go-based collector:
CGO_ENABLED=0 GOARCH=arm64 go build -o jj-ebpf-agent ./cmd/agent
Loongson LoongArch requires GOARCH=loong64, and the linked libbpf must be a version with LoongArch support or the eBPF object load will fail outright. Always run readelf -h on the artifact on the target CPU to confirm the architecture before shipping it, so you never send an amd64 binary by mistake. Build once per architecture and pin the result in an internal registry; do not rebuild on the fly during a migration, because a subtle compiler or libbpf version difference is the last thing you want to debug under time pressure.
Loading eBPF programs needs CAP_BPF and CAP_PERFMON. When running the collector in a container, mount /sys/kernel/btf and declare capabilities explicitly instead of lazily running privileged:
securityContext:
capabilities:
add: ["CAP_BPF", "CAP_PERFMON", "CAP_SYS_RESOURCE"]
volumeMounts:
- name: btf
mountPath: /sys/kernel/btf
readOnly: true
Domestic-computing environments hold a stricter security bar, and running the collector with minimal privileges is a part of any audit you cannot skip. If the verifier rejects a program, read the kernel log carefully: the error usually names the exact instruction and the missing capability, which is far more actionable than guessing. On hardened kernels, seccomp or LSM policies can also block the bpf syscall even when capabilities are present, so check those before concluding the kernel is unsupported.
Start with a 24-hour load test on one ARM node and watch three things: the collector's own CPU usage, which should stay under 5%; the kernel log for verifier errors; and whether the data arriving in the console is continuous with no gaps. Run the same workload on an x86 node and compare the numbers side by side so you have a baseline rather than an absolute guess. Keep the test matrix small but real: idle, steady load, and a burst, each for a few hours.
Watch specifically for BTF relocations. On ARM and LoongArch the byte order and struct layouts differ from x86, so a program that loads cleanly on x86 can fail relocation on the target. A relocation failure appears as a verifier message naming an unresolved field, which usually means the program was not built CO-RE against the target's vmlinux.h.
A final piece of practical advice: in a domestic-computing environment eBPF is a nice-to-have, not a requirement. If the kernel or CPU does not support it, fall back to OpenTelemetry SDK instrumentation or agent-side collection; you still get the metrics, and you should never let eBPF block an entire migration. Ship the migration on a plan that works today, and revisit eBPF once the kernel and toolchain catch up.