1// +build linux 2 3/* 4Copyright 2017 The Kubernetes Authors. 5 6Licensed under the Apache License, Version 2.0 (the "License"); 7you may not use this file except in compliance with the License. 8You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12Unless required by applicable law or agreed to in writing, software 13distributed under the License is distributed on an "AS IS" BASIS, 14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15See the License for the specific language governing permissions and 16limitations under the License. 17*/ 18 19package iptables 20 21import ( 22 "fmt" 23 "net" 24 "os" 25 "time" 26 27 "golang.org/x/sys/unix" 28 utilerrors "k8s.io/apimachinery/pkg/util/errors" 29 "k8s.io/apimachinery/pkg/util/wait" 30) 31 32type locker struct { 33 lock16 *os.File 34 lock14 *net.UnixListener 35} 36 37func (l *locker) Close() error { 38 errList := []error{} 39 if l.lock16 != nil { 40 if err := l.lock16.Close(); err != nil { 41 errList = append(errList, err) 42 } 43 } 44 if l.lock14 != nil { 45 if err := l.lock14.Close(); err != nil { 46 errList = append(errList, err) 47 } 48 } 49 return utilerrors.NewAggregate(errList) 50} 51 52func grabIptablesLocks(lockfilePath14x, lockfilePath16x string) (iptablesLocker, error) { 53 var err error 54 var success bool 55 56 l := &locker{} 57 defer func(l *locker) { 58 // Clean up immediately on failure 59 if !success { 60 l.Close() 61 } 62 }(l) 63 64 // Grab both 1.6.x and 1.4.x-style locks; we don't know what the 65 // iptables-restore version is if it doesn't support --wait, so we 66 // can't assume which lock method it'll use. 67 68 // Roughly duplicate iptables 1.6.x xtables_lock() function. 69 l.lock16, err = os.OpenFile(lockfilePath16x, os.O_CREATE, 0600) 70 if err != nil { 71 return nil, fmt.Errorf("failed to open iptables lock %s: %v", lockfilePath16x, err) 72 } 73 74 if err := wait.PollImmediate(200*time.Millisecond, 2*time.Second, func() (bool, error) { 75 if err := grabIptablesFileLock(l.lock16); err != nil { 76 return false, nil 77 } 78 return true, nil 79 }); err != nil { 80 return nil, fmt.Errorf("failed to acquire new iptables lock: %v", err) 81 } 82 83 // Roughly duplicate iptables 1.4.x xtables_lock() function. 84 if err := wait.PollImmediate(200*time.Millisecond, 2*time.Second, func() (bool, error) { 85 l.lock14, err = net.ListenUnix("unix", &net.UnixAddr{Name: lockfilePath14x, Net: "unix"}) 86 if err != nil { 87 return false, nil 88 } 89 return true, nil 90 }); err != nil { 91 return nil, fmt.Errorf("failed to acquire old iptables lock: %v", err) 92 } 93 94 success = true 95 return l, nil 96} 97 98func grabIptablesFileLock(f *os.File) error { 99 return unix.Flock(int(f.Fd()), unix.LOCK_EX|unix.LOCK_NB) 100} 101