From 9b46209f1bf2ea30d91a1d20ccf9a908a5be5632 Mon Sep 17 00:00:00 2001 From: Siyuan Date: Mon, 13 Oct 2025 16:17:35 +0000 Subject: [PATCH] fix: clean up udhcpc processes --- network.go | 1 + pkg/nmlite/jetdhcpc/legacy.go | 15 +++++++++++---- pkg/nmlite/manager.go | 27 +++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/network.go b/network.go index 719fdd0c..8a7c2761 100644 --- a/network.go +++ b/network.go @@ -151,6 +151,7 @@ func initNetwork() error { if err := nm.AddInterface(NetIfName, nc); err != nil { return fmt.Errorf("failed to add interface: %w", err) } + _ = nm.CleanUpLegacyDHCPClients() networkManager = nm diff --git a/pkg/nmlite/jetdhcpc/legacy.go b/pkg/nmlite/jetdhcpc/legacy.go index b8ee4c0b..6fa2ddf9 100644 --- a/pkg/nmlite/jetdhcpc/legacy.go +++ b/pkg/nmlite/jetdhcpc/legacy.go @@ -8,6 +8,8 @@ import ( "strconv" "strings" "syscall" + + "github.com/rs/zerolog" ) func readFileNoStat(filename string) ([]byte, error) { @@ -36,7 +38,8 @@ func toCmdline(path string) ([]string, error) { return strings.Split(string(bytes.TrimRight(data, "\x00")), "\x00"), nil } -func (c *Client) killUdhcpc() error { +// KillUdhcpC kills all udhcpc processes +func KillUdhcpC(l *zerolog.Logger) error { // read procfs for udhcpc processes // we do not use procfs.AllProcs() because we want to avoid the overhead of reading the entire procfs processes, err := os.ReadDir("/proc") @@ -76,11 +79,11 @@ func (c *Client) killUdhcpc() error { } if len(matchedPids) == 0 { - c.l.Info().Msg("no udhcpc processes found") + l.Info().Msg("no udhcpc processes found") return nil } - c.l.Info().Ints("pids", matchedPids).Msg("found udhcpc processes, terminating") + l.Info().Ints("pids", matchedPids).Msg("found udhcpc processes, terminating") for _, pid := range matchedPids { err := syscall.Kill(pid, syscall.SIGTERM) @@ -88,8 +91,12 @@ func (c *Client) killUdhcpc() error { return err } - c.l.Info().Int("pid", pid).Msg("terminated udhcpc process") + l.Info().Int("pid", pid).Msg("terminated udhcpc process") } return nil } + +func (c *Client) killUdhcpc() error { + return KillUdhcpC(c.l) +} diff --git a/pkg/nmlite/manager.go b/pkg/nmlite/manager.go index d8a0ddd8..03496d9e 100644 --- a/pkg/nmlite/manager.go +++ b/pkg/nmlite/manager.go @@ -11,6 +11,7 @@ import ( "github.com/jetkvm/kvm/internal/logging" "github.com/jetkvm/kvm/internal/network/types" + "github.com/jetkvm/kvm/pkg/nmlite/jetdhcpc" "github.com/jetkvm/kvm/pkg/nmlite/link" "github.com/rs/zerolog" ) @@ -214,6 +215,32 @@ func (nm *NetworkManager) SetOnDHCPLeaseChange(callback func(iface string, lease nm.onDHCPLeaseChange = callback } +func (nm *NetworkManager) shouldKillLegacyDHCPClients() bool { + nm.mu.RLock() + defer nm.mu.RUnlock() + + // TODO: remove it when we need to support multiple interfaces + for _, im := range nm.interfaces { + if im.dhcpClient.clientType != "udhcpc" { + return true + } + + if im.config.IPv4Mode.String != "dhcp" { + return true + } + } + return false +} + +// CleanUpLegacyDHCPClients cleans up legacy DHCP clients +func (nm *NetworkManager) CleanUpLegacyDHCPClients() error { + shouldKill := nm.shouldKillLegacyDHCPClients() + if shouldKill { + return jetdhcpc.KillUdhcpC(nm.logger) + } + return nil +} + // Stop stops the network manager and all managed interfaces func (nm *NetworkManager) Stop() error { nm.mu.Lock()