diff --git a/net/veth.go b/net/veth.go index eea00485..fbca71c3 100644 --- a/net/veth.go +++ b/net/veth.go @@ -13,7 +13,7 @@ import ( ) // create and attach a veth to the Weave bridge -func CreateAndAttachVeth(name, peerName, bridgeName string, mtu int, init func(peer netlink.Link) error) (*netlink.Veth, error) { +func CreateAndAttachVeth(name, peerName, bridgeName string, mtu int, keepTXOn bool, init func(peer netlink.Link) error) (*netlink.Veth, error) { bridge, err := netlink.LinkByName(bridgeName) if err != nil { return nil, fmt.Errorf(`bridge "%s" not present; did you launch weave?`, bridgeName) @@ -42,7 +42,7 @@ func CreateAndAttachVeth(name, peerName, bridgeName string, mtu int, init func(p if err := netlink.LinkSetMasterByIndex(veth, bridge.Attrs().Index); err != nil { return cleanup(`unable to set master of %s: %s`, name, err) } - if bridgeType == Bridge { + if bridgeType == Bridge && !keepTXOn { if err := EthtoolTXOff(peerName); err != nil { return cleanup(`unable to set tx off on %q: %s`, peerName, err) } @@ -111,14 +111,14 @@ func interfaceExistsInNamespace(ns netns.NsHandle, ifName string) bool { return err == nil } -func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, withMulticastRoute bool, cidrs []*net.IPNet) error { +func AttachContainer(ns netns.NsHandle, id, ifName, bridgeName string, mtu int, withMulticastRoute bool, cidrs []*net.IPNet, keepTXOn bool) error { if !interfaceExistsInNamespace(ns, ifName) { maxIDLen := IFNAMSIZ - 1 - len(vethPrefix+"pl") if len(id) > maxIDLen { id = id[:maxIDLen] // trim passed ID if too long } name, peerName := vethPrefix+"pl"+id, vethPrefix+"pg"+id - _, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, func(veth netlink.Link) error { + _, err := CreateAndAttachVeth(name, peerName, bridgeName, mtu, keepTXOn, func(veth netlink.Link) error { if err := netlink.LinkSetNsFd(veth, int(ns)); err != nil { return fmt.Errorf("failed to move veth to container netns: %s", err) } diff --git a/plugin/net/cni.go b/plugin/net/cni.go index f43ef967..eddd7dc7 100644 --- a/plugin/net/cni.go +++ b/plugin/net/cni.go @@ -92,7 +92,7 @@ func (c *CNIPlugin) CmdAdd(args *skel.CmdArgs) error { id = fmt.Sprintf("%x", data) } - if err := weavenet.AttachContainer(ns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&result.IP4.IP}); err != nil { + if err := weavenet.AttachContainer(ns, id, args.IfName, conf.BrName, conf.MTU, false, []*net.IPNet{&result.IP4.IP}, false); err != nil { return err } if err := weavenet.WithNetNSLink(ns, args.IfName, func(link netlink.Link) error { diff --git a/plugin/net/driver.go b/plugin/net/driver.go index 675ca93d..d8132529 100644 --- a/plugin/net/driver.go +++ b/plugin/net/driver.go @@ -134,8 +134,9 @@ func (driver *driver) JoinEndpoint(j *api.JoinRequest) (*api.JoinResponse, error if err != nil { return nil, driver.error("JoinEndpoint", "unable to find network info: %s", err) } + name, peerName := vethPair(j.EndpointID) - if _, err := weavenet.CreateAndAttachVeth(name, peerName, weavenet.WeaveBridgeName, 0, nil); err != nil { + if _, err := weavenet.CreateAndAttachVeth(name, peerName, weavenet.WeaveBridgeName, 0, false, nil); err != nil { return nil, driver.error("JoinEndpoint", "%s", err) } diff --git a/prog/weaveutil/attach.go b/prog/weaveutil/attach.go index 2dbe037f..83a3085a 100644 --- a/prog/weaveutil/attach.go +++ b/prog/weaveutil/attach.go @@ -3,12 +3,15 @@ package main import ( "fmt" "net" + "os" "strconv" "syscall" docker "github.com/fsouza/go-dockerclient" "github.com/vishvananda/netns" + "github.com/weaveworks/weave/api" + "github.com/weaveworks/weave/common" weavenet "github.com/weaveworks/weave/net" ) @@ -17,11 +20,26 @@ func attach(args []string) error { cmdUsage("attach-container", "[--no-multicast-route] ...") } + client := api.NewClient(os.Getenv("WEAVE_HTTP_ADDR"), common.Log) + keepTXOn := false + isAWSVPC := false + // In a case of an error, we skip applying necessary steps for AWSVPC, because + // "attach" should work without the weave router running. + if t, err := client.LocalRangeTracker(); err != nil { + fmt.Fprintf(os.Stderr, "unable to determine tracker: %s; skipping AWSVPC initialization\n", err) + } else if t == "awsvpc" { + isAWSVPC = true + keepTXOn = true + } + withMulticastRoute := true if args[0] == "--no-multicast-route" { withMulticastRoute = false args = args[1:] } + if isAWSVPC { + withMulticastRoute = false + } pid, nsContainer, err := containerPidAndNs(args[0]) if err != nil { @@ -40,7 +58,22 @@ func attach(args []string) error { if err != nil { return err } - err = weavenet.AttachContainer(nsContainer, fmt.Sprint(pid), weavenet.VethName, args[1], mtu, withMulticastRoute, cidrs) + + if isAWSVPC { + // Currently, we allow only IP addresses from the default subnet + if defaultSubnet, err := client.DefaultSubnet(); err != nil { + fmt.Fprintf(os.Stderr, "unable to retrieve default subnet: %s; skipping AWSVPC checks\n", err) + } else { + for _, cidr := range cidrs { + if !sameSubnet(cidr, defaultSubnet) { + format := "AWSVPC constraints violation: %s does not belong to the default subnet %s" + return fmt.Errorf(format, cidr, defaultSubnet) + } + } + } + } + + err = weavenet.AttachContainer(nsContainer, fmt.Sprint(pid), weavenet.VethName, args[1], mtu, withMulticastRoute, cidrs, keepTXOn) // If we detected an error but the container has died, tell the user that instead. if err != nil && !processExists(pid) { err = fmt.Errorf("Container %s died", args[0]) @@ -48,6 +81,16 @@ func attach(args []string) error { return err } +// sameSubnet checks whether ip belongs to network's subnet +func sameSubnet(ip *net.IPNet, network *net.IPNet) bool { + if network.Contains(ip.IP) { + i1, i2 := ip.Mask.Size() + n1, n2 := network.Mask.Size() + return i1 == n1 && i2 == n2 + } + return false +} + func containerPidAndNs(containerID string) (int, netns.NsHandle, error) { c, err := docker.NewVersionedClientFromEnv("1.18") if err != nil {