Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support IPv6 addresses during fingerprinting #2536

Merged
merged 10 commits into from
Apr 10, 2017
94 changes: 54 additions & 40 deletions client/fingerprint/network.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package fingerprint

import (
"errors"
"fmt"
"log"
"net"
Expand Down Expand Up @@ -56,10 +55,11 @@ func NewNetworkFingerprint(logger *log.Logger) Fingerprint {
}

func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
// newNetwork is populated and addded to the Nodes resources
newNetwork := &structs.NetworkResource{}
var ip string
if node.Resources == nil {
node.Resources = &structs.Resources{}
}

// Find the named interface
intf, err := f.findInterface(cfg.NetworkInterface)
switch {
case err != nil:
Expand All @@ -69,66 +69,80 @@ func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node)
return false, nil
}

if ip, err = f.ipAddress(intf); err != nil {
return false, fmt.Errorf("Unable to find IP address of interface: %s, err: %v", intf.Name, err)
}

newNetwork.Device = intf.Name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to set device name

Copy link
Contributor Author

@diptanu diptanu Apr 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node.Attributes["unique.network.ip-address"] = ip
newNetwork.IP = ip
newNetwork.CIDR = newNetwork.IP + "/32"

f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP %v during fingerprinting", intf.Name, ip)

// Record the throughput of the interface
var mbits int
throughput := f.linkSpeed(intf.Name)
if cfg.NetworkSpeed != 0 {
newNetwork.MBits = cfg.NetworkSpeed
f.logger.Printf("[DEBUG] fingerprint.network: setting link speed to user configured speed: %d", newNetwork.MBits)
mbits = cfg.NetworkSpeed
f.logger.Printf("[DEBUG] fingerprint.network: setting link speed to user configured speed: %d", mbits)
} else if throughput != 0 {
newNetwork.MBits = throughput
f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, newNetwork.MBits)
mbits = throughput
f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, mbits)
} else {
newNetwork.MBits = defaultNetworkSpeed
mbits = defaultNetworkSpeed
f.logger.Printf("[DEBUG] fingerprint.network: link speed could not be detected and no speed specified by user. Defaulting to %d", defaultNetworkSpeed)
}

if node.Resources == nil {
node.Resources = &structs.Resources{}
// Create the network resources from the interface
nwResources, err := f.createNetworkResources(mbits, intf)
if err != nil {
return false, err
}

node.Resources.Networks = append(node.Resources.Networks, newNetwork)
// Add the network resources to the node
for _, nwResource := range nwResources {
node.Resources.Networks = append(node.Resources.Networks, nwResource)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node.Resources.Networks = nwResource outside of the loop?

f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP: %v, CIDR: %v during fingerprinting",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove during fingerprinting. The prefix is fingerprint.network :)

intf.Name, nwResource.IP, nwResource.CIDR)
}

if len(nwResources) > 0 {
node.Attributes["unique.network.ip-address"] = nwResources[0].IP
}

// return true, because we have a network connection
return true, nil
}

// Gets the ipv4 addr for a network interface
func (f *NetworkFingerprint) ipAddress(intf *net.Interface) (string, error) {
var addrs []net.Addr
var err error

if addrs, err = f.interfaceDetector.Addrs(intf); err != nil {
return "", err
}

if len(addrs) == 0 {
return "", errors.New(fmt.Sprintf("Interface %s has no IP address", intf.Name))
// createNetworkResources creates network resources for every IP
func (f *NetworkFingerprint) createNetworkResources(throughput int, intf *net.Interface) ([]*structs.NetworkResource, error) {
// Find the interface with the name
addrs, err := f.interfaceDetector.Addrs(intf)
if err != nil {
return nil, err
}
nwResources := make([]*structs.NetworkResource, 0)
for _, addr := range addrs {
// Create a new network resource
newNetwork := &structs.NetworkResource{
Device: intf.Name,
MBits: throughput,
}

// Find the IP Addr and the CIDR from the Address
var ip net.IP
switch v := (addr).(type) {
case *net.IPNet:
ip = v.IP
newNetwork.IP = v.IP.String()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this get overrides right below?

case *net.IPAddr:
ip = v.IP
}

// If the ip is link-local then we ignore it
if ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get a test around these and IPv4/6 CIDRs

continue
}
newNetwork.IP = ip.String()
if ip.To4() != nil {
return ip.String(), nil
newNetwork.CIDR = newNetwork.IP + "/32"
} else {
newNetwork.CIDR = newNetwork.IP + "/128"
}
}

return "", fmt.Errorf("Couldn't parse IP address for interface %s", intf.Name)

nwResources = append(nwResources, newNetwork)
}
return nwResources, nil
}

// Checks if the device is marked UP by the operator
Expand All @@ -138,8 +152,8 @@ func (f *NetworkFingerprint) isDeviceEnabled(intf *net.Interface) bool {

// Checks if the device has any IP address configured
func (f *NetworkFingerprint) deviceHasIpAddress(intf *net.Interface) bool {
_, err := f.ipAddress(intf)
return err == nil
addrs, err := f.interfaceDetector.Addrs(intf)
return err == nil && len(addrs) != 0
}

func (n *NetworkFingerprint) isDeviceLoopBackOrPointToPoint(intf *net.Interface) bool {
Expand Down