summaryrefslogtreecommitdiff
path: root/extendedstats/unix.go
diff options
context:
space:
mode:
authorWill Hawkins <[email protected]>2022-06-05 03:32:17 -0400
committerWill Hawkins <[email protected]>2022-06-05 03:32:17 -0400
commitd06438ff7414abfcc5a2a1bd13a935ee594f0842 (patch)
tree52517463088faaf2ad85ffddb7e45860384b08ac /extendedstats/unix.go
parent9be87fa5ec89c9e393c9c93b3cb36668c71593d6 (diff)
[Feature] Add -extended-stats for *nix platforms
On *nix platforms, there is now a `-extended-stats` option that will print out some extended statistics for the test. The statistics are based on information gleaned from the `TCP_INFO` of the underlying TCP connections. What is implemented so far is just a proof of concept of the extended stats that could be calculated. Depending on what users want, we can add additional extended statistics.
Diffstat (limited to 'extendedstats/unix.go')
-rw-r--r--extendedstats/unix.go72
1 files changed, 72 insertions, 0 deletions
diff --git a/extendedstats/unix.go b/extendedstats/unix.go
new file mode 100644
index 0000000..e50d719
--- /dev/null
+++ b/extendedstats/unix.go
@@ -0,0 +1,72 @@
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package extendedstats
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net"
+
+ "github.com/network-quality/goresponsiveness/utilities"
+ "golang.org/x/sys/unix"
+)
+
+type ExtendedStats struct {
+ MaxPathMtu uint64
+ TotalRetransmissions uint64
+ AverageRtt float64
+ rtt_measurements uint64
+ total_rtt float64
+}
+
+func ExtendedStatsAvailable() bool {
+ return true
+}
+
+func (es *ExtendedStats) IncorporateConnectionStats(rawConn net.Conn) {
+ tlsConn, ok := rawConn.(*tls.Conn)
+ if !ok {
+ fmt.Printf("OOPS: Could not get the TCP info for the connection (not a TLS connection)!\n")
+ }
+ tcpConn, ok := tlsConn.NetConn().(*net.TCPConn)
+ if !ok {
+ fmt.Printf("OOPS: Could not get the TCP info for the connection (not a TCP connection)!\n")
+ }
+ if info, err := getTCPInfo(tcpConn); err != nil {
+ fmt.Printf("OOPS: Could not get the TCP info for the connection: %v!\n", err)
+ } else {
+ es.MaxPathMtu = utilities.Max(es.MaxPathMtu, uint64(info.Pmtu))
+ // https://lkml.iu.edu/hypermail/linux/kernel/1705.0/01790.html
+ es.TotalRetransmissions += uint64(info.Total_retrans)
+ es.total_rtt += float64(info.Rtt)
+ es.rtt_measurements += 1
+ es.AverageRtt = es.total_rtt / float64(es.rtt_measurements)
+
+ }
+}
+
+func (es *ExtendedStats) Repr() string {
+ return fmt.Sprintf(`Extended Statistics:
+ Maximum Path MTU: %v
+ Total Retransmissions: %v
+ Average RTT: %v
+`, es.MaxPathMtu, es.TotalRetransmissions, es.AverageRtt)
+}
+
+func getTCPInfo(connection net.Conn) (*unix.TCPInfo, error) {
+ tcpConn, ok := connection.(*net.TCPConn)
+ if !ok {
+ return nil, fmt.Errorf("connection is not a net.TCPConn")
+ }
+ rawConn, err := tcpConn.SyscallConn()
+ if err != nil {
+ return nil, err
+ }
+
+ var info *unix.TCPInfo = nil
+ rawConn.Control(func(fd uintptr) {
+ info, err = unix.GetsockoptTCPInfo(int(fd), unix.SOL_TCP, unix.TCP_INFO)
+ })
+ return info, err
+}