Implement further functionality

- Detect multifunction based on functions available per PCI device
- Merge subfunctions of Loc into main function
- Handle errors better in Loc
- Rename some errors
- Don't exit if already renamed, instead skip renaming and add alias
  (useful with -force)
- Add missing altnames only
- Add alternative naming schemes as altnames
This commit is contained in:
Alex D. 2024-06-25 16:34:47 +00:00
parent b98771012d
commit f2c6fb79dc
Signed by: caskd
GPG Key ID: E5AE8A47B8EFC7ED
4 changed files with 120 additions and 101 deletions

102
loc.go
View File

@ -3,6 +3,7 @@ package main
import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
@ -36,10 +37,21 @@ func (i *iface) ProcLoc() (err error) {
}
var (
pci, usb, tmp string
procmode int
pci, usb string
procmode int
path = strings.Split(devpath, "/")
cdir = strings.Join([]string{
SYSFS,
"devices",
}, "/")
)
for _, v := range strings.Split(devpath, "/") {
for i, v := range path {
if i >= 1 {
// Append to currend directory
cdir = strings.Join([]string{cdir, path[i-1]}, "/")
}
if strings.HasPrefix(v, "pci") {
procmode = PathProcPCI
continue
@ -51,24 +63,92 @@ func (i *iface) ProcLoc() (err error) {
switch procmode {
case PathProcPCI:
{
if tmp, err = i.ProcPCI(v); err != nil {
var (
domain, bus, device, function int
)
if _, err = fmt.Sscanf(v, "%x:%x:%x.%x", &domain, &bus, &device, &function); err != nil {
err = ErrInvalidPCIFormat
continue
}
pci = tmp
var name strings.Builder
if domain != 0 {
// Hey, if you're reading this you're cool.
// Do you know any machine which has a PCI domain other than 0?
// Mail me at caskd@redxen.eu about it.
name.WriteString(fmt.Sprintf("P%d", domain))
}
name.WriteString(fmt.Sprintf("p%ds%d", bus, device))
// List PCI path to see if there's any other functions available under the same device
var matches []string
dir := os.DirFS(cdir)
glob := fmt.Sprintf("%04x:%02x:%02x.?", domain, bus, device)
matches, _ = fs.Glob(dir, glob)
if len(matches) > 1 {
// Multi-function device
name.WriteString(fmt.Sprintf("f%d", function))
}
pci = name.String()
}
case PathProcUSB:
{
if tmp, err = i.ProcUSB(v); err != nil {
var (
bus, conf, iface int
port_path []int
work string
)
res := strings.Split(v, ":")
if len(res) != 2 {
err = ErrInvalidUSBFormat
continue
}
usb = tmp
// Bus and ports
if _, err = fmt.Sscanf(res[0], "%d-%s", &bus, &work); err != nil {
err = ErrInvalidUSBFormat
continue
}
for _, v := range strings.Split(work, ".") {
var cp int
if _, err = fmt.Sscanf(v, "%d", &cp); err != nil {
err = ErrInvalidUSBFormat
continue
}
port_path = append(port_path, cp)
}
// Configuration and interface
if _, err = fmt.Sscanf(res[1], "%d.%d", &conf, &iface); err != nil {
err = ErrInvalidUSBFormat
continue
}
var name strings.Builder
for _, v := range port_path {
name.WriteString(fmt.Sprintf("u%d", v))
}
if conf != 1 {
name.WriteString(fmt.Sprintf("c%d", conf))
}
if iface != 0 {
name.WriteString(fmt.Sprintf("i%d", iface))
}
usb = name.String()
}
}
}
if pci == "" && usb == "" {
return
}
i.names[IfNameLoc] = strings.Join([]string{i.pfx, pci, usb}, "")
// Discard path errors if something was found
if pci != "" && errors.Is(err, ErrInvalidPCIFormat) {
err = nil
}
if usb != "" && errors.Is(err, ErrInvalidUSBFormat) {
err = nil
}
i.names[IfNameLoc] = strings.Join([]string{i.pfx, pci, usb}, "")
return
}

47
main.go
View File

@ -48,7 +48,7 @@ func main() {
var l netlink.Link
if l, err = netlink.LinkByName(ifname); err != nil {
mainlog.Fatalln("Interface", ifname, "disappeared before it could be selected")
mainlog.Fatalln("Interface", ifname, "doesn't exist or disappeared before it could be selected")
}
var cif iface
@ -74,27 +74,38 @@ func main() {
// Main name
// This must be set before the next are following as altname cannot be added if a interface with the same name exists
if ifname == cif.names[main] {
mainlog.Println("Interface already named correctly")
return
}
mainlog.Printf("Renaming %s to %s\n", ifname, cif.names[main])
if err = netlink.LinkSetName(l, cif.names[main]); err != nil {
mainlog.Fatalf("Could not rename interface %s: %s\n", ifname, err)
mainlog.Println("Interface already named correctly, skipping")
} else {
mainlog.Printf("Renaming %s to %s\n", ifname, cif.names[main])
if err = netlink.LinkSetName(l, cif.names[main]); err != nil {
mainlog.Fatalf("Could not rename interface %s: %s\n", ifname, err)
}
}
// Alt names
var result = make(map[string]int)
for k, v := range cif.names {
switch k {
case main:
{
continue
}
default:
{
if err = netlink.LinkAddAltName(l, v); err != nil {
mainlog.Printf("Adding altname %s failed for %s: %s\n", v, ifname, err)
}
}
if k != main {
result[v]++
}
}
// Invalidate main name
result[cif.names[main]]--
// Invalidate already present alternative names
for _, v := range l.Attrs().AltNames {
result[v]--
}
for k, v := range result {
if v != 1 {
continue
}
mainlog.Printf("Adding altname %s for %s\n", k, ifname)
if err = netlink.LinkAddAltName(l, k); err != nil {
mainlog.Printf("Adding altname %s failed for %s: %s\n", k, ifname, err)
}
}
}

23
pci.go
View File

@ -1,23 +0,0 @@
package main
import (
"fmt"
"strings"
)
func (i *iface) ProcPCI(devpath string) (seg string, err error) {
var (
domain, bus, device, function int
)
if _, err = fmt.Sscanf(devpath, "%x:%x:%x.%x", &domain, &bus, &device, &function); err != nil {
err = ErrInvalidPCIFormat
return
}
var name strings.Builder
if domain != 0 {
name.WriteString(fmt.Sprintf("P%d", domain))
}
name.WriteString(fmt.Sprintf("p%ds%df%d", bus, device, function))
seg = name.String()
return
}

49
usb.go
View File

@ -1,49 +0,0 @@
package main
import (
"fmt"
"strings"
)
func (i *iface) ProcUSB(devpath string) (seg string, err error) {
var (
bus, conf, iface int
port_path []int
work string
)
res := strings.Split(devpath, ":")
if len(res) != 2 {
err = ErrInvalidUSBFormat
return
}
// Bus and ports
if _, err = fmt.Sscanf(res[0], "%d-%s", &bus, &work); err != nil {
err = ErrInvalidUSBFormat
return
}
for _, v := range strings.Split(work, ".") {
var cp int
if _, err = fmt.Sscanf(v, "%d", &cp); err != nil {
err = ErrInvalidUSBFormat
return
}
port_path = append(port_path, cp)
}
// Configuration and interface
if _, err = fmt.Sscanf(res[1], "%d.%d", &conf, &iface); err != nil {
err = ErrInvalidUSBFormat
return
}
var b strings.Builder
for _, v := range port_path {
b.WriteString(fmt.Sprintf("u%d", v))
}
b.WriteString(fmt.Sprintf("i%d", iface))
seg = b.String()
return
}