github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/linux_container/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/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 ContainerBandwidthManager struct { 21 containerPath string 22 containerID string 23 24 runner command_runner.CommandRunner 25 } 26 27 func New(containerPath, containerID string, runner command_runner.CommandRunner) *ContainerBandwidthManager { 28 return &ContainerBandwidthManager{ 29 containerPath: containerPath, 30 containerID: containerID, 31 32 runner: runner, 33 } 34 } 35 36 func (m *ContainerBandwidthManager) SetLimits( 37 logger lager.Logger, 38 limits garden.BandwidthLimits, 39 ) error { 40 runner := logging.Runner{ 41 CommandRunner: m.runner, 42 Logger: logger, 43 } 44 45 setRate := exec.Command(path.Join(m.containerPath, "net_rate.sh")) 46 setRate.Env = []string{ 47 fmt.Sprintf("BURST=%d", limits.BurstRateInBytesPerSecond), 48 fmt.Sprintf("RATE=%d", limits.RateInBytesPerSecond*8), 49 } 50 51 return runner.Run(setRate) 52 } 53 54 func (m *ContainerBandwidthManager) GetLimits(logger lager.Logger) (garden.ContainerBandwidthStat, error) { 55 limits := garden.ContainerBandwidthStat{} 56 57 runner := logging.Runner{ 58 CommandRunner: m.runner, 59 Logger: logger, 60 } 61 62 egressOut := new(bytes.Buffer) 63 64 egress := exec.Command(path.Join(m.containerPath, "net.sh"), "get_egress_info") 65 egress.Env = []string{"ID=" + m.containerID} 66 egress.Stdout = egressOut 67 68 err := runner.Run(egress) 69 if err != nil { 70 return limits, err 71 } 72 73 matches := IN_RATE_PATTERN.FindStringSubmatch(string(egressOut.Bytes())) 74 if matches != nil { 75 inRate, err := strconv.ParseUint(matches[1], 10, 0) 76 if err != nil { 77 return limits, err 78 } 79 80 inBurst, err := strconv.ParseUint(matches[3], 10, 0) 81 if err != nil { 82 return limits, err 83 } 84 85 inRateUnit := matches[2] 86 inBurstUnit := matches[4] 87 88 limits.InRate = convertUnits(inRate, inRateUnit) / 8 89 limits.InBurst = convertUnits(inBurst, inBurstUnit) 90 } 91 92 ingressOut := new(bytes.Buffer) 93 94 ingress := exec.Command(path.Join(m.containerPath, "net.sh"), "get_ingress_info") 95 ingress.Env = []string{"ID=" + m.containerID} 96 ingress.Stdout = ingressOut 97 98 err = runner.Run(ingress) 99 if err != nil { 100 return limits, err 101 } 102 103 matches = OUT_RATE_PATTERN.FindStringSubmatch(string(ingressOut.Bytes())) 104 if matches != nil { 105 outRate, err := strconv.ParseUint(matches[1], 10, 0) 106 if err != nil { 107 return limits, err 108 } 109 110 outBurst, err := strconv.ParseUint(matches[3], 10, 0) 111 if err != nil { 112 return limits, err 113 } 114 115 outRateUnit := matches[2] 116 outBurstUnit := matches[4] 117 118 limits.OutRate = convertUnits(outRate, outRateUnit) / 8 119 limits.OutBurst = convertUnits(outBurst, outBurstUnit) 120 } 121 122 return limits, err 123 } 124 125 func convertUnits(num uint64, unit string) uint64 { 126 switch unit { 127 case "K": 128 return num * 1024 129 case "M": 130 return num * (1024 ^ 2) 131 case "G": 132 return num * (1024 ^ 3) 133 default: 134 return num 135 } 136 }