rate-limiter: implement hypervisor-built-in rate limiter

As for hypervisors that support built-in rate limiter, like firecracker,
we use this built-in characteristics to implement rate limiter in kata.
kata-defined rate is in bits with scaling factors of 1000, otherwise fc-defined
rate is in bytes with scaling factors of 1024, so need reversion.

Fixes: #250

Signed-off-by: Penny Zheng <penny.zheng@arm.com>
This commit is contained in:
Penny Zheng 2020-06-16 05:40:27 +00:00
parent 676ad989d7
commit cfeb966763
4 changed files with 71 additions and 6 deletions

View File

@ -908,11 +908,52 @@ func (fc *firecracker) fcAddNetDevice(endpoint Endpoint) {
defer span.Finish()
ifaceID := endpoint.Name()
// The implementation of rate limiter is based on TBF.
// Rate Limiter defines a token bucket with a maximum capacity (size) to store tokens, and an interval for refilling purposes (refill_time).
// The refill-rate is derived from size and refill_time, and it is the constant rate at which the tokens replenish.
refillTime := uint64(1000)
var rxRateLimiter models.RateLimiter
rxSize := fc.config.RxRateLimiterMaxRate
if rxSize > 0 {
fc.Logger().Info("Add rx rate limiter")
// kata-defined rxSize is in bits with scaling factors of 1000, but firecracker-defined
// rxSize is in bytes with scaling factors of 1024, need reversion.
rxSize = revertBytes(rxSize / 8)
rxTokenBucket := models.TokenBucket{
RefillTime: &refillTime,
Size: &rxSize,
}
rxRateLimiter = models.RateLimiter{
Bandwidth: &rxTokenBucket,
}
}
var txRateLimiter models.RateLimiter
txSize := fc.config.TxRateLimiterMaxRate
if txSize > 0 {
fc.Logger().Info("Add tx rate limiter")
// kata-defined txSize is in bits with scaling factors of 1000, but firecracker-defined
// txSize is in bytes with scaling factors of 1024, need reversion.
txSize = revertBytes(txSize / 8)
txTokenBucket := models.TokenBucket{
RefillTime: &refillTime,
Size: &txSize,
}
txRateLimiter = models.RateLimiter{
Bandwidth: &txTokenBucket,
}
}
ifaceCfg := &models.NetworkInterface{
AllowMmdsRequests: false,
GuestMac: endpoint.HardwareAddr(),
IfaceID: &ifaceID,
HostDevName: &endpoint.NetworkPair().TapInterface.TAPIface.Name,
RxRateLimiter: &rxRateLimiter,
TxRateLimiter: &txRateLimiter,
}
fc.fcConfig.NetworkInterfaces = append(fc.fcConfig.NetworkInterfaces, ifaceCfg)
@ -1216,3 +1257,16 @@ func (fc *firecracker) watchConsole() (*os.File, error) {
func (fc *firecracker) isRateLimiterBuiltin() bool {
return true
}
// In firecracker, it accepts the size of rate limiter in scaling factors of 2^10(1024)
// But in kata-defined rate limiter, for better Human-readability, we prefer scaling factors of 10^3(1000).
// func revertByte reverts num from scaling factors of 1000 to 1024, e.g. 10000000(10MB) to 10485760.
func revertBytes(num uint64) uint64 {
a := num / 1000
b := num % 1000
if a == 0 {
return num
} else {
return 1024*revertBytes(a) + b
}
}

View File

@ -45,3 +45,14 @@ func TestFCTruncateID(t *testing.T) {
id = fc.truncateID(testShortID)
assert.Equal(expectedID, id)
}
func TestRevertBytes(t *testing.T) {
assert := assert.New(t)
//10MB
testNum := uint64(10000000)
expectedNum := uint64(10485760)
num := revertBytes(testNum)
assert.Equal(expectedNum, num)
}

View File

@ -19,17 +19,17 @@ type TokenBucket struct {
// The initial size of a token bucket.
// Minimum: 0
OneTimeBurst *int64 `json:"one_time_burst,omitempty"`
OneTimeBurst *uint64 `json:"one_time_burst,omitempty"`
// The amount of milliseconds it takes for the bucket to refill.
// Required: true
// Minimum: 0
RefillTime *int64 `json:"refill_time"`
RefillTime *uint64 `json:"refill_time"`
// The total number of tokens this bucket can hold.
// Required: true
// Minimum: 0
Size *int64 `json:"size"`
Size *uint64 `json:"size"`
}
// Validate validates this token bucket

View File

@ -615,17 +615,17 @@ definitions:
properties:
size:
type: integer
format: int64
format: uint64
description: The total number of tokens this bucket can hold.
minimum: 0
one_time_burst:
type: integer
format: int64
format: uint64
description: The initial size of a token bucket.
minimum: 0
refill_time:
type: integer
format: int64
format: uint64
description: The amount of milliseconds it takes for the bucket to refill.
minimum: 0