Skip to content

Add Gateway API TCPRoute support for raw TCP forwarding - #130

Merged
Shine-neko merged 1 commit into
mainfrom
feat/gateway-tcproute
Jul 21, 2026
Merged

Add Gateway API TCPRoute support for raw TCP forwarding#130
Shine-neko merged 1 commit into
mainfrom
feat/gateway-tcproute

Conversation

@Shine-neko

Copy link
Copy Markdown
Contributor

Adds Gateway API TCPRoute support: forward a whole listener port to backends, plain TCP, no SNI or TLS. Closes the Gateway API: TCPRoute board item.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
spec:
  gatewayClassName: sozune
  listeners:
    - name: raw
      protocol: TCP
      port: 5432
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
spec:
  parentRefs:
    - name: tcpgw
      sectionName: raw
  rules:
    - backendRefs:
        - name: postgres
          port: 5432

Design

TCPRoute is the raw-TCP counterpart to the TLSRoute shipped in #126, with the name-routing removed. Where TLSRoute routes by the ClientHello SNI, TCPRoute routes nothing — one catch-all Protocol::Tcp entrypoint per (route, port), sni: None, forwarding the whole port. It reuses the existing machinery directly: the ParentRef trait, the TcpListenerPorts resolver, tls_entrypoint_defaults, and the same watcher / apply / delete / re-resolve shape.

Same constraint as TLSRoute: the Gateway's TCP listener port must match a proxy.tcp entry in config.yaml — Sōzune binds TCP ports at startup, never from a Gateway alone. A route on an undeclared port is tracked but unserved, and goes live on the next reload once the listener is declared.

Verified on a real cluster

Built into an image and run on kind end to end (not just unit-tested): the k8s suite (tests/e2e/k8s/04-tcproute.sh) installs the TCPRoute CRD, stands up a socat echo backend, and asserts the whole port is forwarded (k8s-tcproute-ok comes back). 43/43 in the k8s suite, 126/126 on the Docker suite (no HTTPS regression), plus 7 new unit tests.

A ReferenceGrant bug this surfaced

Codex review caught that trusted_route_from_namespaces only recognised from.kind == "HTTPRoute", so a ReferenceGrant naming TCPRoute (or TLSRoute) was never recorded and cross-namespace backends for those kinds were always rejected. Fixed to accept all three route kinds — which also unblocks cross-namespace TLSRoute backends, a pre-existing defect.

Known pre-existing issues (not in scope here)

Codex also flagged three defects that live in the shared HTTPRoute/TLSRoute attachment path, not in TCPRoute specifically, so they're left for a dedicated Gateway API hardening pass rather than widened into this PR:

  • parentRef.group: "" (explicit empty) is treated as the Gateway API group; per spec only an omitted group defaults.
  • listener allowedRoutes (namespace from, kind restrictions) is not enforced — ListenerInfo doesn't retain the policy.
  • SCOPE_SUBSCRIBERS/Notify: three notify_one() calls can collapse to one permit if a watcher isn't parked, so a watcher may wait out its 2s tick instead of re-resolving immediately. (Bumped 2→3 here for correctness of the count, but the underlying broadcast guarantee is weak.)

ReferenceGrant kind granularity is also documented as a known looseness: grants are keyed by (from_ns, to_ns), not by route kind, so a grant for one kind admits another kind in the same namespace.

@Shine-neko
Shine-neko merged commit 288b764 into main Jul 21, 2026
3 checks passed
@Shine-neko
Shine-neko deleted the feat/gateway-tcproute branch July 21, 2026 08:14
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.

1 participant