Browse Source

Merge pull request #16 from docker/ci_godeps

Fix Godeps in CI
Arnaud Porterie 10 years ago
parent
commit
735dbcf3ab
26 changed files with 4992 additions and 5 deletions
  1. 18 0
      libnetwork/Godeps/Godeps.json
  2. 720 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver.go
  3. 161 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver_test.go
  4. 160 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator.go
  5. 681 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator_test.go
  6. 10 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network.go
  7. 175 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network_test.go
  8. 153 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator.go
  9. 245 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator_test.go
  10. 176 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper.go
  11. 152 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper_test.go
  12. 18 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mock_proxy.go
  13. 161 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/proxy.go
  14. 118 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/utils.go
  15. 93 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go
  16. 61 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_test.go
  17. 16 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_linux.go
  18. 15 0
      libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go
  19. 2 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS
  20. 31 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go
  21. 1307 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go
  22. 5 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go
  23. 7 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go
  24. 408 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
  25. 88 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
  26. 11 5
      libnetwork/circle.yml

+ 18 - 0
libnetwork/Godeps/Godeps.json

@@ -1,17 +1,35 @@
 {
 	"ImportPath": "github.com/docker/libnetwork",
 	"GoVersion": "go1.4.2",
+	"Packages": [
+		"./..."
+	],
 	"Deps": [
 		{
 			"ImportPath": "github.com/Sirupsen/logrus",
 			"Comment": "v0.6.4-12-g467d9d5",
 			"Rev": "467d9d55c2d2c17248441a8fc661561161f40d5e"
 		},
+		{
+			"ImportPath": "github.com/docker/docker/daemon/networkdriver",
+			"Comment": "v1.4.1-1379-g8e107a9",
+			"Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05"
+		},
+		{
+			"ImportPath": "github.com/docker/docker/pkg/parsers/kernel",
+			"Comment": "v1.4.1-1379-g8e107a9",
+			"Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05"
+		},
 		{
 			"ImportPath": "github.com/docker/docker/pkg/reexec",
 			"Comment": "v1.4.1-1379-g8e107a9",
 			"Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05"
 		},
+		{
+			"ImportPath": "github.com/docker/libcontainer/netlink",
+			"Comment": "v1.4.0-324-g88989e6",
+			"Rev": "88989e66d3a1ab960deb37f3dd7f824d85e1b9bc"
+		},
 		{
 			"ImportPath": "github.com/vishvananda/netlink",
 			"Rev": "8eb64238879fed52fd51c5b30ad20b928fb4c36c"

+ 720 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver.go

@@ -0,0 +1,720 @@
+package bridge
+
+import (
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"net"
+	"os"
+	"strings"
+	"sync"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/docker/daemon/networkdriver"
+	"github.com/docker/docker/daemon/networkdriver/ipallocator"
+	"github.com/docker/docker/daemon/networkdriver/portmapper"
+	"github.com/docker/docker/engine"
+	"github.com/docker/docker/nat"
+	"github.com/docker/docker/pkg/iptables"
+	"github.com/docker/docker/pkg/networkfs/resolvconf"
+	"github.com/docker/docker/pkg/parsers/kernel"
+	"github.com/docker/libcontainer/netlink"
+)
+
+const (
+	DefaultNetworkBridge     = "docker0"
+	MaxAllocatedPortAttempts = 10
+)
+
+// Network interface represents the networking stack of a container
+type networkInterface struct {
+	IP           net.IP
+	IPv6         net.IP
+	PortMappings []net.Addr // there are mappings to the host interfaces
+}
+
+type ifaces struct {
+	c map[string]*networkInterface
+	sync.Mutex
+}
+
+func (i *ifaces) Set(key string, n *networkInterface) {
+	i.Lock()
+	i.c[key] = n
+	i.Unlock()
+}
+
+func (i *ifaces) Get(key string) *networkInterface {
+	i.Lock()
+	res := i.c[key]
+	i.Unlock()
+	return res
+}
+
+var (
+	addrs = []string{
+		// Here we don't follow the convention of using the 1st IP of the range for the gateway.
+		// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
+		// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
+		// on the internal addressing or other stupid things like that.
+		// They shouldn't, but hey, let's not break them unless we really have to.
+		"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
+		"10.0.42.1/16",   // Don't even try using the entire /8, that's too intrusive
+		"10.1.42.1/16",
+		"10.42.42.1/16",
+		"172.16.42.1/24",
+		"172.16.43.1/24",
+		"172.16.44.1/24",
+		"10.0.42.1/24",
+		"10.0.43.1/24",
+		"192.168.42.1/24",
+		"192.168.43.1/24",
+		"192.168.44.1/24",
+	}
+
+	bridgeIface       string
+	bridgeIPv4Network *net.IPNet
+	bridgeIPv6Addr    net.IP
+	globalIPv6Network *net.IPNet
+
+	defaultBindingIP  = net.ParseIP("0.0.0.0")
+	currentInterfaces = ifaces{c: make(map[string]*networkInterface)}
+)
+
+func InitDriver(job *engine.Job) engine.Status {
+	var (
+		networkv4      *net.IPNet
+		networkv6      *net.IPNet
+		addrv4         net.Addr
+		addrsv6        []net.Addr
+		enableIPTables = job.GetenvBool("EnableIptables")
+		enableIPv6     = job.GetenvBool("EnableIPv6")
+		icc            = job.GetenvBool("InterContainerCommunication")
+		ipMasq         = job.GetenvBool("EnableIpMasq")
+		ipForward      = job.GetenvBool("EnableIpForward")
+		bridgeIP       = job.Getenv("BridgeIP")
+		bridgeIPv6     = "fe80::1/64"
+		fixedCIDR      = job.Getenv("FixedCIDR")
+		fixedCIDRv6    = job.Getenv("FixedCIDRv6")
+	)
+
+	if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
+		defaultBindingIP = net.ParseIP(defaultIP)
+	}
+
+	bridgeIface = job.Getenv("BridgeIface")
+	usingDefaultBridge := false
+	if bridgeIface == "" {
+		usingDefaultBridge = true
+		bridgeIface = DefaultNetworkBridge
+	}
+
+	addrv4, addrsv6, err := networkdriver.GetIfaceAddr(bridgeIface)
+
+	if err != nil {
+		// No Bridge existent, create one
+		// If we're not using the default bridge, fail without trying to create it
+		if !usingDefaultBridge {
+			return job.Error(err)
+		}
+
+		// If the iface is not found, try to create it
+		if err := configureBridge(bridgeIP, bridgeIPv6, enableIPv6); err != nil {
+			return job.Error(err)
+		}
+
+		addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
+		if err != nil {
+			return job.Error(err)
+		}
+
+		if fixedCIDRv6 != "" {
+			// Setting route to global IPv6 subnet
+			log.Infof("Adding route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface)
+			if err := netlink.AddRoute(fixedCIDRv6, "", "", bridgeIface); err != nil {
+				log.Fatalf("Could not add route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface)
+			}
+		}
+	} else {
+		// Bridge exists already, getting info...
+		// validate that the bridge ip matches the ip specified by BridgeIP
+		if bridgeIP != "" {
+			networkv4 = addrv4.(*net.IPNet)
+			bip, _, err := net.ParseCIDR(bridgeIP)
+			if err != nil {
+				return job.Error(err)
+			}
+			if !networkv4.IP.Equal(bip) {
+				return job.Errorf("bridge ip (%s) does not match existing bridge configuration %s", networkv4.IP, bip)
+			}
+		}
+
+		// a bridge might exist but not have any IPv6 addr associated with it yet
+		// (for example, an existing Docker installation that has only been used
+		// with IPv4 and docker0 already is set up) In that case, we can perform
+		// the bridge init for IPv6 here, else we will error out below if --ipv6=true
+		if len(addrsv6) == 0 && enableIPv6 {
+			if err := setupIPv6Bridge(bridgeIPv6); err != nil {
+				return job.Error(err)
+			}
+			// recheck addresses now that IPv6 is setup on the bridge
+			addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
+			if err != nil {
+				return job.Error(err)
+			}
+		}
+
+		// TODO: Check if route to fixedCIDRv6 is set
+	}
+
+	if enableIPv6 {
+		bip6, _, err := net.ParseCIDR(bridgeIPv6)
+		if err != nil {
+			return job.Error(err)
+		}
+		found := false
+		for _, addrv6 := range addrsv6 {
+			networkv6 = addrv6.(*net.IPNet)
+			if networkv6.IP.Equal(bip6) {
+				found = true
+				break
+			}
+		}
+		if !found {
+			return job.Errorf("bridge IPv6 does not match existing bridge configuration %s", bip6)
+		}
+	}
+
+	networkv4 = addrv4.(*net.IPNet)
+
+	if enableIPv6 {
+		if len(addrsv6) == 0 {
+			return job.Error(errors.New("IPv6 enabled but no IPv6 detected"))
+		}
+		bridgeIPv6Addr = networkv6.IP
+	}
+
+	// Configure iptables for link support
+	if enableIPTables {
+		if err := setupIPTables(addrv4, icc, ipMasq); err != nil {
+			return job.Error(err)
+		}
+
+	}
+
+	if ipForward {
+		// Enable IPv4 forwarding
+		if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
+			job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
+		}
+
+		if fixedCIDRv6 != "" {
+			// Enable IPv6 forwarding
+			if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil {
+				job.Logf("WARNING: unable to enable IPv6 default forwarding: %s\n", err)
+			}
+			if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, 0644); err != nil {
+				job.Logf("WARNING: unable to enable IPv6 all forwarding: %s\n", err)
+			}
+		}
+	}
+
+	// We can always try removing the iptables
+	if err := iptables.RemoveExistingChain("DOCKER", iptables.Nat); err != nil {
+		return job.Error(err)
+	}
+
+	if enableIPTables {
+		_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat)
+		if err != nil {
+			return job.Error(err)
+		}
+		chain, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter)
+		if err != nil {
+			return job.Error(err)
+		}
+		portmapper.SetIptablesChain(chain)
+	}
+
+	bridgeIPv4Network = networkv4
+	if fixedCIDR != "" {
+		_, subnet, err := net.ParseCIDR(fixedCIDR)
+		if err != nil {
+			return job.Error(err)
+		}
+		log.Debugf("Subnet: %v", subnet)
+		if err := ipallocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil {
+			return job.Error(err)
+		}
+	}
+
+	if fixedCIDRv6 != "" {
+		_, subnet, err := net.ParseCIDR(fixedCIDRv6)
+		if err != nil {
+			return job.Error(err)
+		}
+		log.Debugf("Subnet: %v", subnet)
+		if err := ipallocator.RegisterSubnet(subnet, subnet); err != nil {
+			return job.Error(err)
+		}
+		globalIPv6Network = subnet
+	}
+
+	// Block BridgeIP in IP allocator
+	ipallocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP)
+
+	// https://github.com/docker/docker/issues/2768
+	job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeIPv4Network.IP)
+
+	for name, f := range map[string]engine.Handler{
+		"allocate_interface": Allocate,
+		"release_interface":  Release,
+		"allocate_port":      AllocatePort,
+		"link":               LinkContainers,
+	} {
+		if err := job.Eng.Register(name, f); err != nil {
+			return job.Error(err)
+		}
+	}
+	return engine.StatusOK
+}
+
+func setupIPTables(addr net.Addr, icc, ipmasq bool) error {
+	// Enable NAT
+
+	if ipmasq {
+		natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-o", bridgeIface, "-j", "MASQUERADE"}
+
+		if !iptables.Exists(natArgs...) {
+			if output, err := iptables.Raw(append([]string{"-I"}, natArgs...)...); err != nil {
+				return fmt.Errorf("Unable to enable network bridge NAT: %s", err)
+			} else if len(output) != 0 {
+				return &iptables.ChainError{Chain: "POSTROUTING", Output: output}
+			}
+		}
+	}
+
+	var (
+		args       = []string{"FORWARD", "-i", bridgeIface, "-o", bridgeIface, "-j"}
+		acceptArgs = append(args, "ACCEPT")
+		dropArgs   = append(args, "DROP")
+	)
+
+	if !icc {
+		iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
+
+		if !iptables.Exists(dropArgs...) {
+			log.Debugf("Disable inter-container communication")
+			if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
+				return fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
+			} else if len(output) != 0 {
+				return fmt.Errorf("Error disabling intercontainer communication: %s", output)
+			}
+		}
+	} else {
+		iptables.Raw(append([]string{"-D"}, dropArgs...)...)
+
+		if !iptables.Exists(acceptArgs...) {
+			log.Debugf("Enable inter-container communication")
+			if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
+				return fmt.Errorf("Unable to allow intercontainer communication: %s", err)
+			} else if len(output) != 0 {
+				return fmt.Errorf("Error enabling intercontainer communication: %s", output)
+			}
+		}
+	}
+
+	// Accept all non-intercontainer outgoing packets
+	outgoingArgs := []string{"FORWARD", "-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}
+	if !iptables.Exists(outgoingArgs...) {
+		if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
+			return fmt.Errorf("Unable to allow outgoing packets: %s", err)
+		} else if len(output) != 0 {
+			return &iptables.ChainError{Chain: "FORWARD outgoing", Output: output}
+		}
+	}
+
+	// Accept incoming packets for existing connections
+	existingArgs := []string{"FORWARD", "-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
+
+	if !iptables.Exists(existingArgs...) {
+		if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
+			return fmt.Errorf("Unable to allow incoming packets: %s", err)
+		} else if len(output) != 0 {
+			return &iptables.ChainError{Chain: "FORWARD incoming", Output: output}
+		}
+	}
+	return nil
+}
+
+// configureBridge attempts to create and configure a network bridge interface named `bridgeIface` on the host
+// If bridgeIP is empty, it will try to find a non-conflicting IP from the Docker-specified private ranges
+// If the bridge `bridgeIface` already exists, it will only perform the IP address association with the existing
+// bridge (fixes issue #8444)
+// If an address which doesn't conflict with existing interfaces can't be found, an error is returned.
+func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error {
+	nameservers := []string{}
+	resolvConf, _ := resolvconf.Get()
+	// we don't check for an error here, because we don't really care
+	// if we can't read /etc/resolv.conf. So instead we skip the append
+	// if resolvConf is nil. It either doesn't exist, or we can't read it
+	// for some reason.
+	if resolvConf != nil {
+		nameservers = append(nameservers, resolvconf.GetNameserversAsCIDR(resolvConf)...)
+	}
+
+	var ifaceAddr string
+	if len(bridgeIP) != 0 {
+		_, _, err := net.ParseCIDR(bridgeIP)
+		if err != nil {
+			return err
+		}
+		ifaceAddr = bridgeIP
+	} else {
+		for _, addr := range addrs {
+			_, dockerNetwork, err := net.ParseCIDR(addr)
+			if err != nil {
+				return err
+			}
+			if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil {
+				if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil {
+					ifaceAddr = addr
+					break
+				} else {
+					log.Debugf("%s %s", addr, err)
+				}
+			}
+		}
+	}
+
+	if ifaceAddr == "" {
+		return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", bridgeIface, bridgeIface)
+	}
+	log.Debugf("Creating bridge %s with network %s", bridgeIface, ifaceAddr)
+
+	if err := createBridgeIface(bridgeIface); err != nil {
+		// the bridge may already exist, therefore we can ignore an "exists" error
+		if !os.IsExist(err) {
+			return err
+		}
+	}
+
+	iface, err := net.InterfaceByName(bridgeIface)
+	if err != nil {
+		return err
+	}
+
+	ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr)
+	if err != nil {
+		return err
+	}
+
+	if err := netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
+		return fmt.Errorf("Unable to add private network: %s", err)
+	}
+
+	if enableIPv6 {
+		if err := setupIPv6Bridge(bridgeIPv6); err != nil {
+			return err
+		}
+	}
+
+	if err := netlink.NetworkLinkUp(iface); err != nil {
+		return fmt.Errorf("Unable to start network bridge: %s", err)
+	}
+	return nil
+}
+
+func setupIPv6Bridge(bridgeIPv6 string) error {
+
+	iface, err := net.InterfaceByName(bridgeIface)
+	if err != nil {
+		return err
+	}
+	// Enable IPv6 on the bridge
+	procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6"
+	if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
+		return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
+	}
+
+	ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6)
+	if err != nil {
+		return fmt.Errorf("Unable to parse bridge IPv6 address: %q, error: %v", bridgeIPv6, err)
+	}
+
+	if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil {
+		return fmt.Errorf("Unable to add private IPv6 network: %v", err)
+	}
+
+	return nil
+}
+
+func createBridgeIface(name string) error {
+	kv, err := kernel.GetKernelVersion()
+	// only set the bridge's mac address if the kernel version is > 3.3
+	// before that it was not supported
+	setBridgeMacAddr := err == nil && (kv.Kernel >= 3 && kv.Major >= 3)
+	log.Debugf("setting bridge mac address = %v", setBridgeMacAddr)
+	return netlink.CreateBridge(name, setBridgeMacAddr)
+}
+
+// Generate a IEEE802 compliant MAC address from the given IP address.
+//
+// The generator is guaranteed to be consistent: the same IP will always yield the same
+// MAC address. This is to avoid ARP cache issues.
+func generateMacAddr(ip net.IP) net.HardwareAddr {
+	hw := make(net.HardwareAddr, 6)
+
+	// The first byte of the MAC address has to comply with these rules:
+	// 1. Unicast: Set the least-significant bit to 0.
+	// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
+	// 3. As "small" as possible: The veth address has to be "smaller" than the bridge address.
+	hw[0] = 0x02
+
+	// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
+	// Since this address is locally administered, we can do whatever we want as long as
+	// it doesn't conflict with other addresses.
+	hw[1] = 0x42
+
+	// Insert the IP address into the last 32 bits of the MAC address.
+	// This is a simple way to guarantee the address will be consistent and unique.
+	copy(hw[2:], ip.To4())
+
+	return hw
+}
+
+func linkLocalIPv6FromMac(mac string) (string, error) {
+	hx := strings.Replace(mac, ":", "", -1)
+	hw, err := hex.DecodeString(hx)
+	if err != nil {
+		return "", errors.New("Could not parse MAC address " + mac)
+	}
+
+	hw[0] ^= 0x2
+
+	return fmt.Sprintf("fe80::%x%x:%xff:fe%x:%x%x/64", hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]), nil
+}
+
+// Allocate a network interface
+func Allocate(job *engine.Job) engine.Status {
+	var (
+		ip            net.IP
+		mac           net.HardwareAddr
+		err           error
+		id            = job.Args[0]
+		requestedIP   = net.ParseIP(job.Getenv("RequestedIP"))
+		requestedIPv6 = net.ParseIP(job.Getenv("RequestedIPv6"))
+		globalIPv6    net.IP
+	)
+
+	if requestedIP != nil {
+		ip, err = ipallocator.RequestIP(bridgeIPv4Network, requestedIP)
+	} else {
+		ip, err = ipallocator.RequestIP(bridgeIPv4Network, nil)
+	}
+	if err != nil {
+		return job.Error(err)
+	}
+
+	// If no explicit mac address was given, generate a random one.
+	if mac, err = net.ParseMAC(job.Getenv("RequestedMac")); err != nil {
+		mac = generateMacAddr(ip)
+	}
+
+	if globalIPv6Network != nil {
+		// if globalIPv6Network Size is at least a /80 subnet generate IPv6 address from MAC address
+		netmask_ones, _ := globalIPv6Network.Mask.Size()
+		if requestedIPv6 == nil && netmask_ones <= 80 {
+			requestedIPv6 = globalIPv6Network.IP
+			for i, h := range mac {
+				requestedIPv6[i+10] = h
+			}
+		}
+
+		globalIPv6, err = ipallocator.RequestIP(globalIPv6Network, requestedIPv6)
+		if err != nil {
+			log.Errorf("Allocator: RequestIP v6: %s", err.Error())
+			return job.Error(err)
+		}
+		log.Infof("Allocated IPv6 %s", globalIPv6)
+	}
+
+	out := engine.Env{}
+	out.Set("IP", ip.String())
+	out.Set("Mask", bridgeIPv4Network.Mask.String())
+	out.Set("Gateway", bridgeIPv4Network.IP.String())
+	out.Set("MacAddress", mac.String())
+	out.Set("Bridge", bridgeIface)
+
+	size, _ := bridgeIPv4Network.Mask.Size()
+	out.SetInt("IPPrefixLen", size)
+
+	// if linklocal IPv6
+	localIPv6Net, err := linkLocalIPv6FromMac(mac.String())
+	if err != nil {
+		return job.Error(err)
+	}
+	localIPv6, _, _ := net.ParseCIDR(localIPv6Net)
+	out.Set("LinkLocalIPv6", localIPv6.String())
+	out.Set("MacAddress", mac.String())
+
+	if globalIPv6Network != nil {
+		out.Set("GlobalIPv6", globalIPv6.String())
+		sizev6, _ := globalIPv6Network.Mask.Size()
+		out.SetInt("GlobalIPv6PrefixLen", sizev6)
+		out.Set("IPv6Gateway", bridgeIPv6Addr.String())
+	}
+
+	currentInterfaces.Set(id, &networkInterface{
+		IP:   ip,
+		IPv6: globalIPv6,
+	})
+
+	out.WriteTo(job.Stdout)
+
+	return engine.StatusOK
+}
+
+// release an interface for a select ip
+func Release(job *engine.Job) engine.Status {
+	var (
+		id                 = job.Args[0]
+		containerInterface = currentInterfaces.Get(id)
+	)
+
+	if containerInterface == nil {
+		return job.Errorf("No network information to release for %s", id)
+	}
+
+	for _, nat := range containerInterface.PortMappings {
+		if err := portmapper.Unmap(nat); err != nil {
+			log.Infof("Unable to unmap port %s: %s", nat, err)
+		}
+	}
+
+	if err := ipallocator.ReleaseIP(bridgeIPv4Network, containerInterface.IP); err != nil {
+		log.Infof("Unable to release IPv4 %s", err)
+	}
+	if globalIPv6Network != nil {
+		if err := ipallocator.ReleaseIP(globalIPv6Network, containerInterface.IPv6); err != nil {
+			log.Infof("Unable to release IPv6 %s", err)
+		}
+	}
+	return engine.StatusOK
+}
+
+// Allocate an external port and map it to the interface
+func AllocatePort(job *engine.Job) engine.Status {
+	var (
+		err error
+
+		ip            = defaultBindingIP
+		id            = job.Args[0]
+		hostIP        = job.Getenv("HostIP")
+		hostPort      = job.GetenvInt("HostPort")
+		containerPort = job.GetenvInt("ContainerPort")
+		proto         = job.Getenv("Proto")
+		network       = currentInterfaces.Get(id)
+	)
+
+	if hostIP != "" {
+		ip = net.ParseIP(hostIP)
+		if ip == nil {
+			return job.Errorf("Bad parameter: invalid host ip %s", hostIP)
+		}
+	}
+
+	// host ip, proto, and host port
+	var container net.Addr
+	switch proto {
+	case "tcp":
+		container = &net.TCPAddr{IP: network.IP, Port: containerPort}
+	case "udp":
+		container = &net.UDPAddr{IP: network.IP, Port: containerPort}
+	default:
+		return job.Errorf("unsupported address type %s", proto)
+	}
+
+	//
+	// Try up to 10 times to get a port that's not already allocated.
+	//
+	// In the event of failure to bind, return the error that portmapper.Map
+	// yields.
+	//
+
+	var host net.Addr
+	for i := 0; i < MaxAllocatedPortAttempts; i++ {
+		if host, err = portmapper.Map(container, ip, hostPort); err == nil {
+			break
+		}
+		// There is no point in immediately retrying to map an explicitly
+		// chosen port.
+		if hostPort != 0 {
+			job.Logf("Failed to allocate and map port %d: %s", hostPort, err)
+			break
+		}
+		job.Logf("Failed to allocate and map port: %s, retry: %d", err, i+1)
+	}
+
+	if err != nil {
+		return job.Error(err)
+	}
+
+	network.PortMappings = append(network.PortMappings, host)
+
+	out := engine.Env{}
+	switch netAddr := host.(type) {
+	case *net.TCPAddr:
+		out.Set("HostIP", netAddr.IP.String())
+		out.SetInt("HostPort", netAddr.Port)
+	case *net.UDPAddr:
+		out.Set("HostIP", netAddr.IP.String())
+		out.SetInt("HostPort", netAddr.Port)
+	}
+	if _, err := out.WriteTo(job.Stdout); err != nil {
+		return job.Error(err)
+	}
+
+	return engine.StatusOK
+}
+
+func LinkContainers(job *engine.Job) engine.Status {
+	var (
+		action       = job.Args[0]
+		nfAction     iptables.Action
+		childIP      = job.Getenv("ChildIP")
+		parentIP     = job.Getenv("ParentIP")
+		ignoreErrors = job.GetenvBool("IgnoreErrors")
+		ports        = job.GetenvList("Ports")
+	)
+
+	switch action {
+	case "-A":
+		nfAction = iptables.Append
+	case "-I":
+		nfAction = iptables.Insert
+	case "-D":
+		nfAction = iptables.Delete
+	default:
+		return job.Errorf("Invalid action '%s' specified", action)
+	}
+
+	ip1 := net.ParseIP(parentIP)
+	if ip1 == nil {
+		return job.Errorf("parent IP '%s' is invalid", parentIP)
+	}
+	ip2 := net.ParseIP(childIP)
+	if ip2 == nil {
+		return job.Errorf("child IP '%s' is invalid", childIP)
+	}
+
+	chain := iptables.Chain{Name: "DOCKER", Bridge: bridgeIface}
+	for _, p := range ports {
+		port := nat.Port(p)
+		if err := chain.Link(nfAction, ip1, ip2, port.Int(), port.Proto()); !ignoreErrors && err != nil {
+			return job.Error(err)
+		}
+	}
+	return engine.StatusOK
+}

