mirror of https://github.com/jetkvm/kvm.git
165 lines
3.2 KiB
Go
165 lines
3.2 KiB
Go
// Package link provides a wrapper around netlink.Link and provides a singleton netlink manager.
|
|
package link
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/jetkvm/kvm/internal/sync"
|
|
|
|
"github.com/vishvananda/netlink"
|
|
)
|
|
|
|
var (
|
|
ipv4DefaultRoute = net.IPNet{
|
|
IP: net.IPv4zero,
|
|
Mask: net.CIDRMask(0, 0),
|
|
}
|
|
|
|
ipv6DefaultRoute = net.IPNet{
|
|
IP: net.IPv6zero,
|
|
Mask: net.CIDRMask(0, 0),
|
|
}
|
|
|
|
// Singleton instance
|
|
netlinkManagerInstance *NetlinkManager
|
|
netlinkManagerOnce sync.Once
|
|
|
|
// ErrInterfaceUpTimeout is the error returned when the interface does not come up within the timeout
|
|
ErrInterfaceUpTimeout = errors.New("timeout after waiting for an interface to come up")
|
|
// ErrInterfaceUpCanceled is the error returned when the interface does not come up due to context cancellation
|
|
ErrInterfaceUpCanceled = errors.New("context canceled while waiting for an interface to come up")
|
|
)
|
|
|
|
// Link is a wrapper around netlink.Link
|
|
type Link struct {
|
|
netlink.Link
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// All lock actions should be done in external functions
|
|
// and the internal functions should not be called directly
|
|
|
|
func (l *Link) refresh() error {
|
|
linkName := l.ifName()
|
|
link, err := netlink.LinkByName(linkName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if link == nil {
|
|
return fmt.Errorf("link not found: %s", linkName)
|
|
}
|
|
l.Link = link
|
|
return nil
|
|
}
|
|
|
|
func (l *Link) attrs() *netlink.LinkAttrs {
|
|
return l.Link.Attrs()
|
|
}
|
|
|
|
func (l *Link) ifName() string {
|
|
attrs := l.attrs()
|
|
if attrs.Name == "" {
|
|
return ""
|
|
}
|
|
return attrs.Name
|
|
}
|
|
|
|
// Refresh refreshes the link
|
|
func (l *Link) Refresh() error {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
return l.refresh()
|
|
}
|
|
|
|
// Attrs returns the attributes of the link
|
|
func (l *Link) Attrs() *netlink.LinkAttrs {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
return l.attrs()
|
|
}
|
|
|
|
// Interface returns the interface of the link
|
|
func (l *Link) Interface() *net.Interface {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
ifname := l.ifName()
|
|
if ifname == "" {
|
|
return nil
|
|
}
|
|
iface, err := net.InterfaceByName(ifname)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return iface
|
|
}
|
|
|
|
// HardwareAddr returns the hardware address of the link
|
|
func (l *Link) HardwareAddr() net.HardwareAddr {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
attrs := l.attrs()
|
|
if attrs.HardwareAddr == nil {
|
|
return nil
|
|
}
|
|
return attrs.HardwareAddr
|
|
}
|
|
|
|
// AddrList returns the addresses of the link
|
|
func (l *Link) AddrList(family int) ([]netlink.Addr, error) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
return netlink.AddrList(l.Link, family)
|
|
}
|
|
|
|
func (l *Link) SetMTU(mtu int) error {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
return netlink.LinkSetMTU(l.Link, mtu)
|
|
}
|
|
|
|
// HasGlobalUnicastAddress returns true if the link has a global unicast address
|
|
func (l *Link) HasGlobalUnicastAddress() bool {
|
|
addrs, err := l.AddrList(AfUnspec)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
for _, addr := range addrs {
|
|
if addr.IP.IsGlobalUnicast() {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsSame checks if the link is the same as another link
|
|
func (l *Link) IsSame(other *Link) bool {
|
|
if l == nil || other == nil {
|
|
return false
|
|
}
|
|
|
|
a := l.Attrs()
|
|
b := other.Attrs()
|
|
if a.OperState != b.OperState {
|
|
return false
|
|
}
|
|
if a.Index != b.Index {
|
|
return false
|
|
}
|
|
if a.MTU != b.MTU {
|
|
return false
|
|
}
|
|
if a.HardwareAddr.String() != b.HardwareAddr.String() {
|
|
return false
|
|
}
|
|
return true
|
|
}
|