Route UDP on Gateway API v1.6 with UDPRoute
UDPRoute is for plain UDP traffic that needs to reach a Service backend through a Gateway controller. That is a narrow job, and it does it without pretending to be HTTP or TLS. The useful part is boring: a listener on the Gateway accepts the protocol and port, and the route hands packets to a Service on the backend side.
Why Gateway API v1.6 finally makes UDP feel less like a bolt-on
TCPRoute and UDPRoute moved to gateway.networking.k8s.io/v1 in v1.6.0. The older v1alpha2 versions are deprecated and scheduled for removal later, so sticking with them now just buys future grief. Standard status matters here because it gives you a portable way to describe raw L4 routing instead of depending on whatever shape a controller happened to like.
The change also keeps experimental pieces separate in gateway.networking.x-k8s.io with an X prefix. That split matters because not every idea in the Gateway API is ready for the same treatment as TCPRoute and UDPRoute. Experimental backend work, such as XBackend, stays in that other group for a reason.
What moved to gateway.networking.k8s.io/v1 and what stayed experimental
TCPRoute and UDPRoute are now the stable bits for raw TCP and UDP traffic. They route by protocol and port, with Service backends at the far end. Experimental resources use the gateway.networking.x-k8s.io/v1alpha1 group, and they are not something to build a quiet life around.
One awkward edge is XBackend for ExternalHostname destinations. That is marked as Extended or Optional, and it stays experimental. Service support was left out for that pattern because of confused deputy attack risk, which is a neat way of saying it was a bad idea to make that path look too convenient.
Wire UDPRoute to a Gateway listener without tripping over parentRefs
A UDPRoute does nothing useful until it binds to a Gateway listener. The binding comes through parentRefs, and the route has to match the listener’s protocol and port. Miss that, and the controller can ignore the whole thing without making much noise about it.
Match the listener port, protocol, and allowedRoutes kinds
The Gateway listener needs protocol: UDP and the right port. allowedRoutes must include UDPRoute in kinds, or the route will not be allowed to attach. If the Gateway listens on port 12345, the route has to line up with that listener rather than some vaguely related one.
parentRefs is where the route names the Gateway listener. When sectionName and port are set, the match is narrow and tidy. If those fields are omitted, the route attaches to every matching listener on the Gateway, which is handy until there are more listeners than you expected.
TCPRoute behaves the same way for TCP listeners, so the shape of the config is familiar. The point is not cleverness. It is keeping the route attached to the listener you meant, rather than whatever happened to fit.
Send packets to a Service backend and check the controller really did it
backendRefs points the route at a Service backend, usually by name and port. In the common example, traffic arriving on the Gateway port is proxied to the endpoints of my-foo-service on port 6000. That part is easy to write and easy to get wrong if the Service port does not match what the controller expects.
Read the backendRefs mapping, then test the traffic path
The mapping is plain enough: route on the Gateway side, then send traffic to a Service backend on the other side. The important bit is that the controller has to translate that declaration into real packet handling. A clean YAML file is not proof of life.
Testing matters because controller behaviour is the last mile here. Send traffic through the Gateway listener and check that packets reach the Service endpoints on the target port. If the packet path fails, the route definition may be fine while the controller mapping is not.
Spot the awkward bits: deprecated v1alpha2 objects and controller-specific CRDs
The old v1alpha2 TCPRoute and UDPRoute objects are deprecated. They will not hang around forever, and that alone is enough reason to move off them. A route in the old version may still work today and then become a maintenance problem later, which is a dull way to spend time.
Controller-specific CRDs are another snag. They do not travel between Gateway controllers, so a config that looks fine on one stack may be meaningless on another. That is the price of depending on implementation-specific extras instead of the standard route types.
Gateway API v1.6.0 gives raw L4 routing a proper place, but only if the Gateway listener, parentRefs, and backendRefs all line up. The controller still has to honour the mapping, and that is where the tidy YAML either turns into traffic or does nothing at all.



