pkg/netutil: get default interface for tc commands
Fix https://github.com/coreos/etcd/issues/6841.
This commit is contained in:
@ -43,14 +43,19 @@ func RecoverPort(port int) error {
|
|||||||
|
|
||||||
// SetLatency adds latency in millisecond scale with random variations.
|
// SetLatency adds latency in millisecond scale with random variations.
|
||||||
func SetLatency(ms, rv int) error {
|
func SetLatency(ms, rv int) error {
|
||||||
|
ifce, err := GetDefaultInterface()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if rv > ms {
|
if rv > ms {
|
||||||
rv = 1
|
rv = 1
|
||||||
}
|
}
|
||||||
cmdStr := fmt.Sprintf("sudo tc qdisc add dev eth0 root netem delay %dms %dms distribution normal", ms, rv)
|
cmdStr := fmt.Sprintf("sudo tc qdisc add dev %s root netem delay %dms %dms distribution normal", ifce, ms, rv)
|
||||||
_, err := exec.Command("/bin/sh", "-c", cmdStr).Output()
|
_, err = exec.Command("/bin/sh", "-c", cmdStr).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// the rule has already been added. Overwrite it.
|
// 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", ifce, ms, rv)
|
||||||
_, err = exec.Command("/bin/sh", "-c", cmdStr).Output()
|
_, err = exec.Command("/bin/sh", "-c", cmdStr).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -61,6 +66,10 @@ func SetLatency(ms, rv int) error {
|
|||||||
|
|
||||||
// RemoveLatency resets latency configurations.
|
// RemoveLatency resets latency configurations.
|
||||||
func RemoveLatency() error {
|
func RemoveLatency() error {
|
||||||
_, err := exec.Command("/bin/sh", "-c", "sudo tc qdisc del dev eth0 root netem").Output()
|
ifce, err := GetDefaultInterface()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = exec.Command("/bin/sh", "-c", fmt.Sprintf("sudo tc qdisc del dev %s root netem", ifce)).Output()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -26,3 +26,8 @@ import (
|
|||||||
func GetDefaultHost() (string, error) {
|
func GetDefaultHost() (string, error) {
|
||||||
return "", fmt.Errorf("default host not supported on %s_%s", runtime.GOOS, runtime.GOARCH)
|
return "", fmt.Errorf("default host not supported on %s_%s", runtime.GOOS, runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDefaultInterface fetches the device name of default routable interface.
|
||||||
|
func GetDefaultInterface() (string, error) {
|
||||||
|
return "", fmt.Errorf("default host not supported on %s_%s", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
@ -35,33 +35,21 @@ func GetDefaultHost() (string, error) {
|
|||||||
return "", rerr
|
return "", rerr
|
||||||
}
|
}
|
||||||
|
|
||||||
attrs, aerr := syscall.ParseNetlinkRouteAttr(rmsg)
|
host, oif, err := parsePREFSRC(rmsg)
|
||||||
if aerr != nil {
|
if err != nil {
|
||||||
return "", aerr
|
return "", err
|
||||||
}
|
}
|
||||||
|
if host != "" {
|
||||||
oif := uint32(0)
|
return host, nil
|
||||||
for _, attr := range attrs {
|
|
||||||
if attr.Attr.Type == syscall.RTA_PREFSRC {
|
|
||||||
return net.IP(attr.Value).String(), nil
|
|
||||||
}
|
|
||||||
if attr.Attr.Type == syscall.RTA_OIF {
|
|
||||||
oif = binary.LittleEndian.Uint32(attr.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if oif == 0 {
|
|
||||||
return "", errNoDefaultRoute
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prefsrc not detected, fall back to getting address from iface
|
// prefsrc not detected, fall back to getting address from iface
|
||||||
|
|
||||||
ifmsg, ierr := getIface(oif)
|
ifmsg, ierr := getIface(oif)
|
||||||
if ierr != nil {
|
if ierr != nil {
|
||||||
return "", ierr
|
return "", ierr
|
||||||
}
|
}
|
||||||
|
|
||||||
attrs, aerr = syscall.ParseNetlinkRouteAttr(ifmsg)
|
attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg)
|
||||||
if aerr != nil {
|
if aerr != nil {
|
||||||
return "", aerr
|
return "", aerr
|
||||||
}
|
}
|
||||||
@ -131,3 +119,60 @@ func getIface(idx uint32) (*syscall.NetlinkMessage, error) {
|
|||||||
|
|
||||||
return nil, errNoDefaultRoute
|
return nil, errNoDefaultRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errNoDefaultInterface = fmt.Errorf("could not find default interface")
|
||||||
|
|
||||||
|
func GetDefaultInterface() (string, error) {
|
||||||
|
rmsg, rerr := getDefaultRoute()
|
||||||
|
if rerr != nil {
|
||||||
|
return "", rerr
|
||||||
|
}
|
||||||
|
|
||||||
|
_, oif, err := parsePREFSRC(rmsg)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ifmsg, ierr := getIface(oif)
|
||||||
|
if ierr != nil {
|
||||||
|
return "", ierr
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs, aerr := syscall.ParseNetlinkRouteAttr(ifmsg)
|
||||||
|
if aerr != nil {
|
||||||
|
return "", aerr
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attr := range attrs {
|
||||||
|
if attr.Attr.Type == syscall.IFLA_IFNAME {
|
||||||
|
return string(attr.Value[:len(attr.Value)-1]), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", errNoDefaultInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsePREFSRC returns preferred source address and output interface index (RTA_OIF).
|
||||||
|
func parsePREFSRC(m *syscall.NetlinkMessage) (host string, oif uint32, err error) {
|
||||||
|
var attrs []syscall.NetlinkRouteAttr
|
||||||
|
attrs, err = syscall.ParseNetlinkRouteAttr(m)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attr := range attrs {
|
||||||
|
if attr.Attr.Type == syscall.RTA_PREFSRC {
|
||||||
|
host = net.IP(attr.Value).String()
|
||||||
|
}
|
||||||
|
if attr.Attr.Type == syscall.RTA_OIF {
|
||||||
|
oif = binary.LittleEndian.Uint32(attr.Value)
|
||||||
|
}
|
||||||
|
if host != "" && oif != uint32(0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oif == 0 {
|
||||||
|
err = errNoDefaultRoute
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
27
pkg/netutil/routes_linux_test.go
Normal file
27
pkg/netutil/routes_linux_test.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package netutil
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestGetDefaultInterface(t *testing.T) {
|
||||||
|
ifc, err := GetDefaultInterface()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("default network interface: %q\n", ifc)
|
||||||
|
}
|
Reference in New Issue
Block a user