mirror of https://github.com/jetkvm/kvm.git
use sync trace to track mutexes to make deadlock analysis easier
This commit is contained in:
parent
b04b148a4b
commit
aef26459d3
|
|
@ -3,5 +3,11 @@
|
||||||
"cva",
|
"cva",
|
||||||
"cx"
|
"cx"
|
||||||
],
|
],
|
||||||
|
"gopls": {
|
||||||
|
"build.buildFlags": [
|
||||||
|
"-tags",
|
||||||
|
"synctrace"
|
||||||
|
]
|
||||||
|
},
|
||||||
"git.ignoreLimitWarning": true
|
"git.ignoreLimitWarning": true
|
||||||
}
|
}
|
||||||
|
|
@ -45,6 +45,8 @@ type IPv6StaticConfig struct {
|
||||||
|
|
||||||
// NetworkConfig represents the complete network configuration for an interface
|
// NetworkConfig represents the complete network configuration for an interface
|
||||||
type NetworkConfig struct {
|
type NetworkConfig struct {
|
||||||
|
DHCPClient null.String `json:"dhcp_client,omitempty" one_of:"jetdhcpc,udhcpc" default:"jetdhcpc"`
|
||||||
|
|
||||||
Hostname null.String `json:"hostname,omitempty" validate_type:"hostname"`
|
Hostname null.String `json:"hostname,omitempty" validate_type:"hostname"`
|
||||||
HTTPProxy null.String `json:"http_proxy,omitempty" validate_type:"proxy"`
|
HTTPProxy null.String `json:"http_proxy,omitempty" validate_type:"proxy"`
|
||||||
Domain null.String `json:"domain,omitempty" validate_type:"hostname"`
|
Domain null.String `json:"domain,omitempty" validate_type:"hostname"`
|
||||||
|
|
@ -145,6 +147,7 @@ type DHCPLease struct {
|
||||||
LeaseExpiry *time.Time `json:"lease_expiry,omitempty"` // The expiry time of the lease
|
LeaseExpiry *time.Time `json:"lease_expiry,omitempty"` // The expiry time of the lease
|
||||||
|
|
||||||
InterfaceName string `json:"interface_name,omitempty"` // The name of the interface
|
InterfaceName string `json:"interface_name,omitempty"` // The name of the interface
|
||||||
|
DHCPClient string `json:"dhcp_client,omitempty"` // The DHCP client that obtained the lease
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceState represents the current state of a network interface
|
// InterfaceState represents the current state of a network interface
|
||||||
|
|
@ -173,6 +176,31 @@ type NetworkConfigInterface interface {
|
||||||
IPv6Addresses() []IPAddress
|
IPv6Addresses() []IPAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsIPv6 returns true if the DHCP lease is for an IPv6 address
|
||||||
func (d *DHCPLease) IsIPv6() bool {
|
func (d *DHCPLease) IsIPv6() bool {
|
||||||
return d.IPAddress.To4() == nil
|
return d.IPAddress.To4() == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IPMask returns the IP mask for the DHCP lease
|
||||||
|
func (d *DHCPLease) IPMask() net.IPMask {
|
||||||
|
if d.IsIPv6() {
|
||||||
|
// TODO: not implemented
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mask := net.ParseIP(d.Netmask.String())
|
||||||
|
return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15])
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPNet returns the IP net for the DHCP lease
|
||||||
|
func (d *DHCPLease) IPNet() *net.IPNet {
|
||||||
|
if d.IsIPv6() {
|
||||||
|
// TODO: not implemented
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &net.IPNet{
|
||||||
|
IP: d.IPAddress,
|
||||||
|
Mask: d.IPMask(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ func (t *TimeSync) filterNTPServers(ntpServers []string) ([]string, error) {
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasIPv4 && ip.To4() != nil {
|
if hasIPv4 && ip.To4() != nil {
|
||||||
filteredServers = append(filteredServers, server)
|
filteredServers = append(filteredServers, server)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,9 @@ func (t *TimeSync) doTimeSync() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TimeSync) Sync() error {
|
func (t *TimeSync) Sync() error {
|
||||||
|
t.syncLock.Lock()
|
||||||
|
defer t.syncLock.Unlock()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
now *time.Time
|
now *time.Time
|
||||||
offset *time.Duration
|
offset *time.Duration
|
||||||
|
|
|
||||||
|
|
@ -14,25 +14,23 @@ import (
|
||||||
|
|
||||||
// DHCPClient wraps the dhclient package for use in the network manager
|
// DHCPClient wraps the dhclient package for use in the network manager
|
||||||
type DHCPClient struct {
|
type DHCPClient struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ifaceName string
|
ifaceName string
|
||||||
logger *zerolog.Logger
|
logger *zerolog.Logger
|
||||||
client types.DHCPClient
|
client types.DHCPClient
|
||||||
link netlink.Link
|
clientType string
|
||||||
|
link netlink.Link
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
ipv4Enabled bool
|
ipv4Enabled bool
|
||||||
ipv6Enabled bool
|
ipv6Enabled bool
|
||||||
|
|
||||||
// State management
|
|
||||||
// stateManager *DHCPStateManager
|
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
onLeaseChange func(lease *types.DHCPLease)
|
onLeaseChange func(lease *types.DHCPLease)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDHCPClient creates a new DHCP client
|
// NewDHCPClient creates a new DHCP client
|
||||||
func NewDHCPClient(ctx context.Context, ifaceName string, logger *zerolog.Logger) (*DHCPClient, error) {
|
func NewDHCPClient(ctx context.Context, ifaceName string, logger *zerolog.Logger, clientType string) (*DHCPClient, error) {
|
||||||
if ifaceName == "" {
|
if ifaceName == "" {
|
||||||
return nil, fmt.Errorf("interface name cannot be empty")
|
return nil, fmt.Errorf("interface name cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
@ -42,9 +40,10 @@ func NewDHCPClient(ctx context.Context, ifaceName string, logger *zerolog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
return &DHCPClient{
|
return &DHCPClient{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
ifaceName: ifaceName,
|
ifaceName: ifaceName,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
clientType: clientType,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,10 +69,13 @@ func (dc *DHCPClient) SetOnLeaseChange(callback func(lease *types.DHCPLease)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DHCPClient) initClient() (types.DHCPClient, error) {
|
func (dc *DHCPClient) initClient() (types.DHCPClient, error) {
|
||||||
if false {
|
switch dc.clientType {
|
||||||
|
case "jetdhcpc":
|
||||||
return dc.initJetDHCPC()
|
return dc.initJetDHCPC()
|
||||||
} else {
|
case "udhcpc":
|
||||||
return dc.initUDHCPC()
|
return dc.initUDHCPC()
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid client type: %s", dc.clientType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -204,8 +206,11 @@ func (dc *DHCPClient) handleLeaseChange(lease *types.DHCPLease, isIPv6 bool) {
|
||||||
Str("ip", lease.IPAddress.String()).
|
Str("ip", lease.IPAddress.String()).
|
||||||
Msg("DHCP lease changed")
|
Msg("DHCP lease changed")
|
||||||
|
|
||||||
|
// copy the lease to avoid race conditions
|
||||||
|
leaseCopy := *lease
|
||||||
|
|
||||||
// Notify callback
|
// Notify callback
|
||||||
if dc.onLeaseChange != nil {
|
if dc.onLeaseChange != nil {
|
||||||
dc.onLeaseChange(lease)
|
dc.onLeaseChange(&leaseCopy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
"github.com/jetkvm/kvm/internal/sync"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"golang.org/x/net/idna"
|
"golang.org/x/net/idna"
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jetkvm/kvm/internal/sync"
|
||||||
|
|
||||||
"github.com/jetkvm/kvm/internal/confparser"
|
"github.com/jetkvm/kvm/internal/confparser"
|
||||||
"github.com/jetkvm/kvm/internal/logging"
|
"github.com/jetkvm/kvm/internal/logging"
|
||||||
"github.com/jetkvm/kvm/internal/network/types"
|
"github.com/jetkvm/kvm/internal/network/types"
|
||||||
|
|
@ -78,7 +80,7 @@ func NewInterfaceManager(ctx context.Context, ifaceName string, config *types.Ne
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the dhcp client
|
// create the dhcp client
|
||||||
im.dhcpClient, err = NewDHCPClient(ctx, ifaceName, &scopedLogger)
|
im.dhcpClient, err = NewDHCPClient(ctx, ifaceName, &scopedLogger, config.DHCPClient.String)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create DHCP client: %w", err)
|
return nil, fmt.Errorf("failed to create DHCP client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -562,7 +564,6 @@ func (im *InterfaceManager) monitorInterfaceState() {
|
||||||
defer im.wg.Done()
|
defer im.wg.Done()
|
||||||
|
|
||||||
im.logger.Debug().Msg("monitoring interface state")
|
im.logger.Debug().Msg("monitoring interface state")
|
||||||
|
|
||||||
// TODO: use netlink subscription instead of polling
|
// TODO: use netlink subscription instead of polling
|
||||||
ticker := time.NewTicker(5 * time.Second)
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
@ -574,7 +575,6 @@ func (im *InterfaceManager) monitorInterfaceState() {
|
||||||
case <-im.stopCh:
|
case <-im.stopCh:
|
||||||
return
|
return
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
im.logger.Debug().Msg("checking interface state")
|
|
||||||
if err := im.updateInterfaceState(); err != nil {
|
if err := im.updateInterfaceState(); err != nil {
|
||||||
im.logger.Error().Err(err).Msg("failed to update interface state")
|
im.logger.Error().Err(err).Msg("failed to update interface state")
|
||||||
}
|
}
|
||||||
|
|
@ -727,12 +727,9 @@ func (im *InterfaceManager) applyDHCPLease(lease *types.DHCPLease) error {
|
||||||
|
|
||||||
// convertDHCPLeaseToIPv4Config converts a DHCP lease to IPv4Config
|
// convertDHCPLeaseToIPv4Config converts a DHCP lease to IPv4Config
|
||||||
func (im *InterfaceManager) convertDHCPLeaseToIPv4Config(lease *types.DHCPLease) *types.IPAddress {
|
func (im *InterfaceManager) convertDHCPLeaseToIPv4Config(lease *types.DHCPLease) *types.IPAddress {
|
||||||
mask := lease.Netmask
|
ipNet := lease.IPNet()
|
||||||
|
if ipNet == nil {
|
||||||
// Create IPNet from IP and netmask
|
return nil
|
||||||
ipNet := &net.IPNet{
|
|
||||||
IP: lease.IPAddress,
|
|
||||||
Mask: net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create IPv4Address
|
// Create IPv4Address
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"slices"
|
"slices"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jetkvm/kvm/internal/sync"
|
||||||
|
|
||||||
"github.com/go-co-op/gocron/v2"
|
"github.com/go-co-op/gocron/v2"
|
||||||
"github.com/insomniacslk/dhcp/dhcpv4"
|
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||||
"github.com/insomniacslk/dhcp/dhcpv6"
|
"github.com/insomniacslk/dhcp/dhcpv6"
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ type Lease struct {
|
||||||
|
|
||||||
// ToDHCPLease converts a lease to a DHCP lease.
|
// ToDHCPLease converts a lease to a DHCP lease.
|
||||||
func (l *Lease) ToDHCPLease() *types.DHCPLease {
|
func (l *Lease) ToDHCPLease() *types.DHCPLease {
|
||||||
return &l.DHCPLease
|
lease := &l.DHCPLease
|
||||||
|
lease.DHCPClient = "jetdhcpc"
|
||||||
|
return lease
|
||||||
}
|
}
|
||||||
|
|
||||||
// fromNclient4Lease creates a lease from a nclient4.Lease.
|
// fromNclient4Lease creates a lease from a nclient4.Lease.
|
||||||
|
|
@ -45,9 +47,9 @@ func fromNclient4Lease(l *nclient4.Lease, iface string) *Lease {
|
||||||
// only the fields that we need are set
|
// only the fields that we need are set
|
||||||
lease.Routers = l.ACK.Router()
|
lease.Routers = l.ACK.Router()
|
||||||
lease.IPAddress = l.ACK.YourIPAddr
|
lease.IPAddress = l.ACK.YourIPAddr
|
||||||
|
|
||||||
lease.Netmask = net.IP(l.ACK.SubnetMask())
|
lease.Netmask = net.IP(l.ACK.SubnetMask())
|
||||||
lease.Broadcast = l.ACK.BroadcastAddress()
|
lease.Broadcast = l.ACK.BroadcastAddress()
|
||||||
// lease.MTU = int(resp.Options.Get(dhcpv4.OptionInterfaceMTU))
|
|
||||||
|
|
||||||
lease.NTPServers = l.ACK.NTPServers()
|
lease.NTPServers = l.ACK.NTPServers()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,10 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jetkvm/kvm/internal/sync"
|
||||||
|
|
||||||
"github.com/jetkvm/kvm/internal/network/types"
|
"github.com/jetkvm/kvm/internal/network/types"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ package nmlite
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
|
"github.com/jetkvm/kvm/internal/sync"
|
||||||
|
|
||||||
"github.com/jetkvm/kvm/internal/logging"
|
"github.com/jetkvm/kvm/internal/logging"
|
||||||
"github.com/jetkvm/kvm/internal/network/types"
|
"github.com/jetkvm/kvm/internal/network/types"
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,9 @@ func (l *Lease) ToJSON() string {
|
||||||
|
|
||||||
// ToDHCPLease converts a lease to a DHCP lease.
|
// ToDHCPLease converts a lease to a DHCP lease.
|
||||||
func (l *Lease) ToDHCPLease() *types.DHCPLease {
|
func (l *Lease) ToDHCPLease() *types.DHCPLease {
|
||||||
return &l.DHCPLease
|
lease := &l.DHCPLease
|
||||||
|
lease.DHCPClient = "udhcpc"
|
||||||
|
return lease
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLeaseExpiry sets the lease expiry time.
|
// SetLeaseExpiry sets the lease expiry time.
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jetkvm/kvm/internal/sync"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
"github.com/jetkvm/kvm/internal/network/types"
|
"github.com/jetkvm/kvm/internal/network/types"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,13 @@ export default function DhcpLeaseCard({
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{networkState?.dhcp_lease?.dhcp_client && (
|
||||||
|
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||||
|
<span className="text-sm text-slate-600 dark:text-slate-400">DHCP Client</span>
|
||||||
|
<span className="text-sm font-medium">{networkState?.dhcp_lease?.dhcp_client}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -690,6 +690,7 @@ export interface DhcpLease {
|
||||||
message?: string;
|
message?: string;
|
||||||
tftp?: string;
|
tftp?: string;
|
||||||
bootfile?: string;
|
bootfile?: string;
|
||||||
|
dhcp_client?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPv6Address {
|
export interface IPv6Address {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue