Revert "Merge pull request #921 from oOraph/dev/exclude_subnets_from_traffic_shapping2"

This reverts commit ef076afac1, reversing
changes made to 597408952e.

Signed-off-by: h0nIg <h0nIg@users.noreply.github.com>
This commit is contained in:
h0nIg
2024-10-11 10:03:44 +00:00
committed by Casey Callendrello
parent 8ad0361964
commit d44bbf28af
9 changed files with 652 additions and 2928 deletions

View File

@ -18,7 +18,6 @@ import (
"encoding/json"
"fmt"
"math"
"net"
"github.com/vishvananda/netlink"
@ -40,12 +39,11 @@ const (
// BandwidthEntry corresponds to a single entry in the bandwidth argument,
// see CONVENTIONS.md
type BandwidthEntry struct {
UnshapedSubnets []string `json:"unshapedSubnets"` // Ipv4/ipv6 subnets to be excluded from traffic shaping. UnshapedSubnets and ShapedSubnets parameters are mutually exlusive
ShapedSubnets []string `json:"shapedSubnets"` // Ipv4/ipv6 subnets to be included in traffic shaping. UnshapedSubnets and ShapedSubnets parameters are mutually exlusive
IngressRate uint64 `json:"ingressRate"` // Bandwidth rate in bps for traffic through container. 0 for no limit. If ingressRate is set, ingressBurst must also be set
IngressBurst uint64 `json:"ingressBurst"` // Bandwidth burst in bits for traffic through container. 0 for no limit. If ingressBurst is set, ingressRate must also be set
EgressRate uint64 `json:"egressRate"` // Bandwidth rate in bps for traffic through container. 0 for no limit. If egressRate is set, egressBurst must also be set
EgressBurst uint64 `json:"egressBurst"` // Bandwidth burst in bits for traffic through container. 0 for no limit. If egressBurst is set, egressRate must also be set
IngressRate uint64 `json:"ingressRate"` // Bandwidth rate in bps for traffic through container. 0 for no limit. If ingressRate is set, ingressBurst must also be set
IngressBurst uint64 `json:"ingressBurst"` // Bandwidth burst in bits for traffic through container. 0 for no limit. If ingressBurst is set, ingressRate must also be set
EgressRate uint64 `json:"egressRate"` // Bandwidth rate in bps for traffic through container. 0 for no limit. If egressRate is set, egressBurst must also be set
EgressBurst uint64 `json:"egressBurst"` // Bandwidth burst in bits for traffic through container. 0 for no limit. If egressBurst is set, egressRate must also be set
}
func (bw *BandwidthEntry) isZero() bool {
@ -98,21 +96,10 @@ func parseConfig(stdin []byte) (*PluginConf, error) {
}
func getBandwidth(conf *PluginConf) *BandwidthEntry {
bw := conf.BandwidthEntry
if bw == nil && conf.RuntimeConfig.Bandwidth != nil {
bw = conf.RuntimeConfig.Bandwidth
if conf.BandwidthEntry == nil && conf.RuntimeConfig.Bandwidth != nil {
return conf.RuntimeConfig.Bandwidth
}
if bw != nil {
if bw.UnshapedSubnets == nil {
bw.UnshapedSubnets = make([]string, 0)
}
if bw.ShapedSubnets == nil {
bw.ShapedSubnets = make([]string, 0)
}
}
return bw
return conf.BandwidthEntry
}
func validateRateAndBurst(rate, burst uint64) error {
@ -132,13 +119,13 @@ func getIfbDeviceName(networkName string, containerID string) string {
return utils.MustFormatHashWithPrefix(maxIfbDeviceLength, ifbDevicePrefix, networkName+containerID)
}
func getMTUAndQLen(deviceName string) (int, int, error) {
func getMTU(deviceName string) (int, error) {
link, err := netlink.LinkByName(deviceName)
if err != nil {
return -1, -1, err
return -1, err
}
return link.Attrs().MTU, link.Attrs().TxQLen, nil
return link.Attrs().MTU, nil
}
// get the veth peer of container interface in host namespace
@ -172,28 +159,6 @@ func getHostInterface(interfaces []*current.Interface, containerIfName string, n
return nil, fmt.Errorf("no veth peer of container interface found in host ns")
}
func validateSubnets(unshapedSubnets []string, shapedSubnets []string) error {
if len(unshapedSubnets) > 0 && len(shapedSubnets) > 0 {
return fmt.Errorf("unshapedSubnets and shapedSubnets cannot be both specified, one of them should be discarded")
}
for _, subnet := range unshapedSubnets {
_, _, err := net.ParseCIDR(subnet)
if err != nil {
return fmt.Errorf("bad subnet %q provided, details %s", subnet, err)
}
}
for _, subnet := range shapedSubnets {
_, _, err := net.ParseCIDR(subnet)
if err != nil {
return fmt.Errorf("bad subnet %q provided, details %s", subnet, err)
}
}
return nil
}
func cmdAdd(args *skel.CmdArgs) error {
conf, err := parseConfig(args.StdinData)
if err != nil {
@ -205,10 +170,6 @@ func cmdAdd(args *skel.CmdArgs) error {
return types.PrintResult(conf.PrevResult, conf.CNIVersion)
}
if err = validateSubnets(bandwidth.UnshapedSubnets, bandwidth.ShapedSubnets); err != nil {
return err
}
if conf.PrevResult == nil {
return fmt.Errorf("must be called as chained plugin")
}
@ -230,22 +191,21 @@ func cmdAdd(args *skel.CmdArgs) error {
}
if bandwidth.IngressRate > 0 && bandwidth.IngressBurst > 0 {
err = CreateIngressQdisc(bandwidth.IngressRate, bandwidth.IngressBurst,
bandwidth.UnshapedSubnets, bandwidth.ShapedSubnets, hostInterface.Name)
err = CreateIngressQdisc(bandwidth.IngressRate, bandwidth.IngressBurst, hostInterface.Name)
if err != nil {
return err
}
}
if bandwidth.EgressRate > 0 && bandwidth.EgressBurst > 0 {
mtu, qlen, err := getMTUAndQLen(hostInterface.Name)
mtu, err := getMTU(hostInterface.Name)
if err != nil {
return err
}
ifbDeviceName := getIfbDeviceName(conf.Name, args.ContainerID)
err = CreateIfb(ifbDeviceName, mtu, qlen)
err = CreateIfb(ifbDeviceName, mtu)
if err != nil {
return err
}
@ -259,9 +219,7 @@ func cmdAdd(args *skel.CmdArgs) error {
Name: ifbDeviceName,
Mac: ifbDevice.Attrs().HardwareAddr.String(),
})
err = CreateEgressQdisc(bandwidth.EgressRate, bandwidth.EgressBurst,
bandwidth.UnshapedSubnets, bandwidth.ShapedSubnets, hostInterface.Name,
ifbDeviceName)
err = CreateEgressQdisc(bandwidth.EgressRate, bandwidth.EgressBurst, hostInterface.Name, ifbDeviceName)
if err != nil {
return err
}
@ -340,99 +298,75 @@ func cmdCheck(args *skel.CmdArgs) error {
bandwidth := getBandwidth(bwConf)
if err = validateSubnets(bandwidth.UnshapedSubnets, bandwidth.ShapedSubnets); err != nil {
return fmt.Errorf("failed to check subnets, details %s", err)
}
if bandwidth.IngressRate > 0 && bandwidth.IngressBurst > 0 {
rateInBytes := bandwidth.IngressRate / 8
burstInBytes := bandwidth.IngressBurst / 8
bufferInBytes := buffer(rateInBytes, uint32(burstInBytes))
err = checkHTB(link, rateInBytes, bufferInBytes, bandwidth.ShapedSubnets)
latency := latencyInUsec(latencyInMillis)
limitInBytes := limit(rateInBytes, latency, uint32(burstInBytes))
qdiscs, err := SafeQdiscList(link)
if err != nil {
return err
}
if len(qdiscs) == 0 {
return fmt.Errorf("Failed to find qdisc")
}
for _, qdisc := range qdiscs {
tbf, isTbf := qdisc.(*netlink.Tbf)
if !isTbf {
break
}
if tbf.Rate != rateInBytes {
return fmt.Errorf("Rate doesn't match")
}
if tbf.Limit != limitInBytes {
return fmt.Errorf("Limit doesn't match")
}
if tbf.Buffer != bufferInBytes {
return fmt.Errorf("Buffer doesn't match")
}
}
}
if bandwidth.EgressRate > 0 && bandwidth.EgressBurst > 0 {
rateInBytes := bandwidth.EgressRate / 8
burstInBytes := bandwidth.EgressBurst / 8
bufferInBytes := buffer(rateInBytes, uint32(burstInBytes))
latency := latencyInUsec(latencyInMillis)
limitInBytes := limit(rateInBytes, latency, uint32(burstInBytes))
ifbDeviceName := getIfbDeviceName(bwConf.Name, args.ContainerID)
ifbDevice, err := netlink.LinkByName(ifbDeviceName)
if err != nil {
return fmt.Errorf("get ifb device: %s", err)
}
err = checkHTB(ifbDevice, rateInBytes, bufferInBytes, bandwidth.ShapedSubnets)
qdiscs, err := SafeQdiscList(ifbDevice)
if err != nil {
return err
}
}
return nil
}
func checkHTB(link netlink.Link, rateInBytes uint64, bufferInBytes uint32, shapedSubnets []string) error {
qdiscs, err := SafeQdiscList(link)
if err != nil {
return err
}
if len(qdiscs) == 0 {
return fmt.Errorf("Failed to find qdisc")
}
foundHTB := false
for _, qdisc := range qdiscs {
htb, isHtb := qdisc.(*netlink.Htb)
if !isHtb {
continue
if len(qdiscs) == 0 {
return fmt.Errorf("Failed to find qdisc")
}
if foundHTB {
return fmt.Errorf("Several htb qdisc found for device %s", link.Attrs().Name)
}
foundHTB = true
defaultClassMinorID := ShapedClassMinorID
if len(shapedSubnets) > 0 {
defaultClassMinorID = UnShapedClassMinorID
}
if htb.Defcls != uint32(defaultClassMinorID) {
return fmt.Errorf("Default class does not match")
}
classes, err := netlink.ClassList(link, htb.Handle)
if err != nil {
return fmt.Errorf("Unable to list classes bound to htb qdisc for device %s. Details %s",
link.Attrs().Name, err)
}
if len(classes) != 2 {
return fmt.Errorf("Number of htb classes does not match for device %s (%d != 2)",
link.Attrs().Name, len(classes))
}
for _, c := range classes {
htbClass, isHtb := c.(*netlink.HtbClass)
if !isHtb {
return fmt.Errorf("Unexpected class for parent htb qdisc bound to device %s", link.Attrs().Name)
for _, qdisc := range qdiscs {
tbf, isTbf := qdisc.(*netlink.Tbf)
if !isTbf {
break
}
if htbClass.Handle == htb.Defcls {
if htbClass.Rate != rateInBytes {
return fmt.Errorf("Rate does not match for the default class for device %s (%d != %d)",
link.Attrs().Name, htbClass.Rate, rateInBytes)
}
if htbClass.Buffer != bufferInBytes {
return fmt.Errorf("Burst buffer size does not match for the default class for device %s (%d != %d)",
link.Attrs().Name, htbClass.Buffer, bufferInBytes)
}
} else if htbClass.Handle == netlink.MakeHandle(1, 1) {
if htbClass.Rate != UncappedRate {
return fmt.Errorf("Rate does not match for the uncapped class for device %s (%d != %d)",
link.Attrs().Name, htbClass.Rate, UncappedRate)
}
if tbf.Rate != rateInBytes {
return fmt.Errorf("Rate doesn't match")
}
if tbf.Limit != limitInBytes {
return fmt.Errorf("Limit doesn't match")
}
if tbf.Buffer != bufferInBytes {
return fmt.Errorf("Buffer doesn't match")
}
}
// TODO: check subnet filters
}
return nil