Skip to content

Commit 6774309

Browse files
authored
feat: bandwidth limit (#8862)
* feat: bandwidth limit Signed-off-by: kkk777-7 <kota.kimura0725@gmail.com> * add: crd validation Signed-off-by: kkk777-7 <kota.kimura0725@gmail.com> --------- Signed-off-by: kkk777-7 <kota.kimura0725@gmail.com>
1 parent de1ae65 commit 6774309

29 files changed

Lines changed: 1317 additions & 5 deletions

api/v1alpha1/backendtrafficpolicy_types.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ type BackendTrafficPolicySpec struct {
6767
// BandwidthLimit allows the user to limit the bandwidth of traffic
6868
// sent to and received from the backend.
6969
// +optional
70-
// +notImplementedHide
7170
BandwidthLimit *BandwidthLimitSpec `json:"bandwidthLimit,omitempty"`
7271

7372
// FaultInjection defines the fault injection policy to be applied. This configuration can be used to

api/v1alpha1/bandwidthlimit_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ type BandwidthLimitResponseTrailers struct {
6969
// "bandwidth-request-filter-delay-ms" is delay time in milliseconds in request stream transfer added by the filter.
7070
// "bandwidth-response-filter-delay-ms" is delay time in milliseconds that added by the filter.
7171
//
72+
// +kubebuilder:validation:Pattern=`^[^\r\n\x00]*$`
7273
// +optional
7374
Prefix *string `json:"prefix,omitempty"`
7475
}

api/v1alpha1/envoyproxy_types.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ type EnvoyProxySpec struct {
142142
//
143143
// - envoy.filters.http.ratelimit
144144
//
145+
// - envoy.filters.http.bandwidth_limit
146+
//
145147
// - envoy.filters.http.grpc_web
146148
//
147149
// - envoy.filters.http.grpc_stats
@@ -286,7 +288,7 @@ type FilterPosition struct {
286288
}
287289

288290
// EnvoyFilter defines the type of Envoy HTTP filter.
289-
// +kubebuilder:validation:Enum=envoy.filters.http.custom_response;envoy.filters.http.health_check;envoy.filters.http.fault;envoy.filters.http.cors;envoy.filters.http.header_mutation;envoy.filters.http.ext_authz;envoy.filters.http.api_key_auth;envoy.filters.http.basic_auth;envoy.filters.http.oauth2;envoy.filters.http.jwt_authn;envoy.filters.http.stateful_session;envoy.filters.http.buffer;envoy.filters.http.lua;envoy.filters.http.ext_proc;envoy.filters.http.wasm;envoy.filters.http.dynamic_modules;envoy.filters.http.geoip;envoy.filters.http.rbac;envoy.filters.http.local_ratelimit;envoy.filters.http.ratelimit;envoy.filters.http.grpc_web;envoy.filters.http.grpc_stats;envoy.filters.http.credential_injector;envoy.filters.http.compressor;envoy.filters.http.dynamic_forward_proxy
291+
// +kubebuilder:validation:Enum=envoy.filters.http.custom_response;envoy.filters.http.health_check;envoy.filters.http.fault;envoy.filters.http.cors;envoy.filters.http.header_mutation;envoy.filters.http.ext_authz;envoy.filters.http.api_key_auth;envoy.filters.http.basic_auth;envoy.filters.http.oauth2;envoy.filters.http.jwt_authn;envoy.filters.http.stateful_session;envoy.filters.http.buffer;envoy.filters.http.lua;envoy.filters.http.ext_proc;envoy.filters.http.wasm;envoy.filters.http.dynamic_modules;envoy.filters.http.geoip;envoy.filters.http.rbac;envoy.filters.http.local_ratelimit;envoy.filters.http.ratelimit;envoy.filters.http.bandwidth_limit;envoy.filters.http.grpc_web;envoy.filters.http.grpc_stats;envoy.filters.http.credential_injector;envoy.filters.http.compressor;envoy.filters.http.dynamic_forward_proxy
290292
type EnvoyFilter string
291293

292294
const (
@@ -351,6 +353,9 @@ const (
351353
// EnvoyFilterRateLimit defines the Envoy HTTP rate limit filter.
352354
EnvoyFilterRateLimit EnvoyFilter = "envoy.filters.http.ratelimit"
353355

356+
// EnvoyFilterBandwidthLimit defines the Envoy HTTP bandwidth limit filter.
357+
EnvoyFilterBandwidthLimit EnvoyFilter = "envoy.filters.http.bandwidth_limit"
358+
354359
// EnvoyFilterGRPCWeb defines the Envoy HTTP gRPC-web filter.
355360
EnvoyFilterGRPCWeb EnvoyFilter = "envoy.filters.http.grpc_web"
356361

charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ spec:
135135
including response body transfer time and the time added by the filter.
136136
"bandwidth-request-filter-delay-ms" is delay time in milliseconds in request stream transfer added by the filter.
137137
"bandwidth-response-filter-delay-ms" is delay time in milliseconds that added by the filter.
138+
pattern: ^[^\r\n\x00]*$
138139
type: string
139140
type: object
140141
required:

charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_envoyproxies.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,8 @@ spec:
451451

452452
- envoy.filters.http.ratelimit
453453

454+
- envoy.filters.http.bandwidth_limit
455+
454456
- envoy.filters.http.grpc_web
455457

456458
- envoy.filters.http.grpc_stats
@@ -493,6 +495,7 @@ spec:
493495
- envoy.filters.http.rbac
494496
- envoy.filters.http.local_ratelimit
495497
- envoy.filters.http.ratelimit
498+
- envoy.filters.http.bandwidth_limit
496499
- envoy.filters.http.grpc_web
497500
- envoy.filters.http.grpc_stats
498501
- envoy.filters.http.credential_injector
@@ -524,6 +527,7 @@ spec:
524527
- envoy.filters.http.rbac
525528
- envoy.filters.http.local_ratelimit
526529
- envoy.filters.http.ratelimit
530+
- envoy.filters.http.bandwidth_limit
527531
- envoy.filters.http.grpc_web
528532
- envoy.filters.http.grpc_stats
529533
- envoy.filters.http.credential_injector
@@ -553,6 +557,7 @@ spec:
553557
- envoy.filters.http.rbac
554558
- envoy.filters.http.local_ratelimit
555559
- envoy.filters.http.ratelimit
560+
- envoy.filters.http.bandwidth_limit
556561
- envoy.filters.http.grpc_web
557562
- envoy.filters.http.grpc_stats
558563
- envoy.filters.http.credential_injector

charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ spec:
134134
including response body transfer time and the time added by the filter.
135135
"bandwidth-request-filter-delay-ms" is delay time in milliseconds in request stream transfer added by the filter.
136136
"bandwidth-response-filter-delay-ms" is delay time in milliseconds that added by the filter.
137+
pattern: ^[^\r\n\x00]*$
137138
type: string
138139
type: object
139140
required:

charts/gateway-helm/charts/crds/crds/generated/gateway.envoyproxy.io_envoyproxies.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ spec:
450450

451451
- envoy.filters.http.ratelimit
452452

453+
- envoy.filters.http.bandwidth_limit
454+
453455
- envoy.filters.http.grpc_web
454456

455457
- envoy.filters.http.grpc_stats
@@ -492,6 +494,7 @@ spec:
492494
- envoy.filters.http.rbac
493495
- envoy.filters.http.local_ratelimit
494496
- envoy.filters.http.ratelimit
497+
- envoy.filters.http.bandwidth_limit
495498
- envoy.filters.http.grpc_web
496499
- envoy.filters.http.grpc_stats
497500
- envoy.filters.http.credential_injector
@@ -523,6 +526,7 @@ spec:
523526
- envoy.filters.http.rbac
524527
- envoy.filters.http.local_ratelimit
525528
- envoy.filters.http.ratelimit
529+
- envoy.filters.http.bandwidth_limit
526530
- envoy.filters.http.grpc_web
527531
- envoy.filters.http.grpc_stats
528532
- envoy.filters.http.credential_injector
@@ -552,6 +556,7 @@ spec:
552556
- envoy.filters.http.rbac
553557
- envoy.filters.http.local_ratelimit
554558
- envoy.filters.http.ratelimit
559+
- envoy.filters.http.bandwidth_limit
555560
- envoy.filters.http.grpc_web
556561
- envoy.filters.http.grpc_stats
557562
- envoy.filters.http.credential_injector

internal/gatewayapi/backendtrafficpolicy.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,7 @@ func (t *Translator) mergeBackendTrafficPolicy(routePolicy, gwPolicy *egv1a1.Bac
10311031
func (t *Translator) buildTrafficFeatures(policy *egv1a1.BackendTrafficPolicy) (*ir.TrafficFeatures, error) {
10321032
var (
10331033
rl *ir.RateLimit
1034+
bl *ir.BandwidthLimit
10341035
lb *ir.LoadBalancer
10351036
pp *ir.ProxyProtocol
10361037
hc *ir.HealthCheck
@@ -1055,6 +1056,12 @@ func (t *Translator) buildTrafficFeatures(policy *egv1a1.BackendTrafficPolicy) (
10551056
errs = errors.Join(errs, err)
10561057
}
10571058
}
1059+
if policy.Spec.BandwidthLimit != nil {
1060+
if bl, err = buildBandwidthLimit(policy.Spec.BandwidthLimit); err != nil {
1061+
err = perr.WithMessage(err, "BandwidthLimit")
1062+
errs = errors.Join(errs, err)
1063+
}
1064+
}
10581065
if lb, err = buildLoadBalancer(&policy.Spec.ClusterSettings); err != nil {
10591066
err = perr.WithMessage(err, "LoadBalancer")
10601067
errs = errors.Join(errs, err)
@@ -1120,6 +1127,7 @@ func (t *Translator) buildTrafficFeatures(policy *egv1a1.BackendTrafficPolicy) (
11201127

11211128
return &ir.TrafficFeatures{
11221129
RateLimit: rl,
1130+
BandwidthLimit: bl,
11231131
LoadBalancer: lb,
11241132
ProxyProtocol: pp,
11251133
HealthCheck: hc,
@@ -1668,6 +1676,73 @@ func int64ToUint32(in int64) (uint32, bool) {
16681676
return 0, false
16691677
}
16701678

1679+
func buildBandwidthLimit(bandwidth *egv1a1.BandwidthLimitSpec) (*ir.BandwidthLimit, error) {
1680+
if bandwidth == nil {
1681+
return nil, nil
1682+
}
1683+
1684+
bl := &ir.BandwidthLimit{}
1685+
1686+
if bandwidth.Request != nil {
1687+
bytes, ok := bandwidth.Request.Limit.Value.AsInt64()
1688+
if !ok {
1689+
return nil, fmt.Errorf("request limit value must be convertible to an int64")
1690+
}
1691+
if bytes < 0 {
1692+
return nil, fmt.Errorf("request limit value must be positive")
1693+
}
1694+
kibps, err := bandwidthToKibps(uint64(bytes), bandwidth.Request.Limit.Unit)
1695+
if err != nil {
1696+
return nil, fmt.Errorf("request: %w", err)
1697+
}
1698+
bl.Request = &ir.BandwidthLimitConfig{
1699+
LimitKibps: kibps,
1700+
}
1701+
}
1702+
if bandwidth.Response != nil {
1703+
bytes, ok := bandwidth.Response.Limit.Value.AsInt64()
1704+
if !ok {
1705+
return nil, fmt.Errorf("response limit value must be convertible to an int64")
1706+
}
1707+
if bytes < 0 {
1708+
return nil, fmt.Errorf("response limit value must be positive")
1709+
}
1710+
kibps, err := bandwidthToKibps(uint64(bytes), bandwidth.Response.Limit.Unit)
1711+
if err != nil {
1712+
return nil, fmt.Errorf("response: %w", err)
1713+
}
1714+
bl.Response = &ir.BandwidthLimitConfig{
1715+
LimitKibps: kibps,
1716+
}
1717+
1718+
if bandwidth.Response.ResponseTrailers != nil {
1719+
bl.Response.ResponseTrailers = &ir.BandwidthLimitResponseTrailers{
1720+
Prefix: bandwidth.Response.ResponseTrailers.Prefix,
1721+
}
1722+
}
1723+
}
1724+
return bl, nil
1725+
}
1726+
1727+
// bandwidthToKibps converts bytes-per-unit to kibibytes-per-second (KiB/s).
1728+
// Returns an error if the result is below Envoy's minimum of 1 KiB/s.
1729+
func bandwidthToKibps(limit uint64, unit egv1a1.BandwidthLimitUnit) (uint64, error) {
1730+
var secondsPerUnit uint64
1731+
switch unit {
1732+
case egv1a1.BandwidthLimitUnitMinute:
1733+
secondsPerUnit = 60
1734+
case egv1a1.BandwidthLimitUnitHour:
1735+
secondsPerUnit = 3600
1736+
default: // Second
1737+
secondsPerUnit = 1
1738+
}
1739+
kibps := limit / (secondsPerUnit * 1024)
1740+
if kibps == 0 {
1741+
return 0, fmt.Errorf("bandwidth limit of %d bytes per %s is below the minimum of 1 KiB/s", limit, unit)
1742+
}
1743+
return kibps, nil
1744+
}
1745+
16711746
func (t *Translator) buildFaultInjection(policy *egv1a1.BackendTrafficPolicy) *ir.FaultInjection {
16721747
var (
16731748
fi *ir.FaultInjection
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
gateways:
2+
- apiVersion: gateway.networking.k8s.io/v1
3+
kind: Gateway
4+
metadata:
5+
namespace: envoy-gateway
6+
name: gateway-1
7+
spec:
8+
gatewayClassName: envoy-gateway-class
9+
listeners:
10+
- name: http
11+
protocol: HTTP
12+
port: 80
13+
allowedRoutes:
14+
namespaces:
15+
from: All
16+
httpRoutes:
17+
- apiVersion: gateway.networking.k8s.io/v1
18+
kind: HTTPRoute
19+
metadata:
20+
namespace: default
21+
name: httproute-1
22+
spec:
23+
hostnames:
24+
- gateway.envoyproxy.io
25+
parentRefs:
26+
- namespace: envoy-gateway
27+
name: gateway-1
28+
sectionName: http
29+
rules:
30+
- matches:
31+
- path:
32+
value: "/"
33+
backendRefs:
34+
- name: service-1
35+
port: 8080
36+
backendTrafficPolicies:
37+
- apiVersion: gateway.envoyproxy.io/v1alpha1
38+
kind: BackendTrafficPolicy
39+
metadata:
40+
namespace: envoy-gateway
41+
name: policy-for-gateway
42+
spec:
43+
targetRefs:
44+
- group: gateway.networking.k8s.io
45+
kind: Gateway
46+
name: gateway-1
47+
bandwidthLimit:
48+
request:
49+
limit:
50+
value: 1023
51+
unit: Second

0 commit comments

Comments
 (0)