+ 161 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver_test.go

@@ -0,0 +1,161 @@
+package bridge
+
+import (
+	"net"
+	"strconv"
+	"testing"
+
+	"github.com/docker/docker/daemon/networkdriver/portmapper"
+	"github.com/docker/docker/engine"
+	"github.com/docker/docker/pkg/iptables"
+)
+
+func init() {
+	// reset the new proxy command for mocking out the userland proxy in tests
+	portmapper.NewProxy = portmapper.NewMockProxyCommand
+}
+
+func findFreePort(t *testing.T) int {
+	l, err := net.Listen("tcp", ":0")
+	if err != nil {
+		t.Fatal("Failed to find a free port")
+	}
+	defer l.Close()
+
+	result, err := net.ResolveTCPAddr("tcp", l.Addr().String())
+	if err != nil {
+		t.Fatal("Failed to resolve address to identify free port")
+	}
+	return result.Port
+}
+
+func newPortAllocationJob(eng *engine.Engine, port int) (job *engine.Job) {
+	strPort := strconv.Itoa(port)
+
+	job = eng.Job("allocate_port", "container_id")
+	job.Setenv("HostIP", "127.0.0.1")
+	job.Setenv("HostPort", strPort)
+	job.Setenv("Proto", "tcp")
+	job.Setenv("ContainerPort", strPort)
+	return
+}
+
+func newPortAllocationJobWithInvalidHostIP(eng *engine.Engine, port int) (job *engine.Job) {
+	strPort := strconv.Itoa(port)
+
+	job = eng.Job("allocate_port", "container_id")
+	job.Setenv("HostIP", "localhost")
+	job.Setenv("HostPort", strPort)
+	job.Setenv("Proto", "tcp")
+	job.Setenv("ContainerPort", strPort)
+	return
+}
+
+func TestAllocatePortDetection(t *testing.T) {
+	eng := engine.New()
+	eng.Logging = false
+
+	freePort := findFreePort(t)
+
+	// Init driver
+	job := eng.Job("initdriver")
+	if res := InitDriver(job); res != engine.StatusOK {
+		t.Fatal("Failed to initialize network driver")
+	}
+
+	// Allocate interface
+	job = eng.Job("allocate_interface", "container_id")
+	if res := Allocate(job); res != engine.StatusOK {
+		t.Fatal("Failed to allocate network interface")
+	}
+
+	// Allocate same port twice, expect failure on second call
+	job = newPortAllocationJob(eng, freePort)
+	if res := AllocatePort(job); res != engine.StatusOK {
+		t.Fatal("Failed to find a free port to allocate")
+	}
+	if res := AllocatePort(job); res == engine.StatusOK {
+		t.Fatal("Duplicate port allocation granted by AllocatePort")
+	}
+}
+
+func TestHostnameFormatChecking(t *testing.T) {
+	eng := engine.New()
+	eng.Logging = false
+
+	freePort := findFreePort(t)
+
+	// Init driver
+	job := eng.Job("initdriver")
+	if res := InitDriver(job); res != engine.StatusOK {
+		t.Fatal("Failed to initialize network driver")
+	}
+
+	// Allocate interface
+	job = eng.Job("allocate_interface", "container_id")
+	if res := Allocate(job); res != engine.StatusOK {
+		t.Fatal("Failed to allocate network interface")
+	}
+
+	// Allocate port with invalid HostIP, expect failure with Bad Request http status
+	job = newPortAllocationJobWithInvalidHostIP(eng, freePort)
+	if res := AllocatePort(job); res == engine.StatusOK {
+		t.Fatal("Failed to check invalid HostIP")
+	}
+}
+
+func TestMacAddrGeneration(t *testing.T) {
+	ip := net.ParseIP("192.168.0.1")
+	mac := generateMacAddr(ip).String()
+
+	// Should be consistent.
+	if generateMacAddr(ip).String() != mac {
+		t.Fatal("Inconsistent MAC address")
+	}
+
+	// Should be unique.
+	ip2 := net.ParseIP("192.168.0.2")
+	if generateMacAddr(ip2).String() == mac {
+		t.Fatal("Non-unique MAC address")
+	}
+}
+
+func TestLinkContainers(t *testing.T) {
+	eng := engine.New()
+	eng.Logging = false
+
+	// Init driver
+	job := eng.Job("initdriver")
+	if res := InitDriver(job); res != engine.StatusOK {
+		t.Fatal("Failed to initialize network driver")
+	}
+
+	// Allocate interface
+	job = eng.Job("allocate_interface", "container_id")
+	if res := Allocate(job); res != engine.StatusOK {
+		t.Fatal("Failed to allocate network interface")
+	}
+
+	job.Args[0] = "-I"
+
+	job.Setenv("ChildIP", "172.17.0.2")
+	job.Setenv("ParentIP", "172.17.0.1")
+	job.SetenvBool("IgnoreErrors", false)
+	job.SetenvList("Ports", []string{"1234"})
+
+	bridgeIface = "lo"
+	_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if res := LinkContainers(job); res != engine.StatusOK {
+		t.Fatalf("LinkContainers failed")
+	}
+
+	// flush rules
+	if _, err = iptables.Raw([]string{"-F", "DOCKER"}...); err != nil {
+		t.Fatal(err)
+	}
+
+}

+ 160 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator.go

@@ -0,0 +1,160 @@
+package ipallocator
+
+import (
+	"errors"
+	"math/big"
+	"net"
+	"sync"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/docker/daemon/networkdriver"
+)
+
+// allocatedMap is thread-unsafe set of allocated IP
+type allocatedMap struct {
+	p     map[string]struct{}
+	last  *big.Int
+	begin *big.Int
+	end   *big.Int
+}
+
+func newAllocatedMap(network *net.IPNet) *allocatedMap {
+	firstIP, lastIP := networkdriver.NetworkRange(network)
+	begin := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
+	end := big.NewInt(0).Sub(ipToBigInt(lastIP), big.NewInt(1))
+
+	return &allocatedMap{
+		p:     make(map[string]struct{}),
+		begin: begin,
+		end:   end,
+		last:  big.NewInt(0).Sub(begin, big.NewInt(1)), // so first allocated will be begin
+	}
+}
+
+type networkSet map[string]*allocatedMap
+
+var (
+	ErrNoAvailableIPs           = errors.New("no available ip addresses on network")
+	ErrIPAlreadyAllocated       = errors.New("ip already allocated")
+	ErrIPOutOfRange             = errors.New("requested ip is out of range")
+	ErrNetworkAlreadyRegistered = errors.New("network already registered")
+	ErrBadSubnet                = errors.New("network does not contain specified subnet")
+)
+
+var (
+	lock         = sync.Mutex{}
+	allocatedIPs = networkSet{}
+)
+
+// RegisterSubnet registers network in global allocator with bounds
+// defined by subnet. If you want to use network range you must call
+// this method before first RequestIP, otherwise full network range will be used
+func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
+	lock.Lock()
+	defer lock.Unlock()
+	key := network.String()
+	if _, ok := allocatedIPs[key]; ok {
+		return ErrNetworkAlreadyRegistered
+	}
+	n := newAllocatedMap(network)
+	beginIP, endIP := networkdriver.NetworkRange(subnet)
+	begin := big.NewInt(0).Add(ipToBigInt(beginIP), big.NewInt(1))
+	end := big.NewInt(0).Sub(ipToBigInt(endIP), big.NewInt(1))
+
+	// Check that subnet is within network
+	if !(begin.Cmp(n.begin) >= 0 && end.Cmp(n.end) <= 0 && begin.Cmp(end) == -1) {
+		return ErrBadSubnet
+	}
+	n.begin.Set(begin)
+	n.end.Set(end)
+	n.last.Sub(begin, big.NewInt(1))
+	allocatedIPs[key] = n
+	return nil
+}
+
+// RequestIP requests an available ip from the given network.  It
+// will return the next available ip if the ip provided is nil.  If the
+// ip provided is not nil it will validate that the provided ip is available
+// for use or return an error
+func RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
+	lock.Lock()
+	defer lock.Unlock()
+	key := network.String()
+	allocated, ok := allocatedIPs[key]
+	if !ok {
+		allocated = newAllocatedMap(network)
+		allocatedIPs[key] = allocated
+	}
+
+	if ip == nil {
+		return allocated.getNextIP()
+	}
+	return allocated.checkIP(ip)
+}
+
+// ReleaseIP adds the provided ip back into the pool of
+// available ips to be returned for use.
+func ReleaseIP(network *net.IPNet, ip net.IP) error {
+	lock.Lock()
+	defer lock.Unlock()
+	if allocated, exists := allocatedIPs[network.String()]; exists {
+		delete(allocated.p, ip.String())
+	}
+	return nil
+}
+
+func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
+	if _, ok := allocated.p[ip.String()]; ok {
+		return nil, ErrIPAlreadyAllocated
+	}
+
+	pos := ipToBigInt(ip)
+	// Verify that the IP address is within our network range.
+	if pos.Cmp(allocated.begin) == -1 || pos.Cmp(allocated.end) == 1 {
+		return nil, ErrIPOutOfRange
+	}
+
+	// Register the IP.
+	allocated.p[ip.String()] = struct{}{}
+
+	return ip, nil
+}
+
+// return an available ip if one is currently available.  If not,
+// return the next available ip for the nextwork
+func (allocated *allocatedMap) getNextIP() (net.IP, error) {
+	pos := big.NewInt(0).Set(allocated.last)
+	allRange := big.NewInt(0).Sub(allocated.end, allocated.begin)
+	for i := big.NewInt(0); i.Cmp(allRange) <= 0; i.Add(i, big.NewInt(1)) {
+		pos.Add(pos, big.NewInt(1))
+		if pos.Cmp(allocated.end) == 1 {
+			pos.Set(allocated.begin)
+		}
+		if _, ok := allocated.p[bigIntToIP(pos).String()]; ok {
+			continue
+		}
+		allocated.p[bigIntToIP(pos).String()] = struct{}{}
+		allocated.last.Set(pos)
+		return bigIntToIP(pos), nil
+	}
+	return nil, ErrNoAvailableIPs
+}
+
+// Converts a 4 bytes IP into a 128 bit integer
+func ipToBigInt(ip net.IP) *big.Int {
+	x := big.NewInt(0)
+	if ip4 := ip.To4(); ip4 != nil {
+		return x.SetBytes(ip4)
+	}
+	if ip6 := ip.To16(); ip6 != nil {
+		return x.SetBytes(ip6)
+	}
+
+	log.Errorf("ipToBigInt: Wrong IP length! %s", ip)
+	return nil
+}
+
+// Converts 128 bit integer into a 4 bytes IP address
+func bigIntToIP(v *big.Int) net.IP {
+	return net.IP(v.Bytes())
+}

