diff --git a/net/arp.go b/net/arp.go index 39322b9a..4a4e0d78 100644 --- a/net/arp.go +++ b/net/arp.go @@ -1,9 +1,11 @@ package net -import "path/filepath" -import "fmt" -import "io" -import "os" +import ( + "fmt" + "io" + "os" + "path/filepath" +) // Configure the ARP cache parameters for the given interface. This // makes containers react more quickly to a change in the MAC address diff --git a/net/bridge.go b/net/bridge.go index 19931c82..9e6b06e9 100644 --- a/net/bridge.go +++ b/net/bridge.go @@ -17,11 +17,44 @@ import ( type BridgeType int +/* This code implements three possible configurations to connect + containers to the Weave Net overlay: + +1. Bridge + +-------+ +(container-veth)-+ weave +-(vethwe-bridge)--(vethwe-pcap) + +-------+ + +"weave" is a Linux bridge. "vethwe-pcap" (end of veth pair) is used +to capture and inject packets, by router/pcap.go. + +2. BridgedFastdp + + +-------+ /----------\ +(container-veth)-+ weave +-(vethwe-bridge)--(vethwe-datapath)-+ datapath + + +-------+ \----------/ + +"weave" is a Linux bridge and "datapath" is an Open vSwitch datapath; +they are connected via a veth pair. Packet capture and injection use +the "datapath" device, via "router/fastdp.go:fastDatapathBridge" + +3. Fastdp + + /-------\ +(container-veth)-+ weave + + \-------/ + +"weave" is an Open vSwitch datapath, and capture/injection are as in +BridgedFastdp. Not used by default due to missing conntrack support in +datapath of old kernel versions (https://github.com/weaveworks/weave/issues/1577). +*/ + const ( WeaveBridgeName = "weave" DatapathName = "datapath" + DatapathIfName = "vethwe-datapath" BridgeIfName = "vethwe-bridge" - PcapIfaceName = "vethwe-pcap" + PcapIfName = "vethwe-pcap" None BridgeType = iota Bridge @@ -70,13 +103,11 @@ func DetectBridgeType(weaveBridgeName, datapathName string) BridgeType { } } -var ErrSetBridgeMac = errors.New("Setting $DOCKER_BRIDGE MAC (mitigate https://github.com/docker/docker/issues/14908)") - -func EnforceAddrAssignType(bridgeName string) error { +func EnforceAddrAssignType(bridgeName string) (setAddr bool, err error) { sysctlFilename := filepath.Join("/sys/class/net/", bridgeName, "/addr_assign_type") addrAssignType, err := ioutil.ReadFile(sysctlFilename) if err != nil { - return errors.Wrapf(err, "reading %q", sysctlFilename) + return false, errors.Wrapf(err, "reading %q", sysctlFilename) } // From include/uapi/linux/netdevice.h @@ -88,21 +119,21 @@ func EnforceAddrAssignType(bridgeName string) error { if addrAssignType[0] != '3' { link, err := netlink.LinkByName(bridgeName) if err != nil { - return errors.Wrapf(err, "EnforceAddrAssignType finding bridge %s", bridgeName) + return false, errors.Wrapf(err, "EnforceAddrAssignType finding bridge %s", bridgeName) } mac, err := RandomMAC() if err != nil { - return errors.Wrap(err, "creating random MAC") + return false, errors.Wrap(err, "creating random MAC") } if err := netlink.LinkSetHardwareAddr(link, mac); err != nil { - return errors.Wrapf(err, "setting bridge %s address to %v", bridgeName, mac) + return false, errors.Wrapf(err, "setting bridge %s address to %v", bridgeName, mac) } - return ErrSetBridgeMac + return true, nil } - return nil + return false, nil } func isBridge(link netlink.Link) bool { @@ -181,8 +212,8 @@ type BridgeConfig struct { DatapathName string NoFastdp bool NoBridgedFastdp bool - IsAWSVPC bool - ExpectNPC bool + AWSVPC bool + NPC bool MTU int Mac string Port int @@ -228,7 +259,7 @@ func CreateBridge(procPath string, config *BridgeConfig) (BridgeType, error) { } } - if config.IsAWSVPC { + if config.AWSVPC { bridgeType = AWSVPC // Set proxy_arp on the bridge, so that it could accept packets destined // to containers within the same subnet but running on remote hosts. @@ -306,7 +337,7 @@ func initBridge(config *BridgeConfig) error { if err := initBridgePrep(config); err != nil { return err } - if _, err := CreateAndAttachVeth(BridgeIfName, PcapIfaceName, config.WeaveBridgeName, config.MTU, true, func(veth netlink.Link) error { + if _, err := CreateAndAttachVeth(BridgeIfName, PcapIfName, config.WeaveBridgeName, config.MTU, true, func(veth netlink.Link) error { return netlink.LinkSetUp(veth) }); err != nil { return errors.Wrap(err, "creating pcap veth pair") @@ -342,7 +373,7 @@ func initBridgedFastdp(config *BridgeConfig) error { if err := initBridgePrep(config); err != nil { return err } - if _, err := CreateAndAttachVeth("vethwe-bridge", "vethwe-datapath", config.WeaveBridgeName, config.MTU, true, func(veth netlink.Link) error { + if _, err := CreateAndAttachVeth(BridgeIfName, DatapathIfName, config.WeaveBridgeName, config.MTU, true, func(veth netlink.Link) error { if err := netlink.LinkSetUp(veth); err != nil { return errors.Wrapf(err, "setting link up on %q", veth.Attrs().Name) } @@ -399,9 +430,11 @@ func configureIPTables(config *BridgeConfig) error { } } - if config.ExpectNPC { + if config.NPC { // Steer traffic via the NPC - ipt.NewChain("filter", "WEAVE-NPC") // ignoring errors such as 'chain already exists' + if err = ipt.ClearChain("nat", "WEAVE-NPC"); err != nil { + return errors.Wrap(err, "clearing WEAVE-NPC chain") + } if err = ipt.AppendUnique("filter", "FORWARD", "-o", config.WeaveBridgeName, "-j", "WEAVE-NPC"); err != nil { return err } @@ -428,7 +461,9 @@ func configureIPTables(config *BridgeConfig) error { } // create a chain for masquerading - ipt.NewChain("nat", "WEAVE") // ignoring errors such as 'chain already exists' + if err = ipt.ClearChain("nat", "WEAVE"); err != nil { + return errors.Wrap(err, "clearing WEAVE chain") + } if err = ipt.AppendUnique("nat", "POSTROUTING", "-j", "WEAVE"); err != nil { return err } diff --git a/prog/weaver/main.go b/prog/weaver/main.go index 5c2d8cb5..08d2a90d 100644 --- a/prog/weaver/main.go +++ b/prog/weaver/main.go @@ -170,7 +170,7 @@ func main() { mflag.BoolVar(&resume, []string{"-resume"}, false, "resume connections to previous peers") mflag.StringVar(&bridgeConfig.WeaveBridgeName, []string{"-weave-bridge"}, "weave", "name of weave bridge") mflag.StringVar(&bridgeConfig.DockerBridgeName, []string{"-docker-bridge"}, "", "name of Docker bridge") - mflag.BoolVar(&bridgeConfig.ExpectNPC, []string{"-expect-npc"}, false, "set up iptables rules for npc") + mflag.BoolVar(&bridgeConfig.NPC, []string{"-expect-npc"}, false, "set up iptables rules for npc") mflag.StringVar(&routerName, []string{"#name", "-name"}, "", "name of router (defaults to MAC of interface)") mflag.StringVar(&nickName, []string{"#nickname", "-nickname"}, "", "nickname of peer (defaults to hostname)") mflag.StringVar(&password, []string{"#password", "-password"}, "", "network password") @@ -200,7 +200,7 @@ func main() { mflag.StringVar(&trustedSubnetStr, []string{"-trusted-subnets"}, "", "comma-separated list of trusted subnets in CIDR notation") mflag.StringVar(&dbPrefix, []string{"-db-prefix"}, "/weavedb/weave", "pathname/prefix of filename to store data") mflag.StringVar(&procPath, []string{"-proc-path"}, "/proc", "path to reach host /proc filesystem") - mflag.BoolVar(&bridgeConfig.IsAWSVPC, []string{"-awsvpc"}, false, "use AWS VPC for routing") + mflag.BoolVar(&bridgeConfig.AWSVPC, []string{"-awsvpc"}, false, "use AWS VPC for routing") mflag.StringVar(&hostRoot, []string{"-host-root"}, "", "path to reach host filesystem") mflag.StringVar(&discoveryEndpoint, []string{"-peer-discovery-url"}, "https://cloud.weave.works/api/net", "url for peer discovery") mflag.StringVar(&token, []string{"-token"}, "", "token for peer discovery") @@ -251,8 +251,10 @@ func main() { } if bridgeConfig.DockerBridgeName != "" { - if err := weavenet.EnforceAddrAssignType(bridgeConfig.DockerBridgeName); err != nil { + if setAddr, err := weavenet.EnforceAddrAssignType(bridgeConfig.DockerBridgeName); err != nil { Log.Errorf("While checking address assignment type of %s: %s", bridgeConfig.DockerBridgeName, err) + } else if setAddr { + Log.Warningf("Setting %s MAC (mitigate https://github.com/docker/docker/issues/14908)", bridgeConfig.DockerBridgeName) } } @@ -269,7 +271,7 @@ func main() { networkConfig.Bridge = bridge if bridge != nil { - if err := weavenet.DetectHairpin("vethwe-bridge", Log); err != nil { + if err := weavenet.DetectHairpin(weavenet.BridgeIfName, Log); err != nil { Log.Errorf("DetectHairpin failed: %s", err) } } @@ -283,7 +285,7 @@ func main() { config.TrustedSubnets = parseTrustedSubnets(trustedSubnetStr) config.PeerDiscovery = !noDiscovery - if bridgeConfig.IsAWSVPC && len(config.Password) > 0 { + if bridgeConfig.AWSVPC && len(config.Password) > 0 { Log.Fatalf("--awsvpc mode is not compatible with the --password option") } @@ -329,7 +331,7 @@ func main() { } network := "" - if bridgeConfig.IsAWSVPC { + if bridgeConfig.AWSVPC { network = "awsvpc" } checkForUpdates(dockerVersion, network) @@ -352,7 +354,7 @@ func main() { ) if ipamConfig.Enabled() { var t tracker.LocalRangeTracker - if bridgeConfig.IsAWSVPC { + if bridgeConfig.AWSVPC { Log.Infoln("Creating AWSVPC LocalRangeTracker") t, err = tracker.NewAWSVPCTracker(bridgeConfig.WeaveBridgeName) if err != nil { @@ -430,11 +432,11 @@ func main() { go plugin.Start(httpAddr, dockerCli, pluginSocket, pluginMeshSocket, !noDNS, enablePluginV2) } - if bridgeConfig.IsAWSVPC { + if bridgeConfig.AWSVPC { // Run this on its own goroutine because the allocator can block // We remove the default route installed by the kernel, // because awsvpc has installed it as well - go expose(allocator, defaultSubnet, bridgeConfig.WeaveBridgeName, bridgeConfig.IsAWSVPC) + go expose(allocator, defaultSubnet, bridgeConfig.WeaveBridgeName, bridgeConfig.AWSVPC) } signals.SignalHandlerLoop(common.Log, router) @@ -509,7 +511,7 @@ func createOverlay(bridgeType weavenet.BridgeType, config weavenet.BridgeConfig, bridge = fastdp.Bridge() overlay.Add("fastdp", fastdp.Overlay()) case weavenet.Bridge: - iface, err := weavenet.EnsureInterface(weavenet.PcapIfaceName) + iface, err := weavenet.EnsureInterface(weavenet.PcapIfName) checkFatal(err) bridge, err = weave.NewPcap(iface, bufSzMB*1024*1024) // bufsz flag is in MB checkFatal(err) diff --git a/prog/weaveutil/bridge.go b/prog/weaveutil/bridge.go index 625e279f..de300fdb 100644 --- a/prog/weaveutil/bridge.go +++ b/prog/weaveutil/bridge.go @@ -38,10 +38,13 @@ func createBridge(args []string) error { Mac: args[5], NoFastdp: args[6] != "", NoBridgedFastdp: args[7] != "", - ExpectNPC: args[9] == "--expect-npc", + NPC: args[9] == "--expect-npc", } procPath := args[8] bridgeType, err := weavenet.CreateBridge(procPath, &config) + if err != nil { + return err + } fmt.Println(bridgeType.String()) - return err + return nil }