Summary
Quark resolves container.id / container.name by parsing the process cgroup path in kube_parse_cgroup() (quark.c). Today that parser recognizes Kubernetes and OCI runtime scopes only. LXC has no pattern, so for LXC workloads qp->container stays NULL and ecs_container() never emits container.id, container.name, or container.runtime.
This blocks per container attribution on LXC hosts. Host level eBPF already sees every process across all LXC namespaces with one sensor per host, but the events cannot be tied back to a specific LXC container.
Evidence
quark.c: kube_parse_cgroup(const char *cgroup, char *container_id, size_t) is the only cgroup to id mapping.
quark-test.c: the supported patterns are containerd, cri-containerd and cri-o scopes:
foo/cri-containerd-abc123.scope -> containerd://abc123
foo/containerd-abc123.scope -> containerd://abc123
foo/crio-0123456789.scope -> cri-o://0123456789
There is no LXC case.
ecs.c: ecs_container() emits id, name, runtime only when a container is attached to the process.
go/quark/quark.go: the ECS path (quark_event_to_ecs via GetEventAsECS) emits the container block directly from C, so fixing the C parser is enough for ECS consumers. The structured Go Process struct does not expose a Container field today (it copies Cgroup only); structured consumers would need a separate binding change, out of scope here.
Proposed change
- Add an LXC cgroup matcher alongside the existing runtime patterns. Recognize at least:
lxc.payload.<name> (systemd cgroup driver, cgroup v2)
lxc/<name> and /lxc/<name> (classic layouts)
- Populate
quark_container with the LXC name as id and name, and set runtime to lxc.
- Confirm
container_runtime() in ecs.c maps the new runtime to "lxc".
- Consider making the matcher extensible. Some orchestrators set custom cgroup names, so a small table of known prefixes or an optional configurable pattern would cover non standard layouts without recompiling.
Tests
- Add cases to
quark-test.c for the LXC layouts above, asserting parsed id and name (tests first).
- Negative case: a non container cgroup must still return no match.
Context
@haesbaert this comes from a real Linux host fleet running LXC plus custom orchestration. The host eBPF visibility is solid; the missing piece is the LXC to container.id mapping in the parser. Flagging you as the Quark owner to confirm the approach and which cgroup patterns we should support. Commercial and account context lives in a private tracking issue (linked from there).
Summary
Quark resolves
container.id/container.nameby parsing the process cgroup path inkube_parse_cgroup()(quark.c). Today that parser recognizes Kubernetes and OCI runtime scopes only. LXC has no pattern, so for LXC workloadsqp->containerstays NULL andecs_container()never emitscontainer.id,container.name, orcontainer.runtime.This blocks per container attribution on LXC hosts. Host level eBPF already sees every process across all LXC namespaces with one sensor per host, but the events cannot be tied back to a specific LXC container.
Evidence
quark.c:kube_parse_cgroup(const char *cgroup, char *container_id, size_t)is the only cgroup to id mapping.quark-test.c: the supported patterns are containerd, cri-containerd and cri-o scopes:ecs.c:ecs_container()emitsid,name,runtimeonly when a container is attached to the process.go/quark/quark.go: the ECS path (quark_event_to_ecsviaGetEventAsECS) emits the container block directly from C, so fixing the C parser is enough for ECS consumers. The structured GoProcessstruct does not expose a Container field today (it copiesCgrouponly); structured consumers would need a separate binding change, out of scope here.Proposed change
lxc.payload.<name>(systemd cgroup driver, cgroup v2)lxc/<name>and/lxc/<name>(classic layouts)quark_containerwith the LXC name as id and name, and set runtime tolxc.container_runtime()inecs.cmaps the new runtime to"lxc".Tests
quark-test.cfor the LXC layouts above, asserting parsed id and name (tests first).Context
@haesbaert this comes from a real Linux host fleet running LXC plus custom orchestration. The host eBPF visibility is solid; the missing piece is the LXC to
container.idmapping in the parser. Flagging you as the Quark owner to confirm the approach and which cgroup patterns we should support. Commercial and account context lives in a private tracking issue (linked from there).