+ 681 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator_test.go

@@ -0,0 +1,681 @@
+package ipallocator
+
+import (
+	"fmt"
+	"math/big"
+	"net"
+	"testing"
+)
+
+func reset() {
+	allocatedIPs = networkSet{}
+}
+
+func TestConversion(t *testing.T) {
+	ip := net.ParseIP("127.0.0.1")
+	i := ipToBigInt(ip)
+	if i.Cmp(big.NewInt(0x7f000001)) != 0 {
+		t.Fatal("incorrect conversion")
+	}
+	conv := bigIntToIP(i)
+	if !ip.Equal(conv) {
+		t.Error(conv.String())
+	}
+}
+
+func TestConversionIPv6(t *testing.T) {
+	ip := net.ParseIP("2a00:1450::1")
+	ip2 := net.ParseIP("2a00:1450::2")
+	ip3 := net.ParseIP("2a00:1450::1:1")
+	i := ipToBigInt(ip)
+	val, success := big.NewInt(0).SetString("2a001450000000000000000000000001", 16)
+	if !success {
+		t.Fatal("Hex-String to BigInt conversion failed.")
+	}
+	if i.Cmp(val) != 0 {
+		t.Fatal("incorrent conversion")
+	}
+
+	conv := bigIntToIP(i)
+	conv2 := bigIntToIP(big.NewInt(0).Add(i, big.NewInt(1)))
+	conv3 := bigIntToIP(big.NewInt(0).Add(i, big.NewInt(0x10000)))
+
+	if !ip.Equal(conv) {
+		t.Error("2a00:1450::1 should be equal to " + conv.String())
+	}
+	if !ip2.Equal(conv2) {
+		t.Error("2a00:1450::2 should be equal to " + conv2.String())
+	}
+	if !ip3.Equal(conv3) {
+		t.Error("2a00:1450::1:1 should be equal to " + conv3.String())
+	}
+}
+
+func TestRequestNewIps(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+
+	var ip net.IP
+	var err error
+
+	for i := 1; i < 10; i++ {
+		ip, err = RequestIP(network, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if expected := fmt.Sprintf("192.168.0.%d", i); ip.String() != expected {
+			t.Fatalf("Expected ip %s got %s", expected, ip.String())
+		}
+	}
+	value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
+	if err := ReleaseIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+	ip, err = RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if ip.String() != value {
+		t.Fatalf("Expected to receive the next ip %s got %s", value, ip.String())
+	}
+}
+
+func TestRequestNewIpV6(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
+	}
+
+	var ip net.IP
+	var err error
+	for i := 1; i < 10; i++ {
+		ip, err = RequestIP(network, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if expected := fmt.Sprintf("2a00:1450::%d", i); ip.String() != expected {
+			t.Fatalf("Expected ip %s got %s", expected, ip.String())
+		}
+	}
+	value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
+	if err := ReleaseIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+	ip, err = RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if ip.String() != value {
+		t.Fatalf("Expected to receive the next ip %s got %s", value, ip.String())
+	}
+}
+
+func TestReleaseIp(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+
+	ip, err := RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := ReleaseIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestReleaseIpV6(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
+	}
+
+	ip, err := RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := ReleaseIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestGetReleasedIp(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+
+	ip, err := RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	value := ip.String()
+	if err := ReleaseIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+
+	for i := 0; i < 253; i++ {
+		_, err = RequestIP(network, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		err = ReleaseIP(network, ip)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	ip, err = RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if ip.String() != value {
+		t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
+	}
+}
+
+func TestGetReleasedIpV6(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0},
+	}
+
+	ip, err := RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	value := ip.String()
+	if err := ReleaseIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+
+	for i := 0; i < 253; i++ {
+		_, err = RequestIP(network, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		err = ReleaseIP(network, ip)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	ip, err = RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if ip.String() != value {
+		t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
+	}
+}
+
+func TestRequestSpecificIp(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 224},
+	}
+
+	ip := net.ParseIP("192.168.0.5")
+
+	// Request a "good" IP.
+	if _, err := RequestIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+
+	// Request the same IP again.
+	if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated {
+		t.Fatalf("Got the same IP twice: %#v", err)
+	}
+
+	// Request an out of range IP.
+	if _, err := RequestIP(network, net.ParseIP("192.168.0.42")); err != ErrIPOutOfRange {
+		t.Fatalf("Got an out of range IP: %#v", err)
+	}
+}
+
+func TestRequestSpecificIpV6(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
+	}
+
+	ip := net.ParseIP("2a00:1450::5")
+
+	// Request a "good" IP.
+	if _, err := RequestIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+
+	// Request the same IP again.
+	if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated {
+		t.Fatalf("Got the same IP twice: %#v", err)
+	}
+
+	// Request an out of range IP.
+	if _, err := RequestIP(network, net.ParseIP("2a00:1500::1")); err != ErrIPOutOfRange {
+		t.Fatalf("Got an out of range IP: %#v", err)
+	}
+}
+
+func TestIPAllocator(t *testing.T) {
+	expectedIPs := []net.IP{
+		0: net.IPv4(127, 0, 0, 1),
+		1: net.IPv4(127, 0, 0, 2),
+		2: net.IPv4(127, 0, 0, 3),
+		3: net.IPv4(127, 0, 0, 4),
+		4: net.IPv4(127, 0, 0, 5),
+		5: net.IPv4(127, 0, 0, 6),
+	}
+
+	gwIP, n, _ := net.ParseCIDR("127.0.0.1/29")
+
+	network := &net.IPNet{IP: gwIP, Mask: n.Mask}
+	// Pool after initialisation (f = free, u = used)
+	// 1(f) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
+	//  ↑
+
+	// Check that we get 6 IPs, from 127.0.0.1–127.0.0.6, in that
+	// order.
+	for i := 0; i < 6; i++ {
+		ip, err := RequestIP(network, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		assertIPEquals(t, expectedIPs[i], ip)
+	}
+	// Before loop begin
+	// 1(f) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
+	//  ↑
+
+	// After i = 0
+	// 1(u) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
+	//         ↑
+
+	// After i = 1
+	// 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(f)
+	//                ↑
+
+	// After i = 2
+	// 1(u) - 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
+	//                       ↑
+
+	// After i = 3
+	// 1(u) - 2(u) - 3(u) - 4(u) - 5(f) - 6(f)
+	//                              ↑
+
+	// After i = 4
+	// 1(u) - 2(u) - 3(u) - 4(u) - 5(u) - 6(f)
+	//                                     ↑
+
+	// After i = 5
+	// 1(u) - 2(u) - 3(u) - 4(u) - 5(u) - 6(u)
+	//  ↑
+
+	// Check that there are no more IPs
+	ip, err := RequestIP(network, nil)
+	if err == nil {
+		t.Fatalf("There shouldn't be any IP addresses at this point, got %s\n", ip)
+	}
+
+	// Release some IPs in non-sequential order
+	if err := ReleaseIP(network, expectedIPs[3]); err != nil {
+		t.Fatal(err)
+	}
+	// 1(u) - 2(u) - 3(u) - 4(f) - 5(u) - 6(u)
+	//                       ↑
+
+	if err := ReleaseIP(network, expectedIPs[2]); err != nil {
+		t.Fatal(err)
+	}
+	// 1(u) - 2(u) - 3(f) - 4(f) - 5(u) - 6(u)
+	//                ↑
+
+	if err := ReleaseIP(network, expectedIPs[4]); err != nil {
+		t.Fatal(err)
+	}
+	// 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(u)
+	//                              ↑
+
+	// Make sure that IPs are reused in sequential order, starting
+	// with the first released IP
+	newIPs := make([]net.IP, 3)
+	for i := 0; i < 3; i++ {
+		ip, err := RequestIP(network, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		newIPs[i] = ip
+	}
+	assertIPEquals(t, expectedIPs[2], newIPs[0])
+	assertIPEquals(t, expectedIPs[3], newIPs[1])
+	assertIPEquals(t, expectedIPs[4], newIPs[2])
+
+	_, err = RequestIP(network, nil)
+	if err == nil {
+		t.Fatal("There shouldn't be any IP addresses at this point")
+	}
+}
+
+func TestAllocateFirstIP(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 0},
+		Mask: []byte{255, 255, 255, 0},
+	}
+
+	firstIP := network.IP.To4().Mask(network.Mask)
+	first := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
+
+	ip, err := RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	allocated := ipToBigInt(ip)
+
+	if allocated == first {
+		t.Fatalf("allocated ip should not equal first ip: %d == %d", first, allocated)
+	}
+}
+
+func TestAllocateAllIps(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+
+	var (
+		current, first net.IP
+		err            error
+		isFirst        = true
+	)
+
+	for err == nil {
+		current, err = RequestIP(network, nil)
+		if isFirst {
+			first = current
+			isFirst = false
+		}
+	}
+
+	if err != ErrNoAvailableIPs {
+		t.Fatal(err)
+	}
+
+	if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
+		t.Fatal(err)
+	}
+
+	if err := ReleaseIP(network, first); err != nil {
+		t.Fatal(err)
+	}
+
+	again, err := RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assertIPEquals(t, first, again)
+
+	// ensure that alloc.last == alloc.begin won't result in dead loop
+	if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
+		t.Fatal(err)
+	}
+
+	// Test by making alloc.last the only free ip and ensure we get it back
+	// #1. first of the range, (alloc.last == ipToInt(first) already)
+	if err := ReleaseIP(network, first); err != nil {
+		t.Fatal(err)
+	}
+
+	ret, err := RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assertIPEquals(t, first, ret)
+
+	// #2. last of the range, note that current is the last one
+	last := net.IPv4(192, 168, 0, 254)
+	setLastTo(t, network, last)
+
+	ret, err = RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assertIPEquals(t, last, ret)
+
+	// #3. middle of the range
+	mid := net.IPv4(192, 168, 0, 7)
+	setLastTo(t, network, mid)
+
+	ret, err = RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assertIPEquals(t, mid, ret)
+}
+
+// make sure the pool is full when calling setLastTo.
+// we don't cheat here
+func setLastTo(t *testing.T, network *net.IPNet, ip net.IP) {
+	if err := ReleaseIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+
+	ret, err := RequestIP(network, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assertIPEquals(t, ip, ret)
+
+	if err := ReleaseIP(network, ip); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestAllocateDifferentSubnets(t *testing.T) {
+	defer reset()
+	network1 := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+	network2 := &net.IPNet{
+		IP:   []byte{127, 0, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+	network3 := &net.IPNet{
+		IP:   []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
+	}
+	network4 := &net.IPNet{
+		IP:   []byte{0x2a, 0x00, 0x16, 0x32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+		Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
+	}
+	expectedIPs := []net.IP{
+		0: net.IPv4(192, 168, 0, 1),
+		1: net.IPv4(192, 168, 0, 2),
+		2: net.IPv4(127, 0, 0, 1),
+		3: net.IPv4(127, 0, 0, 2),
+		4: net.ParseIP("2a00:1450::1"),
+		5: net.ParseIP("2a00:1450::2"),
+		6: net.ParseIP("2a00:1450::3"),
+		7: net.ParseIP("2a00:1632::1"),
+		8: net.ParseIP("2a00:1632::2"),
+	}
+
+	ip11, err := RequestIP(network1, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ip12, err := RequestIP(network1, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ip21, err := RequestIP(network2, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ip22, err := RequestIP(network2, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ip31, err := RequestIP(network3, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ip32, err := RequestIP(network3, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ip33, err := RequestIP(network3, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ip41, err := RequestIP(network4, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ip42, err := RequestIP(network4, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	assertIPEquals(t, expectedIPs[0], ip11)
+	assertIPEquals(t, expectedIPs[1], ip12)
+	assertIPEquals(t, expectedIPs[2], ip21)
+	assertIPEquals(t, expectedIPs[3], ip22)
+	assertIPEquals(t, expectedIPs[4], ip31)
+	assertIPEquals(t, expectedIPs[5], ip32)
+	assertIPEquals(t, expectedIPs[6], ip33)
+	assertIPEquals(t, expectedIPs[7], ip41)
+	assertIPEquals(t, expectedIPs[8], ip42)
+}
+
+func TestRegisterBadTwice(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 1, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+	subnet := &net.IPNet{
+		IP:   []byte{192, 168, 1, 8},
+		Mask: []byte{255, 255, 255, 248},
+	}
+
+	if err := RegisterSubnet(network, subnet); err != nil {
+		t.Fatal(err)
+	}
+	subnet = &net.IPNet{
+		IP:   []byte{192, 168, 1, 16},
+		Mask: []byte{255, 255, 255, 248},
+	}
+	if err := RegisterSubnet(network, subnet); err != ErrNetworkAlreadyRegistered {
+		t.Fatalf("Expecteded ErrNetworkAlreadyRegistered error, got %v", err)
+	}
+}
+
+func TestRegisterBadRange(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 1, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+	subnet := &net.IPNet{
+		IP:   []byte{192, 168, 1, 1},
+		Mask: []byte{255, 255, 0, 0},
+	}
+	if err := RegisterSubnet(network, subnet); err != ErrBadSubnet {
+		t.Fatalf("Expected ErrBadSubnet error, got %v", err)
+	}
+}
+
+func TestAllocateFromRange(t *testing.T) {
+	defer reset()
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+	// 192.168.1.9 - 192.168.1.14
+	subnet := &net.IPNet{
+		IP:   []byte{192, 168, 0, 8},
+		Mask: []byte{255, 255, 255, 248},
+	}
+
+	if err := RegisterSubnet(network, subnet); err != nil {
+		t.Fatal(err)
+	}
+	expectedIPs := []net.IP{
+		0: net.IPv4(192, 168, 0, 9),
+		1: net.IPv4(192, 168, 0, 10),
+		2: net.IPv4(192, 168, 0, 11),
+		3: net.IPv4(192, 168, 0, 12),
+		4: net.IPv4(192, 168, 0, 13),
+		5: net.IPv4(192, 168, 0, 14),
+	}
+	for _, ip := range expectedIPs {
+		rip, err := RequestIP(network, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		assertIPEquals(t, ip, rip)
+	}
+
+	if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
+		t.Fatalf("Expected ErrNoAvailableIPs error, got %v", err)
+	}
+	for _, ip := range expectedIPs {
+		ReleaseIP(network, ip)
+		rip, err := RequestIP(network, nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		assertIPEquals(t, ip, rip)
+	}
+}
+
+func assertIPEquals(t *testing.T, ip1, ip2 net.IP) {
+	if !ip1.Equal(ip2) {
+		t.Fatalf("Expected IP %s, got %s", ip1, ip2)
+	}
+}
+
+func BenchmarkRequestIP(b *testing.B) {
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		for j := 0; j < 253; j++ {
+			_, err := RequestIP(network, nil)
+			if err != nil {
+				b.Fatal(err)
+			}
+		}
+		reset()
+	}
+}

+ 10 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network.go

@@ -0,0 +1,10 @@
+package networkdriver
+
+import (
+	"errors"
+)
+
+var (
+	ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")
+	ErrNetworkOverlaps                = errors.New("requested network overlaps with existing network")
+)

+ 175 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network_test.go

@@ -0,0 +1,175 @@
+package networkdriver
+
+import (
+	"github.com/docker/libcontainer/netlink"
+	"net"
+	"testing"
+)
+
+func TestNonOverlapingNameservers(t *testing.T) {
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+	nameservers := []string{
+		"127.0.0.1/32",
+	}
+
+	if err := CheckNameserverOverlaps(nameservers, network); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestOverlapingNameservers(t *testing.T) {
+	network := &net.IPNet{
+		IP:   []byte{192, 168, 0, 1},
+		Mask: []byte{255, 255, 255, 0},
+	}
+	nameservers := []string{
+		"192.168.0.1/32",
+	}
+
+	if err := CheckNameserverOverlaps(nameservers, network); err == nil {
+		t.Fatalf("Expected error %s got %s", ErrNetworkOverlapsWithNameservers, err)
+	}
+}
+
+func TestCheckRouteOverlaps(t *testing.T) {
+	orig := networkGetRoutesFct
+	defer func() {
+		networkGetRoutesFct = orig
+	}()
+	networkGetRoutesFct = func() ([]netlink.Route, error) {
+		routesData := []string{"10.0.2.0/32", "10.0.3.0/24", "10.0.42.0/24", "172.16.42.0/24", "192.168.142.0/24"}
+
+		routes := []netlink.Route{}
+		for _, addr := range routesData {
+			_, netX, _ := net.ParseCIDR(addr)
+			routes = append(routes, netlink.Route{IPNet: netX})
+		}
+		return routes, nil
+	}
+
+	_, netX, _ := net.ParseCIDR("172.16.0.1/24")
+	if err := CheckRouteOverlaps(netX); err != nil {
+		t.Fatal(err)
+	}
+
+	_, netX, _ = net.ParseCIDR("10.0.2.0/24")
+	if err := CheckRouteOverlaps(netX); err == nil {
+		t.Fatalf("10.0.2.0/24 and 10.0.2.0 should overlap but it doesn't")
+	}
+}
+
+func TestCheckNameserverOverlaps(t *testing.T) {
+	nameservers := []string{"10.0.2.3/32", "192.168.102.1/32"}
+
+	_, netX, _ := net.ParseCIDR("10.0.2.3/32")
+
+	if err := CheckNameserverOverlaps(nameservers, netX); err == nil {
+		t.Fatalf("%s should overlap 10.0.2.3/32 but doesn't", netX)
+	}
+
+	_, netX, _ = net.ParseCIDR("192.168.102.2/32")
+
+	if err := CheckNameserverOverlaps(nameservers, netX); err != nil {
+		t.Fatalf("%s should not overlap %v but it does", netX, nameservers)
+	}
+}
+
+func AssertOverlap(CIDRx string, CIDRy string, t *testing.T) {
+	_, netX, _ := net.ParseCIDR(CIDRx)
+	_, netY, _ := net.ParseCIDR(CIDRy)
+	if !NetworkOverlaps(netX, netY) {
+		t.Errorf("%v and %v should overlap", netX, netY)
+	}
+}
+
+func AssertNoOverlap(CIDRx string, CIDRy string, t *testing.T) {
+	_, netX, _ := net.ParseCIDR(CIDRx)
+	_, netY, _ := net.ParseCIDR(CIDRy)
+	if NetworkOverlaps(netX, netY) {
+		t.Errorf("%v and %v should not overlap", netX, netY)
+	}
+}
+
+func TestNetworkOverlaps(t *testing.T) {
+	//netY starts at same IP and ends within netX
+	AssertOverlap("172.16.0.1/24", "172.16.0.1/25", t)
+	//netY starts within netX and ends at same IP
+	AssertOverlap("172.16.0.1/24", "172.16.0.128/25", t)
+	//netY starts and ends within netX
+	AssertOverlap("172.16.0.1/24", "172.16.0.64/25", t)
+	//netY starts at same IP and ends outside of netX
+	AssertOverlap("172.16.0.1/24", "172.16.0.1/23", t)
+	//netY starts before and ends at same IP of netX
+	AssertOverlap("172.16.1.1/24", "172.16.0.1/23", t)
+	//netY starts before and ends outside of netX
+	AssertOverlap("172.16.1.1/24", "172.16.0.1/22", t)
+	//netY starts and ends before netX
+	AssertNoOverlap("172.16.1.1/25", "172.16.0.1/24", t)
+	//netX starts and ends before netY
+	AssertNoOverlap("172.16.1.1/25", "172.16.2.1/24", t)
+}
+
+func TestNetworkRange(t *testing.T) {
+	// Simple class C test
+	_, network, _ := net.ParseCIDR("192.168.0.1/24")
+	first, last := NetworkRange(network)
+	if !first.Equal(net.ParseIP("192.168.0.0")) {
+		t.Error(first.String())
+	}
+	if !last.Equal(net.ParseIP("192.168.0.255")) {
+		t.Error(last.String())
+	}
+
+	// Class A test
+	_, network, _ = net.ParseCIDR("10.0.0.1/8")
+	first, last = NetworkRange(network)
+	if !first.Equal(net.ParseIP("10.0.0.0")) {
+		t.Error(first.String())
+	}
+	if !last.Equal(net.ParseIP("10.255.255.255")) {
+		t.Error(last.String())
+	}
+
+	// Class A, random IP address
+	_, network, _ = net.ParseCIDR("10.1.2.3/8")
+	first, last = NetworkRange(network)
+	if !first.Equal(net.ParseIP("10.0.0.0")) {
+		t.Error(first.String())
+	}
+	if !last.Equal(net.ParseIP("10.255.255.255")) {
+		t.Error(last.String())
+	}
+
+	// 32bit mask
+	_, network, _ = net.ParseCIDR("10.1.2.3/32")
+	first, last = NetworkRange(network)
+	if !first.Equal(net.ParseIP("10.1.2.3")) {
+		t.Error(first.String())
+	}
+	if !last.Equal(net.ParseIP("10.1.2.3")) {
+		t.Error(last.String())
+	}
+
+	// 31bit mask
+	_, network, _ = net.ParseCIDR("10.1.2.3/31")
+	first, last = NetworkRange(network)
+	if !first.Equal(net.ParseIP("10.1.2.2")) {
+		t.Error(first.String())
+	}
+	if !last.Equal(net.ParseIP("10.1.2.3")) {
+		t.Error(last.String())
+	}
+
+	// 26bit mask
+	_, network, _ = net.ParseCIDR("10.1.2.3/26")
+	first, last = NetworkRange(network)
+	if !first.Equal(net.ParseIP("10.1.2.0")) {
+		t.Error(first.String())
+	}
+	if !last.Equal(net.ParseIP("10.1.2.63")) {
+		t.Error(last.String())
+	}
+}

+ 153 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator.go

@@ -0,0 +1,153 @@
+package portallocator
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"sync"
+)
+
+type portMap struct {
+	p    map[int]struct{}
+	last int
+}
+
+func newPortMap() *portMap {
+	return &portMap{
+		p:    map[int]struct{}{},
+		last: EndPortRange,
+	}
+}
+
+type protoMap map[string]*portMap
+
+func newProtoMap() protoMap {
+	return protoMap{
+		"tcp": newPortMap(),
+		"udp": newPortMap(),
+	}
+}
+
+type ipMapping map[string]protoMap
+
+const (
+	BeginPortRange = 49153
+	EndPortRange   = 65535
+)
+
+var (
+	ErrAllPortsAllocated = errors.New("all ports are allocated")
+	ErrUnknownProtocol   = errors.New("unknown protocol")
+)
+
+var (
+	mutex sync.Mutex
+
+	defaultIP = net.ParseIP("0.0.0.0")
+	globalMap = ipMapping{}
+)
+
+type ErrPortAlreadyAllocated struct {
+	ip   string
+	port int
+}
+
+func NewErrPortAlreadyAllocated(ip string, port int) ErrPortAlreadyAllocated {
+	return ErrPortAlreadyAllocated{
+		ip:   ip,
+		port: port,
+	}
+}
+
+func (e ErrPortAlreadyAllocated) IP() string {
+	return e.ip
+}
+
+func (e ErrPortAlreadyAllocated) Port() int {
+	return e.port
+}
+
+func (e ErrPortAlreadyAllocated) IPPort() string {
+	return fmt.Sprintf("%s:%d", e.ip, e.port)
+}
+
+func (e ErrPortAlreadyAllocated) Error() string {
+	return fmt.Sprintf("Bind for %s:%d failed: port is already allocated", e.ip, e.port)
+}
+
+// RequestPort requests new port from global ports pool for specified ip and proto.
+// If port is 0 it returns first free port. Otherwise it cheks port availability
+// in pool and return that port or error if port is already busy.
+func RequestPort(ip net.IP, proto string, port int) (int, error) {
+	mutex.Lock()
+	defer mutex.Unlock()
+
+	if proto != "tcp" && proto != "udp" {
+		return 0, ErrUnknownProtocol
+	}
+
+	if ip == nil {
+		ip = defaultIP
+	}
+	ipstr := ip.String()
+	protomap, ok := globalMap[ipstr]
+	if !ok {
+		protomap = newProtoMap()
+		globalMap[ipstr] = protomap
+	}
+	mapping := protomap[proto]
+	if port > 0 {
+		if _, ok := mapping.p[port]; !ok {
+			mapping.p[port] = struct{}{}
+			return port, nil
+		}
+		return 0, NewErrPortAlreadyAllocated(ipstr, port)
+	}
+
+	port, err := mapping.findPort()
+	if err != nil {
+		return 0, err
+	}
+	return port, nil
+}
+
+// ReleasePort releases port from global ports pool for specified ip and proto.
+func ReleasePort(ip net.IP, proto string, port int) error {
+	mutex.Lock()
+	defer mutex.Unlock()
+
+	if ip == nil {
+		ip = defaultIP
+	}
+	protomap, ok := globalMap[ip.String()]
+	if !ok {
+		return nil
+	}
+	delete(protomap[proto].p, port)
+	return nil
+}
+
+// ReleaseAll releases all ports for all ips.
+func ReleaseAll() error {
+	mutex.Lock()
+	globalMap = ipMapping{}
+	mutex.Unlock()
+	return nil
+}
+
+func (pm *portMap) findPort() (int, error) {
+	port := pm.last
+	for i := 0; i <= EndPortRange-BeginPortRange; i++ {
+		port++
+		if port > EndPortRange {
+			port = BeginPortRange
+		}
+
+		if _, ok := pm.p[port]; !ok {
+			pm.p[port] = struct{}{}
+			pm.last = port
+			return port, nil
+		}
+	}
+	return 0, ErrAllPortsAllocated
+}

+ 245 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator_test.go

@@ -0,0 +1,245 @@
+package portallocator
+
+import (
+	"net"
+	"testing"
+)
+
+func reset() {
+	ReleaseAll()
+}
+
+func TestRequestNewPort(t *testing.T) {
+	defer reset()
+
+	port, err := RequestPort(defaultIP, "tcp", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if expected := BeginPortRange; port != expected {
+		t.Fatalf("Expected port %d got %d", expected, port)
+	}
+}
+
+func TestRequestSpecificPort(t *testing.T) {
+	defer reset()
+
+	port, err := RequestPort(defaultIP, "tcp", 5000)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if port != 5000 {
+		t.Fatalf("Expected port 5000 got %d", port)
+	}
+}
+
+func TestReleasePort(t *testing.T) {
+	defer reset()
+
+	port, err := RequestPort(defaultIP, "tcp", 5000)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if port != 5000 {
+		t.Fatalf("Expected port 5000 got %d", port)
+	}
+
+	if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestReuseReleasedPort(t *testing.T) {
+	defer reset()
+
+	port, err := RequestPort(defaultIP, "tcp", 5000)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if port != 5000 {
+		t.Fatalf("Expected port 5000 got %d", port)
+	}
+
+	if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
+		t.Fatal(err)
+	}
+
+	port, err = RequestPort(defaultIP, "tcp", 5000)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestReleaseUnreadledPort(t *testing.T) {
+	defer reset()
+
+	port, err := RequestPort(defaultIP, "tcp", 5000)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if port != 5000 {
+		t.Fatalf("Expected port 5000 got %d", port)
+	}
+
+	port, err = RequestPort(defaultIP, "tcp", 5000)
+
+	switch err.(type) {
+	case ErrPortAlreadyAllocated:
+	default:
+		t.Fatalf("Expected port allocation error got %s", err)
+	}
+}
+
+func TestUnknowProtocol(t *testing.T) {
+	defer reset()
+
+	if _, err := RequestPort(defaultIP, "tcpp", 0); err != ErrUnknownProtocol {
+		t.Fatalf("Expected error %s got %s", ErrUnknownProtocol, err)
+	}
+}
+
+func TestAllocateAllPorts(t *testing.T) {
+	defer reset()
+
+	for i := 0; i <= EndPortRange-BeginPortRange; i++ {
+		port, err := RequestPort(defaultIP, "tcp", 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if expected := BeginPortRange + i; port != expected {
+			t.Fatalf("Expected port %d got %d", expected, port)
+		}
+	}
+
+	if _, err := RequestPort(defaultIP, "tcp", 0); err != ErrAllPortsAllocated {
+		t.Fatalf("Expected error %s got %s", ErrAllPortsAllocated, err)
+	}
+
+	_, err := RequestPort(defaultIP, "udp", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// release a port in the middle and ensure we get another tcp port
+	port := BeginPortRange + 5
+	if err := ReleasePort(defaultIP, "tcp", port); err != nil {
+		t.Fatal(err)
+	}
+	newPort, err := RequestPort(defaultIP, "tcp", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if newPort != port {
+		t.Fatalf("Expected port %d got %d", port, newPort)
+	}
+
+	// now pm.last == newPort, release it so that it's the only free port of
+	// the range, and ensure we get it back
+	if err := ReleasePort(defaultIP, "tcp", newPort); err != nil {
+		t.Fatal(err)
+	}
+	port, err = RequestPort(defaultIP, "tcp", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if newPort != port {
+		t.Fatalf("Expected port %d got %d", newPort, port)
+	}
+}
+
+func BenchmarkAllocatePorts(b *testing.B) {
+	defer reset()
+
+	for i := 0; i < b.N; i++ {
+		for i := 0; i <= EndPortRange-BeginPortRange; i++ {
+			port, err := RequestPort(defaultIP, "tcp", 0)
+			if err != nil {
+				b.Fatal(err)
+			}
+
+			if expected := BeginPortRange + i; port != expected {
+				b.Fatalf("Expected port %d got %d", expected, port)
+			}
+		}
+		reset()
+	}
+}
+
+func TestPortAllocation(t *testing.T) {
+	defer reset()
+
+	ip := net.ParseIP("192.168.0.1")
+	ip2 := net.ParseIP("192.168.0.2")
+	if port, err := RequestPort(ip, "tcp", 80); err != nil {
+		t.Fatal(err)
+	} else if port != 80 {
+		t.Fatalf("Acquire(80) should return 80, not %d", port)
+	}
+	port, err := RequestPort(ip, "tcp", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if port <= 0 {
+		t.Fatalf("Acquire(0) should return a non-zero port")
+	}
+
+	if _, err := RequestPort(ip, "tcp", port); err == nil {
+		t.Fatalf("Acquiring a port already in use should return an error")
+	}
+
+	if newPort, err := RequestPort(ip, "tcp", 0); err != nil {
+		t.Fatal(err)
+	} else if newPort == port {
+		t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
+	}
+
+	if _, err := RequestPort(ip, "tcp", 80); err == nil {
+		t.Fatalf("Acquiring a port already in use should return an error")
+	}
+	if _, err := RequestPort(ip2, "tcp", 80); err != nil {
+		t.Fatalf("It should be possible to allocate the same port on a different interface")
+	}
+	if _, err := RequestPort(ip2, "tcp", 80); err == nil {
+		t.Fatalf("Acquiring a port already in use should return an error")
+	}
+	if err := ReleasePort(ip, "tcp", 80); err != nil {
+		t.Fatal(err)
+	}
+	if _, err := RequestPort(ip, "tcp", 80); err != nil {
+		t.Fatal(err)
+	}
+
+	port, err = RequestPort(ip, "tcp", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	port2, err := RequestPort(ip, "tcp", port+1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	port3, err := RequestPort(ip, "tcp", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if port3 == port2 {
+		t.Fatal("Requesting a dynamic port should never allocate a used port")
+	}
+}
+
+func TestNoDuplicateBPR(t *testing.T) {
+	defer reset()
+
+	if port, err := RequestPort(defaultIP, "tcp", BeginPortRange); err != nil {
+		t.Fatal(err)
+	} else if port != BeginPortRange {
+		t.Fatalf("Expected port %d got %d", BeginPortRange, port)
+	}
+
+	if port, err := RequestPort(defaultIP, "tcp", 0); err != nil {
+		t.Fatal(err)
+	} else if port == BeginPortRange {
+		t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
+	}
+}

+ 176 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper.go

@@ -0,0 +1,176 @@
+package portmapper
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"sync"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/docker/daemon/networkdriver/portallocator"
+	"github.com/docker/docker/pkg/iptables"
+)
+
+type mapping struct {
+	proto         string
+	userlandProxy UserlandProxy
+	host          net.Addr
+	container     net.Addr
+}
+
+var (
+	chain *iptables.Chain
+	lock  sync.Mutex
+
+	// udp:ip:port
+	currentMappings = make(map[string]*mapping)
+
+	NewProxy = NewProxyCommand
+)
+
+var (
+	ErrUnknownBackendAddressType = errors.New("unknown container address type not supported")
+	ErrPortMappedForIP           = errors.New("port is already mapped to ip")
+	ErrPortNotMapped             = errors.New("port is not mapped")
+)
+
+func SetIptablesChain(c *iptables.Chain) {
+	chain = c
+}
+
+func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err error) {
+	lock.Lock()
+	defer lock.Unlock()
+
+	var (
+		m                 *mapping
+		proto             string
+		allocatedHostPort int
+		proxy             UserlandProxy
+	)
+
+	switch container.(type) {
+	case *net.TCPAddr:
+		proto = "tcp"
+		if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil {
+			return nil, err
+		}
+
+		m = &mapping{
+			proto:     proto,
+			host:      &net.TCPAddr{IP: hostIP, Port: allocatedHostPort},
+			container: container,
+		}
+
+		proxy = NewProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
+	case *net.UDPAddr:
+		proto = "udp"
+		if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil {
+			return nil, err
+		}
+
+		m = &mapping{
+			proto:     proto,
+			host:      &net.UDPAddr{IP: hostIP, Port: allocatedHostPort},
+			container: container,
+		}
+
+		proxy = NewProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port)
+	default:
+		return nil, ErrUnknownBackendAddressType
+	}
+
+	// release the allocated port on any further error during return.
+	defer func() {
+		if err != nil {
+			portallocator.ReleasePort(hostIP, proto, allocatedHostPort)
+		}
+	}()
+
+	key := getKey(m.host)
+	if _, exists := currentMappings[key]; exists {
+		return nil, ErrPortMappedForIP
+	}
+
+	containerIP, containerPort := getIPAndPort(m.container)
+	if err := forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
+		return nil, err
+	}
+
+	cleanup := func() error {
+		// need to undo the iptables rules before we return
+		proxy.Stop()
+		forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
+		if err := portallocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
+			return err
+		}
+
+		return nil
+	}
+
+	if err := proxy.Start(); err != nil {
+		if err := cleanup(); err != nil {
+			return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
+		}
+		return nil, err
+	}
+	m.userlandProxy = proxy
+	currentMappings[key] = m
+	return m.host, nil
+}
+
+func Unmap(host net.Addr) error {
+	lock.Lock()
+	defer lock.Unlock()
+
+	key := getKey(host)
+	data, exists := currentMappings[key]
+	if !exists {
+		return ErrPortNotMapped
+	}
+
+	data.userlandProxy.Stop()
+
+	delete(currentMappings, key)
+
+	containerIP, containerPort := getIPAndPort(data.container)
+	hostIP, hostPort := getIPAndPort(data.host)
+	if err := forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
+		log.Errorf("Error on iptables delete: %s", err)
+	}
+
+	switch a := host.(type) {
+	case *net.TCPAddr:
+		return portallocator.ReleasePort(a.IP, "tcp", a.Port)
+	case *net.UDPAddr:
+		return portallocator.ReleasePort(a.IP, "udp", a.Port)
+	}
+	return nil
+}
+
+func getKey(a net.Addr) string {
+	switch t := a.(type) {
+	case *net.TCPAddr:
+		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "tcp")
+	case *net.UDPAddr:
+		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
+	}
+	return ""
+}
+
+func getIPAndPort(a net.Addr) (net.IP, int) {
+	switch t := a.(type) {
+	case *net.TCPAddr:
+		return t.IP, t.Port
+	case *net.UDPAddr:
+		return t.IP, t.Port
+	}
+	return nil, 0
+}
+
+func forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
+	if chain == nil {
+		return nil
+	}
+	return chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort)
+}

+ 152 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper_test.go

@@ -0,0 +1,152 @@
+package portmapper
+
+import (
+	"net"
+	"testing"
+
+	"github.com/docker/docker/daemon/networkdriver/portallocator"
+	"github.com/docker/docker/pkg/iptables"
+)
+
+func init() {
+	// override this func to mock out the proxy server
+	NewProxy = NewMockProxyCommand
+}
+
+func reset() {
+	chain = nil
+	currentMappings = make(map[string]*mapping)
+}
+
+func TestSetIptablesChain(t *testing.T) {
+	defer reset()
+
+	c := &iptables.Chain{
+		Name:   "TEST",
+		Bridge: "192.168.1.1",
+	}
+
+	if chain != nil {
+		t.Fatal("chain should be nil at init")
+	}
+
+	SetIptablesChain(c)
+	if chain == nil {
+		t.Fatal("chain should not be nil after set")
+	}
+}
+
+func TestMapPorts(t *testing.T) {
+	dstIp1 := net.ParseIP("192.168.0.1")
+	dstIp2 := net.ParseIP("192.168.0.2")
+	dstAddr1 := &net.TCPAddr{IP: dstIp1, Port: 80}
+	dstAddr2 := &net.TCPAddr{IP: dstIp2, Port: 80}
+
+	srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
+	srcAddr2 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.2")}
+
+	addrEqual := func(addr1, addr2 net.Addr) bool {
+		return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
+	}
+
+	if host, err := Map(srcAddr1, dstIp1, 80); err != nil {
+		t.Fatalf("Failed to allocate port: %s", err)
+	} else if !addrEqual(dstAddr1, host) {
+		t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
+			dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network())
+	}
+
+	if _, err := Map(srcAddr1, dstIp1, 80); err == nil {
+		t.Fatalf("Port is in use - mapping should have failed")
+	}
+
+	if _, err := Map(srcAddr2, dstIp1, 80); err == nil {
+		t.Fatalf("Port is in use - mapping should have failed")
+	}
+
+	if _, err := Map(srcAddr2, dstIp2, 80); err != nil {
+		t.Fatalf("Failed to allocate port: %s", err)
+	}
+
+	if Unmap(dstAddr1) != nil {
+		t.Fatalf("Failed to release port")
+	}
+
+	if Unmap(dstAddr2) != nil {
+		t.Fatalf("Failed to release port")
+	}
+
+	if Unmap(dstAddr2) == nil {
+		t.Fatalf("Port already released, but no error reported")
+	}
+}
+
+func TestGetUDPKey(t *testing.T) {
+	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
+
+	key := getKey(addr)
+
+	if expected := "192.168.1.5:53/udp"; key != expected {
+		t.Fatalf("expected key %s got %s", expected, key)
+	}
+}
+
+func TestGetTCPKey(t *testing.T) {
+	addr := &net.TCPAddr{IP: net.ParseIP("192.168.1.5"), Port: 80}
+
+	key := getKey(addr)
+
+	if expected := "192.168.1.5:80/tcp"; key != expected {
+		t.Fatalf("expected key %s got %s", expected, key)
+	}
+}
+
+func TestGetUDPIPAndPort(t *testing.T) {
+	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
+
+	ip, port := getIPAndPort(addr)
+	if expected := "192.168.1.5"; ip.String() != expected {
+		t.Fatalf("expected ip %s got %s", expected, ip)
+	}
+
+	if ep := 53; port != ep {
+		t.Fatalf("expected port %d got %d", ep, port)
+	}
+}
+
+func TestMapAllPortsSingleInterface(t *testing.T) {
+	dstIp1 := net.ParseIP("0.0.0.0")
+	srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
+
+	hosts := []net.Addr{}
+	var host net.Addr
+	var err error
+
+	defer func() {
+		for _, val := range hosts {
+			Unmap(val)
+		}
+	}()
+
+	for i := 0; i < 10; i++ {
+		for i := portallocator.BeginPortRange; i < portallocator.EndPortRange; i++ {
+			if host, err = Map(srcAddr1, dstIp1, 0); err != nil {
+				t.Fatal(err)
+			}
+
+			hosts = append(hosts, host)
+		}
+
+		if _, err := Map(srcAddr1, dstIp1, portallocator.BeginPortRange); err == nil {
+			t.Fatalf("Port %d should be bound but is not", portallocator.BeginPortRange)
+		}
+
+		for _, val := range hosts {
+			if err := Unmap(val); err != nil {
+				t.Fatal(err)
+			}
+		}
+
+		hosts = []net.Addr{}
+	}
+}

+ 18 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mock_proxy.go

@@ -0,0 +1,18 @@
+package portmapper
+
+import "net"
+
+func NewMockProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) UserlandProxy {
+	return &mockProxyCommand{}
+}
+
+type mockProxyCommand struct {
+}
+
+func (p *mockProxyCommand) Start() error {
+	return nil
+}
+
+func (p *mockProxyCommand) Stop() error {
+	return nil
+}

+ 161 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/proxy.go

@@ -0,0 +1,161 @@
+package portmapper
+
+import (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net"
+	"os"
+	"os/exec"
+	"os/signal"
+	"strconv"
+	"syscall"
+	"time"
+
+	"github.com/docker/docker/pkg/proxy"
+	"github.com/docker/docker/pkg/reexec"
+)
+
+const userlandProxyCommandName = "docker-proxy"
+
+func init() {
+	reexec.Register(userlandProxyCommandName, execProxy)
+}
+
+type UserlandProxy interface {
+	Start() error
+	Stop() error
+}
+
+// proxyCommand wraps an exec.Cmd to run the userland TCP and UDP
+// proxies as separate processes.
+type proxyCommand struct {
+	cmd *exec.Cmd
+}
+
+// execProxy is the reexec function that is registered to start the userland proxies
+func execProxy() {
+	f := os.NewFile(3, "signal-parent")
+	host, container := parseHostContainerAddrs()
+
+	p, err := proxy.NewProxy(host, container)
+	if err != nil {
+		fmt.Fprintf(f, "1\n%s", err)
+		f.Close()
+		os.Exit(1)
+	}
+	go handleStopSignals(p)
+	fmt.Fprint(f, "0\n")
+	f.Close()
+
+	// Run will block until the proxy stops
+	p.Run()
+}
+
+// parseHostContainerAddrs parses the flags passed on reexec to create the TCP or UDP
+// net.Addrs to map the host and container ports
+func parseHostContainerAddrs() (host net.Addr, container net.Addr) {
+	var (
+		proto         = flag.String("proto", "tcp", "proxy protocol")
+		hostIP        = flag.String("host-ip", "", "host ip")
+		hostPort      = flag.Int("host-port", -1, "host port")
+		containerIP   = flag.String("container-ip", "", "container ip")
+		containerPort = flag.Int("container-port", -1, "container port")
+	)
+
+	flag.Parse()
+
+	switch *proto {
+	case "tcp":
+		host = &net.TCPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
+		container = &net.TCPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
+	case "udp":
+		host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
+		container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
+	default:
+		log.Fatalf("unsupported protocol %s", *proto)
+	}
+
+	return host, container
+}
+
+func handleStopSignals(p proxy.Proxy) {
+	s := make(chan os.Signal, 10)
+	signal.Notify(s, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP)
+
+	for _ = range s {
+		p.Close()
+
+		os.Exit(0)
+	}
+}
+
+func NewProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) UserlandProxy {
+	args := []string{
+		userlandProxyCommandName,
+		"-proto", proto,
+		"-host-ip", hostIP.String(),
+		"-host-port", strconv.Itoa(hostPort),
+		"-container-ip", containerIP.String(),
+		"-container-port", strconv.Itoa(containerPort),
+	}
+
+	return &proxyCommand{
+		cmd: &exec.Cmd{
+			Path: reexec.Self(),
+			Args: args,
+			SysProcAttr: &syscall.SysProcAttr{
+				Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
+			},
+		},
+	}
+}
+
+func (p *proxyCommand) Start() error {
+	r, w, err := os.Pipe()
+	if err != nil {
+		return fmt.Errorf("proxy unable to open os.Pipe %s", err)
+	}
+	defer r.Close()
+	p.cmd.ExtraFiles = []*os.File{w}
+	if err := p.cmd.Start(); err != nil {
+		return err
+	}
+	w.Close()
+
+	errchan := make(chan error, 1)
+	go func() {
+		buf := make([]byte, 2)
+		r.Read(buf)
+
+		if string(buf) != "0\n" {
+			errStr, err := ioutil.ReadAll(r)
+			if err != nil {
+				errchan <- fmt.Errorf("Error reading exit status from userland proxy: %v", err)
+				return
+			}
+
+			errchan <- fmt.Errorf("Error starting userland proxy: %s", errStr)
+			return
+		}
+		errchan <- nil
+	}()
+
+	select {
+	case err := <-errchan:
+		return err
+	case <-time.After(16 * time.Second):
+		return fmt.Errorf("Timed out proxy starting the userland proxy")
+	}
+}
+
+func (p *proxyCommand) Stop() error {
+	if p.cmd.Process != nil {
+		if err := p.cmd.Process.Signal(os.Interrupt); err != nil {
+			return err
+		}
+		return p.cmd.Wait()
+	}
+	return nil
+}

+ 118 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/utils.go

@@ -0,0 +1,118 @@
+package networkdriver
+
+import (
+	"errors"
+	"fmt"
+	"net"
+
+	"github.com/docker/libcontainer/netlink"
+)
+
+var (
+	networkGetRoutesFct = netlink.NetworkGetRoutes
+	ErrNoDefaultRoute   = errors.New("no default route")
+)
+
+func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
+	if len(nameservers) > 0 {
+		for _, ns := range nameservers {
+			_, nsNetwork, err := net.ParseCIDR(ns)
+			if err != nil {
+				return err
+			}
+			if NetworkOverlaps(toCheck, nsNetwork) {
+				return ErrNetworkOverlapsWithNameservers
+			}
+		}
+	}
+	return nil
+}
+
+func CheckRouteOverlaps(toCheck *net.IPNet) error {
+	networks, err := networkGetRoutesFct()
+	if err != nil {
+		return err
+	}
+
+	for _, network := range networks {
+		if network.IPNet != nil && NetworkOverlaps(toCheck, network.IPNet) {
+			return ErrNetworkOverlaps
+		}
+	}
+	return nil
+}
+
+// Detects overlap between one IPNet and another
+func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
+	if len(netX.IP) == len(netY.IP) {
+		if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
+			return true
+		}
+		if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
+			return true
+		}
+	}
+	return false
+}
+
+// Calculates the first and last IP addresses in an IPNet
+func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
+	var netIP net.IP
+	if network.IP.To4() != nil {
+		netIP = network.IP.To4()
+	} else if network.IP.To16() != nil {
+		netIP = network.IP.To16()
+	} else {
+		return nil, nil
+	}
+
+	lastIP := make([]byte, len(netIP), len(netIP))
+
+	for i := 0; i < len(netIP); i++ {
+		lastIP[i] = netIP[i] | ^network.Mask[i]
+	}
+	return netIP.Mask(network.Mask), net.IP(lastIP)
+}
+
+// Return the first IPv4 address and slice of IPv6 addresses for the specified network interface
+func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) {
+	iface, err := net.InterfaceByName(name)
+	if err != nil {
+		return nil, nil, err
+	}
+	addrs, err := iface.Addrs()
+	if err != nil {
+		return nil, nil, err
+	}
+	var addrs4 []net.Addr
+	var addrs6 []net.Addr
+	for _, addr := range addrs {
+		ip := (addr.(*net.IPNet)).IP
+		if ip4 := ip.To4(); ip4 != nil {
+			addrs4 = append(addrs4, addr)
+		} else if ip6 := ip.To16(); len(ip6) == net.IPv6len {
+			addrs6 = append(addrs6, addr)
+		}
+	}
+	switch {
+	case len(addrs4) == 0:
+		return nil, nil, fmt.Errorf("Interface %v has no IPv4 addresses", name)
+	case len(addrs4) > 1:
+		fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
+			name, (addrs4[0].(*net.IPNet)).IP)
+	}
+	return addrs4[0], addrs6, nil
+}
+
+func GetDefaultRouteIface() (*net.Interface, error) {
+	rs, err := networkGetRoutesFct()
+	if err != nil {
+		return nil, fmt.Errorf("unable to get routes: %v", err)
+	}
+	for _, r := range rs {
+		if r.Default {
+			return r.Iface, nil
+		}
+	}
+	return nil, ErrNoDefaultRoute
+}

+ 93 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go

@@ -0,0 +1,93 @@
+package kernel
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+)
+
+type KernelVersionInfo struct {
+	Kernel int
+	Major  int
+	Minor  int
+	Flavor string
+}
+
+func (k *KernelVersionInfo) String() string {
+	return fmt.Sprintf("%d.%d.%d%s", k.Kernel, k.Major, k.Minor, k.Flavor)
+}
+
+// Compare two KernelVersionInfo struct.
+// Returns -1 if a < b, 0 if a == b, 1 it a > b
+func CompareKernelVersion(a, b *KernelVersionInfo) int {
+	if a.Kernel < b.Kernel {
+		return -1
+	} else if a.Kernel > b.Kernel {
+		return 1
+	}
+
+	if a.Major < b.Major {
+		return -1
+	} else if a.Major > b.Major {
+		return 1
+	}
+
+	if a.Minor < b.Minor {
+		return -1
+	} else if a.Minor > b.Minor {
+		return 1
+	}
+
+	return 0
+}
+
+func GetKernelVersion() (*KernelVersionInfo, error) {
+	var (
+		err error
+	)
+
+	uts, err := uname()
+	if err != nil {
+		return nil, err
+	}
+
+	release := make([]byte, len(uts.Release))
+
+	i := 0
+	for _, c := range uts.Release {
+		release[i] = byte(c)
+		i++
+	}
+
+	// Remove the \x00 from the release for Atoi to parse correctly
+	release = release[:bytes.IndexByte(release, 0)]
+
+	return ParseRelease(string(release))
+}
+
+func ParseRelease(release string) (*KernelVersionInfo, error) {
+	var (
+		kernel, major, minor, parsed int
+		flavor, partial              string
+	)
+
+	// Ignore error from Sscanf to allow an empty flavor.  Instead, just
+	// make sure we got all the version numbers.
+	parsed, _ = fmt.Sscanf(release, "%d.%d%s", &kernel, &major, &partial)
+	if parsed < 2 {
+		return nil, errors.New("Can't parse kernel version " + release)
+	}
+
+	// sometimes we have 3.12.25-gentoo, but sometimes we just have 3.12-1-amd64
+	parsed, _ = fmt.Sscanf(partial, ".%d%s", &minor, &flavor)
+	if parsed < 1 {
+		flavor = partial
+	}
+
+	return &KernelVersionInfo{
+		Kernel: kernel,
+		Major:  major,
+		Minor:  minor,
+		Flavor: flavor,
+	}, nil
+}

+ 61 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_test.go

@@ -0,0 +1,61 @@
+package kernel
+
+import (
+	"testing"
+)
+
+func assertParseRelease(t *testing.T, release string, b *KernelVersionInfo, result int) {
+	var (
+		a *KernelVersionInfo
+	)
+	a, _ = ParseRelease(release)
+
+	if r := CompareKernelVersion(a, b); r != result {
+		t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
+	}
+	if a.Flavor != b.Flavor {
+		t.Fatalf("Unexpected parsed kernel flavor.  Found %s, expected %s", a.Flavor, b.Flavor)
+	}
+}
+
+func TestParseRelease(t *testing.T) {
+	assertParseRelease(t, "3.8.0", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}, 0)
+	assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
+	assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
+	assertParseRelease(t, "3.8.0-19-generic", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "-19-generic"}, 0)
+	assertParseRelease(t, "3.12.8tag", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 8, Flavor: "tag"}, 0)
+	assertParseRelease(t, "3.12-1-amd64", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 0, Flavor: "-1-amd64"}, 0)
+}
+
+func assertKernelVersion(t *testing.T, a, b *KernelVersionInfo, result int) {
+	if r := CompareKernelVersion(a, b); r != result {
+		t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
+	}
+}
+
+func TestCompareKernelVersion(t *testing.T) {
+	assertKernelVersion(t,
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
+		0)
+	assertKernelVersion(t,
+		&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
+		-1)
+	assertKernelVersion(t,
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
+		&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
+		1)
+	assertKernelVersion(t,
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
+		0)
+	assertKernelVersion(t,
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 5},
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
+		1)
+	assertKernelVersion(t,
+		&KernelVersionInfo{Kernel: 3, Major: 0, Minor: 20},
+		&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
+		-1)
+}

