// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package eni import ( "fmt" "net" "github.com/aws/amazon-vpc-cni-plugins/network/vpc" log "github.com/cihub/seelog" ) // ENI represents a VPC Elastic Network Interface. type ENI struct { linkIndex int linkName string macAddress net.HardwareAddr } // NewENI creates a new ENI object. One of linkName or macAddress must be specified. func NewENI(linkName string, macAddress net.HardwareAddr) (*ENI, error) { if linkName == "" && macAddress == nil { return nil, fmt.Errorf("missing linkName and macAddress") } eni := &ENI{ linkName: linkName, macAddress: macAddress, } return eni, nil } // GetLinkIndex returns the local interface index of the ENI. func (eni *ENI) GetLinkIndex() int { return eni.linkIndex } // GetLinkName returns the local interface name of the ENI. func (eni *ENI) GetLinkName() string { return eni.linkName } // GetMACAddress returns the MAC address of the ENI. func (eni *ENI) GetMACAddress() net.HardwareAddr { return eni.macAddress } // String returns a string representation of the ENI. func (eni *ENI) String() string { return fmt.Sprintf("{linkName:%s macAddress:%s}", eni.linkName, eni.macAddress) } // AttachToLink attaches the ENI to a link. func (eni *ENI) AttachToLink() error { var iface *net.Interface var err error if eni.linkName != "" { // Find the interface by name. iface, err = net.InterfaceByName(eni.linkName) if err != nil { log.Errorf("Failed to find an interface with name %s: %v.", eni.linkName, err) return err } } else { // Find the interface by MAC address. interfaces, err := net.Interfaces() if err != nil { return err } iface = getInterfaceByMACAddress(eni.macAddress, interfaces) if iface == nil { log.Errorf("Failed to find an interface with MAC address %s.", eni.macAddress) return fmt.Errorf("invalid MAC address") } } eni.linkIndex = iface.Index eni.linkName = iface.Name eni.macAddress = iface.HardwareAddr return nil } // DetachFromLink detaches the ENI from a link. func (eni *ENI) DetachFromLink() error { eni.linkIndex = 0 return nil } // getInterfaceByMACAddress returns the interface with the specified MAC address. func getInterfaceByMACAddress(macAddress net.HardwareAddr, interfaces []net.Interface) *net.Interface { var chosenInterface *net.Interface // If there are multiple matches, pick the one with the shortest name. for i := 0; i < len(interfaces); i++ { iface := &interfaces[i] if vpc.CompareMACAddress(iface.HardwareAddr, macAddress) { if chosenInterface == nil || len(chosenInterface.Name) > len(iface.Name) { chosenInterface = iface } } } return chosenInterface }