OpenNHP/opennhp · critical
Failed to get the system running time:
Error message
Failed to get the system running time:
What it means
The ebpf engine package's init() calls syscall.Sysinfo to read system uptime and derive the boot time (bootTime), which ebpf time-translation later depends on. If the Sysinfo syscall fails, init panics with 'Failed to get the system running time: ' + the OS error, so the whole nhp-ac process aborts at startup. Because it is a package init, this fires before main() and cannot be caught.
Solutions
- Check the panic text's OS error (e.g. ENOSYS, permission denied) to identify the blocked syscall.
- Adjust the sandbox/seccomp profile to allow sysinfo, or run on a standard Linux kernel.
- If portability is required, replace the panic in init() with a deferred/lazy computation of bootTime (compute on first use) and log/return an error instead of crashing.
- Fallback: derive boot time from /proc/stat's 'btime' field if Sysinfo is unavailable.
- Report/fix upstream if the target platform genuinely lacks Sysinfo support in Go's syscall package.
Example fix
// before
func init() {
var info syscall.Sysinfo_t
if err := syscall.Sysinfo(&info); err != nil {
panic("Failed to get the system running time: " + err.Error())
}
bootTime = now.Add(-time.Duration(info.Uptime) * time.Second)
}
// after
var initBootTimeErr error
func init() {
var info syscall.Sysinfo_t
if err := syscall.Sysinfo(&info); err != nil {
initBootTimeErr = fmt.Errorf("failed to get the system running time: %w", err)
log.Error(initBootTimeErr.Error())
return
}
bootTime = time.Now().Add(-time.Duration(info.Uptime) * time.Second)
} Defensive patterns
Strategy: fallback
Validate before calling
// Pre-flight check in deployment scripts before starting nhp-ac if ! grep -q '^btime' /proc/stat 2>/dev/null; then echo 'warning: sysinfo/proc may be restricted; ebpf boot-time derivation may fail' fi
Try / catch
// init() cannot be caught; recover at the boundary that imports the package
func safeStart() (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("ebpf engine init panicked: %v", r)
}
}()
_ = ebpfegine.BootTime() // triggers package init
return nil
} Prevention
- Deploy nhp-ac only on standard Linux kernels where sysinfo is available.
- Review container seccomp profiles to ensure SYS_sysinfo is allowed.
- Prefer builds where boot-time computation is lazy rather than done in package init().
- Smoke-test the daemon in the target sandbox (gVisor, Firecracker, etc.) before production rollout.
When it happens
Trigger: Starting any binary that imports endpoints/ac/ebpf when syscall.Sysinfo fails — e.g. the kernel does not provide the sysinfo syscall or it is blocked by the sandbox.
Common situations: Running nhp-ac in gVisor/containers or restricted sandboxes that filter syscalls; cross-compiling to an OS/arch where syscall.Sysinfo is unsupported; seccomp profiles dropping SYS_sysinfo.
Understand the failure class
Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.
Related errors
- clock_gettime failed
- eBPF functionality is only supported on Linux, current…
- failed to parse default route
- eBPF functionality is only supported on Linux, current…
- config load error
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/c7538f433a6a4cfc.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/ac/ebpf/ebpfegine.go:68
type Event struct {
Timestamp uint64 `ebpf:"timestamp"`
Action uint8 `ebpf:"action"`
SrcIP uint32 `ebpf:"src_ip"`
DstIP uint32 `ebpf:"dst_ip"`
SrcPort uint16 `ebpf:"src_port"`
DstPort uint16 `ebpf:"dst_port"`
Protocol uint8 `ebpf:"protocol"`
PayloadLen uint16 `ebpf:"payload_len"`
}
var xdpLink link.Link
var tcLink link.Link
var bootTime time.Time
func init() {
var info syscall.Sysinfo_t
if err := syscall.Sysinfo(&info); err != nil {
panic("Failed to get the system running time: " + err.Error())
}
now := time.Now()
bootTime = now.Add(-time.Duration(info.Uptime) * time.Second)
log.Info("System boot time: %v", bootTime)
}
func EbpfEngineLoad(dirPath string, logLevel int, acId string) error {
CleanupBPFFiles()
if err := rlimit.RemoveMemlock(); err != nil {
log.Error("Failed to remove memlock limit")
}
const ebpfenginename string = "nhp_ebpf_xdp.o"
const tcObjName string = "tc_egress.o"
//ebpf nhp_ebpf_xdp.o save to etc/ after clang compile
bpfDir := "etc"
specPath := filepath.Join(bpfDir, ebpfenginename)View on GitHub (pinned to 6e04ca5ff0)