+ 16 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_linux.go

@@ -0,0 +1,16 @@
+package kernel
+
+import (
+	"syscall"
+)
+
+type Utsname syscall.Utsname
+
+func uname() (*syscall.Utsname, error) {
+	uts := &syscall.Utsname{}
+
+	if err := syscall.Uname(uts); err != nil {
+		return nil, err
+	}
+	return uts, nil
+}

+ 15 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go

@@ -0,0 +1,15 @@
+// +build !linux
+
+package kernel
+
+import (
+	"errors"
+)
+
+type Utsname struct {
+	Release [65]byte
+}
+
+func uname() (*Utsname, error) {
+	return nil, errors.New("Kernel version detection is available only on linux")
+}

+ 2 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS

@@ -0,0 +1,2 @@
+Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
+Guillaume J. Charmes <guillaume@docker.com> (@creack)

+ 31 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go

@@ -0,0 +1,31 @@
+// Packet netlink provide access to low level Netlink sockets and messages.
+//
+// Actual implementations are in:
+// netlink_linux.go
+// netlink_darwin.go
+package netlink
+
+import (
+	"errors"
+	"net"
+)
+
+var (
+	ErrWrongSockType   = errors.New("Wrong socket type")
+	ErrShortResponse   = errors.New("Got short response from netlink")
+	ErrInterfaceExists = errors.New("Network interface already exists")
+)
+
+// A Route is a subnet associated with the interface to reach it.
+type Route struct {
+	*net.IPNet
+	Iface   *net.Interface
+	Default bool
+}
+
+// An IfAddr defines IP network settings for a given network interface
+type IfAddr struct {
+	Iface *net.Interface
+	IP    net.IP
+	IPNet *net.IPNet
+}

