diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 93e9b41..cf11720 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,44 +1,31 @@ { "ImportPath": "github.com/docker/libnetwork", - "GoVersion": "go1.4.2", - "Packages": [ - "./..." - ], + "GoVersion": "go1.2.1", "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/iptables", - "Comment": "v1.4.1-1379-g8e107a9", - "Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05" + "Comment": "v1.4.1-2492-ge690ad9", + "Rev": "e690ad92925a045344bde8d2d59d7a7f602dded6" }, { "ImportPath": "github.com/docker/docker/pkg/parsers/kernel", - "Comment": "v1.4.1-1379-g8e107a9", - "Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05" + "Comment": "v1.4.1-2492-ge690ad9", + "Rev": "e690ad92925a045344bde8d2d59d7a7f602dded6" }, { "ImportPath": "github.com/docker/docker/pkg/proxy", - "Comment": "v1.4.1-1379-g8e107a9", - "Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05" + "Comment": "v1.4.1-2492-ge690ad9", + "Rev": "e690ad92925a045344bde8d2d59d7a7f602dded6" }, { "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" + "Comment": "v1.4.1-2492-ge690ad9", + "Rev": "e690ad92925a045344bde8d2d59d7a7f602dded6" }, { "ImportPath": "github.com/vishvananda/netlink", diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver.go deleted file mode 100644 index 5f7ae9c..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver.go +++ /dev/null @@ -1,720 +0,0 @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver_test.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver_test.go deleted file mode 100644 index 02bea9c..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver_test.go +++ /dev/null @@ -1,161 +0,0 @@ -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) - } - -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator.go deleted file mode 100644 index a728d1b..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator.go +++ /dev/null @@ -1,160 +0,0 @@ -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()) -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator_test.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator_test.go deleted file mode 100644 index 8e0d8fd..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator_test.go +++ /dev/null @@ -1,681 +0,0 @@ -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() - } -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network.go deleted file mode 100644 index 8dda789..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network.go +++ /dev/null @@ -1,10 +0,0 @@ -package networkdriver - -import ( - "errors" -) - -var ( - ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver") - ErrNetworkOverlaps = errors.New("requested network overlaps with existing network") -) diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network_test.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network_test.go deleted file mode 100644 index 1a6336b..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network_test.go +++ /dev/null @@ -1,175 +0,0 @@ -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()) - } -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator.go deleted file mode 100644 index 3414d11..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator.go +++ /dev/null @@ -1,153 +0,0 @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator_test.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator_test.go deleted file mode 100644 index 72581f1..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator_test.go +++ /dev/null @@ -1,245 +0,0 @@ -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) - } -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper.go deleted file mode 100644 index 9f2ca5a..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper.go +++ /dev/null @@ -1,176 +0,0 @@ -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) -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper_test.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper_test.go deleted file mode 100644 index 42e44a1..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper_test.go +++ /dev/null @@ -1,152 +0,0 @@ -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{} - } -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mock_proxy.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mock_proxy.go deleted file mode 100644 index 253ce83..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mock_proxy.go +++ /dev/null @@ -1,18 +0,0 @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/proxy.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/proxy.go deleted file mode 100644 index 5d0aa0b..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/proxy.go +++ /dev/null @@ -1,161 +0,0 @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/utils.go b/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/utils.go deleted file mode 100644 index 9f0c88c..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/utils.go +++ /dev/null @@ -1,118 +0,0 @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/MAINTAINERS b/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/MAINTAINERS deleted file mode 100644 index 134b02a..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/MAINTAINERS +++ /dev/null @@ -1,2 +0,0 @@ -Michael Crosby (@crosbymichael) -Jessie Frazelle (@jfrazelle) diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/iptables.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/iptables.go index 010c99b..f8b3aa7 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/iptables.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/iptables.go @@ -9,7 +9,7 @@ import ( "strconv" "strings" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" ) type Action string @@ -21,6 +21,7 @@ const ( Insert Action = "-I" Nat Table = "nat" Filter Table = "filter" + Mangle Table = "mangle" ) var ( @@ -82,7 +83,7 @@ func NewChain(name, bridge string, table Table) (*Chain, error) { preroute := []string{ "-m", "addrtype", "--dst-type", "LOCAL"} - if !Exists(preroute...) { + if !Exists(Nat, "PREROUTING", preroute...) { if err := c.Prerouting(Append, preroute...); err != nil { return nil, fmt.Errorf("Failed to inject docker in PREROUTING chain: %s", err) } @@ -91,17 +92,17 @@ func NewChain(name, bridge string, table Table) (*Chain, error) { "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8"} - if !Exists(output...) { + if !Exists(Nat, "OUTPUT", output...) { if err := c.Output(Append, output...); err != nil { return nil, fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err) } } case Filter: - link := []string{"FORWARD", + link := []string{ "-o", c.Bridge, "-j", c.Name} - if !Exists(link...) { - insert := append([]string{string(Insert)}, link...) + if !Exists(Filter, "FORWARD", link...) { + insert := append([]string{string(Insert), "FORWARD"}, link...) if output, err := Raw(insert...); err != nil { return nil, err } else if len(output) != 0 { @@ -242,19 +243,25 @@ func (c *Chain) Remove() error { } // Check if a rule exists -func Exists(args ...string) bool { +func Exists(table Table, chain string, rule ...string) bool { + if string(table) == "" { + table = Filter + } + // iptables -C, --check option was added in v.1.4.11 // http://ftp.netfilter.org/pub/iptables/changes-iptables-1.4.11.txt // try -C // if exit status is 0 then return true, the rule exists - if _, err := Raw(append([]string{"-C"}, args...)...); err == nil { + if _, err := Raw(append([]string{ + "-t", string(table), "-C", chain}, rule...)...); err == nil { return true } - // parse iptables-save for the rule - rule := strings.Replace(strings.Join(args, " "), "-t nat ", "", -1) - existingRules, _ := exec.Command("iptables-save").Output() + // parse "iptables -S" for the rule (this checks rules in a specific chain + // in a specific table) + ruleString := strings.Join(rule, " ") + existingRules, _ := exec.Command("iptables", "-t", string(table), "-S", chain).Output() // regex to replace ips in rule // because MASQUERADE rule will not be exactly what was passed @@ -262,7 +269,7 @@ func Exists(args ...string) bool { return strings.Contains( re.ReplaceAllString(string(existingRules), "?"), - re.ReplaceAllString(rule, "?"), + re.ReplaceAllString(ruleString, "?"), ) } @@ -276,7 +283,7 @@ func Raw(args ...string) ([]byte, error) { args = append([]string{"--wait"}, args...) } - log.Debugf("%s, %v", iptablesPath, args) + logrus.Debugf("%s, %v", iptablesPath, args) output, err := exec.Command(iptablesPath, args...).CombinedOutput() if err != nil { diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/iptables_test.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/iptables_test.go index 8aaf429..ced4262 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/iptables_test.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/iptables/iptables_test.go @@ -39,8 +39,7 @@ func TestForward(t *testing.T) { t.Fatal(err) } - dnatRule := []string{natChain.Name, - "-t", string(natChain.Table), + dnatRule := []string{ "!", "-i", filterChain.Bridge, "-d", ip.String(), "-p", proto, @@ -49,12 +48,11 @@ func TestForward(t *testing.T) { "--to-destination", dstAddr + ":" + strconv.Itoa(dstPort), } - if !Exists(dnatRule...) { + if !Exists(natChain.Table, natChain.Name, dnatRule...) { t.Fatalf("DNAT rule does not exist") } - filterRule := []string{filterChain.Name, - "-t", string(filterChain.Table), + filterRule := []string{ "!", "-i", filterChain.Bridge, "-o", filterChain.Bridge, "-d", dstAddr, @@ -63,12 +61,11 @@ func TestForward(t *testing.T) { "-j", "ACCEPT", } - if !Exists(filterRule...) { + if !Exists(filterChain.Table, filterChain.Name, filterRule...) { t.Fatalf("filter rule does not exist") } - masqRule := []string{"POSTROUTING", - "-t", string(natChain.Table), + masqRule := []string{ "-d", dstAddr, "-s", dstAddr, "-p", proto, @@ -76,7 +73,7 @@ func TestForward(t *testing.T) { "-j", "MASQUERADE", } - if !Exists(masqRule...) { + if !Exists(natChain.Table, "POSTROUTING", masqRule...) { t.Fatalf("MASQUERADE rule does not exist") } } @@ -94,8 +91,7 @@ func TestLink(t *testing.T) { t.Fatal(err) } - rule1 := []string{filterChain.Name, - "-t", string(filterChain.Table), + rule1 := []string{ "-i", filterChain.Bridge, "-o", filterChain.Bridge, "-p", proto, @@ -104,12 +100,11 @@ func TestLink(t *testing.T) { "--dport", strconv.Itoa(port), "-j", "ACCEPT"} - if !Exists(rule1...) { + if !Exists(filterChain.Table, filterChain.Name, rule1...) { t.Fatalf("rule1 does not exist") } - rule2 := []string{filterChain.Name, - "-t", string(filterChain.Table), + rule2 := []string{ "-i", filterChain.Bridge, "-o", filterChain.Bridge, "-p", proto, @@ -118,7 +113,7 @@ func TestLink(t *testing.T) { "--sport", strconv.Itoa(port), "-j", "ACCEPT"} - if !Exists(rule2...) { + if !Exists(filterChain.Table, filterChain.Name, rule2...) { t.Fatalf("rule2 does not exist") } } @@ -133,17 +128,16 @@ func TestPrerouting(t *testing.T) { t.Fatal(err) } - rule := []string{"PREROUTING", - "-t", string(Nat), + rule := []string{ "-j", natChain.Name} rule = append(rule, args...) - if !Exists(rule...) { + if !Exists(natChain.Table, "PREROUTING", rule...) { t.Fatalf("rule does not exist") } - delRule := append([]string{"-D"}, rule...) + delRule := append([]string{"-D", "PREROUTING", "-t", string(Nat)}, rule...) if _, err = Raw(delRule...); err != nil { t.Fatal(err) } @@ -159,17 +153,17 @@ func TestOutput(t *testing.T) { t.Fatal(err) } - rule := []string{"OUTPUT", - "-t", string(natChain.Table), + rule := []string{ "-j", natChain.Name} rule = append(rule, args...) - if !Exists(rule...) { + if !Exists(natChain.Table, "OUTPUT", rule...) { t.Fatalf("rule does not exist") } - delRule := append([]string{"-D"}, rule...) + delRule := append([]string{"-D", "OUTPUT", "-t", + string(natChain.Table)}, rule...) if _, err = Raw(delRule...); err != nil { t.Fatal(err) } diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/MAINTAINERS b/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/MAINTAINERS deleted file mode 100644 index 8c89025..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/MAINTAINERS +++ /dev/null @@ -1 +0,0 @@ -Erik Hollensbe (@erikh) diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/tcp_proxy.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/tcp_proxy.go index eacf142..9942e6d 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/tcp_proxy.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/tcp_proxy.go @@ -5,7 +5,7 @@ import ( "net" "syscall" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" ) type TCPProxy struct { @@ -31,7 +31,7 @@ func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) { func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) { backend, err := net.DialTCP("tcp", nil, proxy.backendAddr) if err != nil { - log.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err) + logrus.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err) client.Close() return } @@ -78,7 +78,7 @@ func (proxy *TCPProxy) Run() { for { client, err := proxy.listener.Accept() if err != nil { - log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) + logrus.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) return } go proxy.clientLoop(client.(*net.TCPConn), quit) diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/udp_proxy.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/udp_proxy.go index a3fcf11..2a073df 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/udp_proxy.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/proxy/udp_proxy.go @@ -8,7 +8,7 @@ import ( "syscall" "time" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" ) const ( @@ -105,7 +105,7 @@ func (proxy *UDPProxy) Run() { // ECONNREFUSED like Read do (see comment in // UDPProxy.replyLoop) if !isClosedError(err) { - log.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) + logrus.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) } break } @@ -116,7 +116,7 @@ func (proxy *UDPProxy) Run() { if !hit { proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr) if err != nil { - log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) + logrus.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) proxy.connTrackLock.Unlock() continue } @@ -127,7 +127,7 @@ func (proxy *UDPProxy) Run() { for i := 0; i != read; { written, err := proxyConn.Write(readBuf[i:read]) if err != nil { - log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) + logrus.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) break } i += written diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/MAINTAINERS b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/MAINTAINERS deleted file mode 100644 index e48a0c7..0000000 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/MAINTAINERS +++ /dev/null @@ -1 +0,0 @@ -Michael Crosby (@crosbymichael) diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/reexec.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/reexec.go index 774e71c..a5f01a2 100644 --- a/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/reexec.go +++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/reexec/reexec.go @@ -35,8 +35,14 @@ func Self() string { name := os.Args[0] if filepath.Base(name) == name { if lp, err := exec.LookPath(name); err == nil { - name = lp + return lp } } + // handle conversion of relative paths to absolute + if absName, err := filepath.Abs(name); err == nil { + return absName + } + // if we coudn't get absolute name, return original + // (NOTE: Go only errors on Abs() if os.Getwd fails) return name } diff --git a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS b/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS deleted file mode 100644 index 1cb5513..0000000 --- a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS +++ /dev/null @@ -1,2 +0,0 @@ -Michael Crosby (@crosbymichael) -Guillaume J. Charmes (@creack) diff --git a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go b/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go deleted file mode 100644 index 9088366..0000000 --- a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go +++ /dev/null @@ -1,31 +0,0 @@ -// 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 -} diff --git a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go b/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go deleted file mode 100644 index 3ecb81f..0000000 --- a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go +++ /dev/null @@ -1,1307 +0,0 @@ -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 -} diff --git a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go b/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go deleted file mode 100644 index 779e58a..0000000 --- a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go +++ /dev/null @@ -1,5 +0,0 @@ -package netlink - -func ifrDataByte(b byte) uint8 { - return uint8(b) -} diff --git a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go b/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go deleted file mode 100644 index f151722..0000000 --- a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !arm - -package netlink - -func ifrDataByte(b byte) int8 { - return int8(b) -} diff --git a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go b/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go deleted file mode 100644 index 3f6511a..0000000 --- a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go +++ /dev/null @@ -1,408 +0,0 @@ -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) - } -} diff --git a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go b/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go deleted file mode 100644 index 4b11bf8..0000000 --- a/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go +++ /dev/null @@ -1,88 +0,0 @@ -// +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 -} diff --git a/drivers/bridge/bridge.go b/drivers/bridge/bridge.go index fb62bfa..39deb5c 100644 --- a/drivers/bridge/bridge.go +++ b/drivers/bridge/bridge.go @@ -2,8 +2,11 @@ package bridge import ( "net" + "sync" "github.com/docker/libnetwork" + "github.com/docker/libnetwork/ipallocator" + "github.com/docker/libnetwork/portmapper" ) const ( @@ -11,6 +14,18 @@ const ( vethPrefix = "veth" ) +var ( + once sync.Once + ipAllocator *ipallocator.IPAllocator + portMapper *portmapper.PortMapper +) + +func initPortMapper() { + once.Do(func() { + portMapper = portmapper.New() + }) +} + // Configuration info for the "simplebridge" driver. type Configuration struct { BridgeName string @@ -27,6 +42,8 @@ type Configuration struct { type driver struct{} func init() { + ipAllocator = ipallocator.New() + initPortMapper() libnetwork.RegisterNetworkType(networkType, &driver{}, &Configuration{}) } diff --git a/drivers/bridge/network.go b/drivers/bridge/network.go index a4df0db..75fad89 100644 --- a/drivers/bridge/network.go +++ b/drivers/bridge/network.go @@ -7,7 +7,6 @@ import ( "github.com/docker/libcontainer/utils" "github.com/docker/libnetwork" - "github.com/docker/libnetwork/ipallocator" "github.com/vishvananda/netlink" ) @@ -78,14 +77,14 @@ func (b *bridgeNetwork) Link(name string) ([]*libnetwork.Interface, error) { return nil, err } - ip4, err := ipallocator.RequestIP(b.bridge.bridgeIPv4, nil) + ip4, err := ipAllocator.RequestIP(b.bridge.bridgeIPv4, nil) if err != nil { return nil, err } ipv4Addr := net.IPNet{IP: ip4, Mask: b.bridge.bridgeIPv4.Mask} if b.bridge.Config.EnableIPv6 { - ip6, err := ipallocator.RequestIP(b.bridge.bridgeIPv6, nil) + ip6, err := ipAllocator.RequestIP(b.bridge.bridgeIPv6, nil) if err != nil { return nil, err } diff --git a/drivers/bridge/setup_fixedcidrv4.go b/drivers/bridge/setup_fixedcidrv4.go index ee94d2d..4c2b9b9 100644 --- a/drivers/bridge/setup_fixedcidrv4.go +++ b/drivers/bridge/setup_fixedcidrv4.go @@ -4,7 +4,6 @@ import ( "fmt" log "github.com/Sirupsen/logrus" - "github.com/docker/libnetwork/ipallocator" ) func setupFixedCIDRv4(i *bridgeInterface) error { @@ -14,7 +13,7 @@ func setupFixedCIDRv4(i *bridgeInterface) error { } log.Debugf("Using IPv4 subnet: %v", i.Config.FixedCIDR) - if err := ipallocator.RegisterSubnet(addrv4.IPNet, i.Config.FixedCIDR); err != nil { + if err := ipAllocator.RegisterSubnet(addrv4.IPNet, i.Config.FixedCIDR); err != nil { return fmt.Errorf("Setup FixedCIDRv4 failed for subnet %s in %s: %v", i.Config.FixedCIDR, addrv4.IPNet, err) } diff --git a/drivers/bridge/setup_fixedcidrv4_test.go b/drivers/bridge/setup_fixedcidrv4_test.go index 964f339..8913c7e 100644 --- a/drivers/bridge/setup_fixedcidrv4_test.go +++ b/drivers/bridge/setup_fixedcidrv4_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/docker/libnetwork" - "github.com/docker/libnetwork/ipallocator" ) func TestSetupFixedCIDRv4(t *testing.T) { @@ -29,7 +28,7 @@ func TestSetupFixedCIDRv4(t *testing.T) { t.Fatalf("Failed to setup bridge FixedCIDRv4: %v", err) } - if ip, err := ipallocator.RequestIP(br.Config.FixedCIDR, nil); err != nil { + if ip, err := ipAllocator.RequestIP(br.Config.FixedCIDR, nil); err != nil { t.Fatalf("Failed to request IP to allocator: %v", err) } else if expected := "192.168.2.1"; ip.String() != expected { t.Fatalf("Expected allocated IP %s, got %s", expected, ip) diff --git a/drivers/bridge/setup_fixedcidrv6.go b/drivers/bridge/setup_fixedcidrv6.go index d272ded..6aca274 100644 --- a/drivers/bridge/setup_fixedcidrv6.go +++ b/drivers/bridge/setup_fixedcidrv6.go @@ -4,12 +4,11 @@ import ( "fmt" log "github.com/Sirupsen/logrus" - "github.com/docker/libnetwork/ipallocator" ) func setupFixedCIDRv6(i *bridgeInterface) error { log.Debugf("Using IPv6 subnet: %v", i.Config.FixedCIDRv6) - if err := ipallocator.RegisterSubnet(i.Config.FixedCIDRv6, i.Config.FixedCIDRv6); err != nil { + if err := ipAllocator.RegisterSubnet(i.Config.FixedCIDRv6, i.Config.FixedCIDRv6); err != nil { return fmt.Errorf("Setup FixedCIDRv6 failed for subnet %s in %s: %v", i.Config.FixedCIDRv6, i.Config.FixedCIDRv6, err) } diff --git a/drivers/bridge/setup_fixedcidrv6_test.go b/drivers/bridge/setup_fixedcidrv6_test.go index 2cc3534..2d185f3 100644 --- a/drivers/bridge/setup_fixedcidrv6_test.go +++ b/drivers/bridge/setup_fixedcidrv6_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/docker/libnetwork" - "github.com/docker/libnetwork/ipallocator" ) func TestSetupFixedCIDRv6(t *testing.T) { @@ -29,7 +28,7 @@ func TestSetupFixedCIDRv6(t *testing.T) { t.Fatalf("Failed to setup bridge FixedCIDRv6: %v", err) } - if ip, err := ipallocator.RequestIP(br.Config.FixedCIDRv6, nil); err != nil { + if ip, err := ipAllocator.RequestIP(br.Config.FixedCIDRv6, nil); err != nil { t.Fatalf("Failed to request IP to allocator: %v", err) } else if expected := "2002:db8::1"; ip.String() != expected { t.Fatalf("Expected allocated IP %s, got %s", expected, ip) diff --git a/drivers/bridge/setup_ip_tables.go b/drivers/bridge/setup_ip_tables.go index c2ef682..f74c5a7 100644 --- a/drivers/bridge/setup_ip_tables.go +++ b/drivers/bridge/setup_ip_tables.go @@ -6,7 +6,6 @@ import ( "github.com/docker/docker/pkg/iptables" "github.com/docker/libnetwork" - "github.com/docker/libnetwork/portmapper" ) // DockerChain: DOCKER iptable chain name @@ -38,17 +37,25 @@ func setupIPTables(i *bridgeInterface) error { return fmt.Errorf("Failed to create FILTER chain: %s", err.Error()) } - portmapper.SetIptablesChain(chain) + portMapper.SetIptablesChain(chain) return nil } +type iptRule struct { + table iptables.Table + chain string + preArgs []string + args []string +} + func setupIPTablesInternal(bridgeIface string, addr net.Addr, icc, ipmasq, enable bool) error { + var ( address = addr.String() - natRule = []string{"POSTROUTING", "-t", "nat", "-s", address, "!", "-o", bridgeIface, "-j", "MASQUERADE"} - outRule = []string{"FORWARD", "-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"} - inRule = []string{"FORWARD", "-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"} + natRule = iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-s", address, "!", "-o", bridgeIface, "-j", "MASQUERADE"}} + outRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}} + inRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}} ) // Set NAT. @@ -76,28 +83,32 @@ func setupIPTablesInternal(bridgeIface string, addr net.Addr, icc, ipmasq, enabl return nil } -func programChainRule(ruleArgs []string, ruleDescr string, insert bool) error { +func programChainRule(rule iptRule, ruleDescr string, insert bool) error { var ( prefix []string operation string condition bool + doesExist = iptables.Exists(rule.table, rule.chain, rule.args...) ) if insert { - condition = !iptables.Exists(ruleArgs...) - prefix = []string{"-I"} + condition = !doesExist + prefix = []string{"-I", rule.chain} operation = "enable" } else { - condition = iptables.Exists(ruleArgs...) - prefix = []string{"-D"} + condition = doesExist + prefix = []string{"-D", rule.chain} operation = "disable" } + if rule.preArgs != nil { + prefix = append(rule.preArgs, prefix...) + } if condition { - if output, err := iptables.Raw(append(prefix, ruleArgs...)...); err != nil { + if output, err := iptables.Raw(append(prefix, rule.args...)...); err != nil { return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error()) } else if len(output) != 0 { - return &iptables.ChainError{Chain: ruleDescr, Output: output} + return &iptables.ChainError{Chain: rule.chain, Output: output} } } @@ -106,27 +117,29 @@ func programChainRule(ruleArgs []string, ruleDescr string, insert bool) error { func setIcc(bridgeIface string, iccEnable, insert bool) error { var ( - args = []string{"FORWARD", "-i", bridgeIface, "-o", bridgeIface, "-j"} + table = iptables.Filter + chain = "FORWARD" + args = []string{"-i", bridgeIface, "-o", bridgeIface, "-j"} acceptArgs = append(args, "ACCEPT") dropArgs = append(args, "DROP") ) if insert { if !iccEnable { - iptables.Raw(append([]string{"-D"}, acceptArgs...)...) + iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...) - if !iptables.Exists(dropArgs...) { - if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil { + if !iptables.Exists(table, chain, dropArgs...) { + if output, err := iptables.Raw(append([]string{"-I", chain}, dropArgs...)...); err != nil { return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error()) } else if len(output) != 0 { return fmt.Errorf("Error disabling intercontainer communication: %s", output) } } } else { - iptables.Raw(append([]string{"-D"}, dropArgs...)...) + iptables.Raw(append([]string{"-D", chain}, dropArgs...)...) - if !iptables.Exists(acceptArgs...) { - if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil { + if !iptables.Exists(table, chain, acceptArgs...) { + if output, err := iptables.Raw(append([]string{"-I", chain}, acceptArgs...)...); err != nil { return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error()) } else if len(output) != 0 { return fmt.Errorf("Error enabling intercontainer communication: %s", output) @@ -136,12 +149,12 @@ func setIcc(bridgeIface string, iccEnable, insert bool) error { } else { // Remove any ICC rule. if !iccEnable { - if iptables.Exists(dropArgs...) { - iptables.Raw(append([]string{"-D"}, dropArgs...)...) + if iptables.Exists(table, chain, dropArgs...) { + iptables.Raw(append([]string{"-D", chain}, dropArgs...)...) } } else { - if iptables.Exists(acceptArgs...) { - iptables.Raw(append([]string{"-D"}, acceptArgs...)...) + if iptables.Exists(table, chain, acceptArgs...) { + iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...) } } } diff --git a/drivers/bridge/setup_ip_tables_test.go b/drivers/bridge/setup_ip_tables_test.go index 1f0d967..ca2913f 100644 --- a/drivers/bridge/setup_ip_tables_test.go +++ b/drivers/bridge/setup_ip_tables_test.go @@ -19,19 +19,20 @@ func TestProgramIPTable(t *testing.T) { // Store various iptables chain rules we care for. rules := []struct { - ruleArgs []string - descr string - }{{[]string{"FORWARD", "-d", "127.1.2.3", "-i", "lo", "-o", "lo", "-j", "DROP"}, "Test Loopback"}, - {[]string{"POSTROUTING", "-t", "nat", "-s", iptablesTestBridgeIP, "!", "-o", DefaultBridgeName, "-j", "MASQUERADE"}, "NAT Test"}, - {[]string{"FORWARD", "-i", DefaultBridgeName, "!", "-o", DefaultBridgeName, "-j", "ACCEPT"}, "Test ACCEPT NON_ICC OUTGOING"}, - {[]string{"FORWARD", "-o", DefaultBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}, "Test ACCEPT INCOMING"}, - {[]string{"FORWARD", "-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "ACCEPT"}, "Test enable ICC"}, - {[]string{"FORWARD", "-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "DROP"}, "Test disable ICC"}, + rule iptRule + descr string + }{ + {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-d", "127.1.2.3", "-i", "lo", "-o", "lo", "-j", "DROP"}}, "Test Loopback"}, + {iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-s", iptablesTestBridgeIP, "!", "-o", DefaultBridgeName, "-j", "MASQUERADE"}}, "NAT Test"}, + {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "!", "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test ACCEPT NON_ICC OUTGOING"}, + {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", DefaultBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}}, "Test ACCEPT INCOMING"}, + {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test enable ICC"}, + {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "DROP"}}, "Test disable ICC"}, } // Assert the chain rules' insertion and removal. for _, c := range rules { - assertIPTableChainProgramming(c.ruleArgs, c.descr, t) + assertIPTableChainProgramming(c.rule, c.descr, t) } } @@ -74,20 +75,20 @@ func createTestBridge(br *bridgeInterface, t *testing.T) { } // Assert base function which pushes iptables chain rules on insertion and removal. -func assertIPTableChainProgramming(args []string, descr string, t *testing.T) { +func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) { // Add - if err := programChainRule(args, descr, true); err != nil { + if err := programChainRule(rule, descr, true); err != nil { t.Fatalf("Failed to program iptable rule %s: %s", descr, err.Error()) } - if iptables.Exists(args...) == false { + if iptables.Exists(rule.table, rule.chain, rule.args...) == false { t.Fatalf("Failed to effectively program iptable rule: %s", descr) } // Remove - if err := programChainRule(args, descr, false); err != nil { + if err := programChainRule(rule, descr, false); err != nil { t.Fatalf("Failed to remove iptable rule %s: %s", descr, err.Error()) } - if iptables.Exists(args...) == true { + if iptables.Exists(rule.table, rule.chain, rule.args...) == true { t.Fatalf("Failed to effectively remove iptable rule: %s", descr) } } diff --git a/ipallocator/allocator.go b/ipallocator/allocator.go index 7f0c566..9783456 100644 --- a/ipallocator/allocator.go +++ b/ipallocator/allocator.go @@ -8,7 +8,7 @@ import ( "net" "sync" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/libnetwork" ) @@ -48,19 +48,26 @@ var ( ErrBadSubnet = errors.New("network does not contain specified subnet") ) -var ( - lock = sync.Mutex{} - allocatedIPs = networkSet{} -) +// IPAllocator manages the ipam +type IPAllocator struct { + allocatedIPs networkSet + mutex sync.Mutex +} + +// New returns a new instance of IPAllocator +func New() *IPAllocator { + return &IPAllocator{networkSet{}, sync.Mutex{}} +} // 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() +func (a *IPAllocator) RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error { + a.mutex.Lock() + defer a.mutex.Unlock() + key := network.String() - if _, ok := allocatedIPs[key]; ok { + if _, ok := a.allocatedIPs[key]; ok { return ErrNetworkAlreadyRegistered } n := newAllocatedMap(network) @@ -75,7 +82,7 @@ func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error { n.begin.Set(begin) n.end.Set(end) n.last.Sub(begin, big.NewInt(1)) - allocatedIPs[key] = n + a.allocatedIPs[key] = n return nil } @@ -83,14 +90,15 @@ func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error { // 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() +func (a *IPAllocator) RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) { + a.mutex.Lock() + defer a.mutex.Unlock() + key := network.String() - allocated, ok := allocatedIPs[key] + allocated, ok := a.allocatedIPs[key] if !ok { allocated = newAllocatedMap(network) - allocatedIPs[key] = allocated + a.allocatedIPs[key] = allocated } if ip == nil { @@ -101,10 +109,11 @@ func RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) { // 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 { +func (a *IPAllocator) ReleaseIP(network *net.IPNet, ip net.IP) error { + a.mutex.Lock() + defer a.mutex.Unlock() + + if allocated, exists := a.allocatedIPs[network.String()]; exists { delete(allocated.p, ip.String()) } return nil @@ -128,7 +137,7 @@ func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) { } // return an available ip if one is currently available. If not, -// return the next available ip for the nextwork +// return the next available ip for the network func (allocated *allocatedMap) getNextIP() (net.IP, error) { pos := big.NewInt(0).Set(allocated.last) allRange := big.NewInt(0).Sub(allocated.end, allocated.begin) @@ -157,7 +166,7 @@ func ipToBigInt(ip net.IP) *big.Int { return x.SetBytes(ip6) } - log.Errorf("ipToBigInt: Wrong IP length! %s", ip) + logrus.Errorf("ipToBigInt: Wrong IP length! %s", ip) return nil } diff --git a/ipallocator/allocator_test.go b/ipallocator/allocator_test.go index 8e0d8fd..fffe6e3 100644 --- a/ipallocator/allocator_test.go +++ b/ipallocator/allocator_test.go @@ -7,10 +7,6 @@ import ( "testing" ) -func reset() { - allocatedIPs = networkSet{} -} - func TestConversion(t *testing.T) { ip := net.ParseIP("127.0.0.1") i := ipToBigInt(ip) @@ -52,7 +48,8 @@ func TestConversionIPv6(t *testing.T) { } func TestRequestNewIps(t *testing.T) { - defer reset() + a := New() + network := &net.IPNet{ IP: []byte{192, 168, 0, 1}, Mask: []byte{255, 255, 255, 0}, @@ -62,7 +59,7 @@ func TestRequestNewIps(t *testing.T) { var err error for i := 1; i < 10; i++ { - ip, err = RequestIP(network, nil) + ip, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -72,10 +69,10 @@ func TestRequestNewIps(t *testing.T) { } } value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String() - if err := ReleaseIP(network, ip); err != nil { + if err := a.ReleaseIP(network, ip); err != nil { t.Fatal(err) } - ip, err = RequestIP(network, nil) + ip, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -85,7 +82,8 @@ func TestRequestNewIps(t *testing.T) { } func TestRequestNewIpV6(t *testing.T) { - defer reset() + a := New() + 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 @@ -94,7 +92,7 @@ func TestRequestNewIpV6(t *testing.T) { var ip net.IP var err error for i := 1; i < 10; i++ { - ip, err = RequestIP(network, nil) + ip, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -104,10 +102,10 @@ func TestRequestNewIpV6(t *testing.T) { } } value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String() - if err := ReleaseIP(network, ip); err != nil { + if err := a.ReleaseIP(network, ip); err != nil { t.Fatal(err) } - ip, err = RequestIP(network, nil) + ip, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -117,68 +115,70 @@ func TestRequestNewIpV6(t *testing.T) { } func TestReleaseIp(t *testing.T) { - defer reset() + a := New() + network := &net.IPNet{ IP: []byte{192, 168, 0, 1}, Mask: []byte{255, 255, 255, 0}, } - ip, err := RequestIP(network, nil) + ip, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } - if err := ReleaseIP(network, ip); err != nil { + if err := a.ReleaseIP(network, ip); err != nil { t.Fatal(err) } } func TestReleaseIpV6(t *testing.T) { - defer reset() + a := New() + 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) + ip, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } - if err := ReleaseIP(network, ip); err != nil { + if err := a.ReleaseIP(network, ip); err != nil { t.Fatal(err) } } func TestGetReleasedIp(t *testing.T) { - defer reset() + a := New() network := &net.IPNet{ IP: []byte{192, 168, 0, 1}, Mask: []byte{255, 255, 255, 0}, } - ip, err := RequestIP(network, nil) + ip, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } value := ip.String() - if err := ReleaseIP(network, ip); err != nil { + if err := a.ReleaseIP(network, ip); err != nil { t.Fatal(err) } for i := 0; i < 253; i++ { - _, err = RequestIP(network, nil) + _, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } - err = ReleaseIP(network, ip) + err = a.ReleaseIP(network, ip) if err != nil { t.Fatal(err) } } - ip, err = RequestIP(network, nil) + ip, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -189,34 +189,35 @@ func TestGetReleasedIp(t *testing.T) { } func TestGetReleasedIpV6(t *testing.T) { - defer reset() + a := New() + 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) + ip, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } value := ip.String() - if err := ReleaseIP(network, ip); err != nil { + if err := a.ReleaseIP(network, ip); err != nil { t.Fatal(err) } for i := 0; i < 253; i++ { - _, err = RequestIP(network, nil) + _, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } - err = ReleaseIP(network, ip) + err = a.ReleaseIP(network, ip) if err != nil { t.Fatal(err) } } - ip, err = RequestIP(network, nil) + ip, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -227,7 +228,8 @@ func TestGetReleasedIpV6(t *testing.T) { } func TestRequestSpecificIp(t *testing.T) { - defer reset() + a := New() + network := &net.IPNet{ IP: []byte{192, 168, 0, 1}, Mask: []byte{255, 255, 255, 224}, @@ -236,23 +238,24 @@ func TestRequestSpecificIp(t *testing.T) { ip := net.ParseIP("192.168.0.5") // Request a "good" IP. - if _, err := RequestIP(network, ip); err != nil { + if _, err := a.RequestIP(network, ip); err != nil { t.Fatal(err) } // Request the same IP again. - if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated { + if _, err := a.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 { + if _, err := a.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() + a := New() + 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 @@ -261,22 +264,24 @@ func TestRequestSpecificIpV6(t *testing.T) { ip := net.ParseIP("2a00:1450::5") // Request a "good" IP. - if _, err := RequestIP(network, ip); err != nil { + if _, err := a.RequestIP(network, ip); err != nil { t.Fatal(err) } // Request the same IP again. - if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated { + if _, err := a.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 { + if _, err := a.RequestIP(network, net.ParseIP("2a00:1500::1")); err != ErrIPOutOfRange { t.Fatalf("Got an out of range IP: %#v", err) } } func TestIPAllocator(t *testing.T) { + a := New() + expectedIPs := []net.IP{ 0: net.IPv4(127, 0, 0, 1), 1: net.IPv4(127, 0, 0, 2), @@ -296,7 +301,7 @@ func TestIPAllocator(t *testing.T) { // 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) + ip, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -332,25 +337,25 @@ func TestIPAllocator(t *testing.T) { // ↑ // Check that there are no more IPs - ip, err := RequestIP(network, nil) + ip, err := a.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 { + if err := a.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 { + if err := a.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 { + if err := a.ReleaseIP(network, expectedIPs[4]); err != nil { t.Fatal(err) } // 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(u) @@ -360,7 +365,7 @@ func TestIPAllocator(t *testing.T) { // with the first released IP newIPs := make([]net.IP, 3) for i := 0; i < 3; i++ { - ip, err := RequestIP(network, nil) + ip, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -371,14 +376,15 @@ func TestIPAllocator(t *testing.T) { assertIPEquals(t, expectedIPs[3], newIPs[1]) assertIPEquals(t, expectedIPs[4], newIPs[2]) - _, err = RequestIP(network, nil) + _, err = a.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() + a := New() + network := &net.IPNet{ IP: []byte{192, 168, 0, 0}, Mask: []byte{255, 255, 255, 0}, @@ -387,7 +393,7 @@ func TestAllocateFirstIP(t *testing.T) { firstIP := network.IP.To4().Mask(network.Mask) first := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1)) - ip, err := RequestIP(network, nil) + ip, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -399,7 +405,8 @@ func TestAllocateFirstIP(t *testing.T) { } func TestAllocateAllIps(t *testing.T) { - defer reset() + a := New() + network := &net.IPNet{ IP: []byte{192, 168, 0, 1}, Mask: []byte{255, 255, 255, 0}, @@ -412,7 +419,7 @@ func TestAllocateAllIps(t *testing.T) { ) for err == nil { - current, err = RequestIP(network, nil) + current, err = a.RequestIP(network, nil) if isFirst { first = current isFirst = false @@ -423,15 +430,15 @@ func TestAllocateAllIps(t *testing.T) { t.Fatal(err) } - if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs { + if _, err := a.RequestIP(network, nil); err != ErrNoAvailableIPs { t.Fatal(err) } - if err := ReleaseIP(network, first); err != nil { + if err := a.ReleaseIP(network, first); err != nil { t.Fatal(err) } - again, err := RequestIP(network, nil) + again, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -439,17 +446,17 @@ func TestAllocateAllIps(t *testing.T) { assertIPEquals(t, first, again) // ensure that alloc.last == alloc.begin won't result in dead loop - if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs { + if _, err := a.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 { + if err := a.ReleaseIP(network, first); err != nil { t.Fatal(err) } - ret, err := RequestIP(network, nil) + ret, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -458,9 +465,9 @@ func TestAllocateAllIps(t *testing.T) { // #2. last of the range, note that current is the last one last := net.IPv4(192, 168, 0, 254) - setLastTo(t, network, last) + setLastTo(t, a, network, last) - ret, err = RequestIP(network, nil) + ret, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -469,9 +476,9 @@ func TestAllocateAllIps(t *testing.T) { // #3. middle of the range mid := net.IPv4(192, 168, 0, 7) - setLastTo(t, network, mid) + setLastTo(t, a, network, mid) - ret, err = RequestIP(network, nil) + ret, err = a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -481,25 +488,25 @@ func TestAllocateAllIps(t *testing.T) { // 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 { +func setLastTo(t *testing.T, a *IPAllocator, network *net.IPNet, ip net.IP) { + if err := a.ReleaseIP(network, ip); err != nil { t.Fatal(err) } - ret, err := RequestIP(network, nil) + ret, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } assertIPEquals(t, ip, ret) - if err := ReleaseIP(network, ip); err != nil { + if err := a.ReleaseIP(network, ip); err != nil { t.Fatal(err) } } func TestAllocateDifferentSubnets(t *testing.T) { - defer reset() + a := New() network1 := &net.IPNet{ IP: []byte{192, 168, 0, 1}, Mask: []byte{255, 255, 255, 0}, @@ -528,39 +535,39 @@ func TestAllocateDifferentSubnets(t *testing.T) { 8: net.ParseIP("2a00:1632::2"), } - ip11, err := RequestIP(network1, nil) + ip11, err := a.RequestIP(network1, nil) if err != nil { t.Fatal(err) } - ip12, err := RequestIP(network1, nil) + ip12, err := a.RequestIP(network1, nil) if err != nil { t.Fatal(err) } - ip21, err := RequestIP(network2, nil) + ip21, err := a.RequestIP(network2, nil) if err != nil { t.Fatal(err) } - ip22, err := RequestIP(network2, nil) + ip22, err := a.RequestIP(network2, nil) if err != nil { t.Fatal(err) } - ip31, err := RequestIP(network3, nil) + ip31, err := a.RequestIP(network3, nil) if err != nil { t.Fatal(err) } - ip32, err := RequestIP(network3, nil) + ip32, err := a.RequestIP(network3, nil) if err != nil { t.Fatal(err) } - ip33, err := RequestIP(network3, nil) + ip33, err := a.RequestIP(network3, nil) if err != nil { t.Fatal(err) } - ip41, err := RequestIP(network4, nil) + ip41, err := a.RequestIP(network4, nil) if err != nil { t.Fatal(err) } - ip42, err := RequestIP(network4, nil) + ip42, err := a.RequestIP(network4, nil) if err != nil { t.Fatal(err) } @@ -576,7 +583,7 @@ func TestAllocateDifferentSubnets(t *testing.T) { } func TestRegisterBadTwice(t *testing.T) { - defer reset() + a := New() network := &net.IPNet{ IP: []byte{192, 168, 1, 1}, Mask: []byte{255, 255, 255, 0}, @@ -586,20 +593,20 @@ func TestRegisterBadTwice(t *testing.T) { Mask: []byte{255, 255, 255, 248}, } - if err := RegisterSubnet(network, subnet); err != nil { + if err := a.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 { + if err := a.RegisterSubnet(network, subnet); err != ErrNetworkAlreadyRegistered { t.Fatalf("Expecteded ErrNetworkAlreadyRegistered error, got %v", err) } } func TestRegisterBadRange(t *testing.T) { - defer reset() + a := New() network := &net.IPNet{ IP: []byte{192, 168, 1, 1}, Mask: []byte{255, 255, 255, 0}, @@ -608,13 +615,13 @@ func TestRegisterBadRange(t *testing.T) { IP: []byte{192, 168, 1, 1}, Mask: []byte{255, 255, 0, 0}, } - if err := RegisterSubnet(network, subnet); err != ErrBadSubnet { + if err := a.RegisterSubnet(network, subnet); err != ErrBadSubnet { t.Fatalf("Expected ErrBadSubnet error, got %v", err) } } func TestAllocateFromRange(t *testing.T) { - defer reset() + a := New() network := &net.IPNet{ IP: []byte{192, 168, 0, 1}, Mask: []byte{255, 255, 255, 0}, @@ -625,7 +632,7 @@ func TestAllocateFromRange(t *testing.T) { Mask: []byte{255, 255, 255, 248}, } - if err := RegisterSubnet(network, subnet); err != nil { + if err := a.RegisterSubnet(network, subnet); err != nil { t.Fatal(err) } expectedIPs := []net.IP{ @@ -637,19 +644,19 @@ func TestAllocateFromRange(t *testing.T) { 5: net.IPv4(192, 168, 0, 14), } for _, ip := range expectedIPs { - rip, err := RequestIP(network, nil) + rip, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } assertIPEquals(t, ip, rip) } - if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs { + if _, err := a.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) + a.ReleaseIP(network, ip) + rip, err := a.RequestIP(network, nil) if err != nil { t.Fatal(err) } @@ -669,13 +676,15 @@ func BenchmarkRequestIP(b *testing.B) { Mask: []byte{255, 255, 255, 0}, } b.ResetTimer() + for i := 0; i < b.N; i++ { + a := New() + for j := 0; j < 253; j++ { - _, err := RequestIP(network, nil) + _, err := a.RequestIP(network, nil) if err != nil { b.Fatal(err) } } - reset() } } diff --git a/portallocator/portallocator.go b/portallocator/portallocator.go index ed913dd..51b60aa 100644 --- a/portallocator/portallocator.go +++ b/portallocator/portallocator.go @@ -1,54 +1,31 @@ package portallocator import ( + "bufio" "errors" "fmt" "net" + "os" "sync" + + "github.com/Sirupsen/logrus" ) -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 indicates the first port in port range - BeginPortRange = 49153 - // EndPortRange indicates the last port in port range - EndPortRange = 65535 + // DefaultPortRangeStart indicates the first port in port range + DefaultPortRangeStart = 49153 + // DefaultPortRangeEnd indicates the last port in port range + DefaultPortRangeEnd = 65535 ) +type ipMapping map[string]protoMap + var ( // ErrAllPortsAllocated is returned when no more ports are available ErrAllPortsAllocated = errors.New("all ports are allocated") // ErrUnknownProtocol is returned when an unknown protocol was specified ErrUnknownProtocol = errors.New("unknown protocol") -) - -var ( - mutex sync.Mutex - - defaultIP = net.ParseIP("0.0.0.0") - globalMap = ipMapping{} + defaultIP = net.ParseIP("0.0.0.0") ) // ErrPortAlreadyAllocated is the returned error information when a requested port is already being used @@ -84,12 +61,59 @@ func (e ErrPortAlreadyAllocated) Error() string { return fmt.Sprintf("Bind for %s:%d failed: port is already allocated", e.ip, e.port) } +type ( + // PortAllocator manages the transport ports database + PortAllocator struct { + mutex sync.Mutex + ipMap ipMapping + Begin int + End int + } + portMap struct { + p map[int]struct{} + begin, end int + last int + } + protoMap map[string]*portMap +) + +// New returns a new instance of PortAllocator +func New() *PortAllocator { + start, end, err := getDynamicPortRange() + if err != nil { + logrus.Warn(err) + start, end = DefaultPortRangeStart, DefaultPortRangeEnd + } + return &PortAllocator{ + ipMap: ipMapping{}, + Begin: start, + End: end, + } +} + +func getDynamicPortRange() (start int, end int, err error) { + const portRangeKernelParam = "/proc/sys/net/ipv4/ip_local_port_range" + portRangeFallback := fmt.Sprintf("using fallback port range %d-%d", DefaultPortRangeStart, DefaultPortRangeEnd) + file, err := os.Open(portRangeKernelParam) + if err != nil { + return 0, 0, fmt.Errorf("port allocator - %s due to error: %v", portRangeFallback, err) + } + n, err := fmt.Fscanf(bufio.NewReader(file), "%d\t%d", &start, &end) + if n != 2 || err != nil { + if err == nil { + err = fmt.Errorf("unexpected count of parsed numbers (%d)", n) + } + return 0, 0, fmt.Errorf("port allocator - failed to parse system ephemeral port range from %s - %s: %v", portRangeKernelParam, portRangeFallback, err) + } + return start, end, nil +} + // 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() +func (p *PortAllocator) RequestPort(ip net.IP, proto string, port int) (int, error) { + p.mutex.Lock() + defer p.mutex.Unlock() if proto != "tcp" && proto != "udp" { return 0, ErrUnknownProtocol @@ -99,10 +123,14 @@ func RequestPort(ip net.IP, proto string, port int) (int, error) { ip = defaultIP } ipstr := ip.String() - protomap, ok := globalMap[ipstr] + protomap, ok := p.ipMap[ipstr] if !ok { - protomap = newProtoMap() - globalMap[ipstr] = protomap + protomap = protoMap{ + "tcp": p.newPortMap(), + "udp": p.newPortMap(), + } + + p.ipMap[ipstr] = protomap } mapping := protomap[proto] if port > 0 { @@ -121,14 +149,14 @@ func RequestPort(ip net.IP, proto string, port int) (int, error) { } // 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() +func (p *PortAllocator) ReleasePort(ip net.IP, proto string, port int) error { + p.mutex.Lock() + defer p.mutex.Unlock() if ip == nil { ip = defaultIP } - protomap, ok := globalMap[ip.String()] + protomap, ok := p.ipMap[ip.String()] if !ok { return nil } @@ -136,20 +164,29 @@ func ReleasePort(ip net.IP, proto string, port int) error { return nil } +func (p *PortAllocator) newPortMap() *portMap { + return &portMap{ + p: map[int]struct{}{}, + begin: p.Begin, + end: p.End, + last: p.End, + } +} + // ReleaseAll releases all ports for all ips. -func ReleaseAll() error { - mutex.Lock() - globalMap = ipMapping{} - mutex.Unlock() +func (p *PortAllocator) ReleaseAll() error { + p.mutex.Lock() + p.ipMap = ipMapping{} + p.mutex.Unlock() return nil } func (pm *portMap) findPort() (int, error) { port := pm.last - for i := 0; i <= EndPortRange-BeginPortRange; i++ { + for i := 0; i <= pm.end-pm.begin; i++ { port++ - if port > EndPortRange { - port = BeginPortRange + if port > pm.end { + port = pm.begin } if _, ok := pm.p[port]; !ok { diff --git a/portallocator/portallocator_test.go b/portallocator/portallocator_test.go index 72581f1..1720123 100644 --- a/portallocator/portallocator_test.go +++ b/portallocator/portallocator_test.go @@ -5,27 +5,23 @@ import ( "testing" ) -func reset() { - ReleaseAll() -} - func TestRequestNewPort(t *testing.T) { - defer reset() + p := New() - port, err := RequestPort(defaultIP, "tcp", 0) + port, err := p.RequestPort(defaultIP, "tcp", 0) if err != nil { t.Fatal(err) } - if expected := BeginPortRange; port != expected { + if expected := p.Begin; port != expected { t.Fatalf("Expected port %d got %d", expected, port) } } func TestRequestSpecificPort(t *testing.T) { - defer reset() + p := New() - port, err := RequestPort(defaultIP, "tcp", 5000) + port, err := p.RequestPort(defaultIP, "tcp", 5000) if err != nil { t.Fatal(err) } @@ -35,9 +31,9 @@ func TestRequestSpecificPort(t *testing.T) { } func TestReleasePort(t *testing.T) { - defer reset() + p := New() - port, err := RequestPort(defaultIP, "tcp", 5000) + port, err := p.RequestPort(defaultIP, "tcp", 5000) if err != nil { t.Fatal(err) } @@ -45,15 +41,15 @@ func TestReleasePort(t *testing.T) { t.Fatalf("Expected port 5000 got %d", port) } - if err := ReleasePort(defaultIP, "tcp", 5000); err != nil { + if err := p.ReleasePort(defaultIP, "tcp", 5000); err != nil { t.Fatal(err) } } func TestReuseReleasedPort(t *testing.T) { - defer reset() + p := New() - port, err := RequestPort(defaultIP, "tcp", 5000) + port, err := p.RequestPort(defaultIP, "tcp", 5000) if err != nil { t.Fatal(err) } @@ -61,20 +57,20 @@ func TestReuseReleasedPort(t *testing.T) { t.Fatalf("Expected port 5000 got %d", port) } - if err := ReleasePort(defaultIP, "tcp", 5000); err != nil { + if err := p.ReleasePort(defaultIP, "tcp", 5000); err != nil { t.Fatal(err) } - port, err = RequestPort(defaultIP, "tcp", 5000) + port, err = p.RequestPort(defaultIP, "tcp", 5000) if err != nil { t.Fatal(err) } } func TestReleaseUnreadledPort(t *testing.T) { - defer reset() + p := New() - port, err := RequestPort(defaultIP, "tcp", 5000) + port, err := p.RequestPort(defaultIP, "tcp", 5000) if err != nil { t.Fatal(err) } @@ -82,7 +78,7 @@ func TestReleaseUnreadledPort(t *testing.T) { t.Fatalf("Expected port 5000 got %d", port) } - port, err = RequestPort(defaultIP, "tcp", 5000) + port, err = p.RequestPort(defaultIP, "tcp", 5000) switch err.(type) { case ErrPortAlreadyAllocated: @@ -92,42 +88,40 @@ func TestReleaseUnreadledPort(t *testing.T) { } func TestUnknowProtocol(t *testing.T) { - defer reset() - - if _, err := RequestPort(defaultIP, "tcpp", 0); err != ErrUnknownProtocol { + if _, err := New().RequestPort(defaultIP, "tcpp", 0); err != ErrUnknownProtocol { t.Fatalf("Expected error %s got %s", ErrUnknownProtocol, err) } } func TestAllocateAllPorts(t *testing.T) { - defer reset() + p := New() - for i := 0; i <= EndPortRange-BeginPortRange; i++ { - port, err := RequestPort(defaultIP, "tcp", 0) + for i := 0; i <= p.End-p.Begin; i++ { + port, err := p.RequestPort(defaultIP, "tcp", 0) if err != nil { t.Fatal(err) } - if expected := BeginPortRange + i; port != expected { + if expected := p.Begin + i; port != expected { t.Fatalf("Expected port %d got %d", expected, port) } } - if _, err := RequestPort(defaultIP, "tcp", 0); err != ErrAllPortsAllocated { + if _, err := p.RequestPort(defaultIP, "tcp", 0); err != ErrAllPortsAllocated { t.Fatalf("Expected error %s got %s", ErrAllPortsAllocated, err) } - _, err := RequestPort(defaultIP, "udp", 0) + _, err := p.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 { + port := p.Begin + 5 + if err := p.ReleasePort(defaultIP, "tcp", port); err != nil { t.Fatal(err) } - newPort, err := RequestPort(defaultIP, "tcp", 0) + newPort, err := p.RequestPort(defaultIP, "tcp", 0) if err != nil { t.Fatal(err) } @@ -137,10 +131,10 @@ func TestAllocateAllPorts(t *testing.T) { // 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 { + if err := p.ReleasePort(defaultIP, "tcp", newPort); err != nil { t.Fatal(err) } - port, err = RequestPort(defaultIP, "tcp", 0) + port, err = p.RequestPort(defaultIP, "tcp", 0) if err != nil { t.Fatal(err) } @@ -150,34 +144,34 @@ func TestAllocateAllPorts(t *testing.T) { } func BenchmarkAllocatePorts(b *testing.B) { - defer reset() + p := New() for i := 0; i < b.N; i++ { - for i := 0; i <= EndPortRange-BeginPortRange; i++ { - port, err := RequestPort(defaultIP, "tcp", 0) + for i := 0; i <= p.End-p.Begin; i++ { + port, err := p.RequestPort(defaultIP, "tcp", 0) if err != nil { b.Fatal(err) } - if expected := BeginPortRange + i; port != expected { + if expected := p.Begin + i; port != expected { b.Fatalf("Expected port %d got %d", expected, port) } } - reset() + p.ReleaseAll() } } func TestPortAllocation(t *testing.T) { - defer reset() + p := New() ip := net.ParseIP("192.168.0.1") ip2 := net.ParseIP("192.168.0.2") - if port, err := RequestPort(ip, "tcp", 80); err != nil { + if port, err := p.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) + port, err := p.RequestPort(ip, "tcp", 0) if err != nil { t.Fatal(err) } @@ -185,41 +179,41 @@ func TestPortAllocation(t *testing.T) { t.Fatalf("Acquire(0) should return a non-zero port") } - if _, err := RequestPort(ip, "tcp", port); err == nil { + if _, err := p.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 { + if newPort, err := p.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 { + if _, err := p.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 { + if _, err := p.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 { + if _, err := p.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 { + if err := p.ReleasePort(ip, "tcp", 80); err != nil { t.Fatal(err) } - if _, err := RequestPort(ip, "tcp", 80); err != nil { + if _, err := p.RequestPort(ip, "tcp", 80); err != nil { t.Fatal(err) } - port, err = RequestPort(ip, "tcp", 0) + port, err = p.RequestPort(ip, "tcp", 0) if err != nil { t.Fatal(err) } - port2, err := RequestPort(ip, "tcp", port+1) + port2, err := p.RequestPort(ip, "tcp", port+1) if err != nil { t.Fatal(err) } - port3, err := RequestPort(ip, "tcp", 0) + port3, err := p.RequestPort(ip, "tcp", 0) if err != nil { t.Fatal(err) } @@ -229,17 +223,17 @@ func TestPortAllocation(t *testing.T) { } func TestNoDuplicateBPR(t *testing.T) { - defer reset() + p := New() - if port, err := RequestPort(defaultIP, "tcp", BeginPortRange); err != nil { + if port, err := p.RequestPort(defaultIP, "tcp", p.Begin); err != nil { t.Fatal(err) - } else if port != BeginPortRange { - t.Fatalf("Expected port %d got %d", BeginPortRange, port) + } else if port != p.Begin { + t.Fatalf("Expected port %d got %d", p.Begin, port) } - if port, err := RequestPort(defaultIP, "tcp", 0); err != nil { + if port, err := p.RequestPort(defaultIP, "tcp", 0); err != nil { t.Fatal(err) - } else if port == BeginPortRange { + } else if port == p.Begin { t.Fatalf("Acquire(0) allocated the same port twice: %d", port) } } diff --git a/portmapper/mapper.go b/portmapper/mapper.go index 3064ecc..f0083e3 100644 --- a/portmapper/mapper.go +++ b/portmapper/mapper.go @@ -6,7 +6,7 @@ import ( "net" "sync" - log "github.com/Sirupsen/logrus" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/iptables" "github.com/docker/libnetwork/portallocator" ) @@ -18,15 +18,7 @@ type mapping struct { container net.Addr } -var ( - chain *iptables.Chain - lock sync.Mutex - - // udp:ip:port - currentMappings = make(map[string]*mapping) - - newProxy = newProxyCommand -) +var newProxy = newProxyCommand var ( // ErrUnknownBackendAddressType refers to an unknown container or unsupported address type @@ -37,15 +29,39 @@ var ( ErrPortNotMapped = errors.New("port is not mapped") ) +// PortMapper manages the network address translation +type PortMapper struct { + chain *iptables.Chain + + // udp:ip:port + currentMappings map[string]*mapping + lock sync.Mutex + + Allocator *portallocator.PortAllocator +} + +// New returns a new instance of PortMapper +func New() *PortMapper { + return NewWithPortAllocator(portallocator.New()) +} + +// NewWithPortAllocator returns a new instance of PortMapper wich will use the specified PortAllocator +func NewWithPortAllocator(allocator *portallocator.PortAllocator) *PortMapper { + return &PortMapper{ + currentMappings: make(map[string]*mapping), + Allocator: allocator, + } +} + // SetIptablesChain sets the specified chain into portmapper -func SetIptablesChain(c *iptables.Chain) { - chain = c +func (pm *PortMapper) SetIptablesChain(c *iptables.Chain) { + pm.chain = c } // Map maps the specified container transport address to the host's network address and transport port -func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err error) { - lock.Lock() - defer lock.Unlock() +func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err error) { + pm.lock.Lock() + defer pm.lock.Unlock() var ( m *mapping @@ -57,7 +73,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er switch container.(type) { case *net.TCPAddr: proto = "tcp" - if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { + if allocatedHostPort, err = pm.Allocator.RequestPort(hostIP, proto, hostPort); err != nil { return nil, err } @@ -70,7 +86,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er 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 { + if allocatedHostPort, err = pm.Allocator.RequestPort(hostIP, proto, hostPort); err != nil { return nil, err } @@ -88,25 +104,25 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er // release the allocated port on any further error during return. defer func() { if err != nil { - portallocator.ReleasePort(hostIP, proto, allocatedHostPort) + pm.Allocator.ReleasePort(hostIP, proto, allocatedHostPort) } }() key := getKey(m.host) - if _, exists := currentMappings[key]; exists { + if _, exists := pm.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 { + if err := pm.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 { + pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) + if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil { return err } @@ -120,36 +136,36 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er return nil, err } m.userlandProxy = proxy - currentMappings[key] = m + pm.currentMappings[key] = m return m.host, nil } // Unmap removes stored mapping for the specified host transport address -func Unmap(host net.Addr) error { - lock.Lock() - defer lock.Unlock() +func (pm *PortMapper) Unmap(host net.Addr) error { + pm.lock.Lock() + defer pm.lock.Unlock() key := getKey(host) - data, exists := currentMappings[key] + data, exists := pm.currentMappings[key] if !exists { return ErrPortNotMapped } data.userlandProxy.Stop() - delete(currentMappings, key) + delete(pm.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) + if err := pm.forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil { + logrus.Errorf("Error on iptables delete: %s", err) } switch a := host.(type) { case *net.TCPAddr: - return portallocator.ReleasePort(a.IP, "tcp", a.Port) + return pm.Allocator.ReleasePort(a.IP, "tcp", a.Port) case *net.UDPAddr: - return portallocator.ReleasePort(a.IP, "udp", a.Port) + return pm.Allocator.ReleasePort(a.IP, "udp", a.Port) } return nil } @@ -174,9 +190,9 @@ func getIPAndPort(a net.Addr) (net.IP, int) { return nil, 0 } -func forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error { - if chain == nil { +func (pm *PortMapper) forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error { + if pm.chain == nil { return nil } - return chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort) + return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort) } diff --git a/portmapper/mapper_test.go b/portmapper/mapper_test.go index 257916b..73c44b7 100644 --- a/portmapper/mapper_test.go +++ b/portmapper/mapper_test.go @@ -5,7 +5,6 @@ import ( "testing" "github.com/docker/docker/pkg/iptables" - "github.com/docker/libnetwork/portallocator" ) func init() { @@ -13,30 +12,26 @@ func init() { newProxy = newMockProxyCommand } -func reset() { - chain = nil - currentMappings = make(map[string]*mapping) -} - func TestSetIptablesChain(t *testing.T) { - defer reset() + pm := New() c := &iptables.Chain{ Name: "TEST", Bridge: "192.168.1.1", } - if chain != nil { + if pm.chain != nil { t.Fatal("chain should be nil at init") } - SetIptablesChain(c) - if chain == nil { + pm.SetIptablesChain(c) + if pm.chain == nil { t.Fatal("chain should not be nil after set") } } func TestMapPorts(t *testing.T) { + pm := New() dstIP1 := net.ParseIP("192.168.0.1") dstIP2 := net.ParseIP("192.168.0.2") dstAddr1 := &net.TCPAddr{IP: dstIP1, Port: 80} @@ -49,34 +44,34 @@ func TestMapPorts(t *testing.T) { return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String()) } - if host, err := Map(srcAddr1, dstIP1, 80); err != nil { + if host, err := pm.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 { + if _, err := pm.Map(srcAddr1, dstIP1, 80); err == nil { t.Fatalf("Port is in use - mapping should have failed") } - if _, err := Map(srcAddr2, dstIP1, 80); err == nil { + if _, err := pm.Map(srcAddr2, dstIP1, 80); err == nil { t.Fatalf("Port is in use - mapping should have failed") } - if _, err := Map(srcAddr2, dstIP2, 80); err != nil { + if _, err := pm.Map(srcAddr2, dstIP2, 80); err != nil { t.Fatalf("Failed to allocate port: %s", err) } - if Unmap(dstAddr1) != nil { + if pm.Unmap(dstAddr1) != nil { t.Fatalf("Failed to release port") } - if Unmap(dstAddr2) != nil { + if pm.Unmap(dstAddr2) != nil { t.Fatalf("Failed to release port") } - if Unmap(dstAddr2) == nil { + if pm.Unmap(dstAddr2) == nil { t.Fatalf("Port already released, but no error reported") } } @@ -115,6 +110,7 @@ func TestGetUDPIPAndPort(t *testing.T) { } func TestMapAllPortsSingleInterface(t *testing.T) { + pm := New() dstIP1 := net.ParseIP("0.0.0.0") srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")} @@ -124,25 +120,26 @@ func TestMapAllPortsSingleInterface(t *testing.T) { defer func() { for _, val := range hosts { - Unmap(val) + pm.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 { + start, end := pm.Allocator.Begin, pm.Allocator.End + for i := start; i < end; i++ { + if host, err = pm.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) + if _, err := pm.Map(srcAddr1, dstIP1, start); err == nil { + t.Fatalf("Port %d should be bound but is not", start) } for _, val := range hosts { - if err := Unmap(val); err != nil { + if err := pm.Unmap(val); err != nil { t.Fatal(err) } }