github.com/Cloud-Foundations/Dominator@v0.3.4/lib/netspeed/impl.go (about) 1 package netspeed 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "net" 8 "os" 9 "strings" 10 "sync" 11 ) 12 13 const ( 14 procRouteFilename = "/proc/net/route" 15 speedPathFormat = "/sys/class/net/%s/speed" 16 ) 17 18 var ( 19 lock sync.Mutex 20 hostToSpeed = make(map[string]uint64) 21 ) 22 23 func getSpeedToAddress(address string) (uint64, bool) { 24 if fields := strings.Split(address, ":"); len(fields) == 2 { 25 return getSpeedToHost(fields[0]) 26 } 27 return 0, false 28 } 29 30 func getSpeedToHost(hostname string) (uint64, bool) { 31 if hostname == "localhost" { 32 return 0, true 33 } 34 lock.Lock() 35 speed, ok := hostToSpeed[hostname] 36 lock.Unlock() 37 if ok { 38 return speed, true 39 } 40 interfaceName, err := findInterfaceForHost(hostname) 41 if err != nil { 42 return 0, false 43 } 44 file, err := os.Open(fmt.Sprintf(speedPathFormat, interfaceName)) 45 if err != nil { 46 return 0, false 47 } 48 defer file.Close() 49 var value uint64 50 nScanned, err := fmt.Fscanf(file, "%d", &value) 51 if err != nil || nScanned < 1 { 52 return 0, false 53 } 54 speed = value * 1000000 / 8 55 lock.Lock() 56 hostToSpeed[hostname] = speed 57 lock.Unlock() 58 return speed, true 59 } 60 61 func findInterfaceForHost(hostname string) (string, error) { 62 var hostIP net.IP 63 if hostname == "" { 64 hostIP = make(net.IP, 4) 65 } else { 66 hostIPs, err := net.LookupIP(hostname) 67 if err != nil { 68 return "", err 69 } 70 if len(hostIPs) < 1 { 71 return "", errors.New("not enough IPs") 72 } 73 hostIP = hostIPs[0] 74 } 75 file, err := os.Open(procRouteFilename) 76 if err != nil { 77 return "", err 78 } 79 defer file.Close() 80 scanner := bufio.NewScanner(file) 81 mostSpecificInterfaceName := "" 82 mostSpecificNetmaskBits := -1 83 for scanner.Scan() { 84 var interfaceName string 85 var destAddr, gatewayAddr, flags, mask uint32 86 var ign int 87 nCopied, err := fmt.Sscanf(scanner.Text(), 88 "%s %x %x %x %d %d %d %x %d %d %d", 89 &interfaceName, &destAddr, &gatewayAddr, &flags, &ign, &ign, &ign, 90 &mask, &ign, &ign, &ign) 91 if err != nil || nCopied < 11 { 92 continue 93 } 94 maskIP := net.IPMask(intToIP(mask)) 95 destIP := intToIP(destAddr) 96 if hostIP.Mask(maskIP).Equal(destIP) { 97 size, _ := maskIP.Size() 98 if size > mostSpecificNetmaskBits { 99 mostSpecificInterfaceName = interfaceName 100 mostSpecificNetmaskBits = size 101 } 102 } 103 } 104 return mostSpecificInterfaceName, scanner.Err() 105 } 106 107 func intToIP(ip uint32) net.IP { 108 result := make(net.IP, 4) 109 for i := range result { 110 result[i] = byte(ip >> uint(8*i)) 111 } 112 return result 113 }