123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- // +build linux
- /*
- Copyright 2015 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package bandwidth
- import (
- "errors"
- "reflect"
- "strings"
- "testing"
- "k8s.io/kubernetes/pkg/api/resource"
- "k8s.io/kubernetes/pkg/util/exec"
- )
- var tcClassOutput = `class htb 1:1 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
- class htb 1:2 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
- class htb 1:3 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
- class htb 1:4 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
- `
- var tcClassOutput2 = `class htb 1:1 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
- class htb 1:2 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
- class htb 1:3 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
- class htb 1:4 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
- class htb 1:5 root prio 0 rate 10000bit ceil 10000bit burst 1600b cburst 1600b
- `
- func TestNextClassID(t *testing.T) {
- tests := []struct {
- output string
- expectErr bool
- expected int
- err error
- }{
- {
- output: tcClassOutput,
- expected: 5,
- },
- {
- output: "\n",
- expected: 1,
- },
- {
- expected: -1,
- expectErr: true,
- err: errors.New("test error"),
- },
- }
- for _, test := range tests {
- fcmd := exec.FakeCmd{
- CombinedOutputScript: []exec.FakeCombinedOutputAction{
- func() ([]byte, error) { return []byte(test.output), test.err },
- },
- }
- fexec := exec.FakeExec{
- CommandScript: []exec.FakeCommandAction{
- func(cmd string, args ...string) exec.Cmd {
- return exec.InitFakeCmd(&fcmd, cmd, args...)
- },
- },
- }
- shaper := &tcShaper{e: &fexec}
- class, err := shaper.nextClassID()
- if test.expectErr {
- if err == nil {
- t.Errorf("unexpected non-error")
- }
- } else {
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if class != test.expected {
- t.Errorf("expected: %d, found %d", test.expected, class)
- }
- }
- }
- }
- func TestHexCIDR(t *testing.T) {
- tests := []struct {
- input string
- output string
- expectErr bool
- }{
- {
- input: "1.2.0.0/16",
- output: "01020000/ffff0000",
- },
- {
- input: "172.17.0.2/32",
- output: "ac110002/ffffffff",
- },
- {
- input: "foo",
- expectErr: true,
- },
- }
- for _, test := range tests {
- output, err := hexCIDR(test.input)
- if test.expectErr {
- if err == nil {
- t.Error("unexpected non-error")
- }
- } else {
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if output != test.output {
- t.Errorf("expected: %s, saw: %s", test.output, output)
- }
- input, err := asciiCIDR(output)
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if input != test.input {
- t.Errorf("expected: %s, saw: %s", test.input, input)
- }
- }
- }
- }
- var tcFilterOutput = `filter parent 1: protocol ip pref 1 u32
- filter parent 1: protocol ip pref 1 u32 fh 800: ht divisor 1
- filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
- match ac110002/ffffffff at 16
- 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
- `
- func TestFindCIDRClass(t *testing.T) {
- tests := []struct {
- cidr string
- output string
- expectErr bool
- expectNotFound bool
- expectedClass string
- expectedHandle string
- err error
- }{
- {
- cidr: "172.17.0.2/32",
- output: tcFilterOutput,
- expectedClass: "1:1",
- expectedHandle: "800::800",
- },
- {
- cidr: "1.2.3.4/16",
- output: tcFilterOutput,
- expectedClass: "1:2",
- expectedHandle: "800::801",
- },
- {
- cidr: "2.2.3.4/16",
- output: tcFilterOutput,
- expectNotFound: true,
- },
- {
- err: errors.New("test error"),
- expectErr: true,
- },
- }
- for _, test := range tests {
- fcmd := exec.FakeCmd{
- CombinedOutputScript: []exec.FakeCombinedOutputAction{
- func() ([]byte, error) { return []byte(test.output), test.err },
- },
- }
- fexec := exec.FakeExec{
- CommandScript: []exec.FakeCommandAction{
- func(cmd string, args ...string) exec.Cmd {
- return exec.InitFakeCmd(&fcmd, cmd, args...)
- },
- },
- }
- shaper := &tcShaper{e: &fexec}
- class, handle, found, err := shaper.findCIDRClass(test.cidr)
- if test.expectErr {
- if err == nil {
- t.Errorf("unexpected non-error")
- }
- } else {
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if test.expectNotFound {
- if found {
- t.Errorf("unexpectedly found an interface: %s %s", class, handle)
- }
- } else {
- if class != test.expectedClass {
- t.Errorf("expected: %s, found %s", test.expectedClass, class)
- }
- if handle != test.expectedHandle {
- t.Errorf("expected: %s, found %s", test.expectedHandle, handle)
- }
- }
- }
- }
- }
- func TestGetCIDRs(t *testing.T) {
- fcmd := exec.FakeCmd{
- CombinedOutputScript: []exec.FakeCombinedOutputAction{
- func() ([]byte, error) { return []byte(tcFilterOutput), nil },
- },
- }
- fexec := exec.FakeExec{
- CommandScript: []exec.FakeCommandAction{
- func(cmd string, args ...string) exec.Cmd {
- return exec.InitFakeCmd(&fcmd, cmd, args...)
- },
- },
- }
- shaper := &tcShaper{e: &fexec}
- cidrs, err := shaper.GetCIDRs()
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- expectedCidrs := []string{"172.17.0.2/32", "1.2.0.0/16"}
- if !reflect.DeepEqual(cidrs, expectedCidrs) {
- t.Errorf("expected: %v, saw: %v", expectedCidrs, cidrs)
- }
- }
- func TestLimit(t *testing.T) {
- tests := []struct {
- cidr string
- ingress *resource.Quantity
- egress *resource.Quantity
- expectErr bool
- expectedCalls int
- err error
- }{
- {
- cidr: "1.2.3.4/32",
- ingress: resource.NewQuantity(10, resource.DecimalSI),
- egress: resource.NewQuantity(20, resource.DecimalSI),
- expectedCalls: 6,
- },
- {
- cidr: "1.2.3.4/32",
- ingress: resource.NewQuantity(10, resource.DecimalSI),
- egress: nil,
- expectedCalls: 3,
- },
- {
- cidr: "1.2.3.4/32",
- ingress: nil,
- egress: resource.NewQuantity(20, resource.DecimalSI),
- expectedCalls: 3,
- },
- {
- cidr: "1.2.3.4/32",
- ingress: nil,
- egress: nil,
- expectedCalls: 0,
- },
- {
- err: errors.New("test error"),
- ingress: resource.NewQuantity(10, resource.DecimalSI),
- egress: resource.NewQuantity(20, resource.DecimalSI),
- expectErr: true,
- },
- }
- for _, test := range tests {
- fcmd := exec.FakeCmd{
- CombinedOutputScript: []exec.FakeCombinedOutputAction{
- func() ([]byte, error) { return []byte(tcClassOutput), test.err },
- func() ([]byte, error) { return []byte{}, test.err },
- func() ([]byte, error) { return []byte{}, test.err },
- func() ([]byte, error) { return []byte(tcClassOutput2), test.err },
- func() ([]byte, error) { return []byte{}, test.err },
- func() ([]byte, error) { return []byte{}, test.err },
- },
- }
- fexec := exec.FakeExec{
- CommandScript: []exec.FakeCommandAction{
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- },
- }
- iface := "cbr0"
- shaper := &tcShaper{e: &fexec, iface: iface}
- if err := shaper.Limit(test.cidr, test.ingress, test.egress); err != nil && !test.expectErr {
- t.Errorf("unexpected error: %v", err)
- return
- } else if err == nil && test.expectErr {
- t.Error("unexpected non-error")
- return
- }
- // No more testing in the error case
- if test.expectErr {
- if fcmd.CombinedOutputCalls != 1 {
- t.Errorf("unexpected number of calls: %d, expected: 1", fcmd.CombinedOutputCalls)
- }
- return
- }
- if fcmd.CombinedOutputCalls != test.expectedCalls {
- t.Errorf("unexpected number of calls: %d, expected: %d", fcmd.CombinedOutputCalls, test.expectedCalls)
- }
- for ix := range fcmd.CombinedOutputLog {
- output := fcmd.CombinedOutputLog[ix]
- if output[0] != "tc" {
- t.Errorf("unexpected command: %s, expected tc", output[0])
- }
- if output[4] != iface {
- t.Errorf("unexpected interface: %s, expected %s (%v)", output[4], iface, output)
- }
- if ix == 1 {
- var expectedRate string
- if test.ingress != nil {
- expectedRate = makeKBitString(test.ingress)
- } else {
- expectedRate = makeKBitString(test.egress)
- }
- if output[11] != expectedRate {
- t.Errorf("unexpected ingress: %s, expected: %s", output[11], expectedRate)
- }
- if output[8] != "1:5" {
- t.Errorf("unexpected class: %s, expected: %s", output[8], "1:5")
- }
- }
- if ix == 2 {
- if output[15] != test.cidr {
- t.Errorf("unexpected cidr: %s, expected: %s", output[15], test.cidr)
- }
- if output[17] != "1:5" {
- t.Errorf("unexpected class: %s, expected: %s", output[17], "1:5")
- }
- }
- if ix == 4 {
- if output[11] != makeKBitString(test.egress) {
- t.Errorf("unexpected egress: %s, expected: %s", output[11], makeKBitString(test.egress))
- }
- if output[8] != "1:6" {
- t.Errorf("unexpected class: %s, expected: %s", output[8], "1:6")
- }
- }
- if ix == 5 {
- if output[15] != test.cidr {
- t.Errorf("unexpected cidr: %s, expected: %s", output[15], test.cidr)
- }
- if output[17] != "1:6" {
- t.Errorf("unexpected class: %s, expected: %s", output[17], "1:5")
- }
- }
- }
- }
- }
- func TestReset(t *testing.T) {
- tests := []struct {
- cidr string
- err error
- expectErr bool
- expectedHandle string
- expectedClass string
- }{
- {
- cidr: "1.2.3.4/16",
- expectedHandle: "800::801",
- expectedClass: "1:2",
- },
- {
- cidr: "172.17.0.2/32",
- expectedHandle: "800::800",
- expectedClass: "1:1",
- },
- {
- err: errors.New("test error"),
- expectErr: true,
- },
- }
- for _, test := range tests {
- fcmd := exec.FakeCmd{
- CombinedOutputScript: []exec.FakeCombinedOutputAction{
- func() ([]byte, error) { return []byte(tcFilterOutput), test.err },
- func() ([]byte, error) { return []byte{}, test.err },
- func() ([]byte, error) { return []byte{}, test.err },
- },
- }
- fexec := exec.FakeExec{
- CommandScript: []exec.FakeCommandAction{
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- },
- }
- iface := "cbr0"
- shaper := &tcShaper{e: &fexec, iface: iface}
- if err := shaper.Reset(test.cidr); err != nil && !test.expectErr {
- t.Errorf("unexpected error: %v", err)
- return
- } else if test.expectErr && err == nil {
- t.Error("unexpected non-error")
- return
- }
- // No more testing in the error case
- if test.expectErr {
- if fcmd.CombinedOutputCalls != 1 {
- t.Errorf("unexpected number of calls: %d, expected: 1", fcmd.CombinedOutputCalls)
- }
- return
- }
- if fcmd.CombinedOutputCalls != 3 {
- t.Errorf("unexpected number of calls: %d, expected: 3", fcmd.CombinedOutputCalls)
- }
- for ix := range fcmd.CombinedOutputLog {
- output := fcmd.CombinedOutputLog[ix]
- if output[0] != "tc" {
- t.Errorf("unexpected command: %s, expected tc", output[0])
- }
- if output[4] != iface {
- t.Errorf("unexpected interface: %s, expected %s (%v)", output[4], iface, output)
- }
- if ix == 1 && output[12] != test.expectedHandle {
- t.Errorf("unexpected handle: %s, expected: %s", output[12], test.expectedHandle)
- }
- if ix == 2 && output[8] != test.expectedClass {
- t.Errorf("unexpected class: %s, expected: %s", output[8], test.expectedClass)
- }
- }
- }
- }
- var tcQdisc = "qdisc htb 1: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n"
- func TestReconcileInterfaceExists(t *testing.T) {
- fcmd := exec.FakeCmd{
- CombinedOutputScript: []exec.FakeCombinedOutputAction{
- func() ([]byte, error) { return []byte(tcQdisc), nil },
- },
- }
- fexec := exec.FakeExec{
- CommandScript: []exec.FakeCommandAction{
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- },
- }
- iface := "cbr0"
- shaper := &tcShaper{e: &fexec, iface: iface}
- err := shaper.ReconcileInterface()
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if fcmd.CombinedOutputCalls != 1 {
- t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
- }
- output := fcmd.CombinedOutputLog[0]
- if len(output) != 5 {
- t.Errorf("unexpected command: %v", output)
- }
- if output[0] != "tc" {
- t.Errorf("unexpected command: %s", output[0])
- }
- if output[4] != iface {
- t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
- }
- if output[2] != "show" {
- t.Errorf("unexpected action: %s", output[2])
- }
- }
- func testReconcileInterfaceHasNoData(t *testing.T, output string) {
- fcmd := exec.FakeCmd{
- CombinedOutputScript: []exec.FakeCombinedOutputAction{
- func() ([]byte, error) { return []byte(output), nil },
- func() ([]byte, error) { return []byte(output), nil },
- },
- }
- fexec := exec.FakeExec{
- CommandScript: []exec.FakeCommandAction{
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- },
- }
- iface := "cbr0"
- shaper := &tcShaper{e: &fexec, iface: iface}
- err := shaper.ReconcileInterface()
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if fcmd.CombinedOutputCalls != 2 {
- t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
- }
- for ix, output := range fcmd.CombinedOutputLog {
- if output[0] != "tc" {
- t.Errorf("unexpected command: %s", output[0])
- }
- if output[4] != iface {
- t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
- }
- if ix == 0 {
- if len(output) != 5 {
- t.Errorf("unexpected command: %v", output)
- }
- if output[2] != "show" {
- t.Errorf("unexpected action: %s", output[2])
- }
- }
- if ix == 1 {
- if len(output) != 11 {
- t.Errorf("unexpected command: %v", output)
- }
- if output[2] != "add" {
- t.Errorf("unexpected action: %s", output[2])
- }
- if output[7] != "1:" {
- t.Errorf("unexpected root class: %s", output[7])
- }
- if output[8] != "htb" {
- t.Errorf("unexpected qdisc algo: %s", output[8])
- }
- }
- }
- }
- func TestReconcileInterfaceDoesntExist(t *testing.T) {
- testReconcileInterfaceHasNoData(t, "\n")
- }
- var tcQdiscNoqueue = "qdisc noqueue 0: root refcnt 2 \n"
- func TestReconcileInterfaceExistsWithNoqueue(t *testing.T) {
- testReconcileInterfaceHasNoData(t, tcQdiscNoqueue)
- }
- var tcQdiscWrong = []string{
- "qdisc htb 2: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n",
- "qdisc foo 1: root refcnt 2 r2q 10 default 30 direct_packets_stat 0\n",
- }
- func TestReconcileInterfaceIsWrong(t *testing.T) {
- for _, test := range tcQdiscWrong {
- fcmd := exec.FakeCmd{
- CombinedOutputScript: []exec.FakeCombinedOutputAction{
- func() ([]byte, error) { return []byte(test), nil },
- func() ([]byte, error) { return []byte("\n"), nil },
- func() ([]byte, error) { return []byte("\n"), nil },
- },
- }
- fexec := exec.FakeExec{
- CommandScript: []exec.FakeCommandAction{
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
- },
- }
- iface := "cbr0"
- shaper := &tcShaper{e: &fexec, iface: iface}
- err := shaper.ReconcileInterface()
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
- if fcmd.CombinedOutputCalls != 3 {
- t.Errorf("unexpected number of calls: %d", fcmd.CombinedOutputCalls)
- }
- for ix, output := range fcmd.CombinedOutputLog {
- if output[0] != "tc" {
- t.Errorf("unexpected command: %s", output[0])
- }
- if output[4] != iface {
- t.Errorf("unexpected interface: %s, expected %s", output[4], iface)
- }
- if ix == 0 {
- if len(output) != 5 {
- t.Errorf("unexpected command: %v", output)
- }
- if output[2] != "show" {
- t.Errorf("unexpected action: %s", output[2])
- }
- }
- if ix == 1 {
- if len(output) != 8 {
- t.Errorf("unexpected command: %v", output)
- }
- if output[2] != "delete" {
- t.Errorf("unexpected action: %s", output[2])
- }
- if output[7] != strings.Split(test, " ")[2] {
- t.Errorf("unexpected class: %s, expected: %s", output[7], strings.Split(test, " ")[2])
- }
- }
- if ix == 2 {
- if len(output) != 11 {
- t.Errorf("unexpected command: %v", output)
- }
- if output[7] != "1:" {
- t.Errorf("unexpected root class: %s", output[7])
- }
- if output[8] != "htb" {
- t.Errorf("unexpected qdisc algo: %s", output[8])
- }
- }
- }
- }
- }
|