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  }