|
@@ -18,13 +18,18 @@ import (
|
|
|
"fmt"
|
|
|
"strings"
|
|
|
|
|
|
- "github.com/coreos/go-iptables/iptables"
|
|
|
log "github.com/golang/glog"
|
|
|
|
|
|
"github.com/coreos/flannel/pkg/ip"
|
|
|
"github.com/coreos/flannel/subnet"
|
|
|
)
|
|
|
|
|
|
+type IPTablesRules interface {
|
|
|
+ AppendUnique(table string, chain string, rulespec ...string) error
|
|
|
+ Delete(table string, chain string, rulespec ...string) error
|
|
|
+ Exists(table string, chain string, rulespec ...string) (bool, error)
|
|
|
+}
|
|
|
+
|
|
|
func rules(ipn ip.IP4Net, lease *subnet.Lease) [][]string {
|
|
|
n := ipn.String()
|
|
|
sn := lease.Subnet.String()
|
|
@@ -41,36 +46,57 @@ func rules(ipn ip.IP4Net, lease *subnet.Lease) [][]string {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func SetupIPMasq(ipn ip.IP4Net, lease *subnet.Lease) error {
|
|
|
- ipt, err := iptables.New()
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("failed to set up IP Masquerade. iptables was not found")
|
|
|
- }
|
|
|
-
|
|
|
+func ipMasqRulesExist(ipt IPTablesRules, ipn ip.IP4Net, lease *subnet.Lease) (bool, error) {
|
|
|
for _, rule := range rules(ipn, lease) {
|
|
|
- log.Info("Adding iptables rule: ", strings.Join(rule, " "))
|
|
|
- err = ipt.AppendUnique("nat", "POSTROUTING", rule...)
|
|
|
+ exists, err := ipt.Exists("nat", "POSTROUTING", rule...)
|
|
|
if err != nil {
|
|
|
- return fmt.Errorf("failed to insert IP masquerade rule: %v", err)
|
|
|
+ // this shouldn't ever happen
|
|
|
+ return false, fmt.Errorf("failed to check rule existence", err)
|
|
|
+ }
|
|
|
+ if !exists {
|
|
|
+ return false, nil
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return nil
|
|
|
+ return true, nil
|
|
|
}
|
|
|
|
|
|
-func TeardownIPMasq(ipn ip.IP4Net, lease *subnet.Lease) error {
|
|
|
- ipt, err := iptables.New()
|
|
|
+func EnsureIPMasq(ipt IPTablesRules, ipn ip.IP4Net, lease *subnet.Lease) error {
|
|
|
+ exists, err := ipMasqRulesExist(ipt, ipn, lease)
|
|
|
if err != nil {
|
|
|
- return fmt.Errorf("failed to teardown IP Masquerade. iptables was not found")
|
|
|
+ return fmt.Errorf("Error checking rule existence: %v", err)
|
|
|
+ }
|
|
|
+ if exists {
|
|
|
+ // if all the rules already exist, no need to do anything
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ // Otherwise, teardown all the rules and set them up again
|
|
|
+ // We do this because the order of the rules is important
|
|
|
+ log.Info("Some iptables rules are missing; deleting and recreating rules")
|
|
|
+ TeardownIPMasq(ipt, ipn, lease)
|
|
|
+ if err = SetupIPMasq(ipt, ipn, lease); err != nil {
|
|
|
+ return fmt.Errorf("Error setting up rules: %v", err)
|
|
|
}
|
|
|
+ return nil
|
|
|
+}
|
|
|
|
|
|
+func SetupIPMasq(ipt IPTablesRules, ipn ip.IP4Net, lease *subnet.Lease) error {
|
|
|
for _, rule := range rules(ipn, lease) {
|
|
|
- log.Info("Deleting iptables rule: ", strings.Join(rule, " "))
|
|
|
- err = ipt.Delete("nat", "POSTROUTING", rule...)
|
|
|
+ log.Info("Adding iptables rule: ", strings.Join(rule, " "))
|
|
|
+ err := ipt.AppendUnique("nat", "POSTROUTING", rule...)
|
|
|
if err != nil {
|
|
|
- return fmt.Errorf("failed to delete IP masquerade rule: %v", err)
|
|
|
+ return fmt.Errorf("failed to insert IP masquerade rule: %v", err)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
+
|
|
|
+func TeardownIPMasq(ipt IPTablesRules, ipn ip.IP4Net, lease *subnet.Lease) {
|
|
|
+ for _, rule := range rules(ipn, lease) {
|
|
|
+ log.Info("Deleting iptables rule: ", strings.Join(rule, " "))
|
|
|
+ // We ignore errors here because if there's an error it's almost certainly because the rule
|
|
|
+ // doesn't exist, which is fine (we don't need to delete rules that don't exist)
|
|
|
+ ipt.Delete("nat", "POSTROUTING", rule...)
|
|
|
+ }
|
|
|
+}
|