diff --git a/client/allocrunner/network_manager_linux.go b/client/allocrunner/network_manager_linux.go index b5bde8eff..0d6ef3e98 100644 --- a/client/allocrunner/network_manager_linux.go +++ b/client/allocrunner/network_manager_linux.go @@ -152,9 +152,17 @@ func newNetworkConfigurator(log hclog.Logger, alloc *structs.Allocation, config switch { case netMode == "bridge": - return newBridgeNetworkConfigurator(log, config.BridgeNetworkName, config.BridgeNetworkAllocSubnet, config.CNIPath, ignorePortMappingHostIP) + c, err := newBridgeNetworkConfigurator(log, config.BridgeNetworkName, config.BridgeNetworkAllocSubnet, config.CNIPath, ignorePortMappingHostIP) + if err != nil { + return nil, err + } + return &synchronizedNetworkConfigurator{c}, nil case strings.HasPrefix(netMode, "cni/"): - return newCNINetworkConfigurator(log, config.CNIPath, config.CNIInterfacePrefix, config.CNIConfigDir, netMode[4:], ignorePortMappingHostIP) + c, err := newCNINetworkConfigurator(log, config.CNIPath, config.CNIInterfacePrefix, config.CNIConfigDir, netMode[4:], ignorePortMappingHostIP) + if err != nil { + return nil, err + } + return &synchronizedNetworkConfigurator{c}, nil default: return &hostNetworkConfigurator{}, nil } diff --git a/client/allocrunner/networking.go b/client/allocrunner/networking.go index 432910b1b..4e508452a 100644 --- a/client/allocrunner/networking.go +++ b/client/allocrunner/networking.go @@ -2,6 +2,7 @@ package allocrunner import ( "context" + "sync" "github.com/hashicorp/nomad/nomad/structs" "github.com/hashicorp/nomad/plugins/drivers" @@ -25,3 +26,26 @@ func (h *hostNetworkConfigurator) Setup(context.Context, *structs.Allocation, *d func (h *hostNetworkConfigurator) Teardown(context.Context, *structs.Allocation, *drivers.NetworkIsolationSpec) error { return nil } + +// networkingGlobalMutex is used by a synchronizedNetworkConfigurator to serialize +// network operations done by the client to prevent race conditions when manipulating +// iptables rules +var networkingGlobalMutex sync.Mutex + +// synchronizedNetworkConfigurator wraps a NetworkConfigurator to provide serialized access to network +// operations performed by the client +type synchronizedNetworkConfigurator struct { + nc NetworkConfigurator +} + +func (s *synchronizedNetworkConfigurator) Setup(ctx context.Context, allocation *structs.Allocation, spec *drivers.NetworkIsolationSpec) (*structs.AllocNetworkStatus, error) { + networkingGlobalMutex.Lock() + defer networkingGlobalMutex.Unlock() + return s.nc.Setup(ctx, allocation, spec) +} + +func (s *synchronizedNetworkConfigurator) Teardown(ctx context.Context, allocation *structs.Allocation, spec *drivers.NetworkIsolationSpec) error { + networkingGlobalMutex.Lock() + defer networkingGlobalMutex.Unlock() + return s.nc.Teardown(ctx, allocation, spec) +}