diff --git a/ebpftracer/l7/http2.go b/ebpftracer/l7/http2.go index 7c484d5..13df64e 100644 --- a/ebpftracer/l7/http2.go +++ b/ebpftracer/l7/http2.go @@ -263,7 +263,10 @@ func (p *Http2Parser) decodeHeaderBlock( req := p.activeRequests[streamId] if req == nil { if len(p.activeRequests) >= maxActiveRequests { - // Too many active streams; skip to prevent unbounded growth + // Too many active streams; set no-op emit so decoder.Write still + // processes the HPACK block (keeps dynamic table in sync) without + // dereferencing a nil request. + decoder.SetEmitFunc(func(hf hpack.HeaderField) {}) break } req = &Http2Request{ diff --git a/main.go b/main.go index b200bfc..dfbe008 100644 --- a/main.go +++ b/main.go @@ -297,8 +297,38 @@ func (o *RateLimitedLogOutput) Write(data []byte) (int, error) { } // readCgroupMemoryLimit reads the memory limit from cgroup v2 or v1. +// The agent runs with hostPID, so /proc/1/cgroup points to the host root (init.scope) +// which has no memory limit. We use /proc/self/cgroup to find the container's own +// cgroup path where kubelet enforces the pod memory limit. func readCgroupMemoryLimit() (int64, error) { - // Try cgroup v2 first + // Parse /proc/self/cgroup to find the container's own cgroup path. + // cgroupv2: "0::/kubepods.slice/.../cri-containerd-xxx.scope" + // cgroupv1: "N:memory:/kubepods/burstable/pod-xxx/container-yyy" + if data, err := os.ReadFile("/proc/self/cgroup"); err == nil { + for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") { + parts := strings.SplitN(line, ":", 3) + if len(parts) < 3 { + continue + } + var cgPath string + if parts[0] == "0" { // cgroup v2 + cgPath = "/sys/fs/cgroup" + parts[2] + "/memory.max" + } else if strings.Contains(parts[1], "memory") { // cgroup v1 + cgPath = "/sys/fs/cgroup/memory" + parts[2] + "/memory.limit_in_bytes" + } + if cgPath != "" { + if mem, err := os.ReadFile(cgPath); err == nil { + s := strings.TrimSpace(string(mem)) + if s != "max" { + if limit, err := strconv.ParseInt(s, 10, 64); err == nil && limit > 0 && limit < 1<<62 { + return limit, nil + } + } + } + } + } + } + // Fallback: try cgroup v2 at root (non-hostPID containers) if data, err := os.ReadFile("/sys/fs/cgroup/memory.max"); err == nil { s := strings.TrimSpace(string(data)) if s != "max" { @@ -307,11 +337,10 @@ func readCgroupMemoryLimit() (int64, error) { } } } - // Try cgroup v1 + // Fallback: try cgroup v1 at root (non-hostPID containers) if data, err := os.ReadFile("/sys/fs/cgroup/memory/memory.limit_in_bytes"); err == nil { s := strings.TrimSpace(string(data)) if limit, err := strconv.ParseInt(s, 10, 64); err == nil { - // cgroup v1 reports a very large number when unlimited if limit < 1<<62 { return limit, nil }