@@ -1031,6 +1031,7 @@ func (t *Translator) mergeBackendTrafficPolicy(routePolicy, gwPolicy *egv1a1.Bac
10311031func (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+
16711746func (t * Translator ) buildFaultInjection (policy * egv1a1.BackendTrafficPolicy ) * ir.FaultInjection {
16721747 var (
16731748 fi * ir.FaultInjection
0 commit comments