mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-16 16:32:03 +00:00
rate-limiter: add ifb interface
Ingress traffic shaping is very limited, and the htb qdisc discipline couldn't be applied to interface ingress traffic. Here, we import a new pseudo network interface, Intermediate Functional Block (ifb). It is an alternative to tc filters for handling ingress traffic, by redirecting interface ingress traffic to ifb and treat it as egress traffic there. Fixes: #250 Signed-off-by: Penny Zheng <penny.zheng@arm.com>
This commit is contained in:
parent
cfeb966763
commit
65a37b7d9c
@ -13,6 +13,7 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"sort"
|
||||
"time"
|
||||
@ -1434,3 +1435,51 @@ func addHTBQdisc(linkIndex int, maxRate uint64) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The Intermediate Functional Block (ifb) pseudo network interface is an alternative
|
||||
// to tc filters for handling ingress traffic,
|
||||
// By redirecting interface ingress traffic to ifb and treat it as egress traffic there,
|
||||
// we could do network shaping to interface inbound traffic.
|
||||
func addIFBDevice() (int, error) {
|
||||
// check whether host supports ifb
|
||||
if ok, err := utils.SupportsIfb(); !ok {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
netHandle, err := netlink.NewHandle()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
defer netHandle.Delete()
|
||||
|
||||
// There exists error when using netlink library to create ifb interface
|
||||
cmd := exec.Command("ip", "link", "add", "dev", "ifb0", "type", "ifb")
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return -1, fmt.Errorf("Could not create link ifb0: %v, error %v", output, err)
|
||||
}
|
||||
|
||||
ifbLink, err := netlink.LinkByName("ifb0")
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if err := netHandle.LinkSetUp(ifbLink); err != nil {
|
||||
return -1, fmt.Errorf("Could not enable link ifb0 %v", err)
|
||||
}
|
||||
|
||||
return ifbLink.Attrs().Index, nil
|
||||
}
|
||||
|
||||
// This is equivalent to calling:
|
||||
// tc filter add dev source parent ffff: protocol all u32 match u8 0 0 action mirred egress redirect dev ifb
|
||||
func addIFBRedirecting(sourceIndex int, ifbIndex int) error {
|
||||
if err := addQdiscIngress(sourceIndex); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := addRedirectTCFilter(sourceIndex, ifbIndex); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -29,6 +29,9 @@ const MaxSocketPathLen = 107
|
||||
// VHostVSockDevicePath path to vhost-vsock device
|
||||
var VHostVSockDevicePath = "/dev/vhost-vsock"
|
||||
|
||||
// sysModuleDir is the directory where system modules locate.
|
||||
var sysModuleDir = "/sys/module"
|
||||
|
||||
// FileCopy copys files from srcPath to dstPath
|
||||
func FileCopy(srcPath, dstPath string) error {
|
||||
if srcPath == "" {
|
||||
@ -235,6 +238,25 @@ func SupportsVsocks() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// SupportsIfb returns true if ifb are supported, otherwise false
|
||||
func SupportsIfb() (bool, error) {
|
||||
ifbModule := "ifb"
|
||||
// First, check to see if the ifb module is already loaded
|
||||
path := filepath.Join(sysModuleDir, ifbModule)
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Try to load the ifb module.
|
||||
// When inserting the ifb module, tell it the number of virtual interfaces you need, here, it's zero.
|
||||
// The default is 2.
|
||||
cmd := exec.Command("modprobe", ifbModule, "numifbs=0")
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return false, fmt.Errorf("modprobe insert ifb module failed: %s", string(output))
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// StartCmd pointer to a function to start a command.
|
||||
// Defined this way to allow mock testing.
|
||||
var StartCmd = func(c *exec.Cmd) error {
|
||||
|
Loading…
Reference in New Issue
Block a user