Skip to content

feat(bpf): implement allow_ethertype L2 gatekeeper#51

Open
leodido wants to merge 8 commits intofeat/multi-value-rodatafrom
feat/allow-ethertype
Open

feat(bpf): implement allow_ethertype L2 gatekeeper#51
leodido wants to merge 8 commits intofeat/multi-value-rodatafrom
feat/allow-ethertype

Conversation

@leodido
Copy link
Copy Markdown
Owner

@leodido leodido commented May 4, 2026

L2 EtherType allowlist program. Drops Ethernet frames whose EtherType
is not in the allowed set. Accepts a +-delimited list of symbolic
names (ipv4, ipv6, arp) or 0x-prefixed hex values.

First multi-value input program, using the infrastructure from PR #49.

Changes

  1. BPF program (bpf/allow_ethertype.bpf.c): reads eth->h_proto,
    linear scans allowed[MAX_MULTI_VALUES] array. Match: tail-call next.
    No match: TC_ACT_SHOT. Fail-closed on truncated Ethernet headers.
    Also adds ETH_P_IPV6, ETH_P_ARP, MAX_MULTI_VALUES to commons.bpf.h.

  2. Parser wiring: case program_allow_ethertype in parse_input()
    calling the existing parse_ethertypes() helper. Added to
    program_requires_input(). input_fields entry in api.lua:
    { field = "ethertypes", multi = true }.

  3. Chain loader: case program_allow_ethertype in
    load_chain_program(). Passes the full ethertypes struct (array + count)
    to set_chain_rodata(). Added to program_supports_chaining().

  4. Tests: 6 flag validation tests (missing input, unknown name, invalid
    hex, duplicates, trailing/leading +). 3 integration tests (standalone
    allow, standalone block, chain). 1 CNI test with fixture.

  5. Docs: README.txt and docs/README.md.

Stacked on

leodido and others added 4 commits May 4, 2026 12:20
L2 EtherType allowlist program. Reads eth->h_proto and checks it
against a configurable set of allowed EtherTypes. Drops frames with
non-matching EtherTypes (TC_ACT_SHOT). Fail-closed on truncated
Ethernet headers.

Rodata: allowed[MAX_MULTI_VALUES] array + num_allowed count + slot
for chain tail-calls. In standalone mode, bpf_tail_call silently
fails and falls through to TC_ACT_OK.

Also adds ETH_P_IPV6, ETH_P_ARP, and MAX_MULTI_VALUES defines to
commons.bpf.h.

Co-authored-by: Ona <no-reply@ona.com>
Add case program_allow_ethertype in parse_input() calling the existing
parse_ethertypes() helper. Add allow_ethertype to program_requires_input().

Add allow_ethertype to input_fields in api.lua as the first multi-value
entry: { field = "ethertypes", multi = true }.

Co-authored-by: Ona <no-reply@ona.com>
Add case program_allow_ethertype in load_chain_program(). Passes the
full ethertypes struct (values[] + count) to set_chain_rodata().

Add allow_ethertype to program_supports_chaining().

Co-authored-by: Ona <no-reply@ona.com>
Flag tests (cli.flags.bats):
- missing input, unknown name, invalid hex, duplicate values,
  trailing +, leading +

Integration tests (cli.bats):
- allow_ethertype ipv4+arp allows IPv4 ping (needs ARP + IPv4)
- allow_ethertype ipv6 blocks IPv4 ping (IPv4 not in allowed set)
- chain allow_ethertype:ipv4+arp,allow_ipv4:ADDR allows matching traffic

CNI test (cni.bats):
- allow_ethertype via CNI with ipv4+arp fixture

Co-authored-by: Ona <no-reply@ona.com>
@leodido leodido changed the title feat(bpf): implement allow_ethertype L2 gatekeeper feat(bpf): implement allow_ethertype L2 gatekeeper May 4, 2026
@leodido leodido self-assigned this May 4, 2026
Co-authored-by: Ona <no-reply@ona.com>
@leodido leodido force-pushed the feat/allow-ethertype branch from d722d44 to ca8c0dd Compare May 4, 2026 12:34
@leodido leodido requested a review from fntlnz May 4, 2026 12:36
leodido and others added 2 commits May 4, 2026 12:53
__u8 overflows at 256. If MAX_MULTI_VALUES were ever increased beyond
255, the loop would never terminate. __u32 is safer and has no
performance cost in BPF.

Co-authored-by: Ona <no-reply@ona.com>
Add flag tests for consecutive ++ delimiter, too many values exceeding
MAX_MULTI_VALUES, and zero hex value 0x0000. Fix missing trailing
newlines in both test files.

Add integration tests for chain blocking non-matching EtherType and
for hex value input (0x0800+0x0806).

Co-authored-by: Ona <no-reply@ona.com>
leodido added a commit that referenced this pull request May 4, 2026
- Fix bpf_printk NDEBUG macro: use do { } while(0) instead of
  { } while(0) to avoid dangling-else in unbraced if/else.
- Update standalone template comment to reflect multi-value rodata
  and the slot default-zero contract.
- Add cross-representation duplicate test (ipv4+0x0800).
- Add integration test: allow_ethertype ipv4 without ARP blocks ping
  (verifies ARP filtering at L2).
- Document chain ordering constraint: allow_ethertype must be first
  because L3+ passthrough paths bypass downstream L2 filters.
- Document VLAN (802.1Q) limitation in both README.txt and docs.

Co-authored-by: Ona <no-reply@ona.com>
Fix bpf_printk no-op macro to use do { } while(0). The previous
{ } while(0) form causes a dangling-else compile error when used
in unbraced if/else blocks.

Document allow_ethertype chain ordering constraint: must be first
in a chain because L3+ programs pass through non-matching traffic
via TC_ACT_OK, bypassing downstream L2 filters. Document 802.1Q
VLAN limitation (outer EtherType is 0x8100, not the payload type).

Add test for cross-representation duplicate detection (ipv4+0x0800).
Add integration test verifying that allow_ethertype ipv4 without arp
blocks ping (ARP resolution fails at L2).

Update standalone template comment to reflect multi-value rodata
layout and the slot default-zero contract.

Co-authored-by: Ona <no-reply@ona.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants