diff --git a/internal/hns/hnsendpoint.go b/internal/hns/hnsendpoint.go index 83b683bd90..21d75f7b8e 100644 --- a/internal/hns/hnsendpoint.go +++ b/internal/hns/hnsendpoint.go @@ -6,7 +6,9 @@ import ( "encoding/json" "net" "strings" + "sync" + "github.com/Microsoft/hcsshim/osversion" "github.com/sirupsen/logrus" ) @@ -36,7 +38,7 @@ type HNSEndpoint struct { SharedContainers []string `json:",omitempty"` } -//SystemType represents the type of the system on which actions are done +// SystemType represents the type of the system on which actions are done type SystemType string // SystemType const @@ -46,6 +48,14 @@ const ( HostType SystemType = "Host" ) +var ( + // Server versions before 2019 (RS5), including Server 2016 (RS1) do not + // support concurrent add/delete of endpoints. Therefore, we need to use + // this mutex and serialize the add/delete of endpoints on those versions. + endpointMu sync.RWMutex + windowsBuild = osversion.Build() +) + // EndpointAttachDetachRequest is the structure used to send request to the container to modify the system // Supported resource types are Network and Request Types are Add/Remove type EndpointAttachDetachRequest struct { @@ -76,6 +86,16 @@ type EndpointStats struct { // HNSEndpointRequest makes a HNS call to modify/query a network endpoint func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) { endpoint := &HNSEndpoint{} + if windowsBuild < osversion.RS5 { + switch method { + case "GET": + endpointMu.RLock() + defer endpointMu.RUnlock() + case "DELETE", "POST": + endpointMu.Lock() + defer endpointMu.Unlock() + } + } err := hnsCall(method, "/endpoints/"+path, request, &endpoint) if err != nil { return nil, err @@ -87,6 +107,10 @@ func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) { // HNSListEndpointRequest makes a HNS call to query the list of available endpoints func HNSListEndpointRequest() ([]HNSEndpoint, error) { var endpoint []HNSEndpoint + if windowsBuild < osversion.RS5 { + endpointMu.RLock() + defer endpointMu.RUnlock() + } err := hnsCall("GET", "/endpoints/", "", &endpoint) if err != nil { return nil, err @@ -181,6 +205,10 @@ func (endpoint *HNSEndpoint) Update() (*HNSEndpoint, error) { if err != nil { return nil, err } + if windowsBuild < osversion.RS5 { + endpointMu.Lock() + defer endpointMu.Unlock() + } err = hnsCall("POST", "/endpoints/"+endpoint.Id, string(jsonString), &endpoint) return endpoint, err @@ -244,6 +272,10 @@ func (endpoint *HNSEndpoint) ContainerAttach(containerID string, compartmentID u if err != nil { return err } + if windowsBuild < osversion.RS5 { + endpointMu.Lock() + defer endpointMu.Unlock() + } return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) } @@ -263,6 +295,10 @@ func (endpoint *HNSEndpoint) ContainerDetach(containerID string) error { if err != nil { return err } + if windowsBuild < osversion.RS5 { + endpointMu.Lock() + defer endpointMu.Unlock() + } return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response) } @@ -281,6 +317,10 @@ func (endpoint *HNSEndpoint) HostAttach(compartmentID uint16) error { if err != nil { return err } + if windowsBuild < osversion.RS5 { + endpointMu.Lock() + defer endpointMu.Unlock() + } return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) } @@ -298,6 +338,10 @@ func (endpoint *HNSEndpoint) HostDetach() error { if err != nil { return err } + if windowsBuild < osversion.RS5 { + endpointMu.Lock() + defer endpointMu.Unlock() + } return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response) } @@ -316,6 +360,10 @@ func (endpoint *HNSEndpoint) VirtualMachineNICAttach(virtualMachineNICName strin if err != nil { return err } + if windowsBuild < osversion.RS5 { + endpointMu.Lock() + defer endpointMu.Unlock() + } return hnsCall("POST", "/endpoints/"+endpoint.Id+"/attach", string(jsonString), &response) } @@ -334,5 +382,9 @@ func (endpoint *HNSEndpoint) VirtualMachineNICDetach() error { if err != nil { return err } + if windowsBuild < osversion.RS5 { + endpointMu.Lock() + defer endpointMu.Unlock() + } return hnsCall("POST", "/endpoints/"+endpoint.Id+"/detach", string(jsonString), &response) }