<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>leodido.dev - eBPF</title>
    <subtitle>Leo&#x27;s take on security, eBPF, Linux, kernel, and whatever tech he meets</subtitle>
    <link rel="self" type="application/atom+xml" href="https://leodido.dev/tags/ebpf/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://leodido.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-02-13T00:00:00+00:00</updated>
    <id>https://leodido.dev/tags/ebpf/atom.xml</id>
    <entry xml:lang="en">
        <title>kfeatures</title>
        <published>2026-02-13T00:00:00+00:00</published>
        <updated>2026-02-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://leodido.dev/projects/kfeatures/"/>
        <id>https://leodido.dev/projects/kfeatures/</id>
        
        <content type="html" xml:base="https://leodido.dev/projects/kfeatures/">&lt;p&gt;&lt;code&gt;kfeatures&lt;&#x2F;code&gt; is a pure-Go library that answers this question.&lt;&#x2F;p&gt;
&lt;p&gt;It probes kernel capabilities at runtime and returns actionable diagnostics: not just &lt;em&gt;unsupported&lt;&#x2F;em&gt;, but &lt;strong&gt;why&lt;&#x2F;strong&gt; and &lt;strong&gt;how to fix it&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Check&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;FeatureBPFLSM&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;FeatureBTF&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; fe&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FeatureError&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; errors&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;As&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;, &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;fe&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;        log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Fatalf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; - &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; fe&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Feature&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; fe&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Reason&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;        &#x2F;&#x2F; Output: BPF LSM - CONFIG_BPF_LSM=y but &amp;#39;bpf&amp;#39; not in active LSM list; add lsm=...,bpf to kernel boot params&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The same answers are available from the CLI for &lt;strong&gt;CI&#x2F;CD gating&lt;&#x2F;strong&gt; (semantic exit codes), and from &lt;code&gt;--mcp&lt;&#x2F;code&gt; mode for &lt;strong&gt;AI agents&lt;&#x2F;strong&gt; (JSON-RPC over stdio, every subcommand exposed as an MCP tool with a discoverable input schema). See &lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;projects&#x2F;kfeatures&#x2F;#cli&quot;&gt;CLI&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-not-cilium-ebpf-features-or-bpftool&quot;&gt;Why not &lt;code&gt;cilium&#x2F;ebpf&#x2F;features&lt;&#x2F;code&gt; or &lt;code&gt;bpftool&lt;&#x2F;code&gt;?&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-not-cilium-ebpf-features-or-bpftool&quot; aria-label=&quot;Anchor link for: why-not-cilium-ebpf-features-or-bpftool&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;cilium&#x2F;ebpf&#x2F;features&quot;&gt;&lt;code&gt;cilium&#x2F;ebpf&#x2F;features&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; answers: &lt;em&gt;&quot;Does this kernel support program type X?&quot;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;man.archlinux.org&#x2F;man&#x2F;bpftool-feature.8.en&quot;&gt;&lt;code&gt;bpftool feature probe&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; answers: &lt;em&gt;&quot;What BPF features does this kernel have?&quot;&lt;&#x2F;em&gt; (CLI only, not embeddable in Go)&lt;&#x2F;p&gt;
&lt;p&gt;Neither tells you whether your tool can &lt;strong&gt;actually run&lt;&#x2F;strong&gt;. For example, BPF LSM requires three things simultaneously: &lt;code&gt;CONFIG_BPF_LSM=y&lt;&#x2F;code&gt; in the kernel config, &lt;code&gt;bpf&lt;&#x2F;code&gt; in the active LSM boot parameter list, and the LSM program type supported by the running kernel. &lt;code&gt;cilium&#x2F;ebpf&#x2F;features&lt;&#x2F;code&gt; can only check the last one. &lt;code&gt;bpftool&lt;&#x2F;code&gt; can check the first and last, but not the second. Neither provides remediation guidance.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Capability&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;&lt;code&gt;cilium&#x2F;ebpf&#x2F;features&lt;&#x2F;code&gt;&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;&lt;code&gt;bpftool feature probe&lt;&#x2F;code&gt;&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;&lt;strong&gt;&lt;code&gt;kfeatures&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;BPF program type probes&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;BPF map type &#x2F; helper probes&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓ †&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;BTF availability&lt;&#x2F;strong&gt; (&lt;code&gt;&#x2F;sys&#x2F;kernel&#x2F;btf&#x2F;vmlinux&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗ *&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Kernel config parsing&lt;&#x2F;strong&gt; (any &lt;code&gt;CONFIG_*&lt;&#x2F;code&gt;, =y&#x2F;=m)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Active LSM list&lt;&#x2F;strong&gt; (&lt;code&gt;&#x2F;sys&#x2F;kernel&#x2F;security&#x2F;lsm&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;BPF LSM enabled&lt;&#x2F;strong&gt; (config + boot params + program type)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;IMA detection&lt;&#x2F;strong&gt; (LSM list + securityfs directory)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;IMA active measurement&lt;&#x2F;strong&gt; (runtime policy detection)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Process capabilities&lt;&#x2F;strong&gt; (CAP_BPF, CAP_SYS_ADMIN, CAP_PERFMON)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Unprivileged BPF status&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Mount-state gates&lt;&#x2F;strong&gt; (bpffs&#x2F;tracefs&#x2F;custom paths via superblock magic)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;ELF requirement extraction&lt;&#x2F;strong&gt; (parse &lt;code&gt;.o&lt;&#x2F;code&gt;, derive requirements)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Composite feature validation&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Actionable diagnostics&lt;&#x2F;strong&gt; (remediation steps)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Selective probing (minimize overhead)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓ ‡&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗ §&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Pure Go, no CGO&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Usable as a Go library&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✗&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;sup&gt;* &lt;code&gt;bpftool&lt;&#x2F;code&gt; checks &lt;code&gt;CONFIG_DEBUG_INFO_BTF&lt;&#x2F;code&gt; in the kernel config but does not verify &lt;code&gt;&#x2F;sys&#x2F;kernel&#x2F;btf&#x2F;vmlinux&lt;&#x2F;code&gt; exists.&lt;&#x2F;sup&gt;
&lt;sup&gt;† Exposed in &lt;code&gt;kfeatures&lt;&#x2F;code&gt; as parameterized requirements (&lt;code&gt;RequireMapType&lt;&#x2F;code&gt;, &lt;code&gt;RequireProgramHelper&lt;&#x2F;code&gt;) consumed by &lt;code&gt;Check(...)&lt;&#x2F;code&gt;.&lt;&#x2F;sup&gt;
&lt;sup&gt;‡ &lt;code&gt;cilium&#x2F;ebpf&#x2F;features&lt;&#x2F;code&gt; is per-function: callers invoke individual probe functions on demand.&lt;&#x2F;sup&gt;
&lt;sup&gt;§ &lt;code&gt;bpftool feature probe&lt;&#x2F;code&gt; runs the full probe set on every invocation.&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Other Go projects (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;aquasecurity&#x2F;libbpfgo&quot;&gt;libbpfgo&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cilium&#x2F;tetragon&quot;&gt;Tetragon&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;libs&quot;&gt;Falco libs&lt;&#x2F;a&gt;) have some feature detection built in, but none is a standalone reusable library. They are either CGO-dependent, tightly coupled to their parent project, or written in C&#x2F;C++.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;a class=&quot;zola-anchor&quot; href=&quot;#installation&quot; aria-label=&quot;Anchor link for: installation&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Library:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; get github.com&#x2F;leodido&#x2F;kfeatures&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CLI binary (Linux amd64 &#x2F; arm64):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Replace VERSION (e.g. 0.5.1) and ARCH (amd64 or arm64).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -sSLO&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;kfeatures&#x2F;releases&#x2F;download&#x2F;v${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&#x2F;kfeatures_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}_linux_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}.tar.gz&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;tar&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; xzf &amp;quot;kfeatures_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}_linux_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}.tar.gz&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;kfeatures&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For supply-chain verification of the binary before extracting, see
&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;projects&#x2F;kfeatures&#x2F;#verifying-releases&quot;&gt;Verifying releases&lt;&#x2F;a&gt; below.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;a class=&quot;zola-anchor&quot; href=&quot;#usage&quot; aria-label=&quot;Anchor link for: usage&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;quick-check&quot;&gt;Quick check&lt;a class=&quot;zola-anchor&quot; href=&quot;#quick-check&quot; aria-label=&quot;Anchor link for: quick-check&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Validate that required kernel features are available:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;errors&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;log&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;github.com&#x2F;leodido&#x2F;kfeatures&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Check&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;FeatureBPFLSM&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;FeatureBTF&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; fe&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FeatureError&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; errors&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;As&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;, &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;fe&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;        log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Fatalf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;kernel not ready: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; - &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; fe&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Feature&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; fe&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Reason&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;mixed-requirements&quot;&gt;Mixed requirements&lt;a class=&quot;zola-anchor&quot; href=&quot;#mixed-requirements&quot; aria-label=&quot;Anchor link for: mixed-requirements&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Combine &lt;code&gt;Feature&lt;&#x2F;code&gt; enums with parameterized workload requirements:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;github.com&#x2F;cilium&#x2F;ebpf&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;github.com&#x2F;cilium&#x2F;ebpf&#x2F;asm&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;github.com&#x2F;leodido&#x2F;kfeatures&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Check&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;FeatureBTF&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;RequireProgramType&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ebpf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;XDP&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;RequireMapType&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ebpf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Hash&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;RequireProgramHelper&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ebpf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;XDP&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; asm&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;FnMapLookupElem&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;custom-mount-paths-requiremount&quot;&gt;Custom mount paths (&lt;code&gt;RequireMount&lt;&#x2F;code&gt;)&lt;a class=&quot;zola-anchor&quot; href=&quot;#custom-mount-paths-requiremount&quot; aria-label=&quot;Anchor link for: custom-mount-paths-requiremount&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Gate on a filesystem mounted at an arbitrary path with the expected superblock magic. Useful when bpffs lives somewhere other than &lt;code&gt;&#x2F;sys&#x2F;fs&#x2F;bpf&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;github.com&#x2F;leodido&#x2F;kfeatures&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;golang.org&#x2F;x&#x2F;sys&#x2F;unix&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Check&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;RequireMount&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&#x2F;run&#x2F;bpf&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; unix&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;BPF_FS_MAGIC&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Magic constants come from &lt;code&gt;golang.org&#x2F;x&#x2F;sys&#x2F;unix&lt;&#x2F;code&gt; (e.g. &lt;code&gt;unix.BPF_FS_MAGIC&lt;&#x2F;code&gt;, &lt;code&gt;unix.TRACEFS_MAGIC&lt;&#x2F;code&gt;, &lt;code&gt;unix.CGROUP2_SUPER_MAGIC&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reusable-presets-featuregroup&quot;&gt;Reusable presets (&lt;code&gt;FeatureGroup&lt;&#x2F;code&gt;)&lt;a class=&quot;zola-anchor&quot; href=&quot;#reusable-presets-featuregroup&quot; aria-label=&quot;Anchor link for: reusable-presets-featuregroup&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;FeatureGroup&lt;&#x2F;code&gt; packages a set of requirements as a single value you can pass anywhere a &lt;code&gt;Requirement&lt;&#x2F;code&gt; is accepted:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; TracingTool&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FeatureGroup&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;FeatureBTF&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;FeatureKprobeMulti&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;RequireProgramType&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ebpf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Kprobe&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Check&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;TracingTool&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;err&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;extract-requirements-from-a-compiled-object-fromelf&quot;&gt;Extract requirements from a compiled object (&lt;code&gt;FromELF&lt;&#x2F;code&gt;)&lt;a class=&quot;zola-anchor&quot; href=&quot;#extract-requirements-from-a-compiled-object-fromelf&quot; aria-label=&quot;Anchor link for: extract-requirements-from-a-compiled-object-fromelf&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Point &lt;code&gt;FromELF&lt;&#x2F;code&gt; at an eBPF &lt;code&gt;.o&lt;&#x2F;code&gt; and get back a &lt;code&gt;FeatureGroup&lt;&#x2F;code&gt; describing its program types, map types, and helper-per-program requirements (directly consumable by &lt;code&gt;Check&lt;&#x2F;code&gt;):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;reqs&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;FromELF&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;.&#x2F;bpf&#x2F;probe.o&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;err&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Check&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;reqs&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Fatalf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;kernel cannot run probe.o: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Output is deterministic (deduplicated, stably ordered). Unknown ELF kinds fail closed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;render-remediation-diagnose&quot;&gt;Render remediation (&lt;code&gt;Diagnose&lt;&#x2F;code&gt;)&lt;a class=&quot;zola-anchor&quot; href=&quot;#render-remediation-diagnose&quot; aria-label=&quot;Anchor link for: render-remediation-diagnose&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;Check&lt;&#x2F;code&gt; returns the diagnosis for the first failing feature. To inspect any feature against a single probe snapshot, call &lt;code&gt;Diagnose&lt;&#x2F;code&gt; directly:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;sf&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Probe&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;sf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;BPFLSMEnabled&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Supported&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    fmt&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;sf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Diagnose&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;FeatureBPFLSM&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;    &#x2F;&#x2F; CONFIG_BPF_LSM=y but &amp;#39;bpf&amp;#39; not in active LSM list; add lsm=...,bpf to kernel boot params&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;full-probe&quot;&gt;Full probe&lt;a class=&quot;zola-anchor&quot; href=&quot;#full-probe&quot; aria-label=&quot;Anchor link for: full-probe&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Probe all features for diagnostics and reporting:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;sf&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Probe&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    log&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;err&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;sf&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sample output (truncated):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Kernel: 6.1.0-generic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Program Types:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  LSM: yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  kprobe: yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  kprobe.multi: yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Core:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  BTF: yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Security Subsystems:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  BPF LSM enabled: yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  IMA enabled: no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  IMA directory: yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Active LSMs: lockdown, capability, yama, apparmor, bpf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Filesystems:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  tracefs: yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  bpffs: yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Individual fields are typed and inspectable programmatically (see &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;leodido&#x2F;kfeatures#SystemFeatures&quot;&gt;&lt;code&gt;SystemFeatures&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;selective-probing&quot;&gt;Selective probing&lt;a class=&quot;zola-anchor&quot; href=&quot;#selective-probing&quot; aria-label=&quot;Anchor link for: selective-probing&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Probe only what you need:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;sf&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; err&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ProbeWith&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;WithProgramTypes&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ebpf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;LSM&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; ebpf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;Kprobe&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;WithSecuritySubsystems&lt;&#x2F;span&gt;&lt;span&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;    kfeatures&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;WithCapabilities&lt;&#x2F;span&gt;&lt;span&gt;(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;WithX&lt;&#x2F;code&gt; options select probe scope. They do not define requirements; use &lt;code&gt;Check(...)&lt;&#x2F;code&gt; for gating.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cli&quot;&gt;CLI&lt;a class=&quot;zola-anchor&quot; href=&quot;#cli&quot; aria-label=&quot;Anchor link for: cli&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;A CLI is included for operator diagnostics, CI&#x2F;CD gating, and AI-agent integration:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install github.com&#x2F;leodido&#x2F;kfeatures&#x2F;cmd&#x2F;kfeatures@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;kfeatures&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; probe&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;                                    # probe all features&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;kfeatures&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; check&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --require&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bpf-lsm,btf,cap-bpf&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;      # exit 0 if met, 1 otherwise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;kfeatures&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; probe&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --json&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;                             # JSON output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;kfeatures&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;                                   # display kernel config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;ci-cd-gating-semantic-exit-codes&quot;&gt;CI&#x2F;CD gating (semantic exit codes)&lt;a class=&quot;zola-anchor&quot; href=&quot;#ci-cd-gating-semantic-exit-codes&quot; aria-label=&quot;Anchor link for: ci-cd-gating-semantic-exit-codes&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;kfeatures check&lt;&#x2F;code&gt; exits &lt;strong&gt;0&lt;&#x2F;strong&gt; when all requirements are met and &lt;strong&gt;1&lt;&#x2F;strong&gt; when any are missing. Drop it into a Helm chart pre-install hook, an init container, or a CI job. With &lt;code&gt;--json&lt;&#x2F;code&gt; the verdict is a parse-friendly object on stdout:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; kfeatures check&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --require&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bpf-lsm,btf&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;  &amp;quot;ok&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;  &amp;quot;feature&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;bpf-lsm&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;  &amp;quot;reason&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;CONFIG_BPF_LSM=y but &amp;#39;bpf&amp;#39; not in active LSM list; add lsm=...,bpf to kernel boot params&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Invocation errors (missing required flag, unknown flag, invalid value, unknown subcommand) emit a structured JSON envelope on stderr and exit with a &lt;strong&gt;semantic&lt;&#x2F;strong&gt; code so wrappers can distinguish &quot;the user invoked us wrong&quot; from &quot;the kernel is missing a feature&quot;:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Exit code&lt;&#x2F;th&gt;&lt;th&gt;Category&lt;&#x2F;th&gt;&lt;th&gt;Example&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;0&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;OK&lt;&#x2F;td&gt;&lt;td&gt;check passed&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;1&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Runtime&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;FeatureError&lt;&#x2F;code&gt;, probe failure, missing kernel config&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;10&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Input&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;missing_required_flag&lt;&#x2F;code&gt;: required flag not provided&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;11&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Input&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;invalid_flag_value&lt;&#x2F;code&gt;: wrong type or unknown enum&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;12&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Input&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;unknown_flag&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;14&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Input&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;unknown_command&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; kfeatures check&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --require&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bogus&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;&amp;quot;error&amp;quot;:&amp;quot;invalid_flag_value&amp;quot;,&amp;quot;exit_code&amp;quot;:11,&amp;quot;flag&amp;quot;:&amp;quot;require&amp;quot;,&amp;quot;got&amp;quot;:&amp;quot;bogus&amp;quot;,&amp;quot;expected&amp;quot;:&amp;quot;feature&amp;quot;,&amp;quot;command&amp;quot;:&amp;quot;kfeatures check&amp;quot;,&amp;quot;message&amp;quot;:&amp;quot;invalid argument &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;bogus&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; for &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-r, --require&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; flag: unknown feature: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;bogus&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; (available: …)&amp;quot;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Codes follow the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;leodido&#x2F;structcli&#x2F;exitcode&quot;&gt;structcli&#x2F;exitcode&lt;&#x2F;a&gt; categories: input errors &lt;code&gt;10&lt;&#x2F;code&gt;–&lt;code&gt;19&lt;&#x2F;code&gt; are agent-fixable, runtime errors &lt;code&gt;1&lt;&#x2F;code&gt;–&lt;code&gt;9&lt;&#x2F;code&gt; are operator-fixable.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ai-agents-jsonschema-mcp&quot;&gt;AI agents (&lt;code&gt;--jsonschema&lt;&#x2F;code&gt;, &lt;code&gt;--mcp&lt;&#x2F;code&gt;)&lt;a class=&quot;zola-anchor&quot; href=&quot;#ai-agents-jsonschema-mcp&quot; aria-label=&quot;Anchor link for: ai-agents-jsonschema-mcp&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;kfeatures&lt;&#x2F;code&gt; is built to be driven by LLM agents and code-generation tooling without &lt;code&gt;--help&lt;&#x2F;code&gt; scraping.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;--jsonschema&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; dumps a JSON Schema describing a command&#x27;s flags. Use &lt;code&gt;=tree&lt;&#x2F;code&gt; to walk the entire subtree:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; kfeatures check&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --jsonschema&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;.title, .properties | keys&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&amp;quot;kfeatures check&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;json&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;require&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; kfeatures&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --jsonschema=tree&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;map(.title) | map(select(test(&amp;quot;^kfeatures( probe| check| config| version)?$&amp;quot;)))&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;kfeatures&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;kfeatures check&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;kfeatures config&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;kfeatures probe&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;kfeatures version&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(&lt;code&gt;--jsonschema=tree&lt;&#x2F;code&gt; walks every node, including cobra-generated &lt;code&gt;help&lt;&#x2F;code&gt; and &lt;code&gt;completion&lt;&#x2F;code&gt; leaves; filter with &lt;code&gt;jq&lt;&#x2F;code&gt; to the ones you care about.)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;--mcp&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; turns &lt;code&gt;kfeatures&lt;&#x2F;code&gt; into a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;modelcontextprotocol.io&quot;&gt;Model Context Protocol&lt;&#x2F;a&gt; server over stdio. Each runnable leaf command becomes an MCP tool whose input schema mirrors the cobra flag set; agents introspect via &lt;code&gt;tools&#x2F;list&lt;&#x2F;code&gt; and invoke via &lt;code&gt;tools&#x2F;call&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;jsonc&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;&#x2F;&#x2F; Claude Desktop &#x2F; any MCP-aware client config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;  &amp;quot;mcpServers&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;kfeatures&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;      &amp;quot;command&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;kfeatures&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;      &amp;quot;args&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;--mcp&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Tools exposed: &lt;code&gt;probe&lt;&#x2F;code&gt;, &lt;code&gt;check&lt;&#x2F;code&gt;, &lt;code&gt;config&lt;&#x2F;code&gt;. The server stays alive across business-outcome errors (a failing &lt;code&gt;check&lt;&#x2F;code&gt; does not terminate the session), and invocation errors flow through the same structured envelope as the CLI. Pure stdlib JSON-RPC inside &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;structcli&#x2F;tree&#x2F;main&#x2F;mcp&quot;&gt;structcli&lt;&#x2F;a&gt;; no extra heavy SDK dependency.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-it-detects&quot;&gt;What it detects&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-it-detects&quot; aria-label=&quot;Anchor link for: what-it-detects&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Category&lt;&#x2F;th&gt;&lt;th&gt;Features&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Program types&lt;&#x2F;td&gt;&lt;td&gt;LSM, kprobe, kprobe.multi, tracepoint, fentry&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Core&lt;&#x2F;td&gt;&lt;td&gt;BTF availability (CO-RE)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Security&lt;&#x2F;td&gt;&lt;td&gt;BPF LSM enabled, IMA enabled, IMA active measurement, active LSM list&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Capabilities and runtime gates&lt;&#x2F;td&gt;&lt;td&gt;CAP_BPF, CAP_SYS_ADMIN, CAP_PERFMON, unprivileged BPF disabled, BPF stats enabled&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Syscalls&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;bpf()&lt;&#x2F;code&gt;, &lt;code&gt;perf_event_open()&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;JIT&lt;&#x2F;td&gt;&lt;td&gt;enabled, hardened, kallsyms, memory limit, &lt;code&gt;CONFIG_BPF_JIT_ALWAYS_ON&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Filesystems&lt;&#x2F;td&gt;&lt;td&gt;tracefs, debugfs, securityfs, bpffs (gated &lt;code&gt;tracefs&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;bpffs&lt;&#x2F;code&gt; checks verify the filesystem is mounted with the expected superblock magic)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Custom mount gates&lt;&#x2F;td&gt;&lt;td&gt;any path + superblock magic via &lt;code&gt;RequireMount&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Namespaces&lt;&#x2F;td&gt;&lt;td&gt;initial user namespace, initial PID namespace&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Parameterized workload requirements&lt;&#x2F;td&gt;&lt;td&gt;program type, map type, helper-per-program-type via requirement items&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ELF-derived requirements&lt;&#x2F;td&gt;&lt;td&gt;program&#x2F;map types and helper-per-program requirements via &lt;code&gt;FromELF&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Mitigation context&lt;&#x2F;td&gt;&lt;td&gt;Spectre v1&#x2F;v2 vulnerability status&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Kernel config&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;CONFIG_BPF_LSM&lt;&#x2F;code&gt;, &lt;code&gt;CONFIG_IMA&lt;&#x2F;code&gt;, &lt;code&gt;CONFIG_DEBUG_INFO_BTF&lt;&#x2F;code&gt;, &lt;code&gt;CONFIG_FPROBE&lt;&#x2F;code&gt;, any &lt;code&gt;CONFIG_*&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;stability&quot;&gt;Stability&lt;a class=&quot;zola-anchor&quot; href=&quot;#stability&quot; aria-label=&quot;Anchor link for: stability&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Pre-1.0. The public API may change between minor versions; breaking changes are
called out explicitly in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;kfeatures&#x2F;tree&#x2F;main&#x2F;CHANGELOG.md&quot;&gt;CHANGELOG.md&lt;&#x2F;a&gt;. The &lt;code&gt;FromELF&lt;&#x2F;code&gt; contract
(signature, determinism, fail-closed semantics) is frozen; see
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;kfeatures&#x2F;tree&#x2F;main&#x2F;CONTRIBUTING.md#fromelf-contract&quot;&gt;CONTRIBUTING.md&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;a class=&quot;zola-anchor&quot; href=&quot;#requirements&quot; aria-label=&quot;Anchor link for: requirements&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Linux for runtime probing&#x2F;checking (uses Linux-specific syscalls and sysfs).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;FromELF&lt;&#x2F;code&gt; is parser-only and works on any platform.&lt;&#x2F;li&gt;
&lt;li&gt;Some probes require &lt;code&gt;CAP_BPF&lt;&#x2F;code&gt; or &lt;code&gt;CAP_SYS_ADMIN&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;verifying-releases&quot;&gt;Verifying releases&lt;a class=&quot;zola-anchor&quot; href=&quot;#verifying-releases&quot; aria-label=&quot;Anchor link for: verifying-releases&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Every release artifact (each platform tarball and the &lt;code&gt;checksums.txt&lt;&#x2F;code&gt;) is
signed with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sigstore&#x2F;cosign&quot;&gt;cosign&lt;&#x2F;a&gt; keyless signing
backed by GitHub&#x27;s OIDC token. Each artifact has a sibling
&lt;code&gt;&amp;lt;artifact&amp;gt;.sigstore.json&lt;&#x2F;code&gt; bundle containing the signature, the signing
certificate (with the workflow identity baked in), and the Rekor
transparency-log inclusion proof.&lt;&#x2F;p&gt;
&lt;p&gt;To verify before extracting (replace &lt;code&gt;VERSION&lt;&#x2F;code&gt; and &lt;code&gt;ARCH&lt;&#x2F;code&gt;):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -sSLO&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;kfeatures&#x2F;releases&#x2F;download&#x2F;v${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&#x2F;kfeatures_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}_linux_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}.tar.gz&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -sSLO&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;kfeatures&#x2F;releases&#x2F;download&#x2F;v${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&#x2F;kfeatures_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}_linux_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}.tar.gz.sigstore.json&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cosign&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; verify-blob&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  --bundle&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;kfeatures_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}_linux_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}.tar.gz.sigstore.json&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  --certificate-identity&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;kfeatures&#x2F;.github&#x2F;workflows&#x2F;release.yaml@refs&#x2F;tags&#x2F;v${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  --certificate-oidc-issuer&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;token.actions.githubusercontent.com&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;kfeatures_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}_linux_${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;ARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;}.tar.gz&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A successful verification proves that the artifact was produced by the
&lt;code&gt;release.yaml&lt;&#x2F;code&gt; workflow at the tagged revision, signed by GitHub&#x27;s OIDC
issuer, and is recorded on the public Rekor transparency log. Requires
cosign v2.0+.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;contributing&quot;&gt;Contributing&lt;a class=&quot;zola-anchor&quot; href=&quot;#contributing&quot; aria-label=&quot;Anchor link for: contributing&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;See &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;kfeatures&#x2F;tree&#x2F;main&#x2F;CONTRIBUTING.md&quot;&gt;CONTRIBUTING.md&lt;&#x2F;a&gt; for the API model, the
feature-addition checklist, and the development workflow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;license&quot;&gt;License&lt;a class=&quot;zola-anchor&quot; href=&quot;#license&quot; aria-label=&quot;Anchor link for: license&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;kfeatures&#x2F;tree&#x2F;main&#x2F;LICENSE&quot;&gt;Apache License 2.0&lt;&#x2F;a&gt;. Project attribution in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;kfeatures&#x2F;tree&#x2F;main&#x2F;NOTICE&quot;&gt;NOTICE&lt;&#x2F;a&gt;, per Apache 2.0 §4(d).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-apache-2-0&quot;&gt;Why Apache 2.0&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-apache-2-0&quot; aria-label=&quot;Anchor link for: why-apache-2-0&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;kfeatures&lt;&#x2F;code&gt; is pure-Go userspace. No kernel source embedded, no cgo, no GPL&#x2F;LGPL deps. Kernel interaction is uABI only: reads from &lt;code&gt;&#x2F;proc&lt;&#x2F;code&gt; and &lt;code&gt;&#x2F;sys&lt;&#x2F;code&gt;, syscalls and constants via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;golang.org&#x2F;x&#x2F;sys&#x2F;unix&quot;&gt;&lt;code&gt;golang.org&#x2F;x&#x2F;sys&#x2F;unix&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (BSD-3-Clause), ELF parsing via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;github.com&#x2F;cilium&#x2F;ebpf&quot;&gt;&lt;code&gt;github.com&#x2F;cilium&#x2F;ebpf&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; (MIT; never calls &lt;code&gt;BPF_PROG_LOAD&lt;&#x2F;code&gt;). The kernel&#x27;s &lt;code&gt;COPYING&lt;&#x2F;code&gt; carves &quot;user programs that use kernel services by normal system calls&quot; out of GPL: the carve-out &lt;code&gt;ps&lt;&#x2F;code&gt;, &lt;code&gt;ls&lt;&#x2F;code&gt;, and &lt;code&gt;mount&lt;&#x2F;code&gt; rely on.&lt;&#x2F;p&gt;
&lt;p&gt;Apache 2.0 over MIT:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Patent grant (§3). Probing eBPF, LSM, IMA, namespaces, and Spectre mitigations is patent-adjacent. Apache 2.0 grants an irrevocable patent license with defensive termination. MIT has none.&lt;&#x2F;li&gt;
&lt;li&gt;Adopter alignment. Cilium, Tetragon, Tracee, Falco, Pixie, and Inspektor Gadget are Apache 2.0. No compatibility review needed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>traffico</title>
        <published>2022-05-24T00:00:00+00:00</published>
        <updated>2022-05-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://leodido.dev/projects/traffico/"/>
        <id>https://leodido.dev/projects/traffico/</id>
        
        <content type="html" xml:base="https://leodido.dev/projects/traffico/">&lt;p&gt;traffico is a collection of tools to shape traffic on a network using traffic control &lt;code&gt;tc(8)&lt;&#x2F;code&gt;.
It can be used via a CLI tool (&lt;code&gt;traffico&lt;&#x2F;code&gt;) or as a CNI plugin (&lt;code&gt;traffico-cni&lt;&#x2F;code&gt;).
For a list of the available programs and what they do see the &lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;projects&#x2F;traffico&#x2F;#built-in-programs&quot;&gt;Built-in programs&lt;&#x2F;a&gt; section.&lt;&#x2F;p&gt;
&lt;p&gt;The built-in programs are very opinionated and made for the needs of the authors but the framework
is flexible enough to be used for other purposes. You can add programs to the &lt;code&gt;bpf&#x2F;&lt;&#x2F;code&gt; directory
to extend it to other use cases.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;contact&quot;&gt;Contact&lt;a class=&quot;zola-anchor&quot; href=&quot;#contact&quot; aria-label=&quot;Anchor link for: contact&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;If you have problems, questions, ideas or suggestions, please contact us by
posting to https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;traffico&#x2F;issues.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;download&quot;&gt;Download&lt;a class=&quot;zola-anchor&quot; href=&quot;#download&quot; aria-label=&quot;Anchor link for: download&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;To download the very latest source do this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;git&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clone https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;traffico.git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;authors&quot;&gt;Authors&lt;a class=&quot;zola-anchor&quot; href=&quot;#authors&quot; aria-label=&quot;Anchor link for: authors&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Leonardo Di Donato&lt;&#x2F;li&gt;
&lt;li&gt;Lorenzo Fontana&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;a class=&quot;zola-anchor&quot; href=&quot;#usage&quot; aria-label=&quot;Anchor link for: usage&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Traffico can be either used standalone or as a CNI plugin.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;traffico&quot;&gt;traffico&lt;a class=&quot;zola-anchor&quot; href=&quot;#traffico&quot; aria-label=&quot;Anchor link for: traffico&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;traffico&lt;&#x2F;code&gt; is a CLI tool that can be used to load and unload the programs.
You can choose an interface and choose whether the program will be loaded in
&lt;code&gt;INGRESS&lt;&#x2F;code&gt; or &lt;code&gt;EGRESS&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Start with a standalone block program when the policy targets specific traffic
and should leave everything else alone:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;traffico&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --ifname=eth0 --at=INGRESS&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; block_private_ipv4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Programs that accept runtime input (marked &lt;code&gt;[input]&lt;&#x2F;code&gt; in &lt;code&gt;--help&lt;&#x2F;code&gt;) take it as a second positional argument:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;traffico&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --ifname=eth0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; block_ipv4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10.0.0.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;traffico&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --ifname=eth0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; block_port&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 443&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Use standalone allow programs when the interface should admit only the traffic
described by that one program:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;traffico&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --ifname=eth0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; allow_ipv4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10.0.0.10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;traffico&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --ifname=eth0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; allow_proto tcp+udp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;traffico&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --ifname=eth0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; allow_ethertype ipv4+arp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Use &lt;code&gt;--chain&lt;&#x2F;code&gt; when the policy needs multiple ordered stages. Chains that contain
L3&#x2F;L4 programs must start with the L2 gate &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;traffico&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --ifname=eth0 --chain&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;allow_ethertype:ipv4+arp,allow_port:443&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Chains compose checks linearly: each stage narrows the traffic that reaches the
next stage. That works well for single-path policies such as HTTPS to one
service:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;traffico&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --ifname=eth0 --at=EGRESS --chain&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;allow_ethertype:ipv4+arp,allow_ipv4:10.0.0.10,allow_proto:tcp,allow_port:443&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or DNS to one resolver:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;traffico&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --ifname=eth0 --at=EGRESS --chain&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;quot;allow_ethertype:ipv4+arp,allow_dns:10.0.0.53&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These examples are alternative linear policies, not an additive multi-flow
allowlist. Full policies such as &quot;DNS to resolver OR HTTPS to service&quot; need
explicit OR composition.&lt;&#x2F;p&gt;
&lt;p&gt;Chain order is validated before attach. If a chain contains any L3&#x2F;L4 program,
slot 0 must be &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt;, and the layer order must be &lt;code&gt;L2 -&amp;gt; L3 -&amp;gt; L4&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;traffico-cni&quot;&gt;traffico-cni&lt;a class=&quot;zola-anchor&quot; href=&quot;#traffico-cni&quot; aria-label=&quot;Anchor link for: traffico-cni&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;traffico-cni&lt;&#x2F;code&gt; is a meta CNI plugin that allows the traffico programs to be used in CNI.&lt;&#x2F;p&gt;
&lt;p&gt;Meta means that &lt;code&gt;traffico-cni&lt;&#x2F;code&gt; does not create any interface for you,
it is intended to be used as a chained CNI plugin.&lt;&#x2F;p&gt;
&lt;p&gt;The plugin block to use &lt;code&gt;traffico-cni&lt;&#x2F;code&gt; is very similar to how &lt;code&gt;traffico&lt;&#x2F;code&gt; is
used as a CLI tool.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;traffico-cni&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;program&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;block_private_ipv4&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;attachPoint&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;ingress&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Programs that accept runtime input use the &lt;code&gt;&quot;input&quot;&lt;&#x2F;code&gt; field:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;traffico-cni&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;program&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;block_ipv4&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;input&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;10.0.0.1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;attachPoint&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;egress&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here&#x27;s an example CNI config file featuring &lt;code&gt;traffico-cni&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;mynetwork&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;cniVersion&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;0.4.0&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;    &amp;quot;plugins&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;            &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;ptp&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;            &amp;quot;ipMasq&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;            &amp;quot;ipam&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;                &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;host-local&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;                &amp;quot;subnet&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;10.10.10.0&#x2F;24&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;                &amp;quot;resolvConf&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;&#x2F;etc&#x2F;resolv.conf&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;                &amp;quot;routes&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt; &amp;quot;dst&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;0.0.0.0&#x2F;0&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;            &amp;quot;dns&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;                &amp;quot;nameservers&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;1.1.1.1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;1.0.0.1&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;            &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;firewall&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;            &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;traffico-cni&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;            &amp;quot;program&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;block_private_ipv4&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;            &amp;quot;attachPoint&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;ingress&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name&quot;&gt;            &amp;quot;type&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;tc-redirect-tap&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;design-principles&quot;&gt;Design principles&lt;a class=&quot;zola-anchor&quot; href=&quot;#design-principles&quot; aria-label=&quot;Anchor link for: design-principles&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Principle&lt;&#x2F;th&gt;&lt;th&gt;Description&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Standalone vs chained&lt;&#x2F;td&gt;&lt;td&gt;Standalone programs are the only filter on the interface and handle all traffic types themselves. Chained programs pass traffic they do not handle to the next program, trusting that an upstream filter (typically &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt;) already constrained it.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Boundary failures&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;block_*&lt;&#x2F;code&gt; programs fail open (&lt;code&gt;TC_ACT_OK&lt;&#x2F;code&gt;) on truncated headers, unsupported protocols, and subsequent fragments because they target specific traffic. &lt;code&gt;allow_*&lt;&#x2F;code&gt; programs fail closed (&lt;code&gt;TC_ACT_SHOT&lt;&#x2F;code&gt;) on the same failures because they define permitted traffic.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;L2 → L3 → L4 ordering&lt;&#x2F;td&gt;&lt;td&gt;Chains run cheapest and broadest checks first: &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt; (L2), then &lt;code&gt;allow_proto&lt;&#x2F;code&gt; (L3), then &lt;code&gt;allow_port&lt;&#x2F;code&gt; or &lt;code&gt;allow_dns&lt;&#x2F;code&gt; (L4). &lt;code&gt;allow_ipv4&lt;&#x2F;code&gt; fits after L2 and alongside or after L3 protocol filtering.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Non-IPv4 passthrough in chains&lt;&#x2F;td&gt;&lt;td&gt;In chains, L3 and L4 programs pass non-IPv4 traffic to the next program via &lt;code&gt;tail_call_next()&lt;&#x2F;code&gt;. L2 filtering is &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt;&#x27;s job; ARP, IPv6, and other non-IPv4 traffic allowed by L2 must not be silently dropped downstream.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;built-in-programs&quot;&gt;Built-in programs&lt;a class=&quot;zola-anchor&quot; href=&quot;#built-in-programs&quot; aria-label=&quot;Anchor link for: built-in-programs&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Program&lt;&#x2F;th&gt;&lt;th&gt;Description&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;allow_dns&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Allows IPv4 DNS traffic (TCP&#x2F;UDP port 53) to the input resolver. Other IPv4 traffic passes through. Standalone mode blocks non-IPv4; chain mode passes non-IPv4 to the next stage.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;allow_ethertype&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;L2 gatekeeper: drops frames whose outer EtherType is not in the allowed set (e.g., &lt;code&gt;ipv4+arp&lt;&#x2F;code&gt;). Required first when a chain contains L3&#x2F;L4 programs.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;allow_ipv4&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Allows IPv4 traffic to the input address, drops other IPv4 destinations except localhost (127.0.0.0&#x2F;8). Standalone mode blocks non-IPv4; chain mode passes non-IPv4 to the next stage.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;allow_port&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Allows IPv4 TCP&#x2F;UDP traffic to the input port. Other IPv4 protocols pass through. Standalone mode blocks non-IPv4; chain mode passes non-IPv4 to the next stage. TCP&#x2F;UDP subsequent fragments are blocked.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;allow_proto&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;L3 gatekeeper: drops IPv4 packets whose IP protocol is not in the allowed set (e.g., &lt;code&gt;tcp+udp&lt;&#x2F;code&gt;). It unwraps supported VLAN&#x2F;QinQ tags before the IPv4 protocol check. Standalone mode blocks non-IPv4 after VLAN unwrap; chain mode passes it to the next stage.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;block_private_ipv4&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Blocks private IPv4 addresses subnets allowing only SSH access on port 22&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;block_ipv4&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Drops packets with destination equal to the input IPv4 address&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;block_port&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Drops packets with the destination port equal to the input port number&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;nop&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;A simple program that does nothing&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;notes-on-allow-ethertype&quot;&gt;Notes on &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#notes-on-allow-ethertype&quot; aria-label=&quot;Anchor link for: notes-on-allow-ethertype&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Chain ordering:&lt;&#x2F;strong&gt; If a chain contains any L3&#x2F;L4 program, slot 0 must be &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt;. Chain order must be non-decreasing by layer: &lt;code&gt;L2 -&amp;gt; L3 -&amp;gt; L4&lt;&#x2F;code&gt;. Same-layer programs are allowed, and chains may skip L3 after the L2 gate, such as &lt;code&gt;--chain &quot;allow_ethertype:ipv4+arp,allow_port:443&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;VLAN-tagged networks:&lt;&#x2F;strong&gt; Standalone &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt; compares the EtherType in the outer Ethernet header only; it does not unwrap VLAN tags or match the inner payload EtherType. Symbolic names &lt;code&gt;vlan&lt;&#x2F;code&gt; (0x8100) and &lt;code&gt;qinq&lt;&#x2F;code&gt; (0x88A8) are available for standalone filters. In multi-program chains, VLAN TPIDs are rejected because VLAN-aware parsing is not uniform across downstream programs. Example (standalone): &lt;code&gt;allow_ethertype ipv4+arp+vlan&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;notes-on-allow-proto&quot;&gt;Notes on &lt;code&gt;allow_proto&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#notes-on-allow-proto&quot; aria-label=&quot;Anchor link for: notes-on-allow-proto&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Chain ordering:&lt;&#x2F;strong&gt; In a chain, &lt;code&gt;allow_proto&lt;&#x2F;code&gt; should be placed after &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt; and before &lt;code&gt;allow_port&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;allow_dns&lt;&#x2F;code&gt;. This gives &lt;code&gt;L2 -&amp;gt; L3 -&amp;gt; L4&lt;&#x2F;code&gt; ordering with cheapest checks first. Example: &lt;code&gt;--chain &quot;allow_ethertype:ipv4+arp,allow_proto:tcp+udp,allow_port:8080&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;VLAN-tagged IPv4:&lt;&#x2F;strong&gt; &lt;code&gt;allow_proto&lt;&#x2F;code&gt; unwraps supported 802.1Q and QinQ tags before reading the IPv4 protocol. Truncated VLAN headers and unsupported additional VLAN nesting fail closed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Non-IPv4 behavior:&lt;&#x2F;strong&gt; In standalone mode, non-IPv4 traffic is blocked after VLAN unwrap because the program is the complete policy. In chain mode, non-IPv4 traffic is passed to the next stage because L2 policy belongs to &lt;code&gt;allow_ethertype&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;build&quot;&gt;Build&lt;a class=&quot;zola-anchor&quot; href=&quot;#build&quot; aria-label=&quot;Anchor link for: build&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;To compile traffico from source you either provide your &lt;code&gt;vmlinux.h&lt;&#x2F;code&gt; in the
&lt;code&gt;vmlinux&#x2F;&lt;&#x2F;code&gt; directory (default option) or you configure the project to
generate one from your current Linux kernel:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;xmake&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --generate-vmlinux=y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now you will be able to build traffico from source by running:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;xmake&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In case you only want to compile the BPF programs you can do this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;xmake&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -b&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bpf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;test&quot;&gt;Test&lt;a class=&quot;zola-anchor&quot; href=&quot;#test&quot; aria-label=&quot;Anchor link for: test&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;To run the test suite you can do this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;xmake&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -b&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;xmake&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The full test suite includes Scapy-backed advanced packet tests that exercise IP options, fragmentation, and protocol-specific behavior. These require the &lt;code&gt;python-scapy&lt;&#x2F;code&gt; (Arch) or &lt;code&gt;python3-scapy&lt;&#x2F;code&gt; (Ubuntu) package. If Scapy is not installed, the advanced tests are skipped automatically.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Code coverage for eBPF programs</title>
        <published>2022-02-07T00:00:00+00:00</published>
        <updated>2022-02-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://leodido.dev/code-coverage-ebpf/"/>
        <id>https://leodido.dev/code-coverage-ebpf/</id>
        
        <content type="html" xml:base="https://leodido.dev/code-coverage-ebpf/">&lt;p&gt;I bet we all have heard so much about &lt;abbr title=&quot;extended Berkeley Packet Filter&quot;&gt;eBPF&lt;&#x2F;abbr&gt; in recent years. Every day we hear about a new project or application using some eBPF black magic underneath. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.google.com&#x2F;url?q=https:&#x2F;&#x2F;thenewstack.io&#x2F;this-week-in-programming-ebpf-coming-to-a-windows-near-you&quot;&gt;Data&lt;&#x2F;a&gt; shows that eBPF is quickly becoming the first choice for implementing tracing and security applications.&lt;&#x2F;p&gt;
&lt;p&gt;However, one major challenge is that the eBPF ecosystem lacks tooling to make developers&#x27; lives easier. eBPF programs are written in C but compiled for a specific ISA later executed by the eBPF Virtual Machine. LLVM has a specific backend allowing us to write C and get eBPF ELF objects out. There are no tools helping developers to clearly &lt;mark&gt;understand&lt;&#x2F;mark&gt; which &lt;mark&gt;path&lt;&#x2F;mark&gt; their code took while running in the Linux kernel, which &lt;mark&gt;code regions&lt;&#x2F;mark&gt;, or, even better, &lt;mark&gt;code branches&lt;&#x2F;mark&gt; are uncovered, and maybe why.&lt;&#x2F;p&gt;
&lt;p&gt;You may already be familiar with code coverage, which shows you which lines of code execute. Code coverage is usually applied to tests to discover which line gets run and which does not. But even testing the eBPF programs is a pain, given that &lt;code&gt;BPF_PROG_TEST_RUN&lt;&#x2F;code&gt; does not support all the types of eBPF programs living in the Linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;That&#x27;s why I sat down and wrote bpfcov&lt;&#x2F;a&gt;: a tool to gather &lt;mark&gt;source-based coverage&lt;&#x2F;mark&gt; info for our eBPF programs running in the Linux kernel. Whether they are getting loaded via &lt;code&gt;BPF_PROG_TEST_RUN&lt;&#x2F;code&gt; or by other ordinary means. Until today, there was no simple way to visualize how the flow of your eBPF program running in the kernel was. Hopefully, there is one starting today.&lt;&#x2F;p&gt;
&lt;p&gt;So, let&#x27;s jump straight into the topic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;source-based-code-coverage-for-ebpf&quot;&gt;Source-based code coverage for eBPF&lt;a class=&quot;zola-anchor&quot; href=&quot;#source-based-code-coverage-for-ebpf&quot; aria-label=&quot;Anchor link for: source-based-code-coverage-for-ebpf&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Everyone reading this post probably knows what the code coverage is. Common line-level coverage gives us a sense of what line is executed. In some cases, it even tells us how many times a line got executed.&lt;&#x2F;p&gt;
&lt;p&gt;When building this tool, driven by my experience fighting with BPF, I knew I wanted something more. Line-level granularity is often too coarse. We do not want an approximation of what code actually executed.
We need something more precise to understand the execution path of our eBPF programs in the Linux kernel. We even want to know what part of an &lt;code&gt;if&lt;&#x2F;code&gt; conditional executed&lt;label for=&quot;sn-1&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-1&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;I suggest you watch &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?app=desktop&amp;amp;v=H1hvtJPGWNQ&quot;&gt;this talk&lt;&#x2F;a&gt; by Alan Phipps to know more about branch coverage.&lt;&#x2F;span&gt;. Source-based code coverage is what I wanted for this reason.&lt;&#x2F;p&gt;
&lt;p&gt;Since it starts at code generation time in LLVM, it has the notion of &lt;mark&gt;regions&lt;&#x2F;mark&gt; of the code, &lt;mark&gt;branches&lt;&#x2F;mark&gt;, and so on. It even precisely counts things like &lt;mark&gt;short-circuited conditionals&lt;&#x2F;mark&gt;, thanks to the &lt;mark&gt;counter expression&lt;&#x2F;mark&gt; and arithmetics between them. It generates coverage summaries with very fine-grained code regions, helping us find gaps in the code and its execution flow.&lt;&#x2F;p&gt;
&lt;p&gt;So, given eBPF programs are usually written in C, couldn&#x27;t we just instrument them for &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;clang.llvm.org&#x2F;docs&#x2F;SourceBasedCodeCoverage.html&quot;&gt;source-based code coverage&lt;&#x2F;a&gt; as we would commonly do with Clang for our C programs? I bet this is the first argument popping into the head of many readers. It also was one of my thoughts when approaching this problem. Turns out that we definitely can, and we will do it. But it won&#x27;t work as is.&lt;&#x2F;p&gt;
&lt;p&gt;To understand why it won&#x27;t work, we need to keep in mind that BPF programs are compiled via Clang&lt;label for=&quot;sn-2&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-2&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;Thanks to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;tree&#x2F;main&#x2F;llvm&#x2F;lib&#x2F;Target&#x2F;BPF&quot;&gt;LLVM BPF target&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt; to BPF ELF object files, containing instructions specific to the chosen BPF instruction set, which need to be later loaded in the Linux kernel via the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;html&#x2F;latest&#x2F;userspace-api&#x2F;ebpf&#x2F;syscall.html&quot;&gt;bpf()&lt;&#x2F;a&gt; syscall. Furthermore, it&#x27;s paramount to mention that the BPF programs will be verified by an in-kernel verifier and then executed by the BPF VM.&lt;&#x2F;p&gt;
&lt;p&gt;Such a lifecycle and environment imposes a set of constraints that make it infeasible to get them working with the plain instrumentation that LLVM applies to get source-based code coverage. In fact, when compiling a C program for source-based coverage with the &lt;code&gt;-fprofile-instr-generate&lt;&#x2F;code&gt; and &lt;code&gt;-fcoverage-mapping&lt;&#x2F;code&gt; Clang flags, LLVM instruments it with a bunch of global variables and, in some cases, functions.&lt;&#x2F;p&gt;
&lt;p&gt;Observing the LLVM IR of a C program after compiling it with the &lt;code&gt;-fprofile-instr-generate&lt;&#x2F;code&gt; flag, we can notice that, LLVM...&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;defines the counters, in the form of &lt;code&gt;__profc_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; private global arrays whose size is the number of counters needed to cover all the regions and branches of such a function&lt;&#x2F;li&gt;
&lt;li&gt;marks those counters to be into the &lt;code&gt;__llvm_prf_cnts&lt;&#x2F;code&gt; section of the ELF&lt;&#x2F;li&gt;
&lt;li&gt;defines (and initializes) &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; private global struct instances that contains an identifier of the function, the pointer to its counters, the pointer to the function itself, the number of the counters for the target function, and a bunch of other info needed to tie together the counters and the coverage mappings&lt;&#x2F;li&gt;
&lt;li&gt;marks the &lt;code&gt;__profd_&lt;&#x2F;code&gt; globals to end up into the &lt;code&gt;__llvm_prf_data&lt;&#x2F;code&gt; section of the ELF&lt;&#x2F;li&gt;
&lt;li&gt;defines (and initializes) a private constant (&lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt;) containing the names of the target functions&lt;&#x2F;li&gt;
&lt;li&gt;marks the names constant to end up in the &lt;code&gt;__llvm_prf_names&lt;&#x2F;code&gt; section of the ELF&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The first issue to address here is that we can&#x27;t have random ELF sections (like&lt;code&gt;__llvm_prf_cnts&lt;&#x2F;code&gt;, etc.) into valid BPF ELF files.&lt;&#x2F;p&gt;
&lt;p&gt;We know that we can have eBPF global constants with a scalar type like &lt;code&gt;__profc_&lt;&#x2F;code&gt; ones, at least on recent Linux kernels. At the same time, we know it&#x27;s not wise to have global structs like &lt;code&gt;__profd_&lt;&#x2F;code&gt; or whatever loader for our eBPF programs we will write, as we&#x27;ll need the struct definitions. Too clunky.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;-fprofile-instr-generate&lt;&#x2F;code&gt; flag also generates a global constructor and a set of global functions, all prefixed with &lt;code&gt;__llvm_profile&lt;&#x2F;code&gt;, intended to set up the profiling runtime in the resulting binary so that when it dies or exits it will automatically generate a &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;Here we meet another stumbling block to overcome. The BPF verifier will refuse our BPF ELF containing strange global functions, not to mention &quot;constructors&quot;...&lt;&#x2F;p&gt;
&lt;p&gt;We need to get rid of them and replace their functionality with a feasible approach for BPF. Clearly, LLVM also patches our instructions in the right spots, by placing the counters and incrementing them. As you can see in the following annotated screenshot:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;profile-instr-generate2.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;profile-instr-generate2.png&quot; alt=&quot;LLVM IR incrementing profiling counters at the correct spots&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you write an eBPF program incrementing a &lt;mark&gt;counter&lt;&#x2F;mark&gt; (defined as an &lt;mark&gt;eBPF global variable&lt;&#x2F;mark&gt;) you will notice that the resulting instructions will be like those here in the screenshot. It means we can keep these the way they are generated by LLVM and let it do all its magic without interfering at the instructions level. Finally, some good news!&lt;&#x2F;p&gt;
&lt;p&gt;Instead, focusing on the &lt;code&gt;-fcoverage-mapping&lt;&#x2F;code&gt; Clang flag and inspecting the LLVM IR it outputs, we notice that it...&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;defines (and initializes) &lt;code&gt;__covrec_&lt;&#x2F;code&gt; global (constant) structs, most notably containing the same ID that the &lt;code&gt;__profd_&lt;&#x2F;code&gt; variables contain, and a LEB128&lt;label for=&quot;sn-3&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-3&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;The encoding of the coverage mapping values is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;LEB128&quot;&gt;LEB128&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt; encoded string containing all the region, branches, and generally the coverage mapping info&lt;&#x2F;li&gt;
&lt;li&gt;defines (and initializes) a &lt;code&gt;__llvm_coverage_mapping&lt;&#x2F;code&gt;&lt;label for=&quot;sn-4&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-4&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;llvm.org&#x2F;docs&#x2F;CoverageMappingFormat.html&quot;&gt;Coverage Mapping&lt;&#x2F;a&gt; format.&lt;&#x2F;span&gt; function containing meta info about the coverage mapping format (eg., the version), and the source file names&lt;&#x2F;li&gt;
&lt;li&gt;marks the &lt;code&gt;__llvm_coverage_mapping&lt;&#x2F;code&gt; variable to be put into the &lt;code&gt;__llvm_covmap&lt;&#x2F;code&gt; section of the ELF.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In this case, we have the same category of issues mentioned before.&lt;&#x2F;p&gt;
&lt;p&gt;We need to keep at least the header of &lt;code&gt;__llvm_coverage_mapping&lt;&#x2F;code&gt; because it contains the coverage mappings version, which we need for generating a valid &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file&lt;label for=&quot;sn-5&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-5&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;More on the &lt;mark&gt;profraw&lt;&#x2F;mark&gt; format &lt;a href=&quot;&#x2F;demystifying-profraw&quot;&gt;in a previous blog post&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;. Also, we need to put it in a &lt;mark&gt;custom BPF ELF section&lt;&#x2F;mark&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Luckily, we can remove the &lt;code&gt;__covrec_&lt;&#x2F;code&gt; structs from the BPF ELF meant to be loaded in the kernel. We can keep them in a second BPF ELF that would be intended to be given to tools needing the coverage mappings for generating the coverage reports, just like &lt;mark&gt;llvm-cov&lt;&#x2F;mark&gt; does.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-it-s-done&quot;&gt;How it&#x27;s done&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-it-s-done&quot; aria-label=&quot;Anchor link for: how-it-s-done&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;libbpfcov-so-a-llvm-pass&quot;&gt;libBPFCov.so - A LLVM pass&lt;a class=&quot;zola-anchor&quot; href=&quot;#libbpfcov-so-a-llvm-pass&quot; aria-label=&quot;Anchor link for: libbpfcov-so-a-llvm-pass&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;By analyzing the resulting LLVM IR for source-based coverage instrumented programs, we should now have a better understanding of what we need to do for having it on eBPF programs running in the Linux kernel. We now know what to completely get rid of and do differently, and what we need to patch to make it loadable and usable by the BPF VM in the kernel.&lt;&#x2F;p&gt;
&lt;p&gt;The plan is simple: get Clang to instrument a BPF LLVM intermediate representation for source-based code coverage, then patch it to model it into a valid representation for BPF ELF.&lt;&#x2F;p&gt;
&lt;p&gt;How do we need to transform it?&lt;&#x2F;p&gt;
&lt;p&gt;First of all, we are so lucky we don&#x27;t have to mess with the actual BPF instructions, namely the counters increments. We can keep them the way they are. This is a huge win because we let LLVM keep track of the global state of the registers and we avoid a lot of work this way.&lt;&#x2F;p&gt;
&lt;p&gt;But for sure we have to strip any profile initialization stuff that Clang creates, things like &lt;code&gt;__llvm_profile_runtime&lt;&#x2F;code&gt; and &lt;code&gt;__llvm_profile_init&lt;&#x2F;code&gt; - when present - are no good for the BPF VM in the kernel.&lt;&#x2F;p&gt;
&lt;p&gt;We also want to ensure the global variables, whether constants or not, have the right visibility (ie., &lt;code&gt;dso_local&lt;&#x2F;code&gt;) and linkage, to have them in the &lt;mark&gt;libbpf&lt;&#x2F;mark&gt; skeletons if we plan to use them.&lt;&#x2F;p&gt;
&lt;p&gt;For the global structs that we need for generating the &lt;mark&gt;profraw&lt;&#x2F;mark&gt; files, namely the &lt;code&gt;__profd_&lt;&#x2F;code&gt; variables, we just transform them into different and single global variables, one for each field.&lt;&#x2F;p&gt;
&lt;p&gt;For example, this is what I did for the &lt;code&gt;__profd_*&lt;&#x2F;code&gt; variables which originally are a struct with 7 fields. For other global structs like the &lt;code&gt;__covrec_&lt;&#x2F;code&gt; ones, we can just strip them from the BPF ELF that is meant to be loaded in the kernel.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, the report generation phase (ie., &lt;mark&gt;llvm-cov&lt;&#x2F;mark&gt; or &lt;mark&gt;bpfcov out&lt;&#x2F;mark&gt;) will need them for knowing at which line and column a code region or a branch starts. For this reason, I decided to give the LLVM pass an option (enabled with the &lt;code&gt;strip-initializers-only&lt;&#x2F;code&gt; flag) that keeps them, so we can later create a BPF ELF that is only meant for this phase and not for loading.&lt;&#x2F;p&gt;
&lt;p&gt;This BPF ELF will have &lt;code&gt;.bpf.obj&lt;&#x2F;code&gt; as an extension, rather than &lt;code&gt;.bpf.o&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we know that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;libbpf&#x2F;libbpf&quot;&gt;libbpf&lt;&#x2F;a&gt; supports (on recent Linux kernels) &lt;mark&gt;eBPF global variables&lt;&#x2F;mark&gt;&lt;label for=&quot;sn-6&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-6&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;Kernel patch: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;patchwork.ozlabs.org&#x2F;project&#x2F;netdev&#x2F;cover&#x2F;20190409212018.32423-1-daniel@iogearbox.net&#x2F;&quot;&gt;eBPF support for global data&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;, which are simply eBPF maps with one single value, and we are planning to use them. But, as already mentioned, it does not accept or recognize the ELF sections that the Clang instrumentation injects in the intermediate representation.&lt;&#x2F;p&gt;
&lt;p&gt;So we need our LLVM pass to change them to &lt;mark&gt;custom eBPF sections&lt;&#x2F;mark&gt;&lt;label for=&quot;sn-7&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-7&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;Kernel patch: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lore.kernel.org&#x2F;bpf&#x2F;20211021014404.2635234-8-andrii@kernel.org&#x2F;&quot;&gt;libbpf: support global data&#x2F;bss&#x2F;rodata sections&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;. The eBPF custom sections are in the form of &lt;code&gt;.rodata.*&lt;&#x2F;code&gt; or &lt;code&gt;.data.*&lt;&#x2F;code&gt; made to contain static and&#x2F;or global data. We can change the section of the counters to be &lt;code&gt;.data.profc&lt;&#x2F;code&gt;. The section of the &lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt; from &lt;code&gt;_llvm_prf_names&lt;&#x2F;code&gt; to &lt;code&gt;.rodata.profn&lt;&#x2F;code&gt;, and so on. You can find all this logic summarized in these &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;blob&#x2F;5607ee6b5419cd72dfd9c17e00455188865f8766&#x2F;lib&#x2F;BPFCov.cpp#L660-L694&quot;&gt;bits of code&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So, assuming the following dummy eBPF program:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;code-coverage-ebpf-programs-dummy-ebpf.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;code-coverage-ebpf-programs-dummy-ebpf.png&quot; alt=&quot;Raw tracepoint on sys_enter with eBPF&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think that the following snippet tells everything about what we obtain from the &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt; LLVM pass:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;libbpfcov-llvm-ir.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;libbpfcov-llvm-ir.png&quot; alt=&quot;Resulting LLVM IR after running bpfcov libBPFCov.so LLVM pass&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For example, you may notice that we have 2 &lt;code&gt;__profc_&lt;&#x2F;code&gt; counters.&lt;&#x2F;p&gt;
&lt;p&gt;The first is for the &lt;code&gt;BPF_PROG&lt;&#x2F;code&gt; macro that expands to a function, the second for the actual BPF raw tracepoint program &lt;code&gt;hook_sys_enter&lt;&#x2F;code&gt;. This one has size 3. That&#x27;s because the &lt;code&gt;hook_sys_enter&lt;&#x2F;code&gt; function has 3 main regions: the entry of the function, the &lt;code&gt;if&lt;&#x2F;code&gt; conditional, and the &lt;code&gt;for&lt;&#x2F;code&gt; cycle.&lt;&#x2F;p&gt;
&lt;p&gt;You may also notice that the LLVM pass, for each one of the 2 functions we have, split the &lt;code&gt;__profd_&lt;&#x2F;code&gt; global structs into 7 different global variables in the &lt;code&gt;.rodata.profd&lt;&#x2F;code&gt; section.&lt;&#x2F;p&gt;
&lt;p&gt;Someone who has an eye for it may also have noticed that the third field of &lt;code&gt;__profd_&lt;&#x2F;code&gt; (now &lt;code&gt;__profd_something.2&lt;&#x2F;code&gt;) does not contain anymore the address of its counters. I didn&#x27;t want (nor I could) to expose kernel addresses, so I put here the offset of the counters in their section (&lt;code&gt;.data.profc&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Finally, you can also see that, as anticipated before, we completely deleted the &lt;code&gt;__covrec_&lt;&#x2F;code&gt; global constant structs from this IR that&#x27;s meant to generate a valid and loadable BPF ELF. While the instructions incrementing the counters in the correct spots are not touched at all. So we don&#x27;t need another screenshot to show them!&lt;&#x2F;p&gt;
&lt;p&gt;The only missing moving part is how to generate a valid &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file. We stripped any logic for doing it. We know that for generating it we need all the globals we left in this LLVM intermediate representation. But we have no sane way to hook the exit or the stop of an eBPF program in the Linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;Suddenly, inspiration came: let&#x27;s &lt;mark&gt;pin&lt;&#x2F;mark&gt; the globals to the &lt;mark&gt;BPF file system&lt;&#x2F;mark&gt; so that we can decouple the process of generating the &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file from the running (and exiting) of the instrumented eBPF application!&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s what the &lt;mark&gt;bpfcov&lt;&#x2F;mark&gt; &lt;strong&gt;CLI&lt;&#x2F;strong&gt; does.&lt;&#x2F;p&gt;
&lt;p&gt;Before moving to the next section, I suggest you go to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov repository&lt;&#x2F;a&gt; and start building the pass to obtain &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt;. You can find the instructions on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;blob&#x2F;main&#x2F;README.md#building&quot;&gt;how to build it here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;instrument-your-ebpf-program&quot;&gt;Instrument your eBPF program&lt;a class=&quot;zola-anchor&quot; href=&quot;#instrument-your-ebpf-program&quot; aria-label=&quot;Anchor link for: instrument-your-ebpf-program&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we have built &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt; we can finally take action!&lt;&#x2F;p&gt;
&lt;p&gt;Instrumenting an eBPF program for source-based coverage is not that different than compiling it normally with Clang and the BPF target.&lt;&#x2F;p&gt;
&lt;p&gt;The only difference is that we ask Clang to output LLVM IR (either in textual or binary form), run the &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt; pass on it (with &lt;code&gt;opt&lt;&#x2F;code&gt;), and finally compile it (with &lt;code&gt;llc&lt;&#x2F;code&gt;) to a BPF ELF.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;clang&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -g -O2&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -target&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bpf&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -D__TARGET_ARCH_x86 -I$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;YOUR_INCLUDES&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -fprofile-instr-generate -fcoverage-mapping&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -emit-llvm -S&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; raw_enter.bpf.c&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; raw_enter.bpf.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;opt&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -load-pass-plugin&lt;&#x2F;span&gt;&lt;span&gt; $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;BUILD_DIR&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;lib&#x2F;libBPFCov.so&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -passes=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;bpf-cov&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -S&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; raw_enter.bpf.ll&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; raw_enter.bpf.cov.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;llc&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -march=bpf -filetype=obj -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cov&#x2F;raw_enter.bpf.o raw_enter.bpf.cov.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see in the Makefile inside the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;examples&#x2F;src&quot;&gt;examples&#x2F;src&lt;&#x2F;a&gt; directory of the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov GitHub repository&lt;&#x2F;a&gt; how to automate those steps.&lt;&#x2F;p&gt;
&lt;p&gt;We now have a valid and coverage instrumented BPF ELF: &lt;code&gt;cov&#x2F;raw_enter.bpf.o&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;From now on, you can instruct your loader and userspace code to use it, so to obtain a binary (eg., &lt;code&gt;&#x2F;cov&#x2F;raw_enter&lt;&#x2F;code&gt;) that is your eBPF application.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-it&quot;&gt;Use it&lt;a class=&quot;zola-anchor&quot; href=&quot;#use-it&quot; aria-label=&quot;Anchor link for: use-it&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;bpfcov-run-bpfcov-gen&quot;&gt;bpfcov run + bpfcov gen&lt;a class=&quot;zola-anchor&quot; href=&quot;#bpfcov-run-bpfcov-gen&quot; aria-label=&quot;Anchor link for: bpfcov-run-bpfcov-gen&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;What&#x27;s left to do? Just three steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Run our eBPF application with the &lt;mark&gt;bpfcov&lt;&#x2F;mark&gt; &lt;strong&gt;CLI&lt;&#x2F;strong&gt; run command&lt;&#x2F;li&gt;
&lt;li&gt;Generate its &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file&lt;&#x2F;li&gt;
&lt;li&gt;Generate beautiful source-based coverage reports&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;So, let&#x27;s run our eBPF application with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;bpfcov&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -v2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run cov&#x2F;raw_enter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This command acts similar to strace. It will detect the &lt;code&gt;bpf()&lt;&#x2F;code&gt; syscalls with the &lt;code&gt;BPF_MAP_CREATE&lt;&#x2F;code&gt; command.&lt;&#x2F;p&gt;
&lt;p&gt;Meaning that it will detect the eBPF globals in the &lt;code&gt;.profc&lt;&#x2F;code&gt;, &lt;code&gt;.profd&lt;&#x2F;code&gt;, &lt;code&gt;.profn&lt;&#x2F;code&gt;, and &lt;code&gt;.covmap&lt;&#x2F;code&gt; custom eBPF sections and pin them to the BPF file system, as you can see in the following screenshot.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;bpfcov-run.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;bpfcov-run.png&quot; alt=&quot;Output of bpfcov run&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You may also notice that - since the LLVM pass annotated the counters correctly - &lt;mark&gt;libbpf&lt;&#x2F;mark&gt; can collect relocations for them...&lt;&#x2F;p&gt;
&lt;p&gt;At this point, whether we stopped our eBPF application or it exited... We have eBPF maps pinned to our BPF file system. Let&#x27;s check it:&lt;&#x2F;p&gt;

&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;pinned-maps.png&quot;&gt;
    &lt;img src=&quot;pinned-maps.png&quot;  alt=&quot;eBPF maps pinned by bpfcov&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;Wonderful, we already know that the &lt;code&gt;hook_sys_enter&lt;&#x2F;code&gt; function executed 1 time, the &lt;code&gt;if&lt;&#x2F;code&gt; condition did not evaluate to true, while the &lt;code&gt;for&lt;&#x2F;code&gt; iterated 9 times!&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s time to put the counters, the function names, the functions data, in a &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file now.&lt;&#x2F;p&gt;
&lt;p&gt;This is why the &lt;mark&gt;bpfcov gen&lt;&#x2F;mark&gt; command exists: to dump the pinned maps in a &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;bpfcov&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -v2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gen –unpin cov&#x2F;raw_enter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;bpfcov-gen.png&quot;&gt;
    &lt;img src=&quot;bpfcov-gen.png&quot;  alt=&quot;Generating a profraw file from eBPF pinned maps with bpfcov&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;And this is the resulting &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file for our instrumented eBPF program!&lt;&#x2F;p&gt;
&lt;p&gt;You can see it&#x27;s made of four parts: a header, &lt;code&gt;.rodata.profd&lt;&#x2F;code&gt;, &lt;code&gt;.data.profc&lt;&#x2F;code&gt; (ie., the counters!), and the names (&lt;code&gt;.rodata.profn&lt;&#x2F;code&gt;), plus some padding for alignment...&lt;&#x2F;p&gt;

&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;bpf-profraw.png&quot;&gt;
    &lt;img src=&quot;bpf-profraw.png&quot;  alt=&quot;A profraw file from an eBPF program running in the Linux kernel&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;We can now either use the existing LLVM tools (&lt;mark&gt;llvm-profdata&lt;&#x2F;mark&gt; and &lt;mark&gt;llvm-cov&lt;&#x2F;mark&gt;) with it or simply use the &lt;mark&gt;bpfcov out&lt;&#x2F;mark&gt; subcommand.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;mark&gt;bpfcov out&lt;&#x2F;mark&gt; command is an opinionated shortcut to generate HTML, JSON, or LCOV coverage reports even from multiple eBPF programs and their &lt;mark&gt;profraw&lt;&#x2F;mark&gt; files.&lt;&#x2F;p&gt;
&lt;p&gt;It is very convenient because it avoids us having to generate &lt;mark&gt;profdata&lt;&#x2F;mark&gt; from the &lt;mark&gt;profraw&lt;&#x2F;mark&gt;, calling &lt;mark&gt;llvm-cov&lt;&#x2F;mark&gt; with a bunch of long and different options. And it even works with multiple &lt;mark&gt;profraw&lt;&#x2F;mark&gt; files coming from different eBPF applications...&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;bpfcov&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; out&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; yey –f html cov&#x2F;raw_enter.profraw ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It outputs a very nice HTML directory whose index file gives us summaries not only about function and line coverage but also and notably about region and branch coverages for our eBPF applications.&lt;&#x2F;p&gt;

&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;mult1.png&quot;&gt;
    &lt;img src=&quot;mult1.png&quot;  alt=&quot;HTML report of source-base code coverage of a few eBPF programs&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;By clicking on any item in the table we end up visualizing very fine-grained, source-based coverage. A good example is the one in the following image:&lt;&#x2F;p&gt;

&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;html1.png&quot;&gt;
    &lt;img src=&quot;html1.png&quot;  alt=&quot;HTML report of a raw tracepoint eBPF program on sys_enter&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;Furthermore, it does work also on very complicated and real-life eBPF programs. For example, the following screenshot is a part of the coverage report obtained for a BPF LSM test (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;torvalds&#x2F;linux&#x2F;blob&#x2F;master&#x2F;tools&#x2F;testing&#x2F;selftests&#x2F;bpf&#x2F;progs&#x2F;lsm.c&quot;&gt;progs&#x2F;lsm.c&lt;&#x2F;a&gt;, loaded by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;torvalds&#x2F;linux&#x2F;blob&#x2F;master&#x2F;tools&#x2F;testing&#x2F;selftests&#x2F;bpf&#x2F;prog_tests&#x2F;test_lsm.c&quot;&gt;prog_tests&#x2F;test_lsm.c&lt;&#x2F;a&gt;) living in the Linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;html2.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;html2.png&quot; alt=&quot;HTML report of a few BPF LSM programs from the Linux kernel&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Thanks to this tool I can finally understand that over a total of eight executions of the &lt;code&gt;lsm&#x2F;file_mprotect&lt;&#x2F;code&gt; BPF LSM program on my kernel, its &lt;code&gt;is_stack&lt;&#x2F;code&gt; variable was true two times out of eight, because six times the &lt;code&gt;vma-&amp;gt;vm_end &amp;gt;= vma-&amp;gt;vm_mm-&amp;gt;start_stack&lt;&#x2F;code&gt; branch condition (98:58) evaluated to false.&lt;&#x2F;p&gt;
&lt;p&gt;Line 100, using &lt;code&gt;is_stack&lt;&#x2F;code&gt; in another condition, confirms that it was indeed true two times out of six. And that, for this reason (first operand - 100:6 - &lt;code&gt;is_stack&lt;&#x2F;code&gt; being false six times), the following check (100:18) on &lt;code&gt;monitored_pid&lt;&#x2F;code&gt; was short-circuited and evaluated (to true, by the way) only two times.&lt;&#x2F;p&gt;
&lt;p&gt;We finally have a tool helping us write and understand the way our eBPF programs run in the Linux kernel. I can&#x27;t stress enough how this is something I dreamt of so many times during the past few years I&#x27;ve been working with BPF...&lt;&#x2F;p&gt;
&lt;p&gt;Hope that the eBPF community and ecosystem will find bpfcov useful and cool the same way I do.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bits-of-the-future&quot;&gt;Bits of the future&lt;a class=&quot;zola-anchor&quot; href=&quot;#bits-of-the-future&quot; aria-label=&quot;Anchor link for: bits-of-the-future&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov&lt;&#x2F;a&gt; tool is open-source, and it will stay that way. It is still in its early days so it will probably need a bit more tests, examples, and fixes. Just like any new software out there.&lt;&#x2F;p&gt;
&lt;p&gt;I will soon publish another project showcasing the coverage of the kernel BPF selftests, using this tool. This means there are a lot of contribution opportunities. I&#x27;d invite you to take a look at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;its source code&lt;&#x2F;a&gt; and send patches! :blush:&lt;&#x2F;p&gt;
&lt;p&gt;Also, in case you want to start using it on your eBPF applications and repositories, feel free to contact me for support. I&#x27;d love to help you to use it.&lt;&#x2F;p&gt;
&lt;p&gt;From a technical perspective these are the topics that are on top of my mind for its future:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A project like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov&lt;&#x2F;a&gt; &lt;strong&gt;must&lt;&#x2F;strong&gt; have a logo!&lt;&#x2F;li&gt;
&lt;li&gt;Write &lt;mark&gt;llvm-lit&lt;&#x2F;mark&gt; tests for the &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt; LLVM pass&lt;&#x2F;li&gt;
&lt;li&gt;Support newer LLVM versions&lt;&#x2F;li&gt;
&lt;li&gt;Workaround solutions to have it working on Linux kernels where BPF does not support custom eBPF sections and eBPF globals&lt;&#x2F;li&gt;
&lt;li&gt;Create a versioning and release process&lt;&#x2F;li&gt;
&lt;li&gt;Publish artifacts on GitHub (&lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt;, &lt;mark&gt;bpfcov&lt;&#x2F;mark&gt; &lt;strong&gt;CLI&lt;&#x2F;strong&gt; binary)&lt;&#x2F;li&gt;
&lt;li&gt;Add more examples&lt;&#x2F;li&gt;
&lt;li&gt;Publish HTML reports of the example eBPF applications via GitHub pages&lt;&#x2F;li&gt;
&lt;li&gt;Maybe, contribute it &lt;strong&gt;upstream&lt;&#x2F;strong&gt; to the LLVM BPF target!&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;fosdem-2022&quot;&gt;FOSDEM 2022&lt;a class=&quot;zola-anchor&quot; href=&quot;#fosdem-2022&quot; aria-label=&quot;Anchor link for: fosdem-2022&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In case you made it to the end, and you still want to hear more details on building source-based coverage for eBPF, I want to bring to your attention that I gave a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fosdem.org&#x2F;2022&#x2F;schedule&#x2F;event&#x2F;llvm_ebpf&#x2F;&quot;&gt;talk&lt;&#x2F;a&gt; on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov&lt;&#x2F;a&gt; at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fosdem.org&#x2F;2022&#x2F;schedule&#x2F;event&#x2F;llvm_ebpf&#x2F;&quot;&gt;FOSDEM 2022&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I will update my &lt;a href=&quot;&#x2F;talks&quot;&gt;speaking&lt;&#x2F;a&gt; section with the video recording as soon it&#x27;ll be ready.&lt;&#x2F;p&gt;
&lt;p&gt;In the meantime, you can take a look at the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;speakerdeck.com&#x2F;leodido&#x2F;coverage-for-ebpf-programs&quot;&gt;talk&#x27;s deck&lt;&#x2F;a&gt;&lt;label for=&quot;sn-8&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-8&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;While you can find the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;presentations&#x2F;tree&#x2F;master&#x2F;2022&#x2F;02&#x2F;05&#x2F;fosdem-llvm-room&#x2F;coverage-for-ebpf-programs&quot;&gt;slides in PDF and markdown format here, if you prefer&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;While at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;elastic&#x2F;bpfcov&lt;&#x2F;a&gt; you can take a look at the project. Don&#x27;t forget to star it, if you don&#x27;t mind! :star:&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>bpfcov</title>
        <published>2022-01-10T00:00:00+00:00</published>
        <updated>2022-01-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://leodido.dev/projects/bpfcov/"/>
        <id>https://leodido.dev/projects/bpfcov/</id>
        
        <content type="html" xml:base="https://leodido.dev/projects/bpfcov/">&lt;p&gt;This project provides 2 main components:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;libBPFCov.so&lt;&#x2F;code&gt; - an &lt;strong&gt;out-of-tree LLVM pass&lt;&#x2F;strong&gt; to &lt;strong&gt;instrument&lt;&#x2F;strong&gt; your &lt;strong&gt;eBPF programs&lt;&#x2F;strong&gt; for coverage.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;bpfcov&lt;&#x2F;code&gt; - a &lt;strong&gt;CLI&lt;&#x2F;strong&gt; to &lt;strong&gt;collect source-based coverage&lt;&#x2F;strong&gt; from your eBPF programs.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: center&quot;&gt;&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;docs&#x2F;assets&#x2F;stdo1.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img width=&quot;1604&quot; alt=&quot;Source-based code coverage for BPF raw tracepoints&quot; src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;elastic&#x2F;bpfcov&#x2F;main&#x2F;docs&#x2F;assets&#x2F;stdo1.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;docs&#x2F;assets&#x2F;stdo2.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img width=&quot;1604&quot; alt=&quot;Source-based code coverage for BPF LSM programs&quot; src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;elastic&#x2F;bpfcov&#x2F;main&#x2F;docs&#x2F;assets&#x2F;stdo2.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;docs&#x2F;assets&#x2F;mult1.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img width=&quot;1604&quot; alt=&quot;HTML coverage index for multiple eBPF programs&quot; src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;elastic&#x2F;bpfcov&#x2F;main&#x2F;docs&#x2F;assets&#x2F;mult1.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;docs&#x2F;assets&#x2F;html2.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img width=&quot;1604&quot; alt=&quot;HTML coverage report for eBPF programs&quot; src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;elastic&#x2F;bpfcov&#x2F;main&#x2F;docs&#x2F;assets&#x2F;html2.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;docs&#x2F;assets&#x2F;html1.png&quot;&gt;&lt;img width=&quot;1604&quot; alt=&quot;HTML coverage report for eBPF programs&quot; src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;elastic&#x2F;bpfcov&#x2F;main&#x2F;docs&#x2F;assets&#x2F;html1.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;docs&#x2F;assets&#x2F;json1.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img width=&quot;1604&quot; alt=&quot;JSON report for multiple eBPF programs&quot; src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;elastic&#x2F;bpfcov&#x2F;main&#x2F;docs&#x2F;assets&#x2F;json1.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;docs&#x2F;assets&#x2F;lcov1.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img width=&quot;1604&quot; alt=&quot;LCOV info file from multiple eBPF programs&quot; src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;elastic&#x2F;bpfcov&#x2F;main&#x2F;docs&#x2F;assets&#x2F;lcov1.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;docs&#x2F;assets&#x2F;html3.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img width=&quot;1604&quot; alt=&quot;HTML line coverage report for eBPF programs&quot; src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;elastic&#x2F;bpfcov&#x2F;main&#x2F;docs&#x2F;assets&#x2F;html3.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;docs&#x2F;assets&#x2F;html4.png&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;img width=&quot;1604&quot; alt=&quot;HTML line coverage report for eBPF programs&quot; src=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;elastic&#x2F;bpfcov&#x2F;main&#x2F;docs&#x2F;assets&#x2F;html4.png&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;a class=&quot;zola-anchor&quot; href=&quot;#overview&quot; aria-label=&quot;Anchor link for: overview&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;This section aims to provide a high-level overiew of the steps you need to get started with &lt;strong&gt;bpfcov&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;projects&#x2F;bpfcov&#x2F;#building&quot;&gt;Compile the LLVM pass&lt;&#x2F;a&gt; obtaining &lt;code&gt;libBPFCov.so&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Instrument your eBPF program by compiling it and by running the LLVM pass (&lt;code&gt;libBPFCov.so&lt;&#x2F;code&gt;) on it&lt;&#x2F;li&gt;
&lt;li&gt;Build the userspace code of your eBPF application&lt;&#x2F;li&gt;
&lt;li&gt;Execute your eBPF application in the kernel through the &lt;code&gt;bpfcov run ...&lt;&#x2F;code&gt; command&lt;&#x2F;li&gt;
&lt;li&gt;Generate the &lt;code&gt;.profraw&lt;&#x2F;code&gt; file from the run through the &lt;code&gt;bpfcov gen ...&lt;&#x2F;code&gt; command
&lt;ol&gt;
&lt;li&gt;Having a &lt;code&gt;.profraw&lt;&#x2F;code&gt; makes this tool fully interoperable&lt;&#x2F;li&gt;
&lt;li&gt;Having a &lt;code&gt;.profraw&lt;&#x2F;code&gt; allows you to generate a variety of coverage reports in different formats&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Use the LLVM toolchain to create coverage reports as documented in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;clang.llvm.org&#x2F;docs&#x2F;SourceBasedCodeCoverage.html#creating-coverage-reports&quot;&gt;LLVM docs&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;In case you are impatient and want to jump straight into getting your hands dirty, then the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;examples&#x2F;&quot;&gt;examples&lt;&#x2F;a&gt; directory contains a few dummy eBPF programs to showcase what &lt;strong&gt;bpfcov&lt;&#x2F;strong&gt; does.&lt;&#x2F;p&gt;
&lt;p&gt;It basically automates steps 2 and 3. Its &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;examples&#x2F;README.md&quot;&gt;README&lt;&#x2F;a&gt; contains more details.&lt;&#x2F;p&gt;
&lt;p&gt;While the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;cli&#x2F;README.md&quot;&gt;README of the cli directory&lt;&#x2F;a&gt; gives you more details about the steps 4 and 5 (and also 6).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;a class=&quot;zola-anchor&quot; href=&quot;#usage&quot; aria-label=&quot;Anchor link for: usage&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Here I will highlight the &lt;em&gt;manual&lt;&#x2F;em&gt; steps to use it.&lt;&#x2F;p&gt;
&lt;p&gt;I suggest you to automate most of them like I did in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;examples&#x2F;src&#x2F;Makefile&quot;&gt;examples Makefile&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, assuming you have &lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;projects&#x2F;bpfcov&#x2F;#building&quot;&gt;built&lt;&#x2F;a&gt; the LLVM pass, you can then use your fresh &lt;code&gt;libBPFCov.so&lt;&#x2F;code&gt; to instrument your eBPF programs for coverage (steps 2 and 3 above).&lt;&#x2F;p&gt;
&lt;p&gt;How to do it?&lt;&#x2F;p&gt;
&lt;p&gt;First, you need to compile your eBPF program almost as usual but to LLVM IR...&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;clang&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -g -O2&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -target&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bpf&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -D__TARGET_ARCH_x86 -I$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;YOUR_INCLUDES&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -fprofile-instr-generate -fcoverage-mapping&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -emit-llvm -S&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; program.bpf.c&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; program.bpf.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice it doesn&#x27;t matter if you use the textual (&lt;code&gt;*.ll&lt;&#x2F;code&gt;) or the binary form (&lt;code&gt;*.bc&lt;&#x2F;code&gt;).
Obviously, the former is more readable.&lt;&#x2F;p&gt;
&lt;p&gt;The same logic applies to &lt;code&gt;opt&lt;&#x2F;code&gt;: by default it generates &lt;code&gt;*.bc&lt;&#x2F;code&gt;.
Using the &lt;code&gt;-S&lt;&#x2F;code&gt; flag you can obtain the output in textual form (&lt;code&gt;*.ll&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Anyhow, it&#x27;s time to run the LLVM pass on the LLVM IR we obtained.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s do it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;opt&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -load-pass-plugin&lt;&#x2F;span&gt;&lt;span&gt; $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;BUILD_DIR&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;lib&#x2F;libBPFCov.so&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -passes=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;bpf-cov&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -S&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; program.bpf.ll&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; program.bpf.cov.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We should have obtained a new LLVM IR that&#x27;s now valid and loadable from the BPF VM in the Linux kernel. Almost there, YaY!&lt;&#x2F;p&gt;
&lt;p&gt;From it, we can obtain a valid BPF ELF now:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;llc&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -march=bpf -filetype=obj -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cov&#x2F;program.bpf.o program.bpf.cov.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;While we are at it, it is also worth running the LLVM pass again (with a flag) to obtain another BPF ELF containing all the &lt;strong&gt;profiling&lt;&#x2F;strong&gt; and &lt;strong&gt;coverage mapping&lt;&#x2F;strong&gt; info.
It will come in handy later with &lt;code&gt;llvm-cov&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;opt&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -load&lt;&#x2F;span&gt;&lt;span&gt; $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;BUILD_DIR&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;lib&#x2F;libBPFCov.so&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -strip-initializers-only -bpf-cov&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    program.bpf.ll&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    llc&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -march=bpf -filetype=obj -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cov&#x2F;program.bpf.obj&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point, we can compile our userspace application loading the eBPF instrumented program (&lt;code&gt;cov&#x2F;program.bpf.o&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Doing this when using &lt;code&gt;libbpf&lt;&#x2F;code&gt; and skeletons is very easy. Nothing different from the common steps: &lt;code&gt;bpftool&lt;&#x2F;code&gt;, &lt;code&gt;cc&lt;&#x2F;code&gt;, etc.&lt;&#x2F;p&gt;
&lt;p&gt;In the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;examples&#x2F;&quot;&gt;examples&lt;&#x2F;a&gt; directory, you can find further explainations.&lt;&#x2F;p&gt;
&lt;p&gt;So assuming we got our instrumented binary ready (&lt;code&gt;cov&#x2F;program&lt;&#x2F;code&gt;), we can run it via the &lt;code&gt;bpfcov&lt;&#x2F;code&gt; CLI.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;bpfcov run cov&#x2F;program&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Wait for it to exit, or stop it with CTRL+C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;bpfcov gen&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --unpin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cov&#x2F;program&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Again, in case you wanna know more about these 2 steps, refer this time to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;cli&#x2F;README.md&quot;&gt;CLI README&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now we have a magic &lt;code&gt;cov&#x2F;program.profraw&lt;&#x2F;code&gt; file...&lt;&#x2F;p&gt;
&lt;p&gt;And we can use the LLVM toolchain to generate very fine-grained coverage reports like those in the screenshots!&lt;&#x2F;p&gt;
&lt;p&gt;Refer to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;clang.llvm.org&#x2F;docs&#x2F;SourceBasedCodeCoverage.html#creating-coverage-reports&quot;&gt;LLVM docs&lt;&#x2F;a&gt; to learn how to do it.&lt;&#x2F;p&gt;
&lt;p&gt;But no worries, it&#x27;s just about invoking &lt;code&gt;llvm-profdata&lt;&#x2F;code&gt; and &lt;code&gt;llvm-cov&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;lvm-profdata&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; merge&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -sparse&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cov&#x2F;program.profraw&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cov&#x2F;program.profdata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;llvm-cov&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; show&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    --format=html&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    --show-line-counts-or-regions --show-region-summary --show-branch-summary&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    --instr-profile=cov&#x2F;profdata.profdata&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -object&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cov&#x2F;program.bpf.obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    --output-dir=cov&#x2F;html_report&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Anyayws, &lt;strong&gt;bpfcov&lt;&#x2F;strong&gt; also provides you an opinionated shortcut command to generate HTML, JSON, and LCOV coverage reports:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;bpfcov&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; out&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --format=html&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cov&#x2F;program.profraw&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;development-environment&quot;&gt;Development Environment&lt;a class=&quot;zola-anchor&quot; href=&quot;#development-environment&quot; aria-label=&quot;Anchor link for: development-environment&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In order to &lt;strong&gt;build&lt;&#x2F;strong&gt; the BPFCov library (&lt;code&gt;libBPFCov.so&lt;&#x2F;code&gt;) you will need:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;LLVM 12+&lt;&#x2F;li&gt;
&lt;li&gt;CMake 3.13.4+&lt;&#x2F;li&gt;
&lt;li&gt;C++ compiler that supports C++14&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In order to &lt;strong&gt;use&lt;&#x2F;strong&gt; it, you will need:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;clang 12 (to generate the input LLVM files)&lt;&#x2F;li&gt;
&lt;li&gt;its &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;llvm.org&#x2F;docs&#x2F;CommandGuide&#x2F;opt.html&quot;&gt;opt&lt;&#x2F;a&gt; binary to run the LLVM pass&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This project has been tested on 5.15 Linux kernels.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;building&quot;&gt;Building&lt;a class=&quot;zola-anchor&quot; href=&quot;#building&quot; aria-label=&quot;Anchor link for: building&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Build as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; build&lt;&#x2F;span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt; cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cmake&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -DLT_LLVM_INSTALL_DIR=&#x2F;path&#x2F;to&#x2F;llvm&#x2F;installation&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice that the &lt;code&gt;LT_LLVM_INSTALL_DIR&lt;&#x2F;code&gt; variable should be set to the root of either the installation (usually &lt;code&gt;&#x2F;usr&lt;&#x2F;code&gt;) or the build directory of LLVM.&lt;&#x2F;p&gt;
&lt;p&gt;It is used to locate the corresponding &lt;code&gt;LLVMConfig.cmake&lt;&#x2F;code&gt; script that is used to set the include and the
library paths.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;a class=&quot;zola-anchor&quot; href=&quot;#testing&quot; aria-label=&quot;Anchor link for: testing&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;TBD&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To run the tests you will need to install &lt;strong&gt;llvm-lit&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Usually, you can install it with &lt;strong&gt;pip&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pip&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install lit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Running the tests is as simple as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;lit&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; build&#x2F;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>falco</title>
        <published>2016-01-19T00:00:00+00:00</published>
        <updated>2016-01-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://leodido.dev/projects/falco/"/>
        <id>https://leodido.dev/projects/falco/</id>
        
        <content type="html" xml:base="https://leodido.dev/projects/falco/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;falco.org&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;falco.org&#x2F;img&#x2F;brand&#x2F;falco-horizontal-color.svg&quot; alt=&quot;Falco&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;falco.org&#x2F;&quot;&gt;Falco&lt;&#x2F;a&gt; is a cloud native runtime security tool for Linux operating systems. It is designed to detect and alert on abnormal behavior and potential security threats in real-time.&lt;&#x2F;p&gt;
&lt;p&gt;At its core, Falco is a kernel monitoring and detection agent that observes events, such as syscalls, based on custom rules. Falco can enhance these events by integrating metadata from the container runtime and Kubernetes. The collected events can be analyzed off-host in SIEM or data lake systems.&lt;&#x2F;p&gt;
&lt;p&gt;Falco, originally created by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sysdig.com&quot;&gt;Sysdig&lt;&#x2F;a&gt;, is a &lt;strong&gt;graduated project&lt;&#x2F;strong&gt; under the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cncf.io&quot;&gt;Cloud Native Computing Foundation&lt;&#x2F;a&gt; (CNCF) used in production by various &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&#x2F;blob&#x2F;master&#x2F;ADOPTERS.md&quot;&gt;organisations&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For detailed technical information and insights into the cyber threats that Falco can detect, visit the official &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;falco.org&#x2F;&quot;&gt;Falco&lt;&#x2F;a&gt; website.&lt;&#x2F;p&gt;
&lt;p&gt;For comprehensive information on the latest updates and changes to the project, please refer to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&#x2F;tree&#x2F;master&#x2F;CHANGELOG.md&quot;&gt;Change Log&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-falco-project&quot;&gt;The Falco Project&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-falco-project&quot; aria-label=&quot;Anchor link for: the-falco-project&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The Falco Project codebase is maintained under the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&quot;&gt;falcosecurity GitHub organization&lt;&#x2F;a&gt;. The primary repository, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&quot;&gt;falcosecurity&#x2F;falco&lt;&#x2F;a&gt;, holds the source code for the Falco binary, while other sub-projects are hosted in dedicated repositories. This approach of isolating components into specialized repositories enhances modularity and focused development. Notable &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;evolution?tab=readme-ov-file#core&quot;&gt;core repositories&lt;&#x2F;a&gt; include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;libs&quot;&gt;falcosecurity&#x2F;libs&lt;&#x2F;a&gt;: This repository hosts Falco&#x27;s core libraries, which constitute the majority of the binary’s source code and provide essential features, such as kernel drivers.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;rules&quot;&gt;falcosecurity&#x2F;rules&lt;&#x2F;a&gt;: It contains the official ruleset for Falco, offering pre-defined detection rules for various security threats and abnormal behaviors.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;plugins&quot;&gt;falcosecurity&#x2F;plugins&lt;&#x2F;a&gt;: This repository supports integration with external services through plugins that extend Falco&#x27;s capabilities beyond syscalls and container events, with plans for evolving specialized functionalities in future releases.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falcoctl&quot;&gt;falcosecurity&#x2F;falcoctl&lt;&#x2F;a&gt;: A command-line utility designed for managing and interacting with Falco.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;charts&quot;&gt;falcosecurity&#x2F;charts&lt;&#x2F;a&gt;: This repository provides Helm charts for deploying Falco and its ecosystem, simplifying the installation and management process.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For further insights into our repositories and additional details about our governance model, please visit the official hub of The Falco Project: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;evolution&quot;&gt;falcosecurity&#x2F;evolution&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-started-with-falco&quot;&gt;Getting Started with Falco&lt;a class=&quot;zola-anchor&quot; href=&quot;#getting-started-with-falco&quot; aria-label=&quot;Anchor link for: getting-started-with-falco&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re new to Falco, begin your journey with our &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;falco.org&#x2F;docs&#x2F;getting-started&#x2F;&quot;&gt;Getting Started&lt;&#x2F;a&gt; guide. For production deployments, please refer to our comprehensive &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;falco.org&#x2F;docs&#x2F;setup&#x2F;&quot;&gt;Setup&lt;&#x2F;a&gt; documentation.&lt;&#x2F;p&gt;
&lt;p&gt;As final recommendations before deploying Falco, verify environment compatibility, define your detection goals, optimize performance, choose the appropriate build, and plan for SIEM or data lake integration to ensure effective incident response.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;demo-environment&quot;&gt;Demo Environment&lt;a class=&quot;zola-anchor&quot; href=&quot;#demo-environment&quot; aria-label=&quot;Anchor link for: demo-environment&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;A demo environment is provided via a docker-compose file that can be started on a docker host which includes falco, falcosidekick, falcosidekick-ui and its required redis database. For more information see the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&#x2F;tree&#x2F;master&#x2F;docker&#x2F;docker-compose&#x2F;&quot;&gt;docker-compose section&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;join-the-community&quot;&gt;Join the Community&lt;a class=&quot;zola-anchor&quot; href=&quot;#join-the-community&quot; aria-label=&quot;Anchor link for: join-the-community&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;To get involved with the Falco Project please visit the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;community&quot;&gt;Community&lt;&#x2F;a&gt; repository to find more information and ways to get involved.&lt;&#x2F;p&gt;
&lt;p&gt;If you have any questions about Falco or contributing, do not hesitate to file an issue or contact the Falco maintainers and community members for assistance.&lt;&#x2F;p&gt;
&lt;p&gt;How to reach out?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Join the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.slack.com&#x2F;messages&#x2F;falco&quot;&gt;#falco&lt;&#x2F;a&gt; channel on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;slack.k8s.io&quot;&gt;Kubernetes Slack&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Join the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lists.cncf.io&#x2F;g&#x2F;cncf-falco-dev&quot;&gt;Falco mailing list&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;File an &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&#x2F;issues&quot;&gt;issue&lt;&#x2F;a&gt; or make feature requests.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;commitment-to-falco-s-own-security&quot;&gt;Commitment to Falco&#x27;s Own Security&lt;a class=&quot;zola-anchor&quot; href=&quot;#commitment-to-falco-s-own-security&quot; aria-label=&quot;Anchor link for: commitment-to-falco-s-own-security&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Full reports of various security audits can be found &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&#x2F;tree&#x2F;master&#x2F;audits&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In addition, you can refer to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&#x2F;security&quot;&gt;falco&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;libs&#x2F;security&quot;&gt;libs&lt;&#x2F;a&gt; security sections for detailed updates on security advisories and policies.&lt;&#x2F;p&gt;
&lt;p&gt;To report security vulnerabilities, please follow the community process outlined in the documentation found &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;.github&#x2F;blob&#x2F;main&#x2F;SECURITY.md&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;building&quot;&gt;Building&lt;a class=&quot;zola-anchor&quot; href=&quot;#building&quot; aria-label=&quot;Anchor link for: building&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;For comprehensive, step-by-step instructions on building Falco from source, please refer to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;falco.org&#x2F;docs&#x2F;developer-guide&#x2F;source&#x2F;&quot;&gt;official documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;a class=&quot;zola-anchor&quot; href=&quot;#testing&quot; aria-label=&quot;Anchor link for: testing&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;details&gt;
	&lt;summary&gt;Expand Testing Instructions&lt;&#x2F;summary&gt;
&lt;p&gt;Falco&#x27;s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;falco.org&#x2F;docs&#x2F;developer-guide&#x2F;source&#x2F;&quot;&gt;Build Falco from source&lt;&#x2F;a&gt; is the go-to resource to understand how to build Falco from source. In addition, the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;libs&quot;&gt;falcosecurity&#x2F;libs&lt;&#x2F;a&gt; repository offers additional valuable information about tests and debugging of Falco&#x27;s underlying libraries and kernel drivers.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s an example of a &lt;code&gt;cmake&lt;&#x2F;code&gt; command that will enable everything you need for all unit tests of this repository:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cmake&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-DUSE_BUNDLED_DEPS=ON&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-DBUILD_DRIVER=ON&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-DBUILD_FALCO_MODERN_BPF=ON&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-DCREATE_TEST_TARGETS=ON&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-DBUILD_FALCO_UNIT_TESTS=ON&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ..&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Build and run the unit test suite:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;nproc&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; processor &#x2F;proc&#x2F;cpuinfo&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; tail&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; awk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;{print $3}&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;make&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -j$((&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;$nproc&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;-1))&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; falco_unit_tests&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Run the tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;unit_tests&#x2F;falco_unit_tests&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Optionally, build the driver of your choice and test run the Falco binary to perform manual tests.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly, The Falco Project has moved its Falco regression tests to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;testing&quot;&gt;falcosecurity&#x2F;testing&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;details&gt;
&lt;&#x2F;br&gt;
&lt;h2 id=&quot;how-to-contribute&quot;&gt;How to Contribute&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-to-contribute&quot; aria-label=&quot;Anchor link for: how-to-contribute&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Please refer to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;.github&#x2F;blob&#x2F;main&#x2F;CONTRIBUTING.md&quot;&gt;Contributing&lt;&#x2F;a&gt; guide and the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;evolution&#x2F;blob&#x2F;main&#x2F;CODE_OF_CONDUCT.md&quot;&gt;Code of Conduct&lt;&#x2F;a&gt; for more information on how to contribute.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;faqs&quot;&gt;FAQs&lt;a class=&quot;zola-anchor&quot; href=&quot;#faqs&quot; aria-label=&quot;Anchor link for: faqs&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;why-is-falco-in-c-rather-than-go-or-language&quot;&gt;Why is Falco in C++ rather than Go or {language}?&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-is-falco-in-c-rather-than-go-or-language&quot; aria-label=&quot;Anchor link for: why-is-falco-in-c-rather-than-go-or-language&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;details&gt;
	&lt;summary&gt;Expand Information&lt;&#x2F;summary&gt;
&lt;ol&gt;
&lt;li&gt;The first lines of code at the base of Falco were written some time ago, where Go didn&#x27;t yet have the same level of maturity and adoption as today.&lt;&#x2F;li&gt;
&lt;li&gt;The Falco execution model is sequential and mono-thread due to the statefulness requirements of the tool, and so most of the concurrency-related selling points of the Go runtime would not be leveraged at all.&lt;&#x2F;li&gt;
&lt;li&gt;The Falco code deals with very low-level programming in many places, and we all know that interfacing Go with C is possible but brings tons of complexity and tradeoffs to the table.&lt;&#x2F;li&gt;
&lt;li&gt;As a security tool meant to consume a crazy high throughput of events per second, Falco needs to squeeze performance in all hot paths at runtime and requires deep control on memory allocation, which the Go runtime can&#x27;t provide (there&#x27;s also garbage collection involved).&lt;&#x2F;li&gt;
&lt;li&gt;Although Go didn&#x27;t suit the engineering requirements of the core of Falco, we still thought that it could be a good candidate for writing Falco extensions through the plugin system. This is the main reason we gave special attention and high priority to the development of the plugin-sdk-go.&lt;&#x2F;li&gt;
&lt;li&gt;Go is not a requirement for having statically-linked binaries. In fact, we provide fully-static Falco builds since few years. The only issue with those is that the plugin system can&#x27;t be supported with the current dynamic library model we currently have.&lt;&#x2F;li&gt;
&lt;li&gt;The plugin system has been envisioned to support multiple languages, so on our end maintaining a C-compatible codebase is the best strategy to ensure maximum cross-language compatibility.&lt;&#x2F;li&gt;
&lt;li&gt;In general, plugins have GLIBC requirements&#x2F;dependencies because they have low-level C bindings required for dynamic loading. A potential solution for the future could be to also support plugin to be statically-linked at compilation time and so released as bundled in the Falco binary. Although no work started yet in this direction, this would solve most issues you reported and would provide a totally-static binary too. Of course, this would not be compatible with dynamic loading anymore, but it may be a viable solution for our static-build flavor of Falco.&lt;&#x2F;li&gt;
&lt;li&gt;Memory safety is definitely a concern and we try our best to keep an high level of quality even though C++ is quite error prone. For instance, we try to use smart pointers whenever possible, we build the libraries with an address sanitizer in our CI, we run Falco through Valgrind before each release, and have ways to stress-test it to detect performance regressions or weird memory usage (e.g. https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;event-generator). On top of that, we also have third parties auditing the codebase by time to time. None of this make a perfect safety standpoint of course, but we try to maximize our odds. Go would definitely make our life easier from this perspective, however the tradeoffs never made it worth it so far due to the points above.&lt;&#x2F;li&gt;
&lt;li&gt;The C++ codebase of falcosecurity&#x2F;libs, which is at the core of Falco, is quite large and complex. Porting all that code to another language would be a major effort requiring lots of development resource and with an high chance of failure and regression. As such, our approach so far has been to choose refactors and code polishing instead, up until we&#x27;ll reach an optimal level of stability, quality, and modularity, on that portion of code. This would allow further developments to be smoother and more feasibile in the future.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;details&gt;
&lt;&#x2F;br&gt;
&lt;h3 id=&quot;what-s-next-for-falco&quot;&gt;What&#x27;s next for Falco?&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-s-next-for-falco&quot; aria-label=&quot;Anchor link for: what-s-next-for-falco&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Stay updated with Falco&#x27;s evolving capabilities by exploring the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;orgs&#x2F;falcosecurity&#x2F;projects&#x2F;5&quot;&gt;Falco Roadmap&lt;&#x2F;a&gt;, which provides insights into the features currently under development and planned for future releases.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;license&quot;&gt;License&lt;a class=&quot;zola-anchor&quot; href=&quot;#license&quot; aria-label=&quot;Anchor link for: license&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Falco is licensed to you under the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&#x2F;tree&#x2F;master&#x2F;COPYING&quot;&gt;Apache 2.0&lt;&#x2F;a&gt; open source license.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;a class=&quot;zola-anchor&quot; href=&quot;#resources&quot; aria-label=&quot;Anchor link for: resources&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;evolution&#x2F;blob&#x2F;main&#x2F;GOVERNANCE.md&quot;&gt;Governance&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;evolution&#x2F;blob&#x2F;main&#x2F;CODE_OF_CONDUCT.md&quot;&gt;Code Of Conduct&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;evolution&#x2F;blob&#x2F;main&#x2F;MAINTAINERS_GUIDELINES.md&quot;&gt;Maintainers Guidelines&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;evolution&#x2F;blob&#x2F;main&#x2F;MAINTAINERS.md&quot;&gt;Maintainers List&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;evolution&#x2F;blob&#x2F;main&#x2F;REPOSITORIES.md&quot;&gt;Repositories Guidelines&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;evolution&#x2F;blob&#x2F;main&#x2F;README.md#repositories&quot;&gt;Repositories List&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&#x2F;blob&#x2F;master&#x2F;ADOPTERS.md&quot;&gt;Adopters List&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;falcosecurity&#x2F;falco&#x2F;tree&#x2F;master&#x2F;RELEASE.md&quot;&gt;Release Process&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;falco.org&#x2F;docs&#x2F;setup&#x2F;&quot;&gt;Setup documentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;falco.org&#x2F;docs&#x2F;troubleshooting&#x2F;&quot;&gt;Troubleshooting&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
</feed>
