1
0
cnlh 5 жил өмнө
parent
commit
e5b3db0c19
1 өөрчлөгдсөн 184 нэмэгдсэн , 0 устгасан
  1. 184 0
      lib/mux/tc.go

+ 184 - 0
lib/mux/tc.go

@@ -1 +1,185 @@
 package mux
+
+import (
+	"errors"
+	"math"
+	"net"
+	"os/exec"
+	"strings"
+)
+
+type Eth struct {
+	EthName string
+	EthAddr string
+}
+
+type TrafficControl struct {
+	Eth *Eth
+}
+
+func Ips() (map[string]string, error) {
+
+	ips := make(map[string]string)
+
+	interfaces, err := net.Interfaces()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, i := range interfaces {
+		byName, err := net.InterfaceByName(i.Name)
+		if err != nil {
+			return nil, err
+		}
+		if !strings.Contains(byName.Name, "Loopback") && !strings.Contains(byName.Name, "isatap") {
+			addresses, _ := byName.Addrs()
+			for _, v := range addresses {
+				ips[byName.Name] = v.String()
+			}
+		}
+	}
+	return ips, nil
+}
+
+// get ip and Eth information by Eth name
+func GetIpAddrByName(EthName string) (Eth *Eth, err error) {
+	interfaces, err := net.Interfaces()
+	if err != nil {
+		return
+	}
+	for _, i := range interfaces {
+		byName, err := net.InterfaceByName(i.Name)
+		if err != nil {
+			return
+		}
+		if byName.Name == EthName || EthName == "" {
+			// except lo
+			if !strings.Contains(byName.Name, "Loopback") && !strings.Contains(byName.Name, "isatap") {
+				addresses, _ := byName.Addrs()
+				for _, v := range addresses {
+					ipMask := strings.Split(v.String(), "/")
+					if len(ipMask) == 2 {
+						Eth.EthAddr = ipMask[0]
+						Eth.EthName = byName.Name
+						return
+					}
+				}
+			}
+		}
+	}
+	err = errors.New("not found interface")
+	return
+}
+
+type tcFunc func() error
+
+func getArrayExhaustivity(arr []tcFunc) (result [][]tcFunc) {
+	var l = int(math.Pow(float64(2), float64(len(arr))) - 1)
+	var t []tcFunc
+	for i := 1; i <= l; i++ {
+		s := i
+		t = []tcFunc{}
+		for k := 0; s > 0; k++ {
+			if s&1 == 1 {
+				t = append(t, arr[k])
+			}
+			s >>= 1
+		}
+		result = append(result, t)
+	}
+	return
+}
+
+func NewTrafficControl(EthName string) (*TrafficControl, error) {
+	Eth, err := GetIpAddrByName(EthName)
+	if err != nil {
+		return nil, err
+	}
+	t := new(TrafficControl)
+	t.Eth = Eth
+	return t, nil
+}
+
+// test the network randomly
+func (tc *TrafficControl) RunNetRangeTest(f func()) error {
+	funcs := tc.getTestVariable()
+	groups := getArrayExhaustivity(funcs)
+	for _, v := range groups {
+		// execute bandwidth control
+		if err := tc.bandwidth("1mbit"); err != nil {
+			return err
+		}
+		// execute random strategy
+		for _, vv := range v {
+			err := vv()
+			if err != nil {
+				return err
+			}
+		}
+		// execute test func
+		f()
+		// clear strategy
+		if err := tc.del(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// create test variables
+func (tc *TrafficControl) getTestVariable() []tcFunc {
+	return []tcFunc{
+		func() error { return tc.delay("add", "100ms", "10ms", "30%") },
+		func() error { return tc.loss("add", "1%", "30%") },
+		func() error { return tc.duplicate("add", "1%") },
+		func() error { return tc.corrupt("add", "0.2%") },
+		func() error { return tc.reorder("change", "10ms", "25%", "50%") },
+	}
+}
+
+// this command sets the transmission of the network card to delayVal. At the same time,
+// about waveRatio of the packets will be delayed by ± wave.
+func (tc *TrafficControl) delay(opt, delayVal, wave, waveRatio string) error {
+	return runCmd(exec.Command("tc", "qdisc", opt, "dev", tc.Eth.EthName, "root", "netem", "delay", delayVal, wave, waveRatio))
+}
+
+// this command sets the transmission of the network card to randomly drop lossRatio of packets with a success rate of lossSuccessRatio.
+func (tc *TrafficControl) loss(opt, lossRatio, lossSuccessRatio string) error {
+	return runCmd(exec.Command("tc", "qdisc", opt, "dev", tc.Eth.EthName, "root", "netem", "loss", lossRatio, lossSuccessRatio))
+}
+
+// this command sets the transmission of the network card to randomly generate repeatRatio duplicate packets
+func (tc *TrafficControl) duplicate(opt, duplicateRatio string) error {
+	return runCmd(exec.Command("tc", "qdisc", opt, "dev", tc.Eth.EthName, "root", "netem", "duplicate", duplicateRatio))
+}
+
+// this command sets the transmission of the network card to randomly generate corruptRatio corrupted packets.
+// the kernel version must be above 2.6.16
+func (tc *TrafficControl) corrupt(opt, corruptRatio string) error {
+	return runCmd(exec.Command("tc", "qdisc", opt, "dev", tc.Eth.EthName, "root", "netem", "corrupt", corruptRatio))
+}
+
+// this command sets the transmission of the network card to: reorderRatio of the packets (reorderRelationRatio related)
+// will be sent immediately, and the other is delayed by delayVal
+func (tc *TrafficControl) reorder(opt, delayVal, reorderRatio, reorderRelationRatio string) error {
+	return runCmd(exec.Command("tc", "qdisc", opt, "dev", tc.Eth.EthName, "root", "netem", "delay", delayVal, "reorder", reorderRatio, reorderRelationRatio))
+}
+
+// remove all tc setting
+func (tc *TrafficControl) del() error {
+	return runCmd(exec.Command("tc", "qdisc", "del", "dev", tc.Eth.EthName, "root"))
+}
+
+// remove all tc setting
+func (tc *TrafficControl) bandwidth(bw string) error {
+	runCmd(exec.Command("tc", "qdisc", "add", "dev", tc.Eth.EthName, "root", "handle", "2:", "htb", "default", "30"))
+	return runCmd(exec.Command("tc", "qdisc", "add", "dev", tc.Eth.EthName, "parent", "2:", "classid", "2:30", "htb", "rate", bw))
+}
+
+func runCmd(cmd *exec.Cmd) error {
+	err := cmd.Run()
+	if err != nil {
+		return err
+	}
+	return nil
+}