package link import ( "errors" "fmt" "strings" "github.com/vishvananda/netlink" "slices" ) var ( defaultTqLength = 1000 backboneInterfacePrefixes = []string{"eno", "ens", "enp", "enx", "eth", "enX"} ) type NetLinker interface { GetFromHardwareAddr(hardwareAddr string) (netlink.Link, error) GetAllNetworkDeviceLinks() ([]netlink.Link, error) GetByName(name string) (netlink.Link, error) Ensure(link netlink.Link) (netlink.Link, error) Delete(name string) error NewIfb(name string, mtu int) netlink.Link } type NetLink struct{} // retrieves link from hardware address (mac address) func (n *NetLink) GetFromHardwareAddr(hardwareAddr string) (netlink.Link, error) { allLinks, err := n.GetAllNetworkDeviceLinks() if err != nil { return nil, err } for _, link := range allLinks { if link.Attrs().HardwareAddr.String() == hardwareAddr { return link, nil } } return nil, fmt.Errorf("interface not found with hardware address: %s", hardwareAddr) } // retrieves all network device links associated on node func (n *NetLink) GetAllNetworkDeviceLinks() ([]netlink.Link, error) { var links []netlink.Link allLinks, err := netlink.LinkList() if err != nil { return nil, fmt.Errorf("error listing links: %w", err) } for _, link := range allLinks { if slices.ContainsFunc(backboneInterfacePrefixes, func(prefix string) bool { return strings.HasPrefix(link.Attrs().Name, prefix) }) { links = append(links, link) } } return links, nil } func (n *NetLink) GetByName(name string) (netlink.Link, error) { link, err := netlink.LinkByName(name) if err != nil { return nil, fmt.Errorf("error getting link %s: %w", name, err) } return link, nil } // Ensures a link exists and is up and returns the updated link with new link index // If the link already exists, we ensure it is up and return the up-to-date link func (n *NetLink) Ensure(link netlink.Link) (netlink.Link, error) { name := link.Attrs().Name if err := netlink.LinkAdd(link); err != nil && !strings.Contains(err.Error(), "file exists") { return nil, fmt.Errorf("error creating link %s: %w", name, err) } link, err := netlink.LinkByName(name) if err != nil { return nil, fmt.Errorf("error retrieving new link %s: %w", name, err) } if err := netlink.LinkSetUp(link); err != nil { return nil, fmt.Errorf("error setting link %s up: %w", name, err) } return link, nil } // Deletes a link if it exists func (n *NetLink) Delete(name string) error { link, err := n.GetByName(name) if err != nil { if errors.As(err, &netlink.LinkNotFoundError{}) { return nil } return fmt.Errorf("error retrieving link %s: %w", name, err) } if err := netlink.LinkDel(link); err != nil { return fmt.Errorf("error deleting link %s: %w", name, err) } return nil } // Creates a new blank ifb link func (n *NetLink) NewIfb(name string, mtu int) netlink.Link { ifbLinkAttrs := netlink.NewLinkAttrs() ifbLinkAttrs.Name = name defaultIfbLink := &netlink.Ifb{ LinkAttrs: ifbLinkAttrs, } defaultIfbLink.TxQLen = defaultTqLength defaultIfbLink.MTU = mtu return defaultIfbLink }