diff --git a/net/bridge.go b/net/bridge.go index c7ab596a..deff2e11 100644 --- a/net/bridge.go +++ b/net/bridge.go @@ -11,7 +11,9 @@ import ( "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + "github.com/weaveworks/weave/common" "github.com/weaveworks/weave/common/odp" + "github.com/weaveworks/weave/net/ipset" ) /* This code implements three possible configurations to connect @@ -47,11 +49,12 @@ datapath of old kernel versions (https://github.com/weaveworks/weave/issues/1577 */ const ( - WeaveBridgeName = "weave" - DatapathName = "datapath" - DatapathIfName = "vethwe-datapath" - BridgeIfName = "vethwe-bridge" - PcapIfName = "vethwe-pcap" + WeaveBridgeName = "weave" + DatapathName = "datapath" + DatapathIfName = "vethwe-datapath" + BridgeIfName = "vethwe-bridge" + PcapIfName = "vethwe-pcap" + NoMasqLocalIpset = ipset.Name("weave-no-masq-local") ) type Bridge interface { @@ -213,6 +216,7 @@ type BridgeConfig struct { MTU int Mac string Port int + NoMasqLocal bool } func (config *BridgeConfig) configuredBridgeType() Bridge { @@ -489,8 +493,25 @@ func configureIPTables(config *BridgeConfig) error { if err := ipt.ClearChain("nat", "WEAVE"); err != nil { return errors.Wrap(err, "failed to clear/create nat/WEAVE chain") } + if err := ipt.AppendUnique("nat", "POSTROUTING", "-j", "WEAVE"); err != nil { + return err + } - return ipt.AppendUnique("nat", "POSTROUTING", "-j", "WEAVE") + // k8s-only: Create the ipset to store CIDRs allocated by IPAM for local pods. + // External traffic sent to these CIDRs avoids SNAT'ing so that NodePort + // with `"externalTrafficPolicy":"Local"` would have the correct src IP addr. + if config.NoMasqLocal { + ips := ipset.New(common.LogLogger()) + _ = ips.Destroy(NoMasqLocalIpset) + if err := ips.Create(NoMasqLocalIpset, ipset.HashNet); err != nil { + return err + } + if err := ipt.Insert("nat", "WEAVE", 1, "-m", "set", "--match-set", string(NoMasqLocalIpset), "dst", "-j", "RETURN"); err != nil { + return err + } + } + + return nil } func linkSetUpByName(linkName string) error { diff --git a/net/ipset/ipset.go b/net/ipset/ipset.go index 1e57b1d7..80580bb9 100644 --- a/net/ipset/ipset.go +++ b/net/ipset/ipset.go @@ -16,6 +16,7 @@ type Type string const ( ListSet = Type("list:set") HashIP = Type("hash:ip") + HashNet = Type("hash:net") ) type Interface interface { diff --git a/prog/weave-npc/main.go b/prog/weave-npc/main.go index 7ba90c2a..d1761e76 100644 --- a/prog/weave-npc/main.go +++ b/prog/weave-npc/main.go @@ -18,8 +18,9 @@ import ( "k8s.io/client-go/tools/cache" "github.com/weaveworks/weave/common" - "github.com/weaveworks/weave/npc" + "github.com/weaveworks/weave/net" "github.com/weaveworks/weave/net/ipset" + "github.com/weaveworks/weave/npc" "github.com/weaveworks/weave/npc/metrics" "github.com/weaveworks/weave/npc/ulogd" ) @@ -56,7 +57,7 @@ func resetIPTables(ipt *iptables.IPTables) error { } func resetIPSets(ips ipset.Interface) error { - // Remove ipsets prefixed `weave-` only + // Remove ipsets prefixed `weave-` excluding weave-no-masq-local (used by weaver). sets, err := ips.List(npc.IpsetNamePrefix) if err != nil { @@ -68,6 +69,9 @@ func resetIPSets(ips ipset.Interface) error { // Must remove references to ipsets by other ipsets before they're destroyed for _, s := range sets { + if s == ipset.Name(net.NoMasqLocalIpset) { + continue + } common.Log.Debugf("Flushing ipset '%s'", string(s)) if err := ips.Flush(s); err != nil { common.Log.Errorf("Failed to flush ipset '%s'", string(s)) @@ -76,6 +80,9 @@ func resetIPSets(ips ipset.Interface) error { } for _, s := range sets { + if s == ipset.Name(net.NoMasqLocalIpset) { + continue + } common.Log.Debugf("Destroying ipset '%s'", string(s)) if err := ips.Destroy(s); err != nil { common.Log.Errorf("Failed to destroy ipset '%s'", string(s)) diff --git a/prog/weaver/main.go b/prog/weaver/main.go index 52a7b6bc..33f18a65 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -221,6 +221,7 @@ func main() { mflag.BoolVar(&pluginConfig.EnableV2Multicast, []string{"-plugin-v2-multicast"}, false, "enable multicast for Docker plugin (v2)") mflag.StringVar(&pluginConfig.Socket, []string{"-plugin-socket"}, "/run/docker/plugins/weave.sock", "plugin socket on which to listen") mflag.StringVar(&pluginConfig.MeshSocket, []string{"-plugin-mesh-socket"}, "/run/docker/plugins/weavemesh.sock", "plugin socket on which to listen in mesh mode") + mflag.BoolVar(&bridgeConfig.NoMasqLocal, []string{"-no-masq-local"}, false, "do not SNAT external traffic sent to pods running on this node (Kubernetes only)") proxyConfig := newProxyConfig()