Skip to content

feat(flower): add IPv6 address match keys#330

Merged
florianl merged 1 commit into
florianl:mainfrom
MaxRink:feat/ipv6-flower-keys
Jul 15, 2026
Merged

feat(flower): add IPv6 address match keys#330
florianl merged 1 commit into
florianl:mainfrom
MaxRink:feat/ipv6-flower-keys

Conversation

@MaxRink

@MaxRink MaxRink commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Wires up the KeyIPv6Src / KeyIPv6SrcMask / KeyIPv6Dst / KeyIPv6DstMask flower match keys. The tcaFlowerKeyIPv6* attribute constants already existed in the enum but had no corresponding Flower struct fields, marshal, or unmarshal — so IPv6 L3 matches could neither be programmed nor read back (an incoming IPv6 flower rule hit the default: arm on unmarshal).

Changes

  • Add KeyIPv6Src/SrcMask/Dst/DstMask *net.IP fields to Flower, mirroring the existing IPv4 keys.
  • Marshal them as the 16-byte TCA_FLOWER_KEY_IPV6_* attributes (vtBytes), and unmarshal via ad.Bytes().
  • Add ipv6ToBytes / bytesToIPv6 helpers (16-byte, reject non-IPv6 input).
  • Extend the TestFlower round-trip with IPv6 src/dst + masks.

go test ./... and go vet ./... pass.

Motivation

Enforcing Kubernetes network policy on SR-IOV VF representors (switchdev) via hardware-offloaded flower filters needs IPv6 L3 matching; this was the one missing piece for a pure-go-tc implementation.

MaxRink added a commit to MaxRink/multi-networkpolicy-nftables that referenced this pull request Jul 15, 2026
Enforce MultiNetworkPolicy on IPv6 as well as IPv4 for SR-IOV VF
interfaces. A flower filter matches exactly one ethertype, so each
emitted FlowerRule is single-family (familyV4 = zero value, familyV6);
the engine emits per-family filters:

  - ipBlock CIDR/Except and podSelector/namespaceSelector peers now keep
    both families (parseCIDRs / resolvePeerIPs); selector IPs become /32
    (v4) or /128 (v6) prefixes.
  - toObject stamps KeyEthType (0x0800 / 0x86dd) and the matching
    KeyIPv4*/KeyIPv6* keys; family folds into mask signature, ordering,
    and reconcile handle so v4/v6 filters never collide.
  - match-any (empty peers) and the per-direction default-deny expand to
    BOTH families — a v4-only catch-all would let v6 fall off the
    first-match pipeline and be implicitly accepted, defeating
    default-deny.
  - CT chain-0 (established/related/invalid/dispatch) is emitted per
    family for the same reason (every flower filter carries an
    ethertype).

Depends on IPv6 flower match keys (KeyIPv6Src/Dst + masks) added to
go-tc; pulled via a temporary replace directive to the fork
(github.com/MaxRink/go-tc) until the upstream PR (florianl/go-tc#330)
merges and tags.

Cross-platform golden tests cover v6 ingress/egress CIDR, v6 Except,
dual-stack ipBlock and podSelector, match-any/default-deny both
families, and per-family CT entry rules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wire up the KeyIPv6Src/SrcMask/Dst/DstMask flower match keys (the
tcaFlowerKeyIPv6* attribute constants already existed but had no struct
fields, marshal, or unmarshal). IPv6 addresses are carried as *net.IP
and encoded as the 16-byte TCA_FLOWER_KEY_IPV6_* attributes, mirroring
the existing IPv4 key handling.

Adds ipv6ToBytes/bytesToIPv6 helpers and extends the flower round-trip
test with IPv6 src/dst + masks.

This unblocks IPv6 support for hardware-offloaded flower filters on
switchdev VF representors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Maximilian Rink <maximilian.rink@telekom.de>
@MaxRink
MaxRink force-pushed the feat/ipv6-flower-keys branch from 3da426f to 0157381 Compare July 15, 2026 17:27

@florianl florianl left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for identifying and closing this gap! 👍

@florianl
florianl merged commit 04acaa1 into florianl:main Jul 15, 2026
32 checks passed
MaxRink added a commit to MaxRink/multi-networkpolicy-nftables that referenced this pull request Jul 15, 2026
florianl/go-tc#330 (IPv6 flower keys) merged upstream. Drop the
github.com/MaxRink/go-tc replace directive and require the upstream
module directly at the merge commit pseudo-version
(v0.4.9-0.20260715183334-04acaa107113). The personal fork is no longer
referenced anywhere in the module graph; re-vendored from upstream.

Once florianl cuts a tagged release containing #330, bump the require to
that tag and drop the pseudo-version.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.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