github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/old/bandwidth_manager/bandwidth_manager.go (about) 1 package bandwidth_manager 2 3 import ( 4 "bytes" 5 "fmt" 6 "os/exec" 7 "path" 8 "regexp" 9 "strconv" 10 11 "github.com/cloudfoundry-incubator/garden" 12 "github.com/cloudfoundry-incubator/garden-linux/old/logging" 13 "github.com/cloudfoundry/gunk/command_runner" 14 "github.com/pivotal-golang/lager" 15 ) 16 17 var IN_RATE_PATTERN = regexp.MustCompile(`qdisc tbf [0-9a-f]+: root refcnt \d+ rate (\d+)([KMG]?)bit burst (\d+)([KMG]?)b`) 18 var OUT_RATE_PATTERN = regexp.MustCompile(`police 0x[0-9a-f]+ rate (\d+)([KMG]?)bit burst (\d+)([KMG]?)b`) 19 20 type BandwidthManager interface { 21 SetLimits(lager.Logger, garden.BandwidthLimits) error 22 GetLimits(lager.Logger) (garden.ContainerBandwidthStat, error) 23 } 24 25 type ContainerBandwidthManager struct { 26 containerPath string 27 containerID string 28 29 runner command_runner.CommandRunner 30 } 31 32 func New(containerPath, containerID string, runner command_runner.CommandRunner) *ContainerBandwidthManager { 33 return &ContainerBandwidthManager{ 34 containerPath: containerPath, 35 containerID: containerID, 36 37 runner: runner, 38 } 39 } 40 41 func (m *ContainerBandwidthManager) SetLimits( 42 logger lager.Logger, 43 limits garden.BandwidthLimits, 44 ) error { 45 runner := logging.Runner{ 46 CommandRunner: m.runner, 47 Logger: logger, 48 } 49 50 setRate := exec.Command(path.Join(m.containerPath, "net_rate.sh")) 51 setRate.Env = []string{ 52 fmt.Sprintf("BURST=%d", limits.BurstRateInBytesPerSecond), 53 fmt.Sprintf("RATE=%d", limits.RateInBytesPerSecond*8), 54 } 55 56 return runner.Run(setRate) 57 } 58 59 func (m *ContainerBandwidthManager) GetLimits(logger lager.Logger) (garden.ContainerBandwidthStat, error) { 60 limits := garden.ContainerBandwidthStat{} 61 62 runner := logging.Runner{ 63 CommandRunner: m.runner, 64 Logger: logger, 65 } 66 67 egressOut := new(bytes.Buffer) 68 69 egress := exec.Command(path.Join(m.containerPath, "net.sh"), "get_egress_info") 70 egress.Env = []string{"ID=" + m.containerID} 71 egress.Stdout = egressOut 72 73 err := runner.Run(egress) 74 if err != nil { 75 return limits, err 76 } 77 78 matches := IN_RATE_PATTERN.FindStringSubmatch(string(egressOut.Bytes())) 79 if matches != nil { 80 inRate, err := strconv.ParseUint(matches[1], 10, 0) 81 if err != nil { 82 return limits, err 83 } 84 85 inBurst, err := strconv.ParseUint(matches[3], 10, 0) 86 if err != nil { 87 return limits, err 88 } 89 90 inRateUnit := matches[2] 91 inBurstUnit := matches[4] 92 93 limits.InRate = convertUnits(inRate, inRateUnit) / 8 94 limits.InBurst = convertUnits(inBurst, inBurstUnit) 95 } 96 97 ingressOut := new(bytes.Buffer) 98 99 ingress := exec.Command(path.Join(m.containerPath, "net.sh"), "get_ingress_info") 100 ingress.Env = []string{"ID=" + m.containerID} 101 ingress.Stdout = ingressOut 102 103 err = runner.Run(ingress) 104 if err != nil { 105 return limits, err 106 } 107 108 matches = OUT_RATE_PATTERN.FindStringSubmatch(string(ingressOut.Bytes())) 109 if matches != nil { 110 outRate, err := strconv.ParseUint(matches[1], 10, 0) 111 if err != nil { 112 return limits, err 113 } 114 115 outBurst, err := strconv.ParseUint(matches[3], 10, 0) 116 if err != nil { 117 return limits, err 118 } 119 120 outRateUnit := matches[2] 121 outBurstUnit := matches[4] 122 123 limits.OutRate = convertUnits(outRate, outRateUnit) / 8 124 limits.OutBurst = convertUnits(outBurst, outBurstUnit) 125 } 126 127 return limits, err 128 } 129 130 func convertUnits(num uint64, unit string) uint64 { 131 switch unit { 132 case "K": 133 return num * 1024 134 case "M": 135 return num * (1024 ^ 2) 136 case "G": 137 return num * (1024 ^ 3) 138 default: 139 return num 140 } 141 }