Skip to content

Commit

Permalink
feat: support new app protocols (#469)
Browse files Browse the repository at this point in the history
* feat: support new app protocols

Signed-off-by: Lin Yang <[email protected]>

* fix: only generate config with FGW supported app protocols

Signed-off-by: Lin Yang <[email protected]>

---------

Signed-off-by: Lin Yang <[email protected]>
  • Loading branch information
reaver-flomesh authored Nov 23, 2024
1 parent 6627e54 commit 4b19032
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 30 deletions.
18 changes: 15 additions & 3 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,9 +568,21 @@ const (

// GatewayAPI Backend Protocol Selection constants
const (
AppProtocolH2C = "kubernetes.io/h2c"
AppProtocolWS = "kubernetes.io/ws"
AppProtocolWSS = "kubernetes.io/wss"
// standard app protocols

K8sAppProtocolH2C = "kubernetes.io/h2c"
K8sAppProtocolWS = "kubernetes.io/ws"
K8sAppProtocolWSS = "kubernetes.io/wss"
FlomeshAppProtocolHTTP = "gateway.flomesh.io/http"
FlomeshAppProtocolGRPC = "gateway.flomesh.io/grpc"

// shortcuts for the standard app protocol

AppProtocolH2C = "h2c"
AppProtocolWS = "ws"
AppProtocolWSS = "wss"
AppProtocolHTTP = "http"
AppProtocolGRPC = "grpc"
)

// PIPY Repo constants
Expand Down
21 changes: 19 additions & 2 deletions pkg/gateway/processor/v2/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"net"
"strings"

"github.com/flomesh-io/fsm/pkg/constants"

corev1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"

Expand Down Expand Up @@ -60,9 +62,24 @@ func toFGWAppProtocol(appProtocol *string) *string {
} {
if strings.HasPrefix(*appProtocol, prefix) {
after, _ := strings.CutPrefix(*appProtocol, prefix)
return ptr.To(after)
if isFGWAppProtocolSupported(after) {
return ptr.To(after)
}
}
}

return appProtocol
if isFGWAppProtocolSupported(*appProtocol) {
return appProtocol
}

return nil
}

func isFGWAppProtocolSupported(appProtocol string) bool {
switch appProtocol {
case constants.AppProtocolH2C, constants.AppProtocolWS, constants.AppProtocolWSS:
return true
default:
return false
}
}
32 changes: 24 additions & 8 deletions pkg/gateway/status/routes/grpcroute.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ import (
"github.com/flomesh-io/fsm/pkg/gateway/status"
)

var (
validGRPCRouteAppProtocols = []string{
constants.K8sAppProtocolH2C,
constants.K8sAppProtocolWS,
constants.K8sAppProtocolWSS,
constants.FlomeshAppProtocolHTTP,
constants.FlomeshAppProtocolGRPC,
constants.AppProtocolH2C,
constants.AppProtocolWS,
constants.AppProtocolWSS,
constants.AppProtocolHTTP,
constants.AppProtocolGRPC,
}
)

func (p *RouteStatusProcessor) processGRPCRouteStatus(route *gwv1.GRPCRoute, parentRef gwv1.ParentReference, rps status.RouteParentStatusObject) bool {
for _, rule := range route.Spec.Rules {
if !p.processGRPCRouteRuleBackendRefs(route, rps, parentRef, rule.BackendRefs) {
Expand Down Expand Up @@ -39,18 +54,19 @@ func (p *RouteStatusProcessor) processGRPCRouteBackend(route *gwv1.GRPCRoute, pa
return false
}

if svcPort.Protocol != corev1.ProtocolTCP {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, fmt.Sprintf("Unsupported protocol %q for backend %s", svcPort.Protocol, svcPort.String()))
return false
}

if svcPort.AppProtocol != nil {
switch *svcPort.AppProtocol {
case constants.AppProtocolH2C:
log.Debug().Msgf("Backend Protocol: %q for service port %q", *svcPort.AppProtocol, svcPort.String())
if svcPort.Protocol != corev1.ProtocolTCP {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, fmt.Sprintf("Unsupported AppProtocol %q for protocol %q", *svcPort.AppProtocol, svcPort.Protocol))
return false
}
default:
if !isSupportedAppProtocol(*svcPort.AppProtocol, validGRPCRouteAppProtocols) {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, fmt.Sprintf("Unsupported AppProtocol %q", *svcPort.AppProtocol))
return false
}
} else {
// Default to HTTP
p.addNormalEvent(route, "AppProtocol", fmt.Sprintf("Defaulting to HTTP/1 app protocol for backend %s", svcPort.String()))
}

p.computeBackendTLSPolicyStatus(route, bk.BackendObjectReference, svcPort, parentRef, func(found bool) {})
Expand Down
32 changes: 23 additions & 9 deletions pkg/gateway/status/routes/httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ import (
"github.com/flomesh-io/fsm/pkg/gateway/status"
)

var (
validHTTPRouteAppProtocols = []string{
constants.K8sAppProtocolH2C,
constants.K8sAppProtocolWS,
constants.K8sAppProtocolWSS,
constants.FlomeshAppProtocolHTTP,
constants.AppProtocolH2C,
constants.AppProtocolWS,
constants.AppProtocolWSS,
constants.AppProtocolHTTP,
}
)

func (p *RouteStatusProcessor) processHTTPRouteStatus(route *gwv1.HTTPRoute, parentRef gwv1.ParentReference, rps status.RouteParentStatusObject) bool {
for _, rule := range route.Spec.Rules {
if !p.processHTTPRouteRuleBackendRefs(route, parentRef, rule.BackendRefs, rps) {
Expand Down Expand Up @@ -39,26 +52,27 @@ func (p *RouteStatusProcessor) processHTTPRouteBackend(route *gwv1.HTTPRoute, pa
return false
}

if svcPort.Protocol != corev1.ProtocolTCP {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, fmt.Sprintf("Unsupported protocol %q for backend %s", svcPort.Protocol, svcPort.String()))
return false
}

if svcPort.AppProtocol != nil {
switch *svcPort.AppProtocol {
case constants.AppProtocolH2C, constants.AppProtocolWS, constants.AppProtocolWSS:
log.Debug().Msgf("Backend Protocol: %q for service port %q", *svcPort.AppProtocol, svcPort.String())
if svcPort.Protocol != corev1.ProtocolTCP {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, fmt.Sprintf("Unsupported AppProtocol %q for protocol %q", *svcPort.AppProtocol, svcPort.Protocol))
return false
}
default:
if !isSupportedAppProtocol(*svcPort.AppProtocol, validHTTPRouteAppProtocols) {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, fmt.Sprintf("Unsupported AppProtocol %q", *svcPort.AppProtocol))
return false
}
} else {
// Default to HTTP
p.addNormalEvent(route, "AppProtocol", fmt.Sprintf("Defaulting to HTTP/1 app protocol for backend %s", svcPort.String()))
}

if !func() bool {
valid := true
p.computeBackendTLSPolicyStatus(route, bk.BackendObjectReference, svcPort, parentRef, func(found bool) {
if !found {
if svcPort.AppProtocol != nil &&
*svcPort.AppProtocol == constants.AppProtocolWSS &&
*svcPort.AppProtocol == constants.K8sAppProtocolWSS &&
svcPort.Protocol == corev1.ProtocolTCP {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, fmt.Sprintf("No matching BackendTLSPolicy was found for the backend protocol %q and appProtocol %q", svcPort.Protocol, *svcPort.AppProtocol))
valid = false
Expand Down
14 changes: 11 additions & 3 deletions pkg/gateway/status/routes/methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func (p *RouteStatusProcessor) addNotAcceptedCondition(route client.Object, rps status.RouteConditionAccessor, reason gwv1.RouteConditionReason, message string) {
defer p.recorder.Eventf(route, corev1.EventTypeWarning, string(reason), message)
p.addWarningEvent(route, string(reason), message)

rps.AddCondition(
gwv1.RouteConditionAccepted,
Expand All @@ -21,7 +21,7 @@ func (p *RouteStatusProcessor) addNotAcceptedCondition(route client.Object, rps
}

func (p *RouteStatusProcessor) addNotResolvedRefsCondition(route client.Object, rps status.RouteConditionAccessor, reason gwv1.RouteConditionReason, message string) {
defer p.recorder.Eventf(route, corev1.EventTypeWarning, string(reason), message)
p.addWarningEvent(route, string(reason), message)

rps.AddCondition(
gwv1.RouteConditionResolvedRefs,
Expand All @@ -32,7 +32,7 @@ func (p *RouteStatusProcessor) addNotResolvedRefsCondition(route client.Object,
}

func (p *RouteStatusProcessor) addResolvedRefsCondition(route client.Object, rps status.RouteConditionAccessor, reason gwv1.RouteConditionReason, message string) {
defer p.recorder.Eventf(route, corev1.EventTypeNormal, string(reason), message)
p.addNormalEvent(route, string(reason), message)

rps.AddCondition(
gwv1.RouteConditionResolvedRefs,
Expand All @@ -41,3 +41,11 @@ func (p *RouteStatusProcessor) addResolvedRefsCondition(route client.Object, rps
message,
)
}

func (p *RouteStatusProcessor) addNormalEvent(route client.Object, reason string, message string) {
defer p.recorder.Eventf(route, corev1.EventTypeNormal, reason, message)
}

func (p *RouteStatusProcessor) addWarningEvent(route client.Object, reason string, message string) {
defer p.recorder.Eventf(route, corev1.EventTypeWarning, reason, message)
}
8 changes: 8 additions & 0 deletions pkg/gateway/status/routes/tcproute.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package routes

import (
"fmt"

corev1 "k8s.io/api/core/v1"
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"

Expand Down Expand Up @@ -36,6 +39,11 @@ func (p *RouteStatusProcessor) processTCPRouteBackend(route *gwv1alpha2.TCPRoute
return false
}

if svcPort.Protocol != corev1.ProtocolTCP {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, fmt.Sprintf("Unsupported protocol %q for backend %s", svcPort.Protocol, svcPort.String()))
return false
}

if svcPort.AppProtocol != nil {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, "AppProtocol is not supported for TCPRoute backend")
return false
Expand Down
8 changes: 3 additions & 5 deletions pkg/gateway/status/routes/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (

"k8s.io/client-go/tools/record"

"github.com/flomesh-io/fsm/pkg/logger"

corev1 "k8s.io/api/core/v1"

gwutils "github.com/flomesh-io/fsm/pkg/gateway/utils"
Expand All @@ -22,9 +20,9 @@ import (
"github.com/flomesh-io/fsm/pkg/gateway/status"
)

var (
log = logger.New("fsm-gateway/status/route")
)
//var (
// log = logger.New("fsm-gateway/status/route")
//)

type PolicyObjectReferenceConditionProvider struct {
ancestorStatus status.PolicyAncestorStatusObject
Expand Down
8 changes: 8 additions & 0 deletions pkg/gateway/status/routes/udproute.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package routes

import (
"fmt"

corev1 "k8s.io/api/core/v1"
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"

Expand Down Expand Up @@ -36,6 +39,11 @@ func (p *RouteStatusProcessor) processUDPRouteBackend(route *gwv1alpha2.UDPRoute
return false
}

if svcPort.Protocol != corev1.ProtocolUDP {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, fmt.Sprintf("Unsupported protocol %q for backend %s", svcPort.Protocol, svcPort.String()))
return false
}

if svcPort.AppProtocol != nil {
p.addNotResolvedRefsCondition(route, rps, gwv1.RouteReasonUnsupportedProtocol, "AppProtocol is not supported for UDPRoute backend")
return false
Expand Down
11 changes: 11 additions & 0 deletions pkg/gateway/status/routes/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package routes

func isSupportedAppProtocol(appProtocol string, allowedAppProtocols []string) bool {
for _, allowed := range allowedAppProtocols {
if appProtocol == allowed {
return true
}
}

return false
}

0 comments on commit 4b19032

Please sign in to comment.