+ 1307 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go

@@ -0,0 +1,1307 @@
+package netlink
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+	"math/rand"
+	"net"
+	"os"
+	"sync/atomic"
+	"syscall"
+	"unsafe"
+)
+
+const (
+	IFNAMSIZ          = 16
+	DEFAULT_CHANGE    = 0xFFFFFFFF
+	IFLA_INFO_KIND    = 1
+	IFLA_INFO_DATA    = 2
+	VETH_INFO_PEER    = 1
+	IFLA_MACVLAN_MODE = 1
+	IFLA_VLAN_ID      = 1
+	IFLA_NET_NS_FD    = 28
+	IFLA_ADDRESS      = 1
+	IFLA_BRPORT_MODE  = 4
+	SIOC_BRADDBR      = 0x89a0
+	SIOC_BRDELBR      = 0x89a1
+	SIOC_BRADDIF      = 0x89a2
+)
+
+const (
+	MACVLAN_MODE_PRIVATE = 1 << iota
+	MACVLAN_MODE_VEPA
+	MACVLAN_MODE_BRIDGE
+	MACVLAN_MODE_PASSTHRU
+)
+
+var nextSeqNr uint32
+
+type ifreqHwaddr struct {
+	IfrnName   [IFNAMSIZ]byte
+	IfruHwaddr syscall.RawSockaddr
+}
+
+type ifreqIndex struct {
+	IfrnName  [IFNAMSIZ]byte
+	IfruIndex int32
+}
+
+type ifreqFlags struct {
+	IfrnName  [IFNAMSIZ]byte
+	Ifruflags uint16
+}
+
+var native binary.ByteOrder
+
+func init() {
+	var x uint32 = 0x01020304
+	if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
+		native = binary.BigEndian
+	} else {
+		native = binary.LittleEndian
+	}
+}
+
+func getIpFamily(ip net.IP) int {
+	if len(ip) <= net.IPv4len {
+		return syscall.AF_INET
+	}
+	if ip.To4() != nil {
+		return syscall.AF_INET
+	}
+	return syscall.AF_INET6
+}
+
+type NetlinkRequestData interface {
+	Len() int
+	ToWireFormat() []byte
+}
+
+type IfInfomsg struct {
+	syscall.IfInfomsg
+}
+
+func newIfInfomsg(family int) *IfInfomsg {
+	return &IfInfomsg{
+		IfInfomsg: syscall.IfInfomsg{
+			Family: uint8(family),
+		},
+	}
+}
+
+func newIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
+	msg := newIfInfomsg(family)
+	parent.children = append(parent.children, msg)
+	return msg
+}
+
+func (msg *IfInfomsg) ToWireFormat() []byte {
+	length := syscall.SizeofIfInfomsg
+	b := make([]byte, length)
+	b[0] = msg.Family
+	b[1] = 0
+	native.PutUint16(b[2:4], msg.Type)
+	native.PutUint32(b[4:8], uint32(msg.Index))
+	native.PutUint32(b[8:12], msg.Flags)
+	native.PutUint32(b[12:16], msg.Change)
+	return b
+}
+
+func (msg *IfInfomsg) Len() int {
+	return syscall.SizeofIfInfomsg
+}
+
+type IfAddrmsg struct {
+	syscall.IfAddrmsg
+}
+
+func newIfAddrmsg(family int) *IfAddrmsg {
+	return &IfAddrmsg{
+		IfAddrmsg: syscall.IfAddrmsg{
+			Family: uint8(family),
+		},
+	}
+}
+
+func (msg *IfAddrmsg) ToWireFormat() []byte {
+	length := syscall.SizeofIfAddrmsg
+	b := make([]byte, length)
+	b[0] = msg.Family
+	b[1] = msg.Prefixlen
+	b[2] = msg.Flags
+	b[3] = msg.Scope
+	native.PutUint32(b[4:8], msg.Index)
+	return b
+}
+
+func (msg *IfAddrmsg) Len() int {
+	return syscall.SizeofIfAddrmsg
+}
+
+type RtMsg struct {
+	syscall.RtMsg
+}
+
+func newRtMsg() *RtMsg {
+	return &RtMsg{
+		RtMsg: syscall.RtMsg{
+			Table:    syscall.RT_TABLE_MAIN,
+			Scope:    syscall.RT_SCOPE_UNIVERSE,
+			Protocol: syscall.RTPROT_BOOT,
+			Type:     syscall.RTN_UNICAST,
+		},
+	}
+}
+
+func (msg *RtMsg) ToWireFormat() []byte {
+	length := syscall.SizeofRtMsg
+	b := make([]byte, length)
+	b[0] = msg.Family
+	b[1] = msg.Dst_len
+	b[2] = msg.Src_len
+	b[3] = msg.Tos
+	b[4] = msg.Table
+	b[5] = msg.Protocol
+	b[6] = msg.Scope
+	b[7] = msg.Type
+	native.PutUint32(b[8:12], msg.Flags)
+	return b
+}
+
+func (msg *RtMsg) Len() int {
+	return syscall.SizeofRtMsg
+}
+
+func rtaAlignOf(attrlen int) int {
+	return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
+}
+
+type RtAttr struct {
+	syscall.RtAttr
+	Data     []byte
+	children []NetlinkRequestData
+}
+
+func newRtAttr(attrType int, data []byte) *RtAttr {
+	return &RtAttr{
+		RtAttr: syscall.RtAttr{
+			Type: uint16(attrType),
+		},
+		children: []NetlinkRequestData{},
+		Data:     data,
+	}
+}
+
+func newRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
+	attr := newRtAttr(attrType, data)
+	parent.children = append(parent.children, attr)
+	return attr
+}
+
+func (a *RtAttr) Len() int {
+	if len(a.children) == 0 {
+		return (syscall.SizeofRtAttr + len(a.Data))
+	}
+
+	l := 0
+	for _, child := range a.children {
+		l += child.Len()
+	}
+	l += syscall.SizeofRtAttr
+	return rtaAlignOf(l + len(a.Data))
+}
+
+func (a *RtAttr) ToWireFormat() []byte {
+	length := a.Len()
+	buf := make([]byte, rtaAlignOf(length))
+
+	if a.Data != nil {
+		copy(buf[4:], a.Data)
+	} else {
+		next := 4
+		for _, child := range a.children {
+			childBuf := child.ToWireFormat()
+			copy(buf[next:], childBuf)
+			next += rtaAlignOf(len(childBuf))
+		}
+	}
+
+	if l := uint16(length); l != 0 {
+		native.PutUint16(buf[0:2], l)
+	}
+	native.PutUint16(buf[2:4], a.Type)
+	return buf
+}
+
+func uint32Attr(t int, n uint32) *RtAttr {
+	buf := make([]byte, 4)
+	native.PutUint32(buf, n)
+	return newRtAttr(t, buf)
+}
+
+type NetlinkRequest struct {
+	syscall.NlMsghdr
+	Data []NetlinkRequestData
+}
+
+func (rr *NetlinkRequest) ToWireFormat() []byte {
+	length := rr.Len
+	dataBytes := make([][]byte, len(rr.Data))
+	for i, data := range rr.Data {
+		dataBytes[i] = data.ToWireFormat()
+		length += uint32(len(dataBytes[i]))
+	}
+	b := make([]byte, length)
+	native.PutUint32(b[0:4], length)
+	native.PutUint16(b[4:6], rr.Type)
+	native.PutUint16(b[6:8], rr.Flags)
+	native.PutUint32(b[8:12], rr.Seq)
+	native.PutUint32(b[12:16], rr.Pid)
+
+	next := 16
+	for _, data := range dataBytes {
+		copy(b[next:], data)
+		next += len(data)
+	}
+	return b
+}
+
+func (rr *NetlinkRequest) AddData(data NetlinkRequestData) {
+	if data != nil {
+		rr.Data = append(rr.Data, data)
+	}
+}
+
+func newNetlinkRequest(proto, flags int) *NetlinkRequest {
+	return &NetlinkRequest{
+		NlMsghdr: syscall.NlMsghdr{
+			Len:   uint32(syscall.NLMSG_HDRLEN),
+			Type:  uint16(proto),
+			Flags: syscall.NLM_F_REQUEST | uint16(flags),
+			Seq:   atomic.AddUint32(&nextSeqNr, 1),
+		},
+	}
+}
+
+type NetlinkSocket struct {
+	fd  int
+	lsa syscall.SockaddrNetlink
+}
+
+func getNetlinkSocket() (*NetlinkSocket, error) {
+	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_ROUTE)
+	if err != nil {
+		return nil, err
+	}
+	s := &NetlinkSocket{
+		fd: fd,
+	}
+	s.lsa.Family = syscall.AF_NETLINK
+	if err := syscall.Bind(fd, &s.lsa); err != nil {
+		syscall.Close(fd)
+		return nil, err
+	}
+
+	return s, nil
+}
+
+func (s *NetlinkSocket) Close() {
+	syscall.Close(s.fd)
+}
+
+func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
+	if err := syscall.Sendto(s.fd, request.ToWireFormat(), 0, &s.lsa); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
+	rb := make([]byte, syscall.Getpagesize())
+	nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
+	if err != nil {
+		return nil, err
+	}
+	if nr < syscall.NLMSG_HDRLEN {
+		return nil, ErrShortResponse
+	}
+	rb = rb[:nr]
+	return syscall.ParseNetlinkMessage(rb)
+}
+
+func (s *NetlinkSocket) GetPid() (uint32, error) {
+	lsa, err := syscall.Getsockname(s.fd)
+	if err != nil {
+		return 0, err
+	}
+	switch v := lsa.(type) {
+	case *syscall.SockaddrNetlink:
+		return v.Pid, nil
+	}
+	return 0, ErrWrongSockType
+}
+
+func (s *NetlinkSocket) CheckMessage(m syscall.NetlinkMessage, seq, pid uint32) error {
+	if m.Header.Seq != seq {
+		return fmt.Errorf("netlink: invalid seq %d, expected %d", m.Header.Seq, seq)
+	}
+	if m.Header.Pid != pid {
+		return fmt.Errorf("netlink: wrong pid %d, expected %d", m.Header.Pid, pid)
+	}
+	if m.Header.Type == syscall.NLMSG_DONE {
+		return io.EOF
+	}
+	if m.Header.Type == syscall.NLMSG_ERROR {
+		e := int32(native.Uint32(m.Data[0:4]))
+		if e == 0 {
+			return io.EOF
+		}
+		return syscall.Errno(-e)
+	}
+	return nil
+}
+
+func (s *NetlinkSocket) HandleAck(seq uint32) error {
+	pid, err := s.GetPid()
+	if err != nil {
+		return err
+	}
+
+outer:
+	for {
+		msgs, err := s.Receive()
+		if err != nil {
+			return err
+		}
+		for _, m := range msgs {
+			if err := s.CheckMessage(m, seq, pid); err != nil {
+				if err == io.EOF {
+					break outer
+				}
+				return err
+			}
+		}
+	}
+
+	return nil
+}
+
+func zeroTerminated(s string) []byte {
+	return []byte(s + "\000")
+}
+
+func nonZeroTerminated(s string) []byte {
+	return []byte(s)
+}
+
+// Add a new network link of a specified type.
+// This is identical to running: ip link add $name type $linkType
+func NetworkLinkAdd(name string, linkType string) error {
+	if name == "" || linkType == "" {
+		return fmt.Errorf("Neither link name nor link type can be empty!")
+	}
+
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	wb.AddData(msg)
+
+	linkInfo := newRtAttr(syscall.IFLA_LINKINFO, nil)
+	newRtAttrChild(linkInfo, IFLA_INFO_KIND, nonZeroTerminated(linkType))
+	wb.AddData(linkInfo)
+
+	nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name))
+	wb.AddData(nameData)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	return s.HandleAck(wb.Seq)
+}
+
+// Delete a network link.
+// This is identical to running: ip link del $name
+func NetworkLinkDel(name string) error {
+	if name == "" {
+		return fmt.Errorf("Network link name can not be empty!")
+	}
+
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	iface, err := net.InterfaceByName(name)
+	if err != nil {
+		return err
+	}
+
+	wb := newNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(iface.Index)
+	wb.AddData(msg)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	return s.HandleAck(wb.Seq)
+}
+
+// Bring up a particular network interface.
+// This is identical to running: ip link set dev $name up
+func NetworkLinkUp(iface *net.Interface) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(iface.Index)
+	msg.Flags = syscall.IFF_UP
+	msg.Change = syscall.IFF_UP
+	wb.AddData(msg)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	return s.HandleAck(wb.Seq)
+}
+
+// Bring down a particular network interface.
+// This is identical to running: ip link set $name down
+func NetworkLinkDown(iface *net.Interface) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(iface.Index)
+	msg.Flags = 0 & ^syscall.IFF_UP
+	msg.Change = DEFAULT_CHANGE
+	wb.AddData(msg)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	return s.HandleAck(wb.Seq)
+}
+
+// Set link layer address ie. MAC Address.
+// This is identical to running: ip link set dev $name address $macaddress
+func NetworkSetMacAddress(iface *net.Interface, macaddr string) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	hwaddr, err := net.ParseMAC(macaddr)
+	if err != nil {
+		return err
+	}
+
+	var (
+		MULTICAST byte = 0x1
+	)
+
+	if hwaddr[0]&0x1 == MULTICAST {
+		return fmt.Errorf("Multicast MAC Address is not supported: %s", macaddr)
+	}
+
+	wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(iface.Index)
+	msg.Change = DEFAULT_CHANGE
+	wb.AddData(msg)
+
+	macdata := make([]byte, 6)
+	copy(macdata, hwaddr)
+	data := newRtAttr(IFLA_ADDRESS, macdata)
+	wb.AddData(data)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+	return s.HandleAck(wb.Seq)
+}
+
+// Set link Maximum Transmission Unit
+// This is identical to running: ip link set dev $name mtu $MTU
+// bridge is a bitch here https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=292088
+// https://bugzilla.redhat.com/show_bug.cgi?id=697021
+// There is a discussion about how to deal with ifcs joining bridge with MTU > 1500
+// Regular network nterfaces do seem to work though!
+func NetworkSetMTU(iface *net.Interface, mtu int) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(iface.Index)
+	msg.Change = DEFAULT_CHANGE
+	wb.AddData(msg)
+	wb.AddData(uint32Attr(syscall.IFLA_MTU, uint32(mtu)))
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+	return s.HandleAck(wb.Seq)
+}
+
+// Set link queue length
+// This is identical to running: ip link set dev $name txqueuelen $QLEN
+func NetworkSetTxQueueLen(iface *net.Interface, txQueueLen int) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(iface.Index)
+	msg.Change = DEFAULT_CHANGE
+	wb.AddData(msg)
+	wb.AddData(uint32Attr(syscall.IFLA_TXQLEN, uint32(txQueueLen)))
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+	return s.HandleAck(wb.Seq)
+}
+
+func networkMasterAction(iface *net.Interface, rtattr *RtAttr) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(iface.Index)
+	msg.Change = DEFAULT_CHANGE
+	wb.AddData(msg)
+	wb.AddData(rtattr)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	return s.HandleAck(wb.Seq)
+}
+
+// Add an interface to bridge.
+// This is identical to running: ip link set $name master $master
+func NetworkSetMaster(iface, master *net.Interface) error {
+	data := uint32Attr(syscall.IFLA_MASTER, uint32(master.Index))
+	return networkMasterAction(iface, data)
+}
+
+// Remove an interface from the bridge
+// This is is identical to to running: ip link $name set nomaster
+func NetworkSetNoMaster(iface *net.Interface) error {
+	data := uint32Attr(syscall.IFLA_MASTER, 0)
+	return networkMasterAction(iface, data)
+}
+
+func networkSetNsAction(iface *net.Interface, rtattr *RtAttr) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(iface.Index)
+	wb.AddData(msg)
+	wb.AddData(rtattr)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	return s.HandleAck(wb.Seq)
+}
+
+// Move a particular network interface to a particular network namespace
+// specified by PID. This is idential to running: ip link set dev $name netns $pid
+func NetworkSetNsPid(iface *net.Interface, nspid int) error {
+	data := uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid))
+	return networkSetNsAction(iface, data)
+}
+
+// Move a particular network interface to a particular mounted
+// network namespace specified by file descriptor.
+// This is idential to running: ip link set dev $name netns $fd
+func NetworkSetNsFd(iface *net.Interface, fd int) error {
+	data := uint32Attr(IFLA_NET_NS_FD, uint32(fd))
+	return networkSetNsAction(iface, data)
+}
+
+// Rname a particular interface to a different name
+// !!! Note that you can't rename an active interface. You need to bring it down before renaming it.
+// This is identical to running: ip link set dev ${oldName} name ${newName}
+func NetworkChangeName(iface *net.Interface, newName string) error {
+	if len(newName) >= IFNAMSIZ {
+		return fmt.Errorf("Interface name %s too long", newName)
+	}
+
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(iface.Index)
+	msg.Change = DEFAULT_CHANGE
+	wb.AddData(msg)
+
+	nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(newName))
+	wb.AddData(nameData)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	return s.HandleAck(wb.Seq)
+}
+
+// Add a new VETH pair link on the host
+// This is identical to running: ip link add name $name type veth peer name $peername
+func NetworkCreateVethPair(name1, name2 string, txQueueLen int) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	wb.AddData(msg)
+
+	nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name1))
+	wb.AddData(nameData)
+
+	txqLen := make([]byte, 4)
+	native.PutUint32(txqLen, uint32(txQueueLen))
+	txqData := newRtAttr(syscall.IFLA_TXQLEN, txqLen)
+	wb.AddData(txqData)
+
+	nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
+	newRtAttrChild(nest1, IFLA_INFO_KIND, zeroTerminated("veth"))
+	nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
+	nest3 := newRtAttrChild(nest2, VETH_INFO_PEER, nil)
+
+	newIfInfomsgChild(nest3, syscall.AF_UNSPEC)
+	newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2))
+
+	txqLen2 := make([]byte, 4)
+	native.PutUint32(txqLen2, uint32(txQueueLen))
+	newRtAttrChild(nest3, syscall.IFLA_TXQLEN, txqLen2)
+
+	wb.AddData(nest1)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	if err := s.HandleAck(wb.Seq); err != nil {
+		if os.IsExist(err) {
+			return ErrInterfaceExists
+		}
+
+		return err
+	}
+
+	return nil
+}
+
+// Add a new VLAN interface with masterDev as its upper device
+// This is identical to running:
+// ip link add name $name link $masterdev type vlan id $id
+func NetworkLinkAddVlan(masterDev, vlanDev string, vlanId uint16) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+
+	masterDevIfc, err := net.InterfaceByName(masterDev)
+	if err != nil {
+		return err
+	}
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	wb.AddData(msg)
+
+	nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
+	newRtAttrChild(nest1, IFLA_INFO_KIND, nonZeroTerminated("vlan"))
+
+	nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
+	vlanData := make([]byte, 2)
+	native.PutUint16(vlanData, vlanId)
+	newRtAttrChild(nest2, IFLA_VLAN_ID, vlanData)
+	wb.AddData(nest1)
+
+	wb.AddData(uint32Attr(syscall.IFLA_LINK, uint32(masterDevIfc.Index)))
+	wb.AddData(newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(vlanDev)))
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+	return s.HandleAck(wb.Seq)
+}
+
+// MacVlan link has LowerDev, UpperDev and operates in Mode mode
+// This simplifies the code when creating MacVlan or MacVtap interface
+type MacVlanLink struct {
+	MasterDev string
+	SlaveDev  string
+	mode      string
+}
+
+func (m MacVlanLink) Mode() uint32 {
+	modeMap := map[string]uint32{
+		"private":  MACVLAN_MODE_PRIVATE,
+		"vepa":     MACVLAN_MODE_VEPA,
+		"bridge":   MACVLAN_MODE_BRIDGE,
+		"passthru": MACVLAN_MODE_PASSTHRU,
+	}
+
+	return modeMap[m.mode]
+}
+
+// Add MAC VLAN network interface with masterDev as its upper device
+// This is identical to running:
+// ip link add name $name link $masterdev type macvlan mode $mode
+func networkLinkMacVlan(dev_type string, mcvln *MacVlanLink) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+
+	masterDevIfc, err := net.InterfaceByName(mcvln.MasterDev)
+	if err != nil {
+		return err
+	}
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	wb.AddData(msg)
+
+	nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
+	newRtAttrChild(nest1, IFLA_INFO_KIND, nonZeroTerminated(dev_type))
+
+	nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
+	macVlanData := make([]byte, 4)
+	native.PutUint32(macVlanData, mcvln.Mode())
+	newRtAttrChild(nest2, IFLA_MACVLAN_MODE, macVlanData)
+	wb.AddData(nest1)
+
+	wb.AddData(uint32Attr(syscall.IFLA_LINK, uint32(masterDevIfc.Index)))
+	wb.AddData(newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(mcvln.SlaveDev)))
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+	return s.HandleAck(wb.Seq)
+}
+
+func NetworkLinkAddMacVlan(masterDev, macVlanDev string, mode string) error {
+	return networkLinkMacVlan("macvlan", &MacVlanLink{
+		MasterDev: masterDev,
+		SlaveDev:  macVlanDev,
+		mode:      mode,
+	})
+}
+
+func NetworkLinkAddMacVtap(masterDev, macVlanDev string, mode string) error {
+	return networkLinkMacVlan("macvtap", &MacVlanLink{
+		MasterDev: masterDev,
+		SlaveDev:  macVlanDev,
+		mode:      mode,
+	})
+}
+
+func networkLinkIpAction(action, flags int, ifa IfAddr) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	family := getIpFamily(ifa.IP)
+
+	wb := newNetlinkRequest(action, flags)
+
+	msg := newIfAddrmsg(family)
+	msg.Index = uint32(ifa.Iface.Index)
+	prefixLen, _ := ifa.IPNet.Mask.Size()
+	msg.Prefixlen = uint8(prefixLen)
+	wb.AddData(msg)
+
+	var ipData []byte
+	if family == syscall.AF_INET {
+		ipData = ifa.IP.To4()
+	} else {
+		ipData = ifa.IP.To16()
+	}
+
+	localData := newRtAttr(syscall.IFA_LOCAL, ipData)
+	wb.AddData(localData)
+
+	addrData := newRtAttr(syscall.IFA_ADDRESS, ipData)
+	wb.AddData(addrData)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	return s.HandleAck(wb.Seq)
+}
+
+// Delete an IP address from an interface. This is identical to:
+// ip addr del $ip/$ipNet dev $iface
+func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+	return networkLinkIpAction(
+		syscall.RTM_DELADDR,
+		syscall.NLM_F_ACK,
+		IfAddr{iface, ip, ipNet},
+	)
+}
+
+// Add an Ip address to an interface. This is identical to:
+// ip addr add $ip/$ipNet dev $iface
+func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+	return networkLinkIpAction(
+		syscall.RTM_NEWADDR,
+		syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK,
+		IfAddr{iface, ip, ipNet},
+	)
+}
+
+// Returns an array of IPNet for all the currently routed subnets on ipv4
+// This is similar to the first column of "ip route" output
+func NetworkGetRoutes() ([]Route, error) {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return nil, err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
+
+	msg := newIfInfomsg(syscall.AF_UNSPEC)
+	wb.AddData(msg)
+
+	if err := s.Send(wb); err != nil {
+		return nil, err
+	}
+
+	pid, err := s.GetPid()
+	if err != nil {
+		return nil, err
+	}
+
+	res := make([]Route, 0)
+
+outer:
+	for {
+		msgs, err := s.Receive()
+		if err != nil {
+			return nil, err
+		}
+		for _, m := range msgs {
+			if err := s.CheckMessage(m, wb.Seq, pid); err != nil {
+				if err == io.EOF {
+					break outer
+				}
+				return nil, err
+			}
+			if m.Header.Type != syscall.RTM_NEWROUTE {
+				continue
+			}
+
+			var r Route
+
+			msg := (*RtMsg)(unsafe.Pointer(&m.Data[0:syscall.SizeofRtMsg][0]))
+
+			if msg.Flags&syscall.RTM_F_CLONED != 0 {
+				// Ignore cloned routes
+				continue
+			}
+
+			if msg.Table != syscall.RT_TABLE_MAIN {
+				// Ignore non-main tables
+				continue
+			}
+
+			if msg.Family != syscall.AF_INET {
+				// Ignore non-ipv4 routes
+				continue
+			}
+
+			if msg.Dst_len == 0 {
+				// Default routes
+				r.Default = true
+			}
+
+			attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+			if err != nil {
+				return nil, err
+			}
+			for _, attr := range attrs {
+				switch attr.Attr.Type {
+				case syscall.RTA_DST:
+					ip := attr.Value
+					r.IPNet = &net.IPNet{
+						IP:   ip,
+						Mask: net.CIDRMask(int(msg.Dst_len), 8*len(ip)),
+					}
+				case syscall.RTA_OIF:
+					index := int(native.Uint32(attr.Value[0:4]))
+					r.Iface, _ = net.InterfaceByIndex(index)
+				}
+			}
+			if r.Default || r.IPNet != nil {
+				res = append(res, r)
+			}
+		}
+	}
+
+	return res, nil
+}
+
+// Add a new route table entry.
+func AddRoute(destination, source, gateway, device string) error {
+	if destination == "" && source == "" && gateway == "" {
+		return fmt.Errorf("one of destination, source or gateway must not be blank")
+	}
+
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	msg := newRtMsg()
+	currentFamily := -1
+	var rtAttrs []*RtAttr
+
+	if destination != "" {
+		destIP, destNet, err := net.ParseCIDR(destination)
+		if err != nil {
+			return fmt.Errorf("destination CIDR %s couldn't be parsed", destination)
+		}
+		destFamily := getIpFamily(destIP)
+		currentFamily = destFamily
+		destLen, bits := destNet.Mask.Size()
+		if destLen == 0 && bits == 0 {
+			return fmt.Errorf("destination CIDR %s generated a non-canonical Mask", destination)
+		}
+		msg.Family = uint8(destFamily)
+		msg.Dst_len = uint8(destLen)
+		var destData []byte
+		if destFamily == syscall.AF_INET {
+			destData = destIP.To4()
+		} else {
+			destData = destIP.To16()
+		}
+		rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_DST, destData))
+	}
+
+	if source != "" {
+		srcIP := net.ParseIP(source)
+		if srcIP == nil {
+			return fmt.Errorf("source IP %s couldn't be parsed", source)
+		}
+		srcFamily := getIpFamily(srcIP)
+		if currentFamily != -1 && currentFamily != srcFamily {
+			return fmt.Errorf("source and destination ip were not the same IP family")
+		}
+		currentFamily = srcFamily
+		msg.Family = uint8(srcFamily)
+		var srcData []byte
+		if srcFamily == syscall.AF_INET {
+			srcData = srcIP.To4()
+		} else {
+			srcData = srcIP.To16()
+		}
+		rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_PREFSRC, srcData))
+	}
+
+	if gateway != "" {
+		gwIP := net.ParseIP(gateway)
+		if gwIP == nil {
+			return fmt.Errorf("gateway IP %s couldn't be parsed", gateway)
+		}
+		gwFamily := getIpFamily(gwIP)
+		if currentFamily != -1 && currentFamily != gwFamily {
+			return fmt.Errorf("gateway, source, and destination ip were not the same IP family")
+		}
+		msg.Family = uint8(gwFamily)
+		var gwData []byte
+		if gwFamily == syscall.AF_INET {
+			gwData = gwIP.To4()
+		} else {
+			gwData = gwIP.To16()
+		}
+		rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_GATEWAY, gwData))
+	}
+
+	wb.AddData(msg)
+	for _, attr := range rtAttrs {
+		wb.AddData(attr)
+	}
+
+	iface, err := net.InterfaceByName(device)
+	if err != nil {
+		return err
+	}
+	wb.AddData(uint32Attr(syscall.RTA_OIF, uint32(iface.Index)))
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+	return s.HandleAck(wb.Seq)
+}
+
+// Add a new default gateway. Identical to:
+// ip route add default via $ip
+func AddDefaultGw(ip, device string) error {
+	return AddRoute("", "", ip, device)
+}
+
+// THIS CODE DOES NOT COMMUNICATE WITH KERNEL VIA RTNETLINK INTERFACE
+// IT IS HERE FOR BACKWARDS COMPATIBILITY WITH OLDER LINUX KERNELS
+// WHICH SHIP WITH OLDER NOT ENTIRELY FUNCTIONAL VERSION OF NETLINK
+func getIfSocket() (fd int, err error) {
+	for _, socket := range []int{
+		syscall.AF_INET,
+		syscall.AF_PACKET,
+		syscall.AF_INET6,
+	} {
+		if fd, err = syscall.Socket(socket, syscall.SOCK_DGRAM, 0); err == nil {
+			break
+		}
+	}
+	if err == nil {
+		return fd, nil
+	}
+	return -1, err
+}
+
+// Create the actual bridge device.  This is more backward-compatible than
+// netlink.NetworkLinkAdd and works on RHEL 6.
+func CreateBridge(name string, setMacAddr bool) error {
+	if len(name) >= IFNAMSIZ {
+		return fmt.Errorf("Interface name %s too long", name)
+	}
+
+	s, err := getIfSocket()
+	if err != nil {
+		return err
+	}
+	defer syscall.Close(s)
+
+	nameBytePtr, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), SIOC_BRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
+		return err
+	}
+	if setMacAddr {
+		return SetMacAddress(name, randMacAddr())
+	}
+	return nil
+}
+
+// Delete the actual bridge device.
+func DeleteBridge(name string) error {
+	s, err := getIfSocket()
+	if err != nil {
+		return err
+	}
+	defer syscall.Close(s)
+
+	nameBytePtr, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+
+	var ifr ifreqFlags
+	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], []byte(name))
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s),
+		syscall.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifr))); err != 0 {
+		return err
+	}
+
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s),
+		SIOC_BRDELBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
+		return err
+	}
+	return nil
+}
+
+// Add a slave to abridge device.  This is more backward-compatible than
+// netlink.NetworkSetMaster and works on RHEL 6.
+func AddToBridge(iface, master *net.Interface) error {
+	if len(master.Name) >= IFNAMSIZ {
+		return fmt.Errorf("Interface name %s too long", master.Name)
+	}
+
+	s, err := getIfSocket()
+	if err != nil {
+		return err
+	}
+	defer syscall.Close(s)
+
+	ifr := ifreqIndex{}
+	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], master.Name)
+	ifr.IfruIndex = int32(iface.Index)
+
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), SIOC_BRADDIF, uintptr(unsafe.Pointer(&ifr))); err != 0 {
+		return err
+	}
+
+	return nil
+}
+
+func randMacAddr() string {
+	hw := make(net.HardwareAddr, 6)
+	for i := 0; i < 6; i++ {
+		hw[i] = byte(rand.Intn(255))
+	}
+	hw[0] &^= 0x1 // clear multicast bit
+	hw[0] |= 0x2  // set local assignment bit (IEEE802)
+	return hw.String()
+}
+
+func SetMacAddress(name, addr string) error {
+	if len(name) >= IFNAMSIZ {
+		return fmt.Errorf("Interface name %s too long", name)
+	}
+
+	hw, err := net.ParseMAC(addr)
+	if err != nil {
+		return err
+	}
+
+	s, err := getIfSocket()
+	if err != nil {
+		return err
+	}
+	defer syscall.Close(s)
+
+	ifr := ifreqHwaddr{}
+	ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
+	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
+
+	for i := 0; i < 6; i++ {
+		ifr.IfruHwaddr.Data[i] = ifrDataByte(hw[i])
+	}
+
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
+		return err
+	}
+	return nil
+}
+
+func SetHairpinMode(iface *net.Interface, enabled bool) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+	req := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_BRIDGE)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(iface.Index)
+	msg.Change = DEFAULT_CHANGE
+	req.AddData(msg)
+
+	mode := []byte{0}
+	if enabled {
+		mode[0] = byte(1)
+	}
+
+	br := newRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
+	newRtAttrChild(br, IFLA_BRPORT_MODE, mode)
+	req.AddData(br)
+	if err := s.Send(req); err != nil {
+		return err
+	}
+
+	return s.HandleAck(req.Seq)
+}
+
+func ChangeName(iface *net.Interface, newName string) error {
+	if len(newName) >= IFNAMSIZ {
+		return fmt.Errorf("Interface name %s too long", newName)
+	}
+
+	fd, err := getIfSocket()
+	if err != nil {
+		return err
+	}
+	defer syscall.Close(fd)
+
+	data := [IFNAMSIZ * 2]byte{}
+	// the "-1"s here are very important for ensuring we get proper null
+	// termination of our new C strings
+	copy(data[:IFNAMSIZ-1], iface.Name)
+	copy(data[IFNAMSIZ:IFNAMSIZ*2-1], newName)
+
+	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 {
+		return errno
+	}
+
+	return nil
+}

