Skip to content

Commit fa2e597

Browse files
author
Arko Dasgupta
committed
perf: preallocate structs in securitypolicy processing
Signed-off-by: Arko Dasgupta <arko@tetrate.io>
1 parent bd44c36 commit fa2e597

File tree

1 file changed

+74
-45
lines changed

1 file changed

+74
-45
lines changed

internal/gatewayapi/securitypolicy.go

Lines changed: 74 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -61,26 +61,39 @@ func (t *Translator) ProcessSecurityPolicies(securityPolicies []*egv1a1.Security
6161

6262
// First build a map out of the routes and gateways for faster lookup since users might have thousands of routes or more.
6363
// For gateways this probably isn't quite as necessary.
64-
routeMap := map[policyTargetRouteKey]*policyRouteTargetContext{}
64+
routeMapSize := len(routes)
65+
gatewayMapSize := len(gateways)
66+
policyMapSize := len(securityPolicies)
67+
68+
// Pre-allocate result slice and maps with estimated capacity to reduce memory allocations
69+
res = make([]*egv1a1.SecurityPolicy, 0, len(securityPolicies))
70+
routeMap := make(map[policyTargetRouteKey]*policyRouteTargetContext, routeMapSize)
6571
for _, route := range routes {
6672
key := policyTargetRouteKey{
6773
Kind: string(route.GetRouteType()),
6874
Name: route.GetName(),
6975
Namespace: route.GetNamespace(),
7076
}
71-
routeMap[key] = &policyRouteTargetContext{RouteContext: route, attachedToRouteRules: make(sets.Set[string])}
77+
routeMap[key] = &policyRouteTargetContext{
78+
RouteContext: route,
79+
attachedToRouteRules: make(sets.Set[string]),
80+
}
7281
}
73-
gatewayMap := map[types.NamespacedName]*policyGatewayTargetContext{}
82+
83+
gatewayMap := make(map[types.NamespacedName]*policyGatewayTargetContext, gatewayMapSize)
7484
for _, gw := range gateways {
7585
key := utils.NamespacedName(gw)
76-
gatewayMap[key] = &policyGatewayTargetContext{GatewayContext: gw, attachedToListeners: make(sets.Set[string])}
86+
gatewayMap[key] = &policyGatewayTargetContext{
87+
GatewayContext: gw,
88+
attachedToListeners: make(sets.Set[string]),
89+
}
7790
}
7891

7992
// Map of Gateway to the routes attached to it.
8093
// The routes are grouped by sectionNames of their targetRefs
81-
gatewayRouteMap := make(map[string]map[string]sets.Set[string])
94+
gatewayRouteMap := make(map[string]map[string]sets.Set[string], gatewayMapSize)
8295

83-
handledPolicies := make(map[types.NamespacedName]*egv1a1.SecurityPolicy)
96+
handledPolicies := make(map[types.NamespacedName]*egv1a1.SecurityPolicy, policyMapSize)
8497

8598
// Translate
8699
// 1. First translate Policies targeting RouteRules
@@ -623,10 +636,33 @@ func (t *Translator) translateSecurityPolicyForRoute(
623636
}
624637
}
625638

