github.com/haraldrudell/parl@v0.4.176/pnet/ifindex.go (about)

     1  /*
     2  © 2020–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package pnet
     7  
     8  import (
     9  	"errors"
    10  	"math"
    11  	"net"
    12  	"net/netip"
    13  	"strconv"
    14  
    15  	"github.com/haraldrudell/parl/perrors"
    16  )
    17  
    18  // IfIndex is a dynamic reference to a network interface on Linux systems
    19  type IfIndex uint32
    20  
    21  func NewIfIndex(index uint32) (ifIndex IfIndex) {
    22  	return IfIndex(index)
    23  }
    24  
    25  func NewIfIndexInt(value int) (ifIndex IfIndex, err error) {
    26  	if value < 0 || value > math.MaxUint32 {
    27  		err = perrors.ErrorfPF("Value not uint32: %d", value)
    28  		return
    29  	}
    30  	ifIndex = IfIndex(value)
    31  	return
    32  }
    33  
    34  // IsValid determines if interface index value is set, ie. > 0
    35  func (ifIndex IfIndex) IsValid() (isValid bool) {
    36  	return ifIndex > 0
    37  }
    38  
    39  // Interface gets net.Interface for ifIndex
    40  //   - netInterface.Name is interface name "eth0"
    41  //   - netInterface.Addr() returns assigned IP addresses
    42  func (ifIndex IfIndex) Interface() (netInterface *net.Interface, isErrNoSuchInterface bool, err error) {
    43  	if netInterface, err = net.InterfaceByIndex(int(ifIndex)); err != nil {
    44  		isErrNoSuchInterface = errors.Is(err, ErrNoSuchInterface)
    45  		err = perrors.ErrorfPF("net.InterfaceByIndex %d %w", ifIndex, err)
    46  	}
    47  	return
    48  }
    49  
    50  // InterfaceAddrs gets Addresses for interface
    51  //   - netInterface.Name is interface name "eth0"
    52  //   - netInterface.Addr() returns assigned IP addresses
    53  func (ifIndex IfIndex) InterfaceAddrs(useNameCache ...NameCacher) (name string, i4, i6 []netip.Prefix, err error) {
    54  	var doCache = NoCache
    55  	if len(useNameCache) > 0 {
    56  		doCache = useNameCache[0]
    57  	}
    58  
    59  	var netInterface *net.Interface
    60  	var isErrNoSuchInterface bool
    61  	if netInterface, isErrNoSuchInterface, err = ifIndex.Interface(); err != nil {
    62  		if isErrNoSuchInterface && doCache != NoCache {
    63  			name, err = networkInterfaceNameCache.CachedName(ifIndex, doCache)
    64  		}
    65  		return // error or from cache
    66  	}
    67  
    68  	name = netInterface.Name
    69  	i4, i6, err = InterfaceAddrs(netInterface)
    70  	return
    71  }
    72  
    73  // Interface gets net.Interface for ifIndex
    74  //   - InterfaceIndex is unique for promting methods
    75  func (ifIndex IfIndex) InterfaceIndex() (interfaceIndex int) {
    76  	return int(ifIndex)
    77  }
    78  
    79  // Zone gets net.IPAddr.Zone string for ifIndex
    80  //   - if an interfa ce name can be ontained, that is the zone
    81  //   - otherwise a numeric zone is used
    82  //   - if ifIndex is invalid, empty string
    83  func (ifIndex IfIndex) Zone() (zone string, isNumeric bool, err error) {
    84  	if ifIndex.IsValid() {
    85  		var iface *net.Interface
    86  		if iface, _, err = ifIndex.Interface(); err == nil { // may fail if interface already deleted
    87  			zone = iface.Name
    88  		} else {
    89  			zone = strconv.Itoa(int(ifIndex))
    90  			isNumeric = true
    91  		}
    92  	}
    93  	return
    94  }
    95  
    96  // "#13"
    97  func (ifIndex IfIndex) String() (s string) {
    98  	return "#" + strconv.Itoa(int(ifIndex))
    99  }