diff --git a/main.go b/main.go index dc3fcda..11058c6 100644 --- a/main.go +++ b/main.go @@ -18,9 +18,9 @@ import ( type Conf struct { Bandwidth struct { - Max int `yaml:"max"` - Min int `yaml:"min"` - Step int `yaml:"step"` + Max float64 `yaml:"max"` + Min float64 `yaml:"min"` + Step float64 `yaml:"step"` } `yaml:"bandwidth"` Interval int `yaml:"interval"` Host string `yaml:"host"` @@ -43,7 +43,7 @@ type UploadManager struct { LastOver time.Time } -func (m UploadManager) Upload() (int, error) { +func (m UploadManager) Upload() (float64, error) { tcCmd := exec.Command("tc", "qdisc", "show", "dev", conf.UploadInterface) out, err := tcCmd.CombinedOutput() if err != nil { @@ -54,14 +54,14 @@ func (m UploadManager) Upload() (int, error) { if err != nil { return 0, err } - return up, nil + return float64(up), nil } else { return 0, fmt.Errorf("could not parse bandwidth from tc") } } -func (m UploadManager) SetUpload(upload int) (int, error) { - tcCmd := exec.Command("tc", "qdisc", "change", "dev", conf.UploadInterface, "root", "cake", "bandwidth", fmt.Sprintf("%dMbit", upload)) +func (m UploadManager) SetUpload(upload float64) (float64, error) { + tcCmd := exec.Command("tc", "qdisc", "change", "dev", conf.UploadInterface, "root", "cake", "bandwidth", fmt.Sprintf("%dMbit", int(upload))) log.Debugf("[TC] exec %s", tcCmd.String()) out, err := tcCmd.CombinedOutput() if err != nil { @@ -89,7 +89,7 @@ func doPing(host string, count int, interval time.Duration) (*ping.Statistics, e return pinger.Statistics(), nil } -func (m UploadManager) isBWInRange(bw int) bool { +func (m UploadManager) isBWInRange(bw float64) bool { return bw <= conf.Bandwidth.Max && bw >= conf.Bandwidth.Min } @@ -104,13 +104,14 @@ func (m UploadManager) pingWorker() error { if stats.AvgRtt.Milliseconds() >= conf.ThrottlePingThreshold { m.LastOver = time.Now() + lastStep := conf.Bandwidth.Step * 0.5 up, err := m.Upload() if err != nil { return err } log.Infof("ping %s over threshold detected, starting extended pings...", stats.AvgRtt) - for stats.AvgRtt.Milliseconds() >= conf.ThrottlePingThreshold && m.isBWInRange(up-conf.Bandwidth.Step) { + for stats.AvgRtt.Milliseconds() >= conf.ThrottlePingThreshold && m.isBWInRange(up-lastStep*2) { stats, err = doPing(conf.Host, conf.ConformationPPP, time.Second) if err != nil { log.Warningf("ping to %s failed: %v", conf.Host, err) @@ -119,14 +120,26 @@ func (m UploadManager) pingWorker() error { } if stats.AvgRtt.Milliseconds() >= conf.ThrottlePingThreshold { - log.Infof("extended ping %s, adjusting upload TC %d->%d", stats.AvgRtt, up, up-conf.Bandwidth.Step) - up, err = m.SetUpload(up - conf.Bandwidth.Step) + lastStep *= 2 + newUp := up - lastStep + + if !m.isBWInRange(newUp) { + newUp = conf.Bandwidth.Min + } + + log.Infof("extended ping %s, adjusting upload TC %f->%f", stats.AvgRtt, up, newUp) + up, err = m.SetUpload(newUp) if err != nil { return err } m.LastOver = time.Now() + + if newUp == conf.Bandwidth.Min { + log.Infof("reached lower limit, stopping extended pings") + break + } } - time.Sleep(20 * time.Second) + time.Sleep(5 * time.Second) } } else if time.Since(m.LastOver) >= time.Duration(conf.TryRestoringAfter)*time.Minute { up, err := m.Upload()