+ 5 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go

@@ -0,0 +1,5 @@
+package netlink
+
+func ifrDataByte(b byte) uint8 {
+	return uint8(b)
+}

+ 7 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go

@@ -0,0 +1,7 @@
+// +build !arm
+
+package netlink
+
+func ifrDataByte(b byte) int8 {
+	return int8(b)
+}

+ 408 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go

@@ -0,0 +1,408 @@
+package netlink
+
+import (
+	"net"
+	"strings"
+	"syscall"
+	"testing"
+)
+
+type testLink struct {
+	name     string
+	linkType string
+}
+
+func addLink(t *testing.T, name string, linkType string) {
+	if err := NetworkLinkAdd(name, linkType); err != nil {
+		t.Fatalf("Unable to create %s link: %s", name, err)
+	}
+}
+
+func readLink(t *testing.T, name string) *net.Interface {
+	iface, err := net.InterfaceByName(name)
+	if err != nil {
+		t.Fatalf("Could not find %s interface: %s", name, err)
+	}
+
+	return iface
+}
+
+func deleteLink(t *testing.T, name string) {
+	if err := NetworkLinkDel(name); err != nil {
+		t.Fatalf("Unable to delete %s link: %s", name, err)
+	}
+}
+
+func upLink(t *testing.T, name string) {
+	iface := readLink(t, name)
+	if err := NetworkLinkUp(iface); err != nil {
+		t.Fatalf("Could not bring UP %#v interface: %s", iface, err)
+	}
+}
+
+func downLink(t *testing.T, name string) {
+	iface := readLink(t, name)
+	if err := NetworkLinkDown(iface); err != nil {
+		t.Fatalf("Could not bring DOWN %#v interface: %s", iface, err)
+	}
+}
+
+func ipAssigned(iface *net.Interface, ip net.IP) bool {
+	addrs, _ := iface.Addrs()
+
+	for _, addr := range addrs {
+		args := strings.SplitN(addr.String(), "/", 2)
+		if args[0] == ip.String() {
+			return true
+		}
+	}
+
+	return false
+}
+
+func TestNetworkLinkAddDel(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	testLinks := []testLink{
+		{"tstEth", "dummy"},
+		{"tstBr", "bridge"},
+	}
+
+	for _, tl := range testLinks {
+		addLink(t, tl.name, tl.linkType)
+		defer deleteLink(t, tl.name)
+		readLink(t, tl.name)
+	}
+}
+
+func TestNetworkLinkUpDown(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	tl := testLink{name: "tstEth", linkType: "dummy"}
+
+	addLink(t, tl.name, tl.linkType)
+	defer deleteLink(t, tl.name)
+
+	upLink(t, tl.name)
+	ifcAfterUp := readLink(t, tl.name)
+
+	if (ifcAfterUp.Flags & syscall.IFF_UP) != syscall.IFF_UP {
+		t.Fatalf("Could not bring UP %#v initerface", tl)
+	}
+
+	downLink(t, tl.name)
+	ifcAfterDown := readLink(t, tl.name)
+
+	if (ifcAfterDown.Flags & syscall.IFF_UP) == syscall.IFF_UP {
+		t.Fatalf("Could not bring DOWN %#v initerface", tl)
+	}
+}
+
+func TestNetworkSetMacAddress(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	tl := testLink{name: "tstEth", linkType: "dummy"}
+	macaddr := "22:ce:e0:99:63:6f"
+
+	addLink(t, tl.name, tl.linkType)
+	defer deleteLink(t, tl.name)
+
+	ifcBeforeSet := readLink(t, tl.name)
+
+	if err := NetworkSetMacAddress(ifcBeforeSet, macaddr); err != nil {
+		t.Fatalf("Could not set %s MAC address on %#v interface: %s", macaddr, tl, err)
+	}
+
+	ifcAfterSet := readLink(t, tl.name)
+
+	if ifcAfterSet.HardwareAddr.String() != macaddr {
+		t.Fatalf("Could not set %s MAC address on %#v interface", macaddr, tl)
+	}
+}
+
+func TestNetworkSetMTU(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	tl := testLink{name: "tstEth", linkType: "dummy"}
+	mtu := 1400
+
+	addLink(t, tl.name, tl.linkType)
+	defer deleteLink(t, tl.name)
+
+	ifcBeforeSet := readLink(t, tl.name)
+
+	if err := NetworkSetMTU(ifcBeforeSet, mtu); err != nil {
+		t.Fatalf("Could not set %d MTU on %#v interface: %s", mtu, tl, err)
+	}
+
+	ifcAfterSet := readLink(t, tl.name)
+
+	if ifcAfterSet.MTU != mtu {
+		t.Fatalf("Could not set %d MTU on %#v interface", mtu, tl)
+	}
+}
+
+func TestNetworkSetMasterNoMaster(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	master := testLink{"tstBr", "bridge"}
+	slave := testLink{"tstEth", "dummy"}
+	testLinks := []testLink{master, slave}
+
+	for _, tl := range testLinks {
+		addLink(t, tl.name, tl.linkType)
+		defer deleteLink(t, tl.name)
+		upLink(t, tl.name)
+	}
+
+	masterIfc := readLink(t, master.name)
+	slaveIfc := readLink(t, slave.name)
+	if err := NetworkSetMaster(slaveIfc, masterIfc); err != nil {
+		t.Fatalf("Could not set %#v to be the master of %#v: %s", master, slave, err)
+	}
+
+	// Trying to figure out a way to test which will not break on RHEL6.
+	// We could check for existence of /sys/class/net/tstEth/upper_tstBr
+	// which should point to the ../tstBr which is the UPPER device i.e. network bridge
+
+	if err := NetworkSetNoMaster(slaveIfc); err != nil {
+		t.Fatalf("Could not UNset %#v master of %#v: %s", master, slave, err)
+	}
+}
+
+func TestNetworkChangeName(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	tl := testLink{"tstEth", "dummy"}
+	newName := "newTst"
+
+	addLink(t, tl.name, tl.linkType)
+
+	linkIfc := readLink(t, tl.name)
+	if err := NetworkChangeName(linkIfc, newName); err != nil {
+		deleteLink(t, tl.name)
+		t.Fatalf("Could not change %#v interface name to %s: %s", tl, newName, err)
+	}
+
+	readLink(t, newName)
+	deleteLink(t, newName)
+}
+
+func TestNetworkLinkAddVlan(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	tl := struct {
+		name string
+		id   uint16
+	}{
+		name: "tstVlan",
+		id:   32,
+	}
+	masterLink := testLink{"tstEth", "dummy"}
+
+	addLink(t, masterLink.name, masterLink.linkType)
+	defer deleteLink(t, masterLink.name)
+
+	if err := NetworkLinkAddVlan(masterLink.name, tl.name, tl.id); err != nil {
+		t.Fatalf("Unable to create %#v VLAN interface: %s", tl, err)
+	}
+
+	readLink(t, tl.name)
+}
+
+func TestNetworkLinkAddMacVlan(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	tl := struct {
+		name string
+		mode string
+	}{
+		name: "tstVlan",
+		mode: "private",
+	}
+	masterLink := testLink{"tstEth", "dummy"}
+
+	addLink(t, masterLink.name, masterLink.linkType)
+	defer deleteLink(t, masterLink.name)
+
+	if err := NetworkLinkAddMacVlan(masterLink.name, tl.name, tl.mode); err != nil {
+		t.Fatalf("Unable to create %#v MAC VLAN interface: %s", tl, err)
+	}
+
+	readLink(t, tl.name)
+}
+
+func TestNetworkLinkAddMacVtap(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	tl := struct {
+		name string
+		mode string
+	}{
+		name: "tstVtap",
+		mode: "private",
+	}
+	masterLink := testLink{"tstEth", "dummy"}
+
+	addLink(t, masterLink.name, masterLink.linkType)
+	defer deleteLink(t, masterLink.name)
+
+	if err := NetworkLinkAddMacVtap(masterLink.name, tl.name, tl.mode); err != nil {
+		t.Fatalf("Unable to create %#v MAC VTAP interface: %s", tl, err)
+	}
+
+	readLink(t, tl.name)
+}
+
+func TestAddDelNetworkIp(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	ifaceName := "lo"
+	ip := net.ParseIP("127.0.1.1")
+	mask := net.IPv4Mask(255, 255, 255, 255)
+	ipNet := &net.IPNet{IP: ip, Mask: mask}
+
+	iface, err := net.InterfaceByName(ifaceName)
+	if err != nil {
+		t.Skip("No 'lo' interface; skipping tests")
+	}
+
+	if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
+		t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err)
+	}
+
+	if !ipAssigned(iface, ip) {
+		t.Fatalf("Could not locate address '%s' in lo address list.", ip.String())
+	}
+
+	if err := NetworkLinkDelIp(iface, ip, ipNet); err != nil {
+		t.Fatalf("Could not delete IP address %s from interface %#v: %s", ip.String(), iface, err)
+	}
+
+	if ipAssigned(iface, ip) {
+		t.Fatalf("Located address '%s' in lo address list after removal.", ip.String())
+	}
+}
+
+func TestAddRouteSourceSelection(t *testing.T) {
+	tstIp := "127.1.1.1"
+	tl := testLink{name: "tstEth", linkType: "dummy"}
+
+	addLink(t, tl.name, tl.linkType)
+	defer deleteLink(t, tl.name)
+
+	ip := net.ParseIP(tstIp)
+	mask := net.IPv4Mask(255, 255, 255, 255)
+	ipNet := &net.IPNet{IP: ip, Mask: mask}
+
+	iface, err := net.InterfaceByName(tl.name)
+	if err != nil {
+		t.Fatalf("Lost created link %#v", tl)
+	}
+
+	if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
+		t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err)
+	}
+
+	upLink(t, tl.name)
+	defer downLink(t, tl.name)
+
+	if err := AddRoute("127.0.0.0/8", tstIp, "", tl.name); err != nil {
+		t.Fatalf("Failed to add route with source address")
+	}
+}
+
+func TestCreateVethPair(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	var (
+		name1 = "veth1"
+		name2 = "veth2"
+	)
+
+	if err := NetworkCreateVethPair(name1, name2, 0); err != nil {
+		t.Fatalf("Could not create veth pair %s %s: %s", name1, name2, err)
+	}
+	defer NetworkLinkDel(name1)
+
+	readLink(t, name1)
+	readLink(t, name2)
+}
+
+//
+// netlink package tests which do not use RTNETLINK
+//
+func TestCreateBridgeWithMac(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	name := "testbridge"
+
+	if err := CreateBridge(name, true); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := net.InterfaceByName(name); err != nil {
+		t.Fatal(err)
+	}
+
+	// cleanup and tests
+
+	if err := DeleteBridge(name); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := net.InterfaceByName(name); err == nil {
+		t.Fatalf("expected error getting interface because %s bridge was deleted", name)
+	}
+}
+
+func TestSetMacAddress(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	name := "testmac"
+	mac := randMacAddr()
+
+	if err := NetworkLinkAdd(name, "bridge"); err != nil {
+		t.Fatal(err)
+	}
+	defer NetworkLinkDel(name)
+
+	if err := SetMacAddress(name, mac); err != nil {
+		t.Fatal(err)
+	}
+
+	iface, err := net.InterfaceByName(name)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if iface.HardwareAddr.String() != mac {
+		t.Fatalf("mac address %q does not match %q", iface.HardwareAddr, mac)
+	}
+}

