net-predictable/misc.go

108 lines
2.2 KiB
Go

package main
import (
"errors"
"fmt"
"io"
"os"
"strconv"
"strings"
)
var (
ErrInvalidPCIFormat = errors.New("Invalid PCI address format")
ErrInvalidUSBFormat = errors.New("Invalid USB address format")
ErrParseMac = errors.New("Failed to parse MAC address")
)
var SYSFS = "/sys"
// Sourced from include/uapi/linux/netdevice.h
// as of v6.8
const (
NET_NAME_UNKNOWN = 0 /* unknown origin (not exposed to userspace) */
NET_NAME_ENUM = 1 /* enumerated by kernel */
NET_NAME_PREDICTABLE = 2 /* predictably named by the kernel */
NET_NAME_USER = 3 /* provided by user-space */
NET_NAME_RENAMED = 4 /* renamed by user-space */
)
type IfNameType int
type IfNameList map[IfNameType]string
const (
IfNameKern IfNameType = iota
IfNameMAC
IfNameLoc
)
type iface struct {
pfx string
netpath string
names IfNameList
}
func New(ifname string) (i iface, err error) {
if strings.HasPrefix(ifname, "eth") {
i.pfx = "en"
} else {
// Fall back to first 2 characters
i.pfx = ifname[0:2]
}
i.names = make(IfNameList)
i.names[IfNameKern] = ifname
i.netpath = strings.Join([]string{SYSFS, "class/net", i.names[IfNameKern]}, "/")
return
}
func (i iface) shouldRun() (should bool, err error) {
ifname_assign_type := strings.Join([]string{i.netpath, "name_assign_type"}, "/")
should = true
var (
file *os.File
contents []byte
)
if file, err = os.Open(ifname_assign_type); err != nil {
err = fmt.Errorf("Failed to open interface rename property: %w", err)
return
}
defer file.Close()
if contents, err = io.ReadAll(file); err != nil {
err = fmt.Errorf("Failed to read interface rename property: %w", err)
return
}
num, _ := strings.CutSuffix(string(contents), "\n")
var res int
if res, err = strconv.Atoi(num); err != nil {
err = fmt.Errorf("Failed to interpret interface rename property as number: %w", err)
return
}
if res != NET_NAME_ENUM {
should = false
return
}
return
}
func (i iface) Process() (err error) {
if lerr := i.ProcLoc(); lerr != nil {
err = lerr
}
if lerr := i.ProcMAC(); lerr != nil {
err = lerr
}
// It can error but as long as we get a identifier along the path it's okay
if i.names[IfNameLoc] == "" && i.names[IfNameMAC] == "" {
return
}
err = nil
return
}