Skip to content

Add support for backendref service appProtocol #3511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/controller/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ func registerControllers(
objectType: &apiv1.Service{},
name: "user-service", // unique controller names are needed and we have multiple Service ctlrs
options: []controller.Option{
controller.WithK8sPredicate(predicate.ServicePortsChangedPredicate{}),
controller.WithK8sPredicate(predicate.ServiceChangedPredicate{}),
},
},
{
Expand Down
11 changes: 11 additions & 0 deletions internal/controller/state/conditions/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,17 @@
}
}

// NewRouteBackendRefUnsupportedProtocol returns a Condition that indicates that the Route has a backendRef with
// an unsupported protocol.
func NewRouteBackendRefUnsupportedProtocol(msg string) Condition {
return Condition{
Type: string(v1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse,
Reason: string(v1.RouteReasonUnsupportedProtocol),
Message: msg,
}

Check warning on line 434 in internal/controller/state/conditions/conditions.go

View check run for this annotation

Codecov / codecov/patch

internal/controller/state/conditions/conditions.go#L428-L434

Added lines #L428 - L434 were not covered by tests
}

// NewRouteInvalidGateway returns a Condition that indicates that the Route is not Accepted because the Gateway it
// references is invalid.
func NewRouteInvalidGateway() Condition {
Expand Down
73 changes: 73 additions & 0 deletions internal/controller/state/graph/backend_refs.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import (
"github.com/nginx/nginx-gateway-fabric/internal/framework/helpers"
)

const (
AppProtocolTypeH2C string = "kubernetes.io/h2c"
AppProtocolTypeWS string = "kubernetes.io/ws"
AppProtocolTypeWSS string = "kubernetes.io/wss"
)

// BackendRef is an internal representation of a backendRef in an HTTP/GRPC/TLSRoute.
type BackendRef struct {
// BackendTLSPolicy is the BackendTLSPolicy of the Service which is referenced by the backendRef.
Expand Down Expand Up @@ -200,6 +206,23 @@ func createBackendRef(
return backendRef, append(conds, conditions.NewRouteBackendRefUnsupportedValue(err.Error()))
}

if svcPort.AppProtocol != nil {
err = validateRouteBackendRefAppProtocol(route.RouteType, *svcPort.AppProtocol, backendTLSPolicy)
if err != nil {
backendRef := BackendRef{
SvcNsName: svcNsName,
BackendTLSPolicy: backendTLSPolicy,
ServicePort: svcPort,
Weight: weight,
Valid: false,
IsMirrorBackend: ref.MirrorBackendIdx != nil,
InvalidForGateways: invalidForGateways,
}

return backendRef, append(conds, conditions.NewRouteBackendRefUnsupportedProtocol(err.Error()))
}
}

backendRef := BackendRef{
SvcNsName: svcNsName,
BackendTLSPolicy: backendTLSPolicy,
Expand Down Expand Up @@ -414,6 +437,56 @@ func validateBackendRef(
return true, conditions.Condition{}
}

// validateRouteBackendRefAppProtocol checks if a given RouteType supports sending traffic to a service AppProtocol.
// Returns nil if true or AppProtocol is not a Kubernetes Standard Application Protocol.
func validateRouteBackendRefAppProtocol(
routeType RouteType,
appProtocol string,
backendTLSPolicy *BackendTLSPolicy,
) error {
err := fmt.Errorf(
"route type %s does not support service port appProtocol %s",
routeType,
appProtocol,
)

// Currently we only support recognition of the Kubernetes Standard Application Protocols defined in KEP-3726.
switch appProtocol {
case AppProtocolTypeH2C:
if routeType == RouteTypeGRPC {
return nil
}

if routeType == RouteTypeHTTP {
return fmt.Errorf("%w; nginx does not support proxying to upstreams with http2 or h2c", err)
}

return err
case AppProtocolTypeWS:
if routeType == RouteTypeHTTP {
return nil
}

return err
case AppProtocolTypeWSS:
if routeType == RouteTypeHTTP {
if backendTLSPolicy != nil {
return nil
}

return fmt.Errorf("%w; missing corresponding BackendTLSPolicy", err)
}

if routeType == RouteTypeTLS {
return nil
}

return err
}

return nil
}

func validateWeight(weight int32) error {
const (
minWeight = 0
Expand Down
Loading
Loading