mirror of https://github.com/jetkvm/kvm.git
164 lines
3.8 KiB
Go
164 lines
3.8 KiB
Go
package nmlite
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/jetkvm/kvm/internal/network/types"
|
|
"github.com/jetkvm/kvm/pkg/nmlite/link"
|
|
"github.com/vishvananda/netlink"
|
|
)
|
|
|
|
// updateInterfaceState updates the current interface state
|
|
func (im *InterfaceManager) updateInterfaceState() error {
|
|
nl, err := im.link()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get interface: %w", err)
|
|
}
|
|
|
|
var stateChanged bool
|
|
|
|
attrs := nl.Attrs()
|
|
|
|
// We should release the lock before calling the callbacks
|
|
// to avoid deadlocks
|
|
im.stateMu.Lock()
|
|
|
|
// Check if the interface is up
|
|
isUp := attrs.OperState == netlink.OperUp
|
|
if im.state.Up != isUp {
|
|
im.state.Up = isUp
|
|
stateChanged = true
|
|
}
|
|
|
|
// Check if the interface is online
|
|
isOnline := isUp && nl.HasGlobalUnicastAddress()
|
|
if im.state.Online != isOnline {
|
|
im.state.Online = isOnline
|
|
stateChanged = true
|
|
}
|
|
|
|
// Check if the MAC address has changed
|
|
if im.state.MACAddress != attrs.HardwareAddr.String() {
|
|
im.state.MACAddress = attrs.HardwareAddr.String()
|
|
stateChanged = true
|
|
}
|
|
|
|
// Update IP addresses
|
|
if ipChanged, err := im.updateInterfaceStateAddresses(nl); err != nil {
|
|
im.logger.Error().Err(err).Msg("failed to update IP addresses")
|
|
} else if ipChanged {
|
|
stateChanged = true
|
|
}
|
|
|
|
im.state.LastUpdated = time.Now()
|
|
im.stateMu.Unlock()
|
|
|
|
// Notify callback if state changed
|
|
if stateChanged && im.onStateChange != nil {
|
|
im.logger.Debug().Interface("state", im.state).Msg("notifying state change")
|
|
im.onStateChange(*im.state)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// updateIPAddresses updates the IP addresses in the state
|
|
func (im *InterfaceManager) updateInterfaceStateAddresses(nl *link.Link) (bool, error) {
|
|
mgr := getNetlinkManager()
|
|
|
|
addrs, err := nl.AddrList(link.AfUnspec)
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to get addresses: %w", err)
|
|
}
|
|
|
|
var (
|
|
ipv4Addresses []string
|
|
ipv6Addresses []types.IPv6Address
|
|
ipv4Addr, ipv6Addr string
|
|
ipv6LinkLocal string
|
|
ipv6Gateway string
|
|
ipv4Ready, ipv6Ready = false, false
|
|
stateChanged = false
|
|
)
|
|
|
|
routes, _ := mgr.ListDefaultRoutes(link.AfInet6)
|
|
if len(routes) > 0 {
|
|
ipv6Gateway = routes[0].Gw.String()
|
|
}
|
|
|
|
for _, addr := range addrs {
|
|
if addr.IP.To4() != nil {
|
|
// IPv4 address
|
|
ipv4Addresses = append(ipv4Addresses, addr.IPNet.String())
|
|
if ipv4Addr == "" {
|
|
ipv4Addr = addr.IP.String()
|
|
ipv4Ready = true
|
|
}
|
|
continue
|
|
}
|
|
|
|
// IPv6 address (if it's not an IPv4 address, it must be an IPv6 address)
|
|
if addr.IP.IsLinkLocalUnicast() {
|
|
ipv6LinkLocal = addr.IP.String()
|
|
continue
|
|
} else if !addr.IP.IsGlobalUnicast() {
|
|
continue
|
|
}
|
|
|
|
ipv6Addresses = append(ipv6Addresses, types.IPv6Address{
|
|
Address: addr.IP,
|
|
Prefix: *addr.IPNet,
|
|
Scope: addr.Scope,
|
|
Flags: addr.Flags,
|
|
ValidLifetime: lifetimeToTime(addr.ValidLft),
|
|
PreferredLifetime: lifetimeToTime(addr.PreferedLft),
|
|
})
|
|
if ipv6Addr == "" {
|
|
ipv6Addr = addr.IP.String()
|
|
ipv6Ready = true
|
|
}
|
|
}
|
|
|
|
if !sortAndCompareStringSlices(im.state.IPv4Addresses, ipv4Addresses) {
|
|
im.state.IPv4Addresses = ipv4Addresses
|
|
stateChanged = true
|
|
}
|
|
|
|
if !sortAndCompareIPv6AddressSlices(im.state.IPv6Addresses, ipv6Addresses) {
|
|
im.state.IPv6Addresses = ipv6Addresses
|
|
stateChanged = true
|
|
}
|
|
|
|
if im.state.IPv4Address != ipv4Addr {
|
|
im.state.IPv4Address = ipv4Addr
|
|
stateChanged = true
|
|
}
|
|
|
|
if im.state.IPv6Address != ipv6Addr {
|
|
im.state.IPv6Address = ipv6Addr
|
|
stateChanged = true
|
|
}
|
|
if im.state.IPv6LinkLocal != ipv6LinkLocal {
|
|
im.state.IPv6LinkLocal = ipv6LinkLocal
|
|
stateChanged = true
|
|
}
|
|
|
|
if im.state.IPv6Gateway != ipv6Gateway {
|
|
im.state.IPv6Gateway = ipv6Gateway
|
|
stateChanged = true
|
|
}
|
|
|
|
if im.state.IPv4Ready != ipv4Ready {
|
|
im.state.IPv4Ready = ipv4Ready
|
|
stateChanged = true
|
|
}
|
|
|
|
if im.state.IPv6Ready != ipv6Ready {
|
|
im.state.IPv6Ready = ipv6Ready
|
|
stateChanged = true
|
|
}
|
|
|
|
return stateChanged, nil
|
|
}
|