Skip to content

Commit

Permalink
Aggregate targets of the same hop
Browse files Browse the repository at this point in the history
  • Loading branch information
sj14 authored and tonobo committed Apr 22, 2021
1 parent 0dfeb33 commit b494630
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 72 deletions.
29 changes: 12 additions & 17 deletions pkg/hop/hop.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type HopStatistic struct {
PID int
Sent int
TTL int
Target string
Targets []string
Last icmp.ICMPReturn
Best icmp.ICMPReturn
Worst icmp.ICMPReturn
Expand Down Expand Up @@ -51,7 +51,7 @@ func (h *HopStatistic) MarshalJSON() ([]byte, error) {
Sent: h.Sent,
TTL: h.TTL,
Loss: h.Loss(),
Target: h.Target,
Target: fmt.Sprintf("%v", h.Targets), // TODO:
PacketBufferSize: h.RingBufferSize,
Last: h.Last.Elapsed.Seconds() * 1000,
Best: h.Best.Elapsed.Seconds() * 1000,
Expand Down Expand Up @@ -126,7 +126,7 @@ func (h *HopStatistic) packets() []*packet {
return v
}

func (h *HopStatistic) Render(lastTTL int, ptrLookup bool) {
func (h *HopStatistic) Render(ptrLookup bool) {
if h.dnsCache == nil {
h.dnsCache = map[string]string{}
}
Expand All @@ -144,14 +144,9 @@ func (h *HopStatistic) Render(lastTTL int, ptrLookup bool) {
})
l := fmt.Sprintf("%d", h.RingBufferSize)

ttl := fmt.Sprintf("%3d:|--", h.TTL)
if h.TTL == lastTTL {
ttl = " "
}

gm.Printf("%s %-20s %5.1f%% %4d %6.1f %6.1f %6.1f %6.1f %"+l+"s\n",
ttl,
fmt.Sprintf("%.20s", h.lookupAddr(ptrLookup)),
gm.Printf("%3d:|-- %-20s %5.1f%% %4d %6.1f %6.1f %6.1f %6.1f %"+l+"s\n",
h.TTL,
fmt.Sprintf("%.20s", h.lookupAddr(ptrLookup, 0)),
h.Loss(),
h.Sent,
h.Last.Elapsed.Seconds()*1000,
Expand All @@ -162,21 +157,21 @@ func (h *HopStatistic) Render(lastTTL int, ptrLookup bool) {
)
}

func (h *HopStatistic) lookupAddr(ptrLookup bool) string {
func (h *HopStatistic) lookupAddr(ptrLookup bool, index int) string {
addr := "???"
if h.Target != "" {
addr = h.Target
if h.Targets[index] != "" {
addr = h.Targets[index]
if ptrLookup {
if key, ok := h.dnsCache[h.Target]; ok {
if key, ok := h.dnsCache[h.Targets[index]]; ok {
addr = key
} else {
names, err := net.LookupAddr(h.Target)
names, err := net.LookupAddr(h.Targets[index])
if err == nil && len(names) > 0 {
addr = names[0]
}
}
}
h.dnsCache[h.Target] = addr
h.dnsCache[h.Targets[index]] = addr
}
return addr
}
89 changes: 34 additions & 55 deletions pkg/mtr/mtr.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"math/rand"
"net"
"os"
"sort"
"strings"
"sync"
"time"

Expand All @@ -24,7 +22,7 @@ type MTR struct {
interval time.Duration
Address string `json:"destination"`
hopsleep time.Duration
Statistic map[string]*hop.HopStatistic `json:"statistic"`
Statistic map[int]*hop.HopStatistic `json:"statistic"`
ringBufferSize int
maxHops int
maxUnknownHops int
Expand Down Expand Up @@ -54,7 +52,7 @@ func NewMTR(addr, srcAddr string, timeout time.Duration, interval time.Duration,
hopsleep: hopsleep,
Address: addr,
mutex: &sync.RWMutex{},
Statistic: map[string]*hop.HopStatistic{},
Statistic: map[int]*hop.HopStatistic{},
maxHops: maxHops,
ringBufferSize: ringBufferSize,
maxUnknownHops: maxUnknownHops,
Expand All @@ -63,105 +61,86 @@ func NewMTR(addr, srcAddr string, timeout time.Duration, interval time.Duration,
}

func (m *MTR) registerStatistic(ttl int, r icmp.ICMPReturn) *hop.HopStatistic {
if r.Addr == "" {
r.Addr = "???"
}
id := fmt.Sprintf("%3d-%v", ttl, r.Addr)

s, ok := m.Statistic[id]
s, ok := m.Statistic[ttl]
if !ok {
s = &hop.HopStatistic{
Sent: 0,
TTL: ttl,
Target: r.Addr,
Timeout: m.timeout,
Last: r,
Best: r,
Worst: r,
Lost: 0,
Packets: ring.New(m.ringBufferSize),
RingBufferSize: m.ringBufferSize,
}
m.Statistic[id] = s
m.Statistic[ttl] = s
}

s.Last = r
s.Sent++

s.Targets = addTarget(s.Targets, r.Addr)

s.Packets = s.Packets.Prev()
s.Packets.Value = r

if !r.Success {
s.Lost++
setSentToHopUnkown(ttl, m.Statistic)
return s // do not count failed into statistics
}

setSentToHopUnkown(ttl, m.Statistic)

s.SumElapsed = r.Elapsed + s.SumElapsed

if s.Best.Elapsed > r.Elapsed {
if !s.Best.Success || s.Best.Elapsed > r.Elapsed {
s.Best = r
}
if s.Worst.Elapsed < r.Elapsed {
s.Worst = r
}

s.Packets = s.Packets.Prev()
s.Packets.Value = r
return s
}

// sent + lost
func ttlCheckedCount(ttl int, m map[string]*hop.HopStatistic) int {
sent := 0

for key, v := range m {
if v.TTL != ttl {
continue
func addTarget(currentTargets []string, toAdd string) []string {
for _, t := range currentTargets {
if t == toAdd {
// already added
return currentTargets
}

if strings.HasSuffix(key, "-???") {
sent += v.Lost
continue
}

sent += v.Sent
}
return sent
}

func setSentToHopUnkown(ttl int, m map[string]*hop.HopStatistic) {
for key, v := range m {
if !strings.HasSuffix(key, "-???") {
continue
}
if v.TTL != ttl {
continue
var newTargets []string
if len(currentTargets) > 0 {
// do not add no-ip target
if toAdd == "" {
return currentTargets
}

v.Sent = ttlCheckedCount(ttl, m)
// remove no-ip target
for _, t := range currentTargets {
if t != "" {
newTargets = append(newTargets, t)
}
}
} else {
newTargets = currentTargets
}

// add the new one
return append(newTargets, toAdd)
}

// TODO: aggregates everything using the first target even when there are multiple
func (m *MTR) Render(offset int) {
gm.MoveCursor(1, offset)
l := fmt.Sprintf("%d", m.ringBufferSize)
gm.Printf("HOP: %-20s %5s%% %4s %6s %6s %6s %6s %"+l+"s\n", "Address", "Loss", "Sent", "Last", "Avg", "Best", "Worst", "Packets")
i := 0

keys := make([]string, 0, len(m.Statistic))
for k := range m.Statistic {
keys = append(keys, k)
}
sort.Strings(keys)

lastTTL := 0
for _, k := range keys {
i++
for i := 1; i <= len(m.Statistic); i++ {
gm.MoveCursor(1, offset+i)
m.mutex.RLock()
m.Statistic[k].Render(lastTTL, m.ptrLookup)
m.Statistic[i].Render(m.ptrLookup)
m.mutex.RUnlock()
lastTTL = m.Statistic[k].TTL
}
}

Expand Down

0 comments on commit b494630

Please sign in to comment.