Skip to content

Commit d89df03

Browse files
authored
fix: calculate HTTPRoute Priority (#128)
Signed-off-by: ashing <[email protected]>
1 parent 8e158ce commit d89df03

File tree

9 files changed

+77
-66
lines changed

9 files changed

+77
-66
lines changed

.github/workflows/conformance-test.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ jobs:
9999
continue-on-error: true
100100
run: |
101101
make conformance-test
102+
103+
- name: Get Logs from api7-ingress-controller
104+
shell: bash
105+
run: |
106+
export KUBECONFIG=/tmp/api7-ingress-cluster.kubeconfig
107+
kubectl logs -n api7ee-conformance-test -l app=api7-ingress-controller
102108
103109
- name: Upload Gateway API Conformance Report
104110
if: ${{ github.event_name == 'push' }}

internal/provider/adc/cache/cache.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
// Licensed to the Apache Software Foundation (ASF) under one or more
2-
// contributor license agreements. See the NOTICE file distributed with
3-
// this work for additional information regarding copyright ownership.
4-
// The ASF licenses this file to You under the Apache License, Version 2.0
5-
// (the "License"); you may not use this file except in compliance with
6-
// the License. You may obtain a copy of the License at
1+
// Licensed under the Apache License, Version 2.0 (the "License");
2+
// you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at
74
//
85
// http://www.apache.org/licenses/LICENSE-2.0
96
//

internal/provider/adc/cache/memdb.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,3 @@
1-
// Licensed to the Apache Software Foundation (ASF) under one or more
2-
// contributor license agreements. See the NOTICE file distributed with
3-
// this work for additional information regarding copyright ownership.
4-
// The ASF licenses this file to You under the Apache License, Version 2.0
5-
// (the "License"); you may not use this file except in compliance with
6-
// the License. You may obtain a copy of the License at
7-
//
8-
// http://www.apache.org/licenses/LICENSE-2.0
9-
//
10-
// Unless required by applicable law or agreed to in writing, software
11-
// distributed under the License is distributed on an "AS IS" BASIS,
12-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
// See the License for the specific language governing permissions and
14-
// limitations under the License.
15-
161
package cache
172

183
import (

internal/provider/adc/cache/schema.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,3 @@
1-
// Licensed to the Apache Software Foundation (ASF) under one or more
2-
// contributor license agreements. See the NOTICE file distributed with
3-
// this work for additional information regarding copyright ownership.
4-
// The ASF licenses this file to You under the Apache License, Version 2.0
5-
// (the "License"); you may not use this file except in compliance with
6-
// the License. You may obtain a copy of the License at
7-
//
8-
// http://www.apache.org/licenses/LICENSE-2.0
9-
//
10-
// Unless required by applicable law or agreed to in writing, software
11-
// distributed under the License is distributed on an "AS IS" BASIS,
12-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
// See the License for the specific language governing permissions and
14-
// limitations under the License.
15-
161
package cache
172

183
import (

internal/provider/adc/store.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,11 @@ func (s *Store) Delete(name string, resourceTypes []string, Labels map[string]st
151151
delete(s.globalruleMap, name)
152152
case "plugin_metadata":
153153
delete(s.pluginMetadataMap, name)
154-
default:
155-
delete(s.cacheMap, name)
156154
}
157155
}
156+
if len(resourceTypes) == 0 {
157+
delete(s.cacheMap, name)
158+
}
158159
return nil
159160
}
160161

internal/provider/adc/translator/httproute.go

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ package translator
1515
import (
1616
"encoding/json"
1717
"fmt"
18-
"sort"
1918
"strings"
2019

2120
"github.com/api7/gopkg/pkg/log"
@@ -354,31 +353,61 @@ func (t *Translator) translateBackendRef(tctx *provider.TranslateContext, ref ga
354353
return t.translateEndpointSlice(portName, weight, endpointSlices)
355354
}
356355

357-
// calculateMatchPriority calculate the priority of HTTPRouteMatch, according to the Gateway API specification
358-
// the higher the return value, the higher the priority
359-
func calculateMatchPriority(match *gatewayv1.HTTPRouteMatch) int64 {
360-
var score int64 = 0
356+
// calculateHTTPRoutePriority calculates the priority of the HTTP route.
357+
// ref: https://github.com/Kong/kubernetes-ingress-controller/blob/57472721319e2c63e56cb8540425257e8e02520f/internal/dataplane/translator/subtranslator/httproute_atc.go#L279-L296
358+
func calculateHTTPRoutePriority(match *gatewayv1.HTTPRouteMatch, ruleIndex int) uint64 {
359+
const (
360+
// ExactPathShiftBits assigns bit 34 to mark if the match is exact path match.
361+
ExactPathShiftBits = 34
362+
// PathLengthShiftBits assigns bits 23-32 to path length. (max length = 1024, but must start with /)
363+
PathLengthShiftBits = 23
364+
// MethodMatchShiftBits assigns bit 22 to mark if method is specified.
365+
MethodMatchShiftBits = 22
366+
// HeaderNumberShiftBits assign bits 17-21 to number of headers. (max number of headers = 16)
367+
HeaderNumberShiftBits = 17
368+
// QueryParamNumberShiftBits makes bits 12-16 used for number of query params (max number of query params = 16)
369+
QueryParamNumberShiftBits = 12
370+
// RuleIndexShiftBits assigns bits 7-11 to rule index. (max number of rules = 16)
371+
RuleIndexShiftBits = 7
372+
)
373+
374+
var priority uint64 = 0
361375

362-
// 1. Exact path matches have the highest priority
376+
// ExactPathShiftBits
363377
if match.Path != nil && match.Path.Type != nil && *match.Path.Type == gatewayv1.PathMatchExact {
364-
score += 10000
365-
} else if match.Path != nil && match.Path.Type != nil && *match.Path.Type == gatewayv1.PathMatchPathPrefix && match.Path.Value != nil {
366-
// 2. Prefix path matches, the longer the string, the higher the priority
367-
score += 1000 + int64(len(*match.Path.Value))
378+
priority |= (1 << ExactPathShiftBits)
379+
}
380+
381+
// PathLengthShiftBits
382+
// max length of path is 1024, but path must start with /, so we use PathLength-1 to fill the bits.
383+
if match.Path != nil && match.Path.Value != nil {
384+
pathLength := len(*match.Path.Value)
385+
if pathLength > 0 {
386+
priority |= (uint64(pathLength-1) << PathLengthShiftBits)
387+
}
368388
}
369389

370-
// 3. Method matching
390+
// MethodMatchShiftBits
371391
if match.Method != nil {
372-
score += 100
392+
priority |= (1 << MethodMatchShiftBits)
373393
}
374394

375-
// 4. Header matching, the more headers, the higher the priority
376-
score += int64(len(match.Headers) * 10)
395+
// HeaderNumberShiftBits
396+
headerCount := len(match.Headers)
397+
priority |= (uint64(headerCount) << HeaderNumberShiftBits)
377398

378-
// 5. Query parameter matching, the more query parameters, the higher the priority
379-
score += int64(len(match.QueryParams))
399+
// QueryParamNumberShiftBits
400+
queryParamCount := len(match.QueryParams)
401+
priority |= (uint64(queryParamCount) << QueryParamNumberShiftBits)
380402

381-
return score
403+
// RuleIndexShiftBits
404+
index := 16 - ruleIndex
405+
if index < 0 {
406+
index = 0
407+
}
408+
priority |= (uint64(index) << RuleIndexShiftBits)
409+
410+
return priority
382411
}
383412

384413
func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRoute *gatewayv1.HTTPRoute) (*TranslateResult, error) {
@@ -393,7 +422,7 @@ func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRou
393422

394423
labels := label.GenLabel(httpRoute)
395424

396-
for i, rule := range rules {
425+
for ruleIndex, rule := range rules {
397426
upstream := adctypes.NewDefaultUpstream()
398427
for _, backend := range rule.BackendRefs {
399428
if backend.Namespace == nil {
@@ -410,7 +439,7 @@ func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRou
410439
service := adctypes.NewDefaultService()
411440
service.Labels = labels
412441

413-
service.Name = adctypes.ComposeServiceNameWithRule(httpRoute.Namespace, httpRoute.Name, fmt.Sprintf("%d", i))
442+
service.Name = adctypes.ComposeServiceNameWithRule(httpRoute.Namespace, httpRoute.Name, fmt.Sprintf("%d", ruleIndex))
414443
service.ID = id.GenID(service.Name)
415444
service.Hosts = hosts
416445
service.Upstream = upstream
@@ -428,11 +457,6 @@ func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRou
428457
},
429458
},
430459
}
431-
} else {
432-
// Sort the matches by priority
433-
sort.Slice(matches, func(a, b int) bool {
434-
return calculateMatchPriority(&matches[a]) > calculateMatchPriority(&matches[b])
435-
})
436460
}
437461

438462
routes := []*adctypes.Route{}
@@ -442,15 +466,15 @@ func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRou
442466
return nil, err
443467
}
444468

445-
name := adctypes.ComposeRouteName(httpRoute.Namespace, httpRoute.Name, fmt.Sprintf("%d-%d", i, j))
469+
name := adctypes.ComposeRouteName(httpRoute.Namespace, httpRoute.Name, fmt.Sprintf("%d-%d", ruleIndex, j))
446470
route.Name = name
447471
route.ID = id.GenID(name)
448472
route.Labels = labels
449473
route.EnableWebsocket = ptr.To(true)
450474

451475
// Set the route priority
452-
priority := calculateMatchPriority(&match)
453-
route.Priority = &priority
476+
priority := calculateHTTPRoutePriority(&match, ruleIndex)
477+
route.Priority = ptr.To(int64(priority))
454478

455479
routes = append(routes, route)
456480
}

test/conformance/suite_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
// Licensed under the Apache License, Version 2.0 (the "License");
2+
// you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at
4+
//
5+
// http://www.apache.org/licenses/LICENSE-2.0
6+
//
7+
// Unless required by applicable law or agreed to in writing, software
8+
// distributed under the License is distributed on an "AS IS" BASIS,
9+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
// See the License for the specific language governing permissions and
11+
// limitations under the License.
112
package conformance
213

314
import (
@@ -149,6 +160,7 @@ func TestMain(m *testing.M) {
149160
Namespace: namespace,
150161
AdminEnpoint: framework.DashboardTLSEndpoint,
151162
StatusAddress: address,
163+
InitSyncDelay: 30 * time.Minute,
152164
})
153165

154166
defaultGatewayProxyOpts = GatewayProxyOpts{

test/e2e/framework/ingress.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type IngressDeployOpts struct {
4646
AdminEnpoint string
4747
StatusAddress string
4848
Replicas int
49+
InitSyncDelay time.Duration
4950
}
5051

5152
func (f *Framework) DeployIngress(opts IngressDeployOpts) {

test/e2e/framework/manifests/ingress.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ data:
345345
# The period between two consecutive syncs.
346346
# The default value is 0 seconds, which means the controller will not sync.
347347
# If you want to enable the sync, set it to a positive value.
348-
init_sync_delay: 1m
348+
init_sync_delay: {{ .InitSyncDelay | default "1m" }}
349349
---
350350
apiVersion: v1
351351
kind: Service

0 commit comments

Comments
 (0)