From 53801a78819f19c4ddfe4b7582ab0458b34ee9c8 Mon Sep 17 00:00:00 2001 From: Gyu-Ho Lee Date: Wed, 16 Nov 2016 10:05:17 -0800 Subject: [PATCH] pkg/netutil: get list of Ethernet for tc command Fix https://github.com/coreos/etcd/issues/6841. --- pkg/netutil/isolate_linux.go | 83 +++++++++++++++++++++++++++++-- pkg/netutil/isolate_linux_test.go | 25 ++++++++++ 2 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 pkg/netutil/isolate_linux_test.go diff --git a/pkg/netutil/isolate_linux.go b/pkg/netutil/isolate_linux.go index c866cea8ee19..26b8585b3e84 100644 --- a/pkg/netutil/isolate_linux.go +++ b/pkg/netutil/isolate_linux.go @@ -15,8 +15,13 @@ package netutil import ( + "bytes" "fmt" + "io/ioutil" + "os" "os/exec" + "path/filepath" + "sort" ) // DropPort drops all tcp packets that are received from the given port and sent to the given port. @@ -43,14 +48,20 @@ func RecoverPort(port int) error { // SetLatency adds latency in millisecond scale with random variations. func SetLatency(ms, rv int) error { + eths, err := getEthernet() + if err != nil { + return err + } + eth := eths[0] + if rv > ms { rv = 1 } - cmdStr := fmt.Sprintf("sudo tc qdisc add dev eth0 root netem delay %dms %dms distribution normal", ms, rv) - _, err := exec.Command("/bin/sh", "-c", cmdStr).Output() + cmdStr := fmt.Sprintf("sudo tc qdisc add dev %s root netem delay %dms %dms distribution normal", eth, ms, rv) + _, err = exec.Command("/bin/sh", "-c", cmdStr).Output() if err != nil { // the rule has already been added. Overwrite it. - cmdStr = fmt.Sprintf("sudo tc qdisc change dev eth0 root netem delay %dms %dms distribution normal", ms, rv) + cmdStr = fmt.Sprintf("sudo tc qdisc change dev %s root netem delay %dms %dms distribution normal", eth, ms, rv) _, err = exec.Command("/bin/sh", "-c", cmdStr).Output() if err != nil { return err @@ -61,6 +72,70 @@ func SetLatency(ms, rv int) error { // RemoveLatency resets latency configurations. func RemoveLatency() error { - _, err := exec.Command("/bin/sh", "-c", "sudo tc qdisc del dev eth0 root netem").Output() + eths, err := getEthernet() + if err != nil { + return err + } + eth := eths[0] + + _, err = exec.Command("/bin/sh", "-c", fmt.Sprintf("sudo tc qdisc del dev %s root netem", eth)).Output() return err } + +func getEthernet() (eths []string, err error) { + var ifs []string + ifs, err = readNetworkInterface() + if err != nil { + return + } + + for _, name := range ifs { + if isEthernet(name) { + eths = append(eths, name) + } + } + if len(eths) == 0 { + return nil, fmt.Errorf("no ethernet network interface found (%v)", ifs) + } + + sort.Strings(eths) + return +} + +const sysClassNet = "/sys/class/net/" + +func readNetworkInterface() ([]string, error) { + d, err := os.Open(sysClassNet) + if err != nil { + return nil, err + } + defer d.Close() + + ns, err := d.Readdirnames(-1) + if err != nil { + return nil, err + } + sort.Strings(ns) + + return ns, nil +} + +var typeEthernet = []byte{49, 10} + +// isEthernet returns true if the network interface is Ethernet. +// '/sys/class/net/type' with 1 is Ethernet 10Mbps, 772 is Loopback device. +// https://github.com/torvalds/linux/blob/master/include/uapi/linux/if_arp.h +func isEthernet(name string) bool { + path := filepath.Join(sysClassNet, name, "type") + f, err := os.Open(path) + if err != nil { + return false + } + defer f.Close() + + b, err := ioutil.ReadAll(f) + if err != nil { + return false + } + return bytes.Equal(typeEthernet, b) +} diff --git a/pkg/netutil/isolate_linux_test.go b/pkg/netutil/isolate_linux_test.go new file mode 100644 index 000000000000..f957a15acdc8 --- /dev/null +++ b/pkg/netutil/isolate_linux_test.go @@ -0,0 +1,25 @@ +// Copyright 2016 The etcd 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 netutil + +import "testing" + +func TestGetEthernet(t *testing.T) { + eths, err := getEthernet() + if err != nil { + t.Fatal(err) + } + t.Log(eths) +}