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  }