From ef5c92032597dbf314c9c370fbc9d31e89e23027 Mon Sep 17 00:00:00 2001 From: chenyaqi01 Date: Mon, 7 Oct 2019 15:09:57 +0800 Subject: [PATCH] bandwidth: use regexp to handle tc output fix newly-added 'chain N' output from 'tc filter show dev XXX' --- pkg/util/bandwidth/linux.go | 26 ++++++++++++++++---------- pkg/util/bandwidth/linux_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/pkg/util/bandwidth/linux.go b/pkg/util/bandwidth/linux.go index f01e7cc02f9e..d841f305ab4f 100644 --- a/pkg/util/bandwidth/linux.go +++ b/pkg/util/bandwidth/linux.go @@ -24,6 +24,7 @@ import ( "encoding/hex" "fmt" "net" + "regexp" "strings" "k8s.io/apimachinery/pkg/api/resource" @@ -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 @@ -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 @@ -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) } } @@ -301,7 +308,6 @@ func (t *tcShaper) Reset(cidr string) error { } } return nil - } func (t *tcShaper) deleteInterface(class string) error { diff --git a/pkg/util/bandwidth/linux_test.go b/pkg/util/bandwidth/linux_test.go index 41643af5ecd2..782adb096a6c 100644 --- a/pkg/util/bandwidth/linux_test.go +++ b/pkg/util/bandwidth/linux_test.go @@ -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 { @@ -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,