Files
cloudpods/pkg/cloudmon/misc/pingutils.go
2023-03-13 09:41:27 +08:00

105 lines
2.5 KiB
Go

// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package misc
import (
"fmt"
"net"
"time"
"github.com/tatsushid/go-fastping"
"yunion.io/x/pkg/errors"
)
type SPingResult struct {
addr string
rtt []time.Duration
count int
}
func NewPingResult(addr string, count int) *SPingResult {
return &SPingResult{
addr: addr,
rtt: make([]time.Duration, 0),
count: count,
}
}
func (pr *SPingResult) Add(rtt time.Duration) {
pr.rtt = append(pr.rtt, rtt)
}
func (pr SPingResult) Rtt() (min time.Duration, avg time.Duration, max time.Duration) {
sum := time.Duration(0)
max = time.Duration(-1)
min = time.Duration(-1)
for _, d := range pr.rtt {
sum += d
if max < 0 || max < d {
max = d
}
if min < 0 || min > d {
min = d
}
}
if len(pr.rtt) > 0 {
avg = sum / time.Duration(len(pr.rtt))
}
return
}
func (pr SPingResult) Loss() int {
return 100 - len(pr.rtt)*100/pr.count
}
func (pr SPingResult) String() string {
min, avg, max := pr.Rtt()
return fmt.Sprintf("%d packets transmitted, %d received, %d%% packet loss, rtt min/avg/max = %d/%d/%d ms", pr.count, len(pr.rtt), pr.Loss(), min/time.Millisecond, avg/time.Millisecond, max/time.Millisecond)
}
func Ping(addrList []string, probeCount, timeoutSecond int, debug bool) (map[string]*SPingResult, error) {
p := fastping.NewPinger()
count := probeCount
timeout := time.Second * time.Duration(timeoutSecond)
p.MaxRTT = timeout
p.Size = 64
p.Debug = debug
result := make(map[string]*SPingResult)
for _, addr := range addrList {
result[addr] = NewPingResult(addr, count)
p.AddIP(addr)
}
p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
result[addr.String()].Add(rtt)
}
p.OnIdle = func() {
}
p.RunLoop()
defer p.Stop()
ticker := time.NewTicker(time.Duration(count) * timeout)
defer ticker.Stop()
select {
case <-p.Done():
if err := p.Err(); err != nil {
return nil, errors.Wrap(err, "ping error")
}
break
case <-ticker.C:
break
}
return result, nil
}