@@ -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,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+
16711740func (t * Translator ) buildFaultInjection (policy * egv1a1.BackendTrafficPolicy ) * ir.FaultInjection {
16721741 var (
16731742 fi * ir.FaultInjection
0 commit comments