diff --git a/.golangci.yml b/.golangci.yml index 41eb7865e3..e1ffba3e2b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -17,7 +17,6 @@ linters: - gocritic - gocyclo - gofmt - - gomnd - goprintffuncname - gosimple - lll diff --git a/cns/service/main.go b/cns/service/main.go index d70fa654cb..532ed17882 100644 --- a/cns/service/main.go +++ b/cns/service/main.go @@ -710,12 +710,15 @@ func main() { } } - // Setting the remote ARP MAC address to 12-34-56-78-9a-bc on windows for external traffic - err = platform.SetSdnRemoteArpMacAddress() + // Setting the remote ARP MAC address to 12-34-56-78-9a-bc on windows for external traffic if HNS is enabled + arpCtx, arpCtxCancel := context.WithTimeout(rootCtx, 30*time.Second) + err = platform.SetSdnRemoteArpMacAddress(arpCtx) if err != nil { logger.Errorf("Failed to set remote ARP MAC address: %v", err) + arpCtxCancel() return } + arpCtxCancel() // We are only setting the PriorityVLANTag in 'cns.Direct' mode, because it neatly maps today, to 'isUsingMultitenancy' // In the future, we would want to have a better CNS flag, to explicitly say, this CNS is using multitenancy diff --git a/platform/os_linux.go b/platform/os_linux.go index 60356d54ce..f6b27146d0 100644 --- a/platform/os_linux.go +++ b/platform/os_linux.go @@ -128,7 +128,7 @@ func KillProcessByName(processName string) error { // SetSdnRemoteArpMacAddress sets the regkey for SDNRemoteArpMacAddress needed for multitenancy // This operation is specific to windows OS -func SetSdnRemoteArpMacAddress() error { +func SetSdnRemoteArpMacAddress(context.Context) error { return nil } diff --git a/platform/os_windows.go b/platform/os_windows.go index 6c5b450a3c..d55ef7c68e 100644 --- a/platform/os_windows.go +++ b/platform/os_windows.go @@ -18,6 +18,9 @@ import ( "github.com/Azure/azure-container-networking/platform/windows/adapter/mellanox" "github.com/pkg/errors" "golang.org/x/sys/windows" + "golang.org/x/sys/windows/registry" + "golang.org/x/sys/windows/svc" + "golang.org/x/sys/windows/svc/mgr" ) const ( @@ -59,17 +62,6 @@ const ( // for vlan tagged arp requests SDNRemoteArpMacAddress = "12-34-56-78-9a-bc" - // Command to get SDNRemoteArpMacAddress registry key - GetSdnRemoteArpMacAddressCommand = "(Get-ItemProperty " + - "-Path HKLM:\\SYSTEM\\CurrentControlSet\\Services\\hns\\State -Name SDNRemoteArpMacAddress).SDNRemoteArpMacAddress" - - // Command to set SDNRemoteArpMacAddress registry key - SetSdnRemoteArpMacAddressCommand = "Set-ItemProperty " + - "-Path HKLM:\\SYSTEM\\CurrentControlSet\\Services\\hns\\State -Name SDNRemoteArpMacAddress -Value \"12-34-56-78-9a-bc\"" - - // Command to restart HNS service - RestartHnsServiceCommand = "Restart-Service -Name hns" - // Interval between successive checks for mellanox adapter's PriorityVLANTag value defaultMellanoxMonitorInterval = 30 * time.Second @@ -172,31 +164,81 @@ func ExecutePowershellCommand(command string) (string, error) { return strings.TrimSpace(stdout.String()), nil } -// SetSdnRemoteArpMacAddress sets the regkey for SDNRemoteArpMacAddress needed for multitenancy -func SetSdnRemoteArpMacAddress() error { - if sdnRemoteArpMacAddressSet == false { - result, err := ExecutePowershellCommand(GetSdnRemoteArpMacAddressCommand) - if err != nil { - return err - } - - // Set the reg key if not already set or has incorrect value - if result != SDNRemoteArpMacAddress { - if _, err = ExecutePowershellCommand(SetSdnRemoteArpMacAddressCommand); err != nil { - log.Printf("Failed to set SDNRemoteArpMacAddress due to error %s", err.Error()) - return err - } +// SetSdnRemoteArpMacAddress sets the regkey for SDNRemoteArpMacAddress needed for multitenancy if hns is enabled +func SetSdnRemoteArpMacAddress(ctx context.Context) error { + if err := setSDNRemoteARPRegKey(); err != nil { + return err + } + log.Printf("SDNRemoteArpMacAddress regKey set successfully") + if err := restartHNS(ctx); err != nil { + return err + } + log.Printf("HNS service restarted successfully") + return nil +} - log.Printf("[Azure CNS] SDNRemoteArpMacAddress regKey set successfully. Restarting hns service.") - if _, err := ExecutePowershellCommand(RestartHnsServiceCommand); err != nil { - log.Printf("Failed to Restart HNS Service due to error %s", err.Error()) - return err - } +func setSDNRemoteARPRegKey() error { + log.Printf("Setting SDNRemoteArpMacAddress regKey") + // open the registry key + k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Services\hns\State`, registry.READ|registry.SET_VALUE) + if err != nil { + if errors.Is(err, registry.ErrNotExist) { + return nil } - - sdnRemoteArpMacAddressSet = true + return errors.Wrap(err, "could not open registry key") + } + defer k.Close() + // check the key value + if v, _, _ := k.GetStringValue("SDNRemoteArpMacAddress"); v == SDNRemoteArpMacAddress { + log.Printf("SDNRemoteArpMacAddress regKey already set") + return nil // already set + } + if err = k.SetStringValue("SDNRemoteArpMacAddress", SDNRemoteArpMacAddress); err != nil { + return errors.Wrap(err, "could not set registry key") } + return nil +} +func restartHNS(ctx context.Context) error { + log.Printf("Restarting HNS service") + // connect to the service manager + m, err := mgr.Connect() + if err != nil { + return errors.Wrap(err, "could not connect to service manager") + } + defer m.Disconnect() //nolint:errcheck // ignore error + // open the HNS service + service, err := m.OpenService("hns") + if err != nil { + return errors.Wrap(err, "could not access service") + } + defer service.Close() + // Stop the service + _, err = service.Control(svc.Stop) + if err != nil { + return errors.Wrap(err, "could not stop service") + } + // Wait for the service to stop + ticker := time.NewTicker(500 * time.Millisecond) //nolint:gomnd // 500ms + defer ticker.Stop() + for { // hacky cancellable do-while + status, err := service.Query() + if err != nil { + return errors.Wrap(err, "could not query service status") + } + if status.State == svc.Stopped { + break + } + select { + case <-ctx.Done(): + return errors.New("context cancelled") + case <-ticker.C: + } + } + // Start the service again + if err := service.Start(); err != nil { + return errors.Wrap(err, "could not start service") + } return nil }