Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bandwidth: use regexp to handle tc output and add IPv6 support #83572

Merged
merged 1 commit into from Mar 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 16 additions & 10 deletions pkg/util/bandwidth/linux.go
Expand Up @@ -24,6 +24,7 @@ import (
"encoding/hex"
"fmt"
"net"
"regexp"
"strings"

"k8s.io/apimachinery/pkg/api/resource"
Expand All @@ -33,6 +34,11 @@ import (
"k8s.io/klog"
)

var (
classShowMatcher = regexp.MustCompile(`class htb (1:\d+)`)
classAndHandleMatcher = regexp.MustCompile(`filter parent 1:.*fh (\d+::\d+).*flowid (\d+:\d+)`)
)

// tcShaper provides an implementation of the Shaper interface on Linux using the 'tc' tool.
// In general, using this requires that the caller posses the NET_CAP_ADMIN capability, though if you
// do this within an container, it only requires the NS_CAPABLE capability for manipulations to that
Expand Down Expand Up @@ -75,13 +81,13 @@ func (t *tcShaper) nextClassID() (int, error) {
if len(line) == 0 {
continue
}
parts := strings.Split(line, " ")
// expected tc line:
// class htb 1:1 root prio 0 rate 1000Kbit ceil 1000Kbit burst 1600b cburst 1600b
if len(parts) != 14 {
return -1, fmt.Errorf("unexpected output from tc: %s (%v)", scanner.Text(), parts)
matches := classShowMatcher.FindStringSubmatch(line)
if len(matches) != 2 {
return -1, fmt.Errorf("unexpected output from tc: %s (%v)", scanner.Text(), matches)
}
classes.Insert(parts[2])
classes.Insert(matches[1])
}

// Make sure it doesn't go forever
Expand Down Expand Up @@ -153,13 +159,14 @@ func (t *tcShaper) findCIDRClass(cidr string) (classAndHandleList [][]string, fo
continue
}
if strings.Contains(line, spec) {
parts := strings.Split(filter, " ")
// expected tc line:
// filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
if len(parts) != 19 {
return classAndHandleList, false, fmt.Errorf("unexpected output from tc: %s %d (%v)", filter, len(parts), parts)
// `filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1` (old version) or
// `filter parent 1: protocol ip pref 1 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 not_in_hw` (new version)
matches := classAndHandleMatcher.FindStringSubmatch(filter)
if len(matches) != 3 {
return classAndHandleList, false, fmt.Errorf("unexpected output from tc: %s %d (%v)", filter, len(matches), matches)
}
resultTmp := []string{parts[18], parts[9]}
resultTmp := []string{matches[2], matches[1]}
classAndHandleList = append(classAndHandleList, resultTmp)
}
}
Expand Down Expand Up @@ -301,7 +308,6 @@ func (t *tcShaper) Reset(cidr string) error {
}
}
return nil

}

func (t *tcShaper) deleteInterface(class string) error {
Expand Down
24 changes: 24 additions & 0 deletions pkg/util/bandwidth/linux_test.go
Expand Up @@ -212,6 +212,13 @@ filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0
filter parent 1: protocol ip pref 1 u32 fh 800::801 order 2049 key ht 800 bkt 0 flowid 1:2
match 01020000/ffff0000 at 16
`
var tcFilterOutputNewVersion = `filter parent 1: protocol ip pref 1 u32
filter parent 1: protocol ip pref 1 u32 chain 0 fh 800: ht divisor 1
filter parent 1: protocol ip pref 1 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1 not_in_hw
match ac110002/ffffffff at 16
filter parent 1: protocol ip pref 1 u32 chain 0 fh 800::801 order 2049 key ht 800 bkt 0 flowid 1:2 not_in_hw
match 01020000/ffff0000 at 16
`

func TestFindCIDRClass(t *testing.T) {
tests := []struct {
Expand Down Expand Up @@ -240,6 +247,23 @@ func TestFindCIDRClass(t *testing.T) {
output: tcFilterOutput,
expectNotFound: true,
},
{
cidr: "172.17.0.2/32",
output: tcFilterOutputNewVersion,
expectedClass: "1:1",
expectedHandle: "800::800",
},
{
cidr: "1.2.3.4/16",
output: tcFilterOutputNewVersion,
expectedClass: "1:2",
expectedHandle: "800::801",
},
{
cidr: "2.2.3.4/16",
output: tcFilterOutputNewVersion,
expectNotFound: true,
},
{
err: errors.New("test error"),
expectErr: true,
Expand Down