Merge pull request #12318 from aarondav/best-effort-iptables-lock

Do our best not to invoke iptables concurrently if --wait is unsupported
This commit is contained in:
Jessie Frazelle 2015-05-07 17:00:26 -07:00
commit 88c612a22d
2 changed files with 48 additions and 2 deletions

View file

@ -8,6 +8,7 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"sync"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
) )
@ -25,8 +26,10 @@ const (
) )
var ( var (
iptablesPath string iptablesPath string
supportsXlock = false supportsXlock = false
// used to lock iptables commands if xtables lock is not supported
bestEffortLock sync.Mutex
ErrIptablesNotFound = errors.New("Iptables not found") ErrIptablesNotFound = errors.New("Iptables not found")
) )
@ -289,6 +292,9 @@ func Raw(args ...string) ([]byte, error) {
} }
if supportsXlock { if supportsXlock {
args = append([]string{"--wait"}, args...) args = append([]string{"--wait"}, args...)
} else {
bestEffortLock.Lock()
defer bestEffortLock.Unlock()
} }
logrus.Debugf("%s, %v", iptablesPath, args) logrus.Debugf("%s, %v", iptablesPath, args)

View file

@ -5,6 +5,7 @@ import (
"os/exec" "os/exec"
"strconv" "strconv"
"strings" "strings"
"sync"
"testing" "testing"
) )
@ -168,6 +169,45 @@ func TestOutput(t *testing.T) {
} }
} }
func TestConcurrencyWithWait(t *testing.T) {
RunConcurrencyTest(t, true)
}
func TestConcurrencyNoWait(t *testing.T) {
RunConcurrencyTest(t, false)
}
// Runs 10 concurrent rule additions. This will fail if iptables
// is actually invoked simultaneously without --wait.
// Note that if iptables does not support the xtable lock on this
// system, then allowXlock has no effect -- it will always be off.
func RunConcurrencyTest(t *testing.T, allowXlock bool) {
var wg sync.WaitGroup
if !allowXlock && supportsXlock {
supportsXlock = false
defer func() { supportsXlock = true }()
}
ip := net.ParseIP("192.168.1.1")
port := 1234
dstAddr := "172.17.0.1"
dstPort := 4321
proto := "tcp"
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
err := natChain.Forward(Append, ip, port, proto, dstAddr, dstPort)
if err != nil {
t.Fatal(err)
}
}()
}
wg.Wait()
}
func TestCleanup(t *testing.T) { func TestCleanup(t *testing.T) {
var err error var err error
var rules []byte var rules []byte