Add AWSVPC setup routines to the attach script

When running in the AWSVPC mode, we need to do the following:

- Keep the HW TX offloading on.
- Check that the allocated address belongs to the default subnet,
  because only one subnet is allowed and it should be the default one.

If it is not possible to determine whether AWSVPC is on, we ignore
all the steps, because the attachment routines have to work
regardless whether the router is running and the AWSVPC detection
is done by querying the /ipinfo/tracker endpoint served by
the router.
This commit is contained in:
Martynas Pumputis authored and Bryan Boreham committed 2016-06-08 16:44:54 +01:00
1 parent de2a70861c
commit 7670fed72c
4 files changed
+51 -7

No files matched your search

+4 -4
View File
@@ -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)
}
+1 -1
View File
@@ -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 {
+2 -1
View File
@@ -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)
}
+44 -1
View File
@@ -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] <container-id> <bridge-name> <mtu> <cidr>...")
}
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 {