pkg.re/essentialkaos/ek.10@v12.41.0+incompatible/system/info_net_linux.go (about) 1 package system 2 3 // ////////////////////////////////////////////////////////////////////////////////// // 4 // // 5 // Copyright (c) 2022 ESSENTIAL KAOS // 6 // Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0> // 7 // // 8 // ////////////////////////////////////////////////////////////////////////////////// // 9 10 import ( 11 "bufio" 12 "errors" 13 "strconv" 14 "strings" 15 "time" 16 17 "pkg.re/essentialkaos/ek.v12/strutil" 18 ) 19 20 // ////////////////////////////////////////////////////////////////////////////////// // 21 22 // Path to file with net info in procfs 23 var procNetFile = "/proc/net/dev" 24 25 // ////////////////////////////////////////////////////////////////////////////////// // 26 27 // GetInterfacesStats returns info about network interfaces 28 func GetInterfacesStats() (map[string]*InterfaceStats, error) { 29 s, closer, err := getFileScanner(procNetFile) 30 31 if err != nil { 32 return nil, err 33 } 34 35 defer closer() 36 37 return parseInterfacesStats(s) 38 } 39 40 // GetNetworkSpeed returns network input/output speed in bytes per second for 41 // all network interfaces 42 func GetNetworkSpeed(duration time.Duration) (uint64, uint64, error) { 43 ii1, err := GetInterfacesStats() 44 45 if err != nil { 46 return 0, 0, err 47 } 48 49 time.Sleep(duration) 50 51 ii2, err := GetInterfacesStats() 52 53 if err != nil { 54 return 0, 0, err 55 } 56 57 in, out := CalculateNetworkSpeed(ii1, ii2, duration) 58 59 return in, out, nil 60 } 61 62 // CalculateNetworkSpeed calculates network input/output speed in bytes per second for 63 // all network interfaces 64 func CalculateNetworkSpeed(ii1, ii2 map[string]*InterfaceStats, duration time.Duration) (uint64, uint64) { 65 if ii1 == nil || ii2 == nil { 66 return 0, 0 67 } 68 69 rb1, tb1 := getActiveInterfacesBytes(ii1) 70 rb2, tb2 := getActiveInterfacesBytes(ii2) 71 72 if rb1+tb1 == 0 || rb2+tb2 == 0 { 73 return 0, 0 74 } 75 76 durationSec := uint64(duration / time.Second) 77 78 return (rb2 - rb1) / durationSec, (tb2 - tb1) / durationSec 79 } 80 81 // ////////////////////////////////////////////////////////////////////////////////// // 82 83 // codebeat:disable[LOC,ABC] 84 85 // parseInterfacesStats parses interfaces stats data 86 func parseInterfacesStats(s *bufio.Scanner) (map[string]*InterfaceStats, error) { 87 var err error 88 89 stats := make(map[string]*InterfaceStats) 90 91 for s.Scan() { 92 text := s.Text() 93 94 if !strings.Contains(text, ":") { 95 continue 96 } 97 98 ii := &InterfaceStats{} 99 100 name := strings.TrimRight(strutil.ReadField(text, 0, true), ":") 101 102 ii.ReceivedBytes, err = strconv.ParseUint(strutil.ReadField(text, 1, true), 10, 64) 103 104 if err != nil { 105 return nil, errors.New("Can't parse field 1 as unsigned integer in " + procNetFile) 106 } 107 108 ii.ReceivedPackets, err = strconv.ParseUint(strutil.ReadField(text, 2, true), 10, 64) 109 110 if err != nil { 111 return nil, errors.New("Can't parse field 2 as unsigned integer in " + procNetFile) 112 } 113 114 ii.TransmittedBytes, err = strconv.ParseUint(strutil.ReadField(text, 9, true), 10, 64) 115 116 if err != nil { 117 return nil, errors.New("Can't parse field 9 as unsigned integer in " + procNetFile) 118 } 119 120 ii.TransmittedPackets, err = strconv.ParseUint(strutil.ReadField(text, 10, true), 10, 64) 121 122 if err != nil { 123 return nil, errors.New("Can't parse field 10 as unsigned integer in " + procNetFile) 124 } 125 126 stats[name] = ii 127 } 128 129 if len(stats) == 0 { 130 return nil, errors.New("Can't parse file " + procNetFile) 131 } 132 133 return stats, nil 134 } 135 136 // codebeat:enable[LOC,ABC] 137 138 // getActiveInterfacesBytes calculate received and transmitted bytes on all interfaces 139 func getActiveInterfacesBytes(is map[string]*InterfaceStats) (uint64, uint64) { 140 var ( 141 received uint64 142 transmitted uint64 143 ) 144 145 for name, info := range is { 146 if strings.HasPrefix(name, "lo") || strings.HasPrefix(name, "bond") { 147 continue 148 } 149 150 if info.ReceivedBytes == 0 && info.TransmittedBytes == 0 { 151 continue 152 } 153 154 received += info.ReceivedBytes 155 transmitted += info.TransmittedBytes 156 } 157 158 return received, transmitted 159 }