Skip to content

Commit 0bb310a

Browse files
arkodgzirain
authored andcommitted
perf: remove reflect from BackendRefContext (envoyproxy#7015)
* similar to envoyproxy#6820 ``` BenchmarkBackendRefContext_Old_HTTPBackendRef-12 5002508 239.5 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_Old_HTTPBackendRef-12 4764154 264.1 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_Old_HTTPBackendRef-12 4866708 238.6 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_Old_HTTPBackendRef-12 5032014 243.8 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_Old_HTTPBackendRef-12 4935594 259.5 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_Old_GRPCBackendRef-12 4833061 245.3 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_Old_GRPCBackendRef-12 4970496 252.1 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_Old_GRPCBackendRef-12 4517140 253.2 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_Old_GRPCBackendRef-12 4556660 273.4 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_Old_GRPCBackendRef-12 5003169 244.2 ns/op 152 B/op 3 allocs/op BenchmarkBackendRefContext_New_HTTPBackendRef-12 1000000000 0.2556 ns/op 0 B/op 0 allocs/op BenchmarkBackendRefContext_New_HTTPBackendRef-12 1000000000 0.2495 ns/op 0 B/op 0 allocs/op BenchmarkBackendRefContext_New_HTTPBackendRef-12 1000000000 0.2499 ns/op 0 B/op 0 allocs/op BenchmarkBackendRefContext_New_HTTPBackendRef-12 1000000000 0.2576 ns/op 0 B/op 0 allocs/op BenchmarkBackendRefContext_New_HTTPBackendRef-12 1000000000 0.2556 ns/op 0 B/op 0 allocs/op BenchmarkBackendRefContext_New_GRPCBackendRef-12 1000000000 0.2505 ns/op 0 B/op 0 allocs/op BenchmarkBackendRefContext_New_GRPCBackendRef-12 1000000000 0.2504 ns/op 0 B/op 0 allocs/op BenchmarkBackendRefContext_New_GRPCBackendRef-12 1000000000 0.2591 ns/op 0 B/op 0 allocs/op BenchmarkBackendRefContext_New_GRPCBackendRef-12 1000000000 0.2502 ns/op 0 B/op 0 allocs/op BenchmarkBackendRefContext_New_GRPCBackendRef-12 1000000000 0.2483 ns/op 0 B/op 0 allocs/op ``` Signed-off-by: Arko Dasgupta <arko@tetrate.io>
1 parent 538e1e2 commit 0bb310a

File tree

6 files changed

+72
-44
lines changed

6 files changed

+72
-44
lines changed

internal/gatewayapi/contexts.go

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -585,25 +585,35 @@ func (r *RouteParentContext) HasCondition(route RouteContext, condType gwapiv1.R
585585
return false
586586
}
587587

588-
// BackendRefContext represents a generic BackendRef object (HTTPBackendRef, GRPCBackendRef or BackendRef itself)
589-
type BackendRefContext any
588+
// BackendRefContext represents a generic BackendRef object
589+
type BackendRefContext interface {
590+
GetBackendRef() *gwapiv1.BackendRef
591+
GetFilters() any
592+
}
590593

591-
func GetBackendRef(b BackendRefContext) *gwapiv1.BackendRef {
592-
rv := reflect.ValueOf(b)
593-
br := rv.FieldByName("BackendRef")
594-
if br.IsValid() {
595-
backendRef := br.Interface().(gwapiv1.BackendRef)
596-
return &backendRef
597-
}
594+
// BackendRefWithFilters wraps backend refs that have filters (HTTPBackendRef, GRPCBackendRef)
595+
type BackendRefWithFilters struct {
596+
BackendRef *gwapiv1.BackendRef
597+
Filters any // []gwapiv1.HTTPRouteFilter or []gwapiv1.GRPCRouteFilter
598+
}
598599

599-
backendRef := b.(gwapiv1.BackendRef)
600-
return &backendRef
600+
func (b BackendRefWithFilters) GetBackendRef() *gwapiv1.BackendRef {
601+
return b.BackendRef
601602
}
602603

603-
func GetFilters(b BackendRefContext) any {
604-
filters := reflect.ValueOf(b).FieldByName("Filters")
605-
if !filters.IsValid() {
606-
return nil
607-
}
608-
return filters.Interface()
604+
func (b BackendRefWithFilters) GetFilters() any {
605+
return b.Filters
606+
}
607+
608+
// DirectBackendRef wraps a BackendRef directly (used by TLS/TCP/UDP routes)
609+
type DirectBackendRef struct {
610+
BackendRef *gwapiv1.BackendRef
611+
}
612+
613+
func (d DirectBackendRef) GetBackendRef() *gwapiv1.BackendRef {
614+
return d.BackendRef
615+
}
616+
617+
func (d DirectBackendRef) GetFilters() any {
618+
return nil
609619
}

internal/gatewayapi/filters.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -945,12 +945,12 @@ func (t *Translator) processRequestMirrorFilter(
945945
return nil
946946
}
947947

948+
weight := int32(1)
948949
mirrorBackend := mirrorFilter.BackendRef
949950

950-
// Wrap the filter's BackendObjectReference into a BackendRef so we can use existing tooling to check it
951-
weight := int32(1)
952-
mirrorBackendRef := gwapiv1.HTTPBackendRef{
953-
BackendRef: gwapiv1.BackendRef{
951+
// Create a DirectBackendRef for the mirror backend (no filters needed)
952+
mirrorBackendRef := DirectBackendRef{
953+
BackendRef: &gwapiv1.BackendRef{
954954
BackendObjectReference: mirrorBackend,
955955
Weight: &weight,
956956
},

internal/gatewayapi/listener.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,8 @@ func (t *Translator) processBackendRefs(name string, backendCluster egv1a1.Backe
817817
return nil, nil, err
818818
}
819819
result := make([]*ir.DestinationSetting, 0, len(backendCluster.BackendRefs))
820-
for _, ref := range backendCluster.BackendRefs {
820+
for i := range backendCluster.BackendRefs {
821+
ref := &backendCluster.BackendRefs[i]
821822
ns := NamespaceDerefOr(ref.Namespace, namespace)
822823
kind := KindDerefOr(ref.Kind, resource.KindService)
823824
switch kind {

internal/gatewayapi/resource/load.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -544,15 +544,15 @@ func addMissingServices(requiredServices map[string]*corev1.Service, obj interfa
544544
case *gwapiv1.HTTPRoute:
545545
objNamespace = route.Namespace
546546
for _, rule := range route.Spec.Rules {
547-
for _, httpBakcendRef := range rule.BackendRefs {
548-
refs = append(refs, httpBakcendRef.BackendRef)
547+
for i := range rule.BackendRefs {
548+
refs = append(refs, rule.BackendRefs[i].BackendRef)
549549
}
550550
}
551551
case *gwapiv1.GRPCRoute:
552552
objNamespace = route.Namespace
553553
for _, rule := range route.Spec.Rules {
554-
for _, gRPCBakcendRef := range rule.BackendRefs {
555-
refs = append(refs, gRPCBakcendRef.BackendRef)
554+
for i := range rule.BackendRefs {
555+
refs = append(refs, rule.BackendRefs[i].BackendRef)
556556
}
557557
}
558558
case *gwapiv1a2.TLSRoute:

internal/gatewayapi/route.go

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,13 @@ func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRe
218218
backendRefNames := make([]string, len(rule.BackendRefs))
219219
backendCustomRefs := []*ir.UnstructuredRef{}
220220
// process each backendRef, and calculate the destination settings for this rule
221-
for i, backendRef := range rule.BackendRefs {
221+
for i := range rule.BackendRefs {
222222
settingName := irDestinationSettingName(destName, i)
223-
ds, unstructuredRef, err := t.processDestination(settingName, backendRef, parentRef, httpRoute, resources)
223+
backendRefCtx := BackendRefWithFilters{
224+
BackendRef: &rule.BackendRefs[i].BackendRef,
225+
Filters: rule.BackendRefs[i].Filters,
226+
}
227+
ds, unstructuredRef, err := t.processDestination(settingName, backendRefCtx, parentRef, httpRoute, resources)
224228
if err != nil {
225229
errs.Add(status.NewRouteStatusError(
226230
fmt.Errorf("failed to process route rule %d backendRef %d: %w", ruleIdx, i, err),
@@ -242,8 +246,8 @@ func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRe
242246
if ds.IsDynamicResolver {
243247
hasDynamicResolver = true
244248
}
245-
backendNamespace := NamespaceDerefOr(backendRef.Namespace, httpRoute.GetNamespace())
246-
backendRefNames[i] = fmt.Sprintf("%s/%s", backendNamespace, backendRef.Name)
249+
backendNamespace := NamespaceDerefOr(rule.BackendRefs[i].Namespace, httpRoute.GetNamespace())
250+
backendRefNames[i] = fmt.Sprintf("%s/%s", backendNamespace, rule.BackendRefs[i].Name)
247251
}
248252

249253
// process each ir route
@@ -664,9 +668,13 @@ func (t *Translator) processGRPCRouteRules(grpcRoute *GRPCRouteContext, parentRe
664668
failedProcessDestination := false
665669

666670
backendRefNames := make([]string, len(rule.BackendRefs))
667-
for i, backendRef := range rule.BackendRefs {
671+
for i := range rule.BackendRefs {
668672
settingName := irDestinationSettingName(destName, i)
669-
ds, _, err := t.processDestination(settingName, backendRef, parentRef, grpcRoute, resources)
673+
backendRefCtx := BackendRefWithFilters{
674+
BackendRef: &rule.BackendRefs[i].BackendRef,
675+
Filters: rule.BackendRefs[i].Filters,
676+
}
677+
ds, _, err := t.processDestination(settingName, backendRefCtx, parentRef, grpcRoute, resources)
670678
if err != nil {
671679
errs.Add(status.NewRouteStatusError(
672680
fmt.Errorf("failed to process route rule %d backendRef %d: %w", ruleIdx, i, err),
@@ -680,8 +688,8 @@ func (t *Translator) processGRPCRouteRules(grpcRoute *GRPCRouteContext, parentRe
680688
continue
681689
}
682690
allDs = append(allDs, ds)
683-
backendNamespace := NamespaceDerefOr(backendRef.Namespace, grpcRoute.GetNamespace())
684-
backendRefNames[i] = fmt.Sprintf("%s/%s", backendNamespace, backendRef.Name)
691+
backendNamespace := NamespaceDerefOr(rule.BackendRefs[i].Namespace, grpcRoute.GetNamespace())
692+
backendRefNames[i] = fmt.Sprintf("%s/%s", backendNamespace, rule.BackendRefs[i].Name)
685693
}
686694

687695
// process each ir route
@@ -955,9 +963,10 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour
955963

956964
// compute backends
957965
for _, rule := range tlsRoute.Spec.Rules {
958-
for i, backendRef := range rule.BackendRefs {
966+
for i := range rule.BackendRefs {
959967
settingName := irDestinationSettingName(destName, i)
960-
ds, _, err := t.processDestination(settingName, backendRef, parentRef, tlsRoute, resources)
968+
backendRefCtx := DirectBackendRef{BackendRef: &rule.BackendRefs[i]}
969+
ds, _, err := t.processDestination(settingName, backendRefCtx, parentRef, tlsRoute, resources)
961970
if err != nil {
962971
resolveErrs.Add(err)
963972
continue
@@ -1110,9 +1119,10 @@ func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resour
11101119
destName = irRouteDestinationName(udpRoute, -1 /*rule index*/)
11111120
)
11121121

1113-
for i, backendRef := range udpRoute.Spec.Rules[0].BackendRefs {
1122+
for i := range udpRoute.Spec.Rules[0].BackendRefs {
11141123
settingName := irDestinationSettingName(destName, i)
1115-
ds, _, err := t.processDestination(settingName, backendRef, parentRef, udpRoute, resources)
1124+
backendRefCtx := DirectBackendRef{BackendRef: &udpRoute.Spec.Rules[0].BackendRefs[i]}
1125+
ds, _, err := t.processDestination(settingName, backendRefCtx, parentRef, udpRoute, resources)
11161126
if err != nil {
11171127
resolveErrs.Add(err)
11181128
continue
@@ -1258,9 +1268,10 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour
12581268
destName = irRouteDestinationName(tcpRoute, -1 /*rule index*/)
12591269
)
12601270

1261-
for i, backendRef := range tcpRoute.Spec.Rules[0].BackendRefs {
1271+
for i := range tcpRoute.Spec.Rules[0].BackendRefs {
12621272
settingName := irDestinationSettingName(destName, i)
1263-
ds, _, err := t.processDestination(settingName, backendRef, parentRef, tcpRoute, resources)
1273+
backendRefCtx := DirectBackendRef{BackendRef: &tcpRoute.Spec.Rules[0].BackendRefs[i]}
1274+
ds, _, err := t.processDestination(settingName, backendRefCtx, parentRef, tcpRoute, resources)
12641275
// skip adding the route and provide the reason via route status.
12651276
if err != nil {
12661277
resolveErrs.Add(err)
@@ -1373,7 +1384,7 @@ func (t *Translator) processDestination(name string, backendRefContext BackendRe
13731384
) (ds *ir.DestinationSetting, unstructuredRef *ir.UnstructuredRef, err status.Error) {
13741385
routeType := route.GetRouteType()
13751386
weight := uint32(1)
1376-
backendRef := GetBackendRef(backendRefContext)
1387+
backendRef := backendRefContext.GetBackendRef()
13771388
if backendRef.Weight != nil {
13781389
weight = uint32(*backendRef.Weight)
13791390
}
@@ -1604,7 +1615,10 @@ func (t *Translator) processServiceDestinationSetting(
16041615
}
16051616

16061617
func getBackendFilters(routeType gwapiv1.Kind, backendRefContext BackendRefContext) (backendFilters any) {
1607-
filters := GetFilters(backendRefContext)
1618+
filters := backendRefContext.GetFilters()
1619+
if filters == nil {
1620+
return nil
1621+
}
16081622
switch routeType {
16091623
case resource.KindHTTPRoute:
16101624
if len(filters.([]gwapiv1.HTTPRouteFilter)) > 0 {

internal/gatewayapi/validate.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929
func (t *Translator) validateBackendRef(backendRefContext BackendRefContext, route RouteContext,
3030
resources *resource.Resources, backendNamespace string, routeKind gwapiv1.Kind,
3131
) status.Error {
32-
backendRef := GetBackendRef(backendRefContext)
32+
backendRef := backendRefContext.GetBackendRef()
3333

3434
if err := t.validateBackendRefFilters(backendRefContext, routeKind); err != nil {
3535
return err
@@ -91,7 +91,10 @@ func (t *Translator) validateBackendRefKind(backendRef *gwapiv1a2.BackendRef) st
9191
}
9292

9393
func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, routeKind gwapiv1.Kind) status.Error {
94-
filters := GetFilters(backendRef)
94+
filters := backendRef.GetFilters()
95+
if filters == nil {
96+
return nil
97+
}
9598
var unsupportedFilters bool
9699

97100
switch routeKind {

0 commit comments

Comments
 (0)