-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathctrlnet.go
92 lines (75 loc) · 1.95 KB
/
ctrlnet.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package ctrlnet
import (
"fmt"
"io/ioutil"
"os/exec"
"strings"
)
type LinkSettings struct {
// Latency between links (in milliseconds)
Latency uint
// Jitter in latency values (in milliseconds)
Jitter uint
// Bandwidth of link (in bits per second)
Bandwidth uint
// PacketLoss percentage on the links (in whole percentage points)
PacketLoss uint8
}
func (ls *LinkSettings) cmd(iface string, init bool) []string {
var cmd = "change"
if init {
cmd = "add"
}
base := []string{"tc", "qdisc", cmd, "dev", iface, "root", "netem"}
// even if latency is zero, put it on so the command never fails
base = append(base, "delay", fmt.Sprintf("%dms", ls.Latency))
if ls.Jitter != 0 {
base = append(base, fmt.Sprintf("%dms", ls.Jitter), "distribution", "normal")
}
if ls.Bandwidth != 0 {
base = append(base, "rate", fmt.Sprint(ls.Bandwidth))
}
if ls.PacketLoss != 0 {
base = append(base, "loss", fmt.Sprintf("%d%%", ls.PacketLoss))
}
return base
}
func initLink(name string) (bool, error) {
out, err := exec.Command("tc", "qdisc", "show").CombinedOutput()
if err != nil {
return false, fmt.Errorf("dev listing failed: %s - %s", string(out), err)
}
lines := strings.Split(string(out), "\n")
for _, l := range lines {
if strings.Contains(l, name) && strings.Contains(l, "netem") {
return false, nil
}
}
return true, nil
}
func SetLink(name string, settings *LinkSettings) error {
doinit, err := initLink(name)
if err != nil {
return err
}
args := settings.cmd(name, doinit)
c := exec.Command(args[0], args[1:]...)
out, err := c.CombinedOutput()
if err != nil {
return fmt.Errorf("error setting link: %s - %s", string(out), err)
}
return nil
}
func GetInterfaces(filter string) ([]string, error) {
ifs, err := ioutil.ReadDir("/sys/devices/virtual/net")
if err != nil {
return nil, err
}
var out []string
for _, i := range ifs {
if strings.Contains(i.Name(), filter) {
out = append(out, i.Name())
}
}
return out, nil
}