Skip to content

Commit 45fa6c6

Browse files
committed
feat: bandwidth limit
Signed-off-by: kkk777-7 <kota.kimura0725@gmail.com>
1 parent e098718 commit 45fa6c6

25 files changed

Lines changed: 1212 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/envoyproxy_types.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ type EnvoyProxySpec struct {
150150
//
151151
// - envoy.filters.http.compressor
152152
//
153+
// - envoy.filters.http.bandwidth_limit
154+
//
153155
// - envoy.filters.http.dynamic_forward_proxy
154156
//
155157
// - envoy.filters.http.router
@@ -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.grpc_web;envoy.filters.http.grpc_stats;envoy.filters.http.credential_injector;envoy.filters.http.compressor;envoy.filters.http.bandwidth_limit;envoy.filters.http.dynamic_forward_proxy
290292
type EnvoyFilter string
291293

292294
const (
@@ -363,6 +365,9 @@ const (
363365
// EnvoyFilterCompressor defines the Envoy HTTP compressor filter.
364366
EnvoyFilterCompressor EnvoyFilter = "envoy.filters.http.compressor"
365367

368+
// EnvoyFilterBandwidthLimit defines the Envoy HTTP bandwidth limit filter.
369+
EnvoyFilterBandwidthLimit EnvoyFilter = "envoy.filters.http.bandwidth_limit"
370+
366371
// EnvoyFilterDynamicForwardProxy defines the Envoy HTTP dynamic forward proxy filter.
367372
EnvoyFilterDynamicForwardProxy EnvoyFilter = "envoy.filters.http.dynamic_forward_proxy"
368373

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
@@ -459,6 +459,8 @@ spec:
459459

460460
- envoy.filters.http.compressor
461461

462+
- envoy.filters.http.bandwidth_limit
463+
462464
- envoy.filters.http.dynamic_forward_proxy
463465

464466
- envoy.filters.http.router
@@ -497,6 +499,7 @@ spec:
497499
- envoy.filters.http.grpc_stats
498500
- envoy.filters.http.credential_injector
499501
- envoy.filters.http.compressor
502+
- envoy.filters.http.bandwidth_limit
500503
- envoy.filters.http.dynamic_forward_proxy
501504
type: string
502505
before:
@@ -528,6 +531,7 @@ spec:
528531
- envoy.filters.http.grpc_stats
529532
- envoy.filters.http.credential_injector
530533
- envoy.filters.http.compressor
534+
- envoy.filters.http.bandwidth_limit
531535
- envoy.filters.http.dynamic_forward_proxy
532536
type: string
533537
name:
@@ -557,6 +561,7 @@ spec:
557561
- envoy.filters.http.grpc_stats
558562
- envoy.filters.http.credential_injector
559563
- envoy.filters.http.compressor
564+
- envoy.filters.http.bandwidth_limit
560565
- envoy.filters.http.dynamic_forward_proxy
561566
type: string
562567
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
@@ -458,6 +458,8 @@ spec:
458458

459459
- envoy.filters.http.compressor
460460

461+
- envoy.filters.http.bandwidth_limit
462+
461463
- envoy.filters.http.dynamic_forward_proxy
462464

463465
- envoy.filters.http.router
@@ -496,6 +498,7 @@ spec:
496498
- envoy.filters.http.grpc_stats
497499
- envoy.filters.http.credential_injector
498500
- envoy.filters.http.compressor
501+
- envoy.filters.http.bandwidth_limit
499502
- envoy.filters.http.dynamic_forward_proxy
500503
type: string
501504
before:
@@ -527,6 +530,7 @@ spec:
527530
- envoy.filters.http.grpc_stats
528531
- envoy.filters.http.credential_injector
529532
- envoy.filters.http.compressor
533+
- envoy.filters.http.bandwidth_limit
530534
- envoy.filters.http.dynamic_forward_proxy
531535
type: string
532536
name:
@@ -556,6 +560,7 @@ spec:
556560
- envoy.filters.http.grpc_stats
557561
- envoy.filters.http.credential_injector
558562
- envoy.filters.http.compressor
563+
- envoy.filters.http.bandwidth_limit
559564
- envoy.filters.http.dynamic_forward_proxy
560565
type: string
561566
required:

internal/gatewayapi/backendtrafficpolicy.go

Lines changed: 69 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,67 @@ 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+
kibps, err := bandwidthToKibps(uint64(bytes), bandwidth.Request.Limit.Unit)
1692+
if err != nil {
1693+
return nil, fmt.Errorf("request: %w", err)
1694+
}
1695+
bl.Request = &ir.BandwidthLimitConfig{
1696+
LimitKibps: kibps,
1697+
}
1698+
}
1699+
if bandwidth.Response != nil {
1700+
bytes, ok := bandwidth.Response.Limit.Value.AsInt64()
1701+
if !ok {
1702+
return nil, fmt.Errorf("response limit value must be convertible to an int64")
1703+
}
1704+
kibps, err := bandwidthToKibps(uint64(bytes), bandwidth.Response.Limit.Unit)
1705+
if err != nil {
1706+
return nil, fmt.Errorf("response: %w", err)
1707+
}
1708+
bl.Response = &ir.BandwidthLimitConfig{
1709+
LimitKibps: kibps,
1710+
}
1711+
1712+
if bandwidth.Response.ResponseTrailers != nil {
1713+
bl.Response.ResponseTrailers = &ir.BandwidthLimitResponseTrailers{
1714+
Prefix: bandwidth.Response.ResponseTrailers.Prefix,
1715+
}
1716+
}
1717+
}
1718+
return bl, nil
1719+
}
1720+
1721+
// bandwidthToKibps converts bytes-per-unit to kibibytes-per-second (KiB/s).
1722+
// Returns an error if the result is below Envoy's minimum of 1 KiB/s.
1723+
func bandwidthToKibps(limit uint64, unit egv1a1.BandwidthLimitUnit) (uint64, error) {
1724+
var secondsPerUnit uint64
1725+
switch unit {
1726+
case egv1a1.BandwidthLimitUnitMinute:
1727+
secondsPerUnit = 60
1728+
case egv1a1.BandwidthLimitUnitHour:
1729+
secondsPerUnit = 3600
1730+
default: // Second
1731+
secondsPerUnit = 1
1732+
}
1733+
kibps := limit / (secondsPerUnit * 1024)
1734+
if kibps == 0 {
1735+
return 0, fmt.Errorf("bandwidth limit of %d bytes per %s is below the minimum of 1 KiB/s", limit, unit)
1736+
}
1737+
return kibps, nil
1738+
}
1739+
16711740
func (t *Translator) buildFaultInjection(policy *egv1a1.BackendTrafficPolicy) *ir.FaultInjection {
16721741
var (
16731742
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)