diff --git a/pkg/daemon/daemon.go b/pkg/daemon/daemon.go index 2981f924..680699ff 100644 --- a/pkg/daemon/daemon.go +++ b/pkg/daemon/daemon.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "strings" + "time" "go.uber.org/zap" "golang.zx2c4.com/wireguard/wgctrl" @@ -108,7 +109,7 @@ func (d *Daemon) Start() error { return fmt.Errorf("initial sync failed: %w", err) } - signals := osx.SetupSignals(osx.SigUpdate) + signals := osx.SetupSignals(osx.SigUpdate, osx.SigReload) wdt, err := d.watchdogTicker() if err != nil && !errors.Is(err, errNotSupported) { @@ -129,6 +130,12 @@ out: if err := d.Sync(); err != nil { d.logger.Error("Failed to synchronize interfaces", zap.Error(err)) } + + case osx.SigReload: + if err := d.reload(); err != nil { + return err + } + default: break out } @@ -276,6 +283,22 @@ func (d *Daemon) watchdogTicker() (<-chan time.Time, error) { return time.NewTicker(wdInterval / 2).C, nil } +func (d *Daemon) reload() error { + if err := d.setState(StateReloading); err != nil { + return fmt.Errorf("failed transition state: %w", err) + } + + if _, err := d.Config.ReloadAllSources(); err != nil { + d.logger.Error("Failed to reload config", zap.Error(err)) + } + + if err := d.setState(StateReady); err != nil { + return fmt.Errorf("failed transition state: %w", err) + } + + return nil +} + func (d *Daemon) setState(s State) error { d.state = s @@ -308,6 +331,18 @@ func (d *Daemon) setState(s State) error { func (d *Daemon) notify(notify string) error { notifyMessages := []string{notify} + if notify == systemd.NotifyReloading { + now, err := osx.GetClockMonotonic() + if err != nil { + return fmt.Errorf("failed to get monotonic clock: %w", err) + } + + notifyMessages = append(notifyMessages, + fmt.Sprintf("MONOTONIC_USEC=%d", now.UnixMicro())) + + d.logger.DebugV(5, "Notifying systemd", zap.Strings("message", notifyMessages)) + } + if _, err := systemd.Notify(false, strings.Join(notifyMessages, "\n")); err != nil { return err } diff --git a/pkg/os/clock_linux.go b/pkg/os/clock_linux.go new file mode 100644 index 00000000..383a91e6 --- /dev/null +++ b/pkg/os/clock_linux.go @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2023-2024 Steffen Vogel +// SPDX-License-Identifier: Apache-2.0 + +package os + +import ( + "syscall" + "time" + "unsafe" + + "golang.org/x/sys/unix" +) + +// GetClockMonotonic returns the current time from the CLOCK_MONOTONIC clock. +func GetClockMonotonic() (t time.Time, err error) { + var ts syscall.Timespec + if _, _, err := syscall.Syscall(syscall.SYS_CLOCK_GETTIME, unix.CLOCK_MONOTONIC, uintptr(unsafe.Pointer(&ts)), 0); err != 0 { + return time.Time{}, err + } + + return time.Unix(int64(ts.Sec), int64(ts.Nsec)), nil //nolint:unconvert +} diff --git a/pkg/os/clock_others.go b/pkg/os/clock_others.go new file mode 100644 index 00000000..e17696d7 --- /dev/null +++ b/pkg/os/clock_others.go @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2023-2024 Steffen Vogel +// SPDX-License-Identifier: Apache-2.0 + +//go:build !linux + +package os + +import ( + "time" +) + +// GetClockMonotonic returns the current time from the CLOCK_MONOTONIC clock. +func GetClockMonotonic() (t time.Time, err error) { + return time.Now(), nil +} diff --git a/pkg/os/signal_others.go b/pkg/os/signal_others.go index 03f52c07..7b0c970f 100644 --- a/pkg/os/signal_others.go +++ b/pkg/os/signal_others.go @@ -11,4 +11,5 @@ import ( const ( SigUpdate = unix.SIGUSR1 + SigReload = unix.SIGHUP ) diff --git a/pkg/os/signal_windows.go b/pkg/os/signal_windows.go index b63913a4..8a69e032 100644 --- a/pkg/os/signal_windows.go +++ b/pkg/os/signal_windows.go @@ -11,4 +11,5 @@ import ( const ( SigUpdate = syscall.Signal(-1) // not supported + SigReload = syscall.Signal(-2) // not supported )