+ 88 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go

@@ -0,0 +1,88 @@
+// +build !linux
+
+package netlink
+
+import (
+	"errors"
+	"net"
+)
+
+var (
+	ErrNotImplemented = errors.New("not implemented")
+)
+
+func NetworkGetRoutes() ([]Route, error) {
+	return nil, ErrNotImplemented
+}
+
+func NetworkLinkAdd(name string, linkType string) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkDel(name string) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkUp(iface *net.Interface) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+	return ErrNotImplemented
+}
+
+func AddRoute(destination, source, gateway, device string) error {
+	return ErrNotImplemented
+}
+
+func AddDefaultGw(ip, device string) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetMTU(iface *net.Interface, mtu int) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetTxQueueLen(iface *net.Interface, txQueueLen int) error {
+	return ErrNotImplemented
+}
+
+func NetworkCreateVethPair(name1, name2 string, txQueueLen int) error {
+	return ErrNotImplemented
+}
+
+func NetworkChangeName(iface *net.Interface, newName string) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetNsFd(iface *net.Interface, fd int) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetNsPid(iface *net.Interface, nspid int) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetMaster(iface, master *net.Interface) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkDown(iface *net.Interface) error {
+	return ErrNotImplemented
+}
+
+func CreateBridge(name string, setMacAddr bool) error {
+	return ErrNotImplemented
+}
+
+func DeleteBridge(name string) error {
+	return ErrNotImplemented
+}
+
+func AddToBridge(iface, master *net.Interface) error {
+	return ErrNotImplemented
+}