639+
// Pre-create security features to avoid repeated allocations
640+
securityFeatures := &ir.SecurityFeatures{
641+
CORS: cors,
642+
JWT: jwt,
643+
OIDC: oidc,
644+
APIKeyAuth: apiKeyAuth,
645+
BasicAuth: basicAuth,
646+
ExtAuth: extAuth,
647+
Authorization: authorization,
648+
}
649+
650+
// Pre-create error response to avoid repeated allocations
651+
var errorResponse *ir.CustomResponse
652+
if errs != nil {
653+
shouldFailOpen := extAuthErr != nil && !hasNonExtAuthError && ptr.Deref(policy.Spec.ExtAuth.FailOpen, false)
654+
if !shouldFailOpen {
655+
errorResponse = &ir.CustomResponse{
656+
StatusCode: ptr.To(uint32(500)),
657+
}
658+
}
659+
}
660+
626661
irKey := t.getIRKey(gtwCtx.Gateway)
627662
for _, listener := range parentRefCtx.listeners {
628663
irListener := xdsIR[irKey].GetHTTPListener(irListenerName(listener))
629664
if irListener != nil {
665+
630666
for _, r := range irListener.Routes {
631667
// If specified the sectionName must match route rule from ir route metadata.
632668
if target.SectionName != nil && string(*target.SectionName) != r.Metadata.SectionName {
@@ -641,26 +677,10 @@ func (t *Translator) translateSecurityPolicyForRoute(
641677
continue
642678
}
643679

644-
r.Security = &ir.SecurityFeatures{
645-
CORS: cors,
646-
JWT: jwt,
647-
OIDC: oidc,
648-
APIKeyAuth: apiKeyAuth,
649-
BasicAuth: basicAuth,
650-
ExtAuth: extAuth,
651-
Authorization: authorization,
652-
}
653-
if errs != nil {
654-
// If there is only error for ext auth and ext auth is set to fail open, then skip the ext auth
655-
// and allow the request to go through.
656-
// Otherwise, return a 500 direct response to avoid unauthorized access.
657-
shouldFailOpen := extAuthErr != nil && !hasNonExtAuthError && ptr.Deref(policy.Spec.ExtAuth.FailOpen, false)
658-
if !shouldFailOpen {
659-
// Return a 500 direct response to avoid unauthorized access
660-
r.DirectResponse = &ir.CustomResponse{
661-
StatusCode: ptr.To(uint32(500)),
662-
}
663-
}
680+
r.Security = securityFeatures
681+
if errorResponse != nil {
682+
// Return a 500 direct response to avoid unauthorized access
683+
r.DirectResponse = errorResponse
664684
}
665685
}
666686
}
@@ -761,6 +781,30 @@ func (t *Translator) translateSecurityPolicyForGateway(
761781
// Should exist since we've validated this
762782
x := xdsIR[irKey]
763783

784+
// Pre-create security features and error response to avoid repeated allocations
785+
securityFeatures := &ir.SecurityFeatures{
786+
CORS: cors,
787+
JWT: jwt,
788+
OIDC: oidc,
789+
APIKeyAuth: apiKeyAuth,
790+
BasicAuth: basicAuth,
791+
ExtAuth: extAuth,
792+
Authorization: authorization,
793+
}
794+
795+
var errorResponse *ir.CustomResponse
796+
if errs != nil {
797+
// If there is only error for ext auth and ext auth is set to fail open, then skip the ext auth
798+
// and allow the request to go through.
799+
// Otherwise, return a 500 direct response to avoid unauthorized access.
800+
shouldFailOpen := extAuthErr != nil && !hasNonExtAuthError && ptr.Deref(policy.Spec.ExtAuth.FailOpen, false)
801+
if !shouldFailOpen {
802+
errorResponse = &ir.CustomResponse{
803+
StatusCode: ptr.To(uint32(500)),
804+
}
805+
}
806+
}
807+
764808
policyTarget := irStringKey(policy.Namespace, string(target.Name))
765809
for _, h := range x.HTTP {
766810
// A HTTPListener name has the format namespace/gatewayName/listenerName
@@ -773,32 +817,17 @@ func (t *Translator) translateSecurityPolicyForGateway(
773817
if target.SectionName != nil && string(*target.SectionName) != h.Metadata.SectionName {
774818
continue
775819
}
820+
776821
// A Policy targeting the specific scope(xRoute rule, xRoute, Gateway listener) wins over a policy
777822
// targeting a lesser specific scope(Gateway).
778823
for _, r := range h.Routes {
779824
// if already set - there's a specific level policy, so skip.
780825
if r.Security != nil {
781826
continue
782827
}
783-
r.Security = &ir.SecurityFeatures{
784-
CORS: cors,
785-
JWT: jwt,
786-
OIDC: oidc,
787-
APIKeyAuth: apiKeyAuth,
788-
BasicAuth: basicAuth,
789-
ExtAuth: extAuth,
790-
Authorization: authorization,
791-
}
792-
if errs != nil {
793-
// If there is only error for ext auth and ext auth is set to fail open, then skip the ext auth
794-
// and allow the request to go through.
795-
// Otherwise, return a 500 direct response to avoid unauthorized access.
796-
shouldFailOpen := extAuthErr != nil && !hasNonExtAuthError && ptr.Deref(policy.Spec.ExtAuth.FailOpen, false)
797-
if !shouldFailOpen {
798-
r.DirectResponse = &ir.CustomResponse{
799-
StatusCode: ptr.To(uint32(500)),
800-
}
801-
}
828+
r.Security = securityFeatures
829+
if errorResponse != nil {
830+
r.DirectResponse = errorResponse
802831
}
803832
}
804833
}

0 commit comments

Comments
 (0)