+ 11 - 5
libnetwork/circle.yml

@@ -1,14 +1,20 @@
 machine:
-    # sudo -E doesn't preserve $PATH, so go isn't found anymore.
     environment:
-        GO_BIN: $(which go)
-        GO_PATH: /home/ubuntu/.go_workspace/bin/
+        BASE_DIR: src/github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
+        CHECKOUT: /home/ubuntu/$CIRCLE_PROJECT_REPONAME
+    pre:
+        # sudo -E doesn't preserve $PATH, so go isn't found anymore.
+        - sudo ln -s $(which go) /usr/local/bin
+
+checkout:
+    post:
+        # We need docker/libnetwork itself in the GOPATH for imports to work.
+        - ln -s $CHECKOUT $(echo $GOPATH | cut -d":" -f1)/$BASE_DIR
 
 dependencies:
     override:
         - go get github.com/tools/godep
     post:
-        - go get github.com/axw/gocov/gocov
         - go get github.com/golang/lint/golint
         - go get golang.org/x/tools/cmd/goimports
 
@@ -17,5 +23,5 @@ test:
         - test -z "$(goimports -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
         - go vet ./...
         - test -z "$(golint ./... | tee /dev/stderr)"
-        - sudo -E $GO_BIN test -test.v ./...
+        - sudo -E $(which godep) go test -test.v ./...