commit
735dbcf3ab
26 changed files with 4992 additions and 5 deletions
18
libnetwork/Godeps/Godeps.json
generated
18
libnetwork/Godeps/Godeps.json
generated
|
@ -1,17 +1,35 @@
|
|||
{
|
||||
"ImportPath": "github.com/docker/libnetwork",
|
||||
"GoVersion": "go1.4.2",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/Sirupsen/logrus",
|
||||
"Comment": "v0.6.4-12-g467d9d5",
|
||||
"Rev": "467d9d55c2d2c17248441a8fc661561161f40d5e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/daemon/networkdriver",
|
||||
"Comment": "v1.4.1-1379-g8e107a9",
|
||||
"Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/parsers/kernel",
|
||||
"Comment": "v1.4.1-1379-g8e107a9",
|
||||
"Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/reexec",
|
||||
"Comment": "v1.4.1-1379-g8e107a9",
|
||||
"Rev": "8e107a93210c54f22ec1354d969c771b1abfbe05"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/libcontainer/netlink",
|
||||
"Comment": "v1.4.0-324-g88989e6",
|
||||
"Rev": "88989e66d3a1ab960deb37f3dd7f824d85e1b9bc"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/vishvananda/netlink",
|
||||
"Rev": "8eb64238879fed52fd51c5b30ad20b928fb4c36c"
|
||||
|
|
720
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver.go
generated
vendored
Normal file
720
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver.go
generated
vendored
Normal file
|
@ -0,0 +1,720 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/networkdriver"
|
||||
"github.com/docker/docker/daemon/networkdriver/ipallocator"
|
||||
"github.com/docker/docker/daemon/networkdriver/portmapper"
|
||||
"github.com/docker/docker/engine"
|
||||
"github.com/docker/docker/nat"
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
"github.com/docker/docker/pkg/networkfs/resolvconf"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultNetworkBridge = "docker0"
|
||||
MaxAllocatedPortAttempts = 10
|
||||
)
|
||||
|
||||
// Network interface represents the networking stack of a container
|
||||
type networkInterface struct {
|
||||
IP net.IP
|
||||
IPv6 net.IP
|
||||
PortMappings []net.Addr // there are mappings to the host interfaces
|
||||
}
|
||||
|
||||
type ifaces struct {
|
||||
c map[string]*networkInterface
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (i *ifaces) Set(key string, n *networkInterface) {
|
||||
i.Lock()
|
||||
i.c[key] = n
|
||||
i.Unlock()
|
||||
}
|
||||
|
||||
func (i *ifaces) Get(key string) *networkInterface {
|
||||
i.Lock()
|
||||
res := i.c[key]
|
||||
i.Unlock()
|
||||
return res
|
||||
}
|
||||
|
||||
var (
|
||||
addrs = []string{
|
||||
// Here we don't follow the convention of using the 1st IP of the range for the gateway.
|
||||
// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
|
||||
// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
|
||||
// on the internal addressing or other stupid things like that.
|
||||
// They shouldn't, but hey, let's not break them unless we really have to.
|
||||
"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
|
||||
"10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive
|
||||
"10.1.42.1/16",
|
||||
"10.42.42.1/16",
|
||||
"172.16.42.1/24",
|
||||
"172.16.43.1/24",
|
||||
"172.16.44.1/24",
|
||||
"10.0.42.1/24",
|
||||
"10.0.43.1/24",
|
||||
"192.168.42.1/24",
|
||||
"192.168.43.1/24",
|
||||
"192.168.44.1/24",
|
||||
}
|
||||
|
||||
bridgeIface string
|
||||
bridgeIPv4Network *net.IPNet
|
||||
bridgeIPv6Addr net.IP
|
||||
globalIPv6Network *net.IPNet
|
||||
|
||||
defaultBindingIP = net.ParseIP("0.0.0.0")
|
||||
currentInterfaces = ifaces{c: make(map[string]*networkInterface)}
|
||||
)
|
||||
|
||||
func InitDriver(job *engine.Job) engine.Status {
|
||||
var (
|
||||
networkv4 *net.IPNet
|
||||
networkv6 *net.IPNet
|
||||
addrv4 net.Addr
|
||||
addrsv6 []net.Addr
|
||||
enableIPTables = job.GetenvBool("EnableIptables")
|
||||
enableIPv6 = job.GetenvBool("EnableIPv6")
|
||||
icc = job.GetenvBool("InterContainerCommunication")
|
||||
ipMasq = job.GetenvBool("EnableIpMasq")
|
||||
ipForward = job.GetenvBool("EnableIpForward")
|
||||
bridgeIP = job.Getenv("BridgeIP")
|
||||
bridgeIPv6 = "fe80::1/64"
|
||||
fixedCIDR = job.Getenv("FixedCIDR")
|
||||
fixedCIDRv6 = job.Getenv("FixedCIDRv6")
|
||||
)
|
||||
|
||||
if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
|
||||
defaultBindingIP = net.ParseIP(defaultIP)
|
||||
}
|
||||
|
||||
bridgeIface = job.Getenv("BridgeIface")
|
||||
usingDefaultBridge := false
|
||||
if bridgeIface == "" {
|
||||
usingDefaultBridge = true
|
||||
bridgeIface = DefaultNetworkBridge
|
||||
}
|
||||
|
||||
addrv4, addrsv6, err := networkdriver.GetIfaceAddr(bridgeIface)
|
||||
|
||||
if err != nil {
|
||||
// No Bridge existent, create one
|
||||
// If we're not using the default bridge, fail without trying to create it
|
||||
if !usingDefaultBridge {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
// If the iface is not found, try to create it
|
||||
if err := configureBridge(bridgeIP, bridgeIPv6, enableIPv6); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
if fixedCIDRv6 != "" {
|
||||
// Setting route to global IPv6 subnet
|
||||
log.Infof("Adding route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface)
|
||||
if err := netlink.AddRoute(fixedCIDRv6, "", "", bridgeIface); err != nil {
|
||||
log.Fatalf("Could not add route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Bridge exists already, getting info...
|
||||
// validate that the bridge ip matches the ip specified by BridgeIP
|
||||
if bridgeIP != "" {
|
||||
networkv4 = addrv4.(*net.IPNet)
|
||||
bip, _, err := net.ParseCIDR(bridgeIP)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
if !networkv4.IP.Equal(bip) {
|
||||
return job.Errorf("bridge ip (%s) does not match existing bridge configuration %s", networkv4.IP, bip)
|
||||
}
|
||||
}
|
||||
|
||||
// a bridge might exist but not have any IPv6 addr associated with it yet
|
||||
// (for example, an existing Docker installation that has only been used
|
||||
// with IPv4 and docker0 already is set up) In that case, we can perform
|
||||
// the bridge init for IPv6 here, else we will error out below if --ipv6=true
|
||||
if len(addrsv6) == 0 && enableIPv6 {
|
||||
if err := setupIPv6Bridge(bridgeIPv6); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
// recheck addresses now that IPv6 is setup on the bridge
|
||||
addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check if route to fixedCIDRv6 is set
|
||||
}
|
||||
|
||||
if enableIPv6 {
|
||||
bip6, _, err := net.ParseCIDR(bridgeIPv6)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
found := false
|
||||
for _, addrv6 := range addrsv6 {
|
||||
networkv6 = addrv6.(*net.IPNet)
|
||||
if networkv6.IP.Equal(bip6) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return job.Errorf("bridge IPv6 does not match existing bridge configuration %s", bip6)
|
||||
}
|
||||
}
|
||||
|
||||
networkv4 = addrv4.(*net.IPNet)
|
||||
|
||||
if enableIPv6 {
|
||||
if len(addrsv6) == 0 {
|
||||
return job.Error(errors.New("IPv6 enabled but no IPv6 detected"))
|
||||
}
|
||||
bridgeIPv6Addr = networkv6.IP
|
||||
}
|
||||
|
||||
// Configure iptables for link support
|
||||
if enableIPTables {
|
||||
if err := setupIPTables(addrv4, icc, ipMasq); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ipForward {
|
||||
// Enable IPv4 forwarding
|
||||
if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
|
||||
job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
|
||||
}
|
||||
|
||||
if fixedCIDRv6 != "" {
|
||||
// Enable IPv6 forwarding
|
||||
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil {
|
||||
job.Logf("WARNING: unable to enable IPv6 default forwarding: %s\n", err)
|
||||
}
|
||||
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, 0644); err != nil {
|
||||
job.Logf("WARNING: unable to enable IPv6 all forwarding: %s\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can always try removing the iptables
|
||||
if err := iptables.RemoveExistingChain("DOCKER", iptables.Nat); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
if enableIPTables {
|
||||
_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
chain, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
portmapper.SetIptablesChain(chain)
|
||||
}
|
||||
|
||||
bridgeIPv4Network = networkv4
|
||||
if fixedCIDR != "" {
|
||||
_, subnet, err := net.ParseCIDR(fixedCIDR)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
log.Debugf("Subnet: %v", subnet)
|
||||
if err := ipallocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
if fixedCIDRv6 != "" {
|
||||
_, subnet, err := net.ParseCIDR(fixedCIDRv6)
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
log.Debugf("Subnet: %v", subnet)
|
||||
if err := ipallocator.RegisterSubnet(subnet, subnet); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
globalIPv6Network = subnet
|
||||
}
|
||||
|
||||
// Block BridgeIP in IP allocator
|
||||
ipallocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP)
|
||||
|
||||
// https://github.com/docker/docker/issues/2768
|
||||
job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeIPv4Network.IP)
|
||||
|
||||
for name, f := range map[string]engine.Handler{
|
||||
"allocate_interface": Allocate,
|
||||
"release_interface": Release,
|
||||
"allocate_port": AllocatePort,
|
||||
"link": LinkContainers,
|
||||
} {
|
||||
if err := job.Eng.Register(name, f); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
}
|
||||
return engine.StatusOK
|
||||
}
|
||||
|
||||
func setupIPTables(addr net.Addr, icc, ipmasq bool) error {
|
||||
// Enable NAT
|
||||
|
||||
if ipmasq {
|
||||
natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-o", bridgeIface, "-j", "MASQUERADE"}
|
||||
|
||||
if !iptables.Exists(natArgs...) {
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, natArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to enable network bridge NAT: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return &iptables.ChainError{Chain: "POSTROUTING", Output: output}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
args = []string{"FORWARD", "-i", bridgeIface, "-o", bridgeIface, "-j"}
|
||||
acceptArgs = append(args, "ACCEPT")
|
||||
dropArgs = append(args, "DROP")
|
||||
)
|
||||
|
||||
if !icc {
|
||||
iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
|
||||
|
||||
if !iptables.Exists(dropArgs...) {
|
||||
log.Debugf("Disable inter-container communication")
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return fmt.Errorf("Error disabling intercontainer communication: %s", output)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iptables.Raw(append([]string{"-D"}, dropArgs...)...)
|
||||
|
||||
if !iptables.Exists(acceptArgs...) {
|
||||
log.Debugf("Enable inter-container communication")
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to allow intercontainer communication: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return fmt.Errorf("Error enabling intercontainer communication: %s", output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accept all non-intercontainer outgoing packets
|
||||
outgoingArgs := []string{"FORWARD", "-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}
|
||||
if !iptables.Exists(outgoingArgs...) {
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to allow outgoing packets: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return &iptables.ChainError{Chain: "FORWARD outgoing", Output: output}
|
||||
}
|
||||
}
|
||||
|
||||
// Accept incoming packets for existing connections
|
||||
existingArgs := []string{"FORWARD", "-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
|
||||
|
||||
if !iptables.Exists(existingArgs...) {
|
||||
if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
|
||||
return fmt.Errorf("Unable to allow incoming packets: %s", err)
|
||||
} else if len(output) != 0 {
|
||||
return &iptables.ChainError{Chain: "FORWARD incoming", Output: output}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// configureBridge attempts to create and configure a network bridge interface named `bridgeIface` on the host
|
||||
// If bridgeIP is empty, it will try to find a non-conflicting IP from the Docker-specified private ranges
|
||||
// If the bridge `bridgeIface` already exists, it will only perform the IP address association with the existing
|
||||
// bridge (fixes issue #8444)
|
||||
// If an address which doesn't conflict with existing interfaces can't be found, an error is returned.
|
||||
func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error {
|
||||
nameservers := []string{}
|
||||
resolvConf, _ := resolvconf.Get()
|
||||
// we don't check for an error here, because we don't really care
|
||||
// if we can't read /etc/resolv.conf. So instead we skip the append
|
||||
// if resolvConf is nil. It either doesn't exist, or we can't read it
|
||||
// for some reason.
|
||||
if resolvConf != nil {
|
||||
nameservers = append(nameservers, resolvconf.GetNameserversAsCIDR(resolvConf)...)
|
||||
}
|
||||
|
||||
var ifaceAddr string
|
||||
if len(bridgeIP) != 0 {
|
||||
_, _, err := net.ParseCIDR(bridgeIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ifaceAddr = bridgeIP
|
||||
} else {
|
||||
for _, addr := range addrs {
|
||||
_, dockerNetwork, err := net.ParseCIDR(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil {
|
||||
if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil {
|
||||
ifaceAddr = addr
|
||||
break
|
||||
} else {
|
||||
log.Debugf("%s %s", addr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ifaceAddr == "" {
|
||||
return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", bridgeIface, bridgeIface)
|
||||
}
|
||||
log.Debugf("Creating bridge %s with network %s", bridgeIface, ifaceAddr)
|
||||
|
||||
if err := createBridgeIface(bridgeIface); err != nil {
|
||||
// the bridge may already exist, therefore we can ignore an "exists" error
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName(bridgeIface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
|
||||
return fmt.Errorf("Unable to add private network: %s", err)
|
||||
}
|
||||
|
||||
if enableIPv6 {
|
||||
if err := setupIPv6Bridge(bridgeIPv6); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := netlink.NetworkLinkUp(iface); err != nil {
|
||||
return fmt.Errorf("Unable to start network bridge: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupIPv6Bridge(bridgeIPv6 string) error {
|
||||
|
||||
iface, err := net.InterfaceByName(bridgeIface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Enable IPv6 on the bridge
|
||||
procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6"
|
||||
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
|
||||
return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
|
||||
}
|
||||
|
||||
ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to parse bridge IPv6 address: %q, error: %v", bridgeIPv6, err)
|
||||
}
|
||||
|
||||
if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil {
|
||||
return fmt.Errorf("Unable to add private IPv6 network: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createBridgeIface(name string) error {
|
||||
kv, err := kernel.GetKernelVersion()
|
||||
// only set the bridge's mac address if the kernel version is > 3.3
|
||||
// before that it was not supported
|
||||
setBridgeMacAddr := err == nil && (kv.Kernel >= 3 && kv.Major >= 3)
|
||||
log.Debugf("setting bridge mac address = %v", setBridgeMacAddr)
|
||||
return netlink.CreateBridge(name, setBridgeMacAddr)
|
||||
}
|
||||
|
||||
// Generate a IEEE802 compliant MAC address from the given IP address.
|
||||
//
|
||||
// The generator is guaranteed to be consistent: the same IP will always yield the same
|
||||
// MAC address. This is to avoid ARP cache issues.
|
||||
func generateMacAddr(ip net.IP) net.HardwareAddr {
|
||||
hw := make(net.HardwareAddr, 6)
|
||||
|
||||
// The first byte of the MAC address has to comply with these rules:
|
||||
// 1. Unicast: Set the least-significant bit to 0.
|
||||
// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
|
||||
// 3. As "small" as possible: The veth address has to be "smaller" than the bridge address.
|
||||
hw[0] = 0x02
|
||||
|
||||
// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
|
||||
// Since this address is locally administered, we can do whatever we want as long as
|
||||
// it doesn't conflict with other addresses.
|
||||
hw[1] = 0x42
|
||||
|
||||
// Insert the IP address into the last 32 bits of the MAC address.
|
||||
// This is a simple way to guarantee the address will be consistent and unique.
|
||||
copy(hw[2:], ip.To4())
|
||||
|
||||
return hw
|
||||
}
|
||||
|
||||
func linkLocalIPv6FromMac(mac string) (string, error) {
|
||||
hx := strings.Replace(mac, ":", "", -1)
|
||||
hw, err := hex.DecodeString(hx)
|
||||
if err != nil {
|
||||
return "", errors.New("Could not parse MAC address " + mac)
|
||||
}
|
||||
|
||||
hw[0] ^= 0x2
|
||||
|
||||
return fmt.Sprintf("fe80::%x%x:%xff:fe%x:%x%x/64", hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]), nil
|
||||
}
|
||||
|
||||
// Allocate a network interface
|
||||
func Allocate(job *engine.Job) engine.Status {
|
||||
var (
|
||||
ip net.IP
|
||||
mac net.HardwareAddr
|
||||
err error
|
||||
id = job.Args[0]
|
||||
requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
|
||||
requestedIPv6 = net.ParseIP(job.Getenv("RequestedIPv6"))
|
||||
globalIPv6 net.IP
|
||||
)
|
||||
|
||||
if requestedIP != nil {
|
||||
ip, err = ipallocator.RequestIP(bridgeIPv4Network, requestedIP)
|
||||
} else {
|
||||
ip, err = ipallocator.RequestIP(bridgeIPv4Network, nil)
|
||||
}
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
// If no explicit mac address was given, generate a random one.
|
||||
if mac, err = net.ParseMAC(job.Getenv("RequestedMac")); err != nil {
|
||||
mac = generateMacAddr(ip)
|
||||
}
|
||||
|
||||
if globalIPv6Network != nil {
|
||||
// if globalIPv6Network Size is at least a /80 subnet generate IPv6 address from MAC address
|
||||
netmask_ones, _ := globalIPv6Network.Mask.Size()
|
||||
if requestedIPv6 == nil && netmask_ones <= 80 {
|
||||
requestedIPv6 = globalIPv6Network.IP
|
||||
for i, h := range mac {
|
||||
requestedIPv6[i+10] = h
|
||||
}
|
||||
}
|
||||
|
||||
globalIPv6, err = ipallocator.RequestIP(globalIPv6Network, requestedIPv6)
|
||||
if err != nil {
|
||||
log.Errorf("Allocator: RequestIP v6: %s", err.Error())
|
||||
return job.Error(err)
|
||||
}
|
||||
log.Infof("Allocated IPv6 %s", globalIPv6)
|
||||
}
|
||||
|
||||
out := engine.Env{}
|
||||
out.Set("IP", ip.String())
|
||||
out.Set("Mask", bridgeIPv4Network.Mask.String())
|
||||
out.Set("Gateway", bridgeIPv4Network.IP.String())
|
||||
out.Set("MacAddress", mac.String())
|
||||
out.Set("Bridge", bridgeIface)
|
||||
|
||||
size, _ := bridgeIPv4Network.Mask.Size()
|
||||
out.SetInt("IPPrefixLen", size)
|
||||
|
||||
// if linklocal IPv6
|
||||
localIPv6Net, err := linkLocalIPv6FromMac(mac.String())
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
localIPv6, _, _ := net.ParseCIDR(localIPv6Net)
|
||||
out.Set("LinkLocalIPv6", localIPv6.String())
|
||||
out.Set("MacAddress", mac.String())
|
||||
|
||||
if globalIPv6Network != nil {
|
||||
out.Set("GlobalIPv6", globalIPv6.String())
|
||||
sizev6, _ := globalIPv6Network.Mask.Size()
|
||||
out.SetInt("GlobalIPv6PrefixLen", sizev6)
|
||||
out.Set("IPv6Gateway", bridgeIPv6Addr.String())
|
||||
}
|
||||
|
||||
currentInterfaces.Set(id, &networkInterface{
|
||||
IP: ip,
|
||||
IPv6: globalIPv6,
|
||||
})
|
||||
|
||||
out.WriteTo(job.Stdout)
|
||||
|
||||
return engine.StatusOK
|
||||
}
|
||||
|
||||
// release an interface for a select ip
|
||||
func Release(job *engine.Job) engine.Status {
|
||||
var (
|
||||
id = job.Args[0]
|
||||
containerInterface = currentInterfaces.Get(id)
|
||||
)
|
||||
|
||||
if containerInterface == nil {
|
||||
return job.Errorf("No network information to release for %s", id)
|
||||
}
|
||||
|
||||
for _, nat := range containerInterface.PortMappings {
|
||||
if err := portmapper.Unmap(nat); err != nil {
|
||||
log.Infof("Unable to unmap port %s: %s", nat, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := ipallocator.ReleaseIP(bridgeIPv4Network, containerInterface.IP); err != nil {
|
||||
log.Infof("Unable to release IPv4 %s", err)
|
||||
}
|
||||
if globalIPv6Network != nil {
|
||||
if err := ipallocator.ReleaseIP(globalIPv6Network, containerInterface.IPv6); err != nil {
|
||||
log.Infof("Unable to release IPv6 %s", err)
|
||||
}
|
||||
}
|
||||
return engine.StatusOK
|
||||
}
|
||||
|
||||
// Allocate an external port and map it to the interface
|
||||
func AllocatePort(job *engine.Job) engine.Status {
|
||||
var (
|
||||
err error
|
||||
|
||||
ip = defaultBindingIP
|
||||
id = job.Args[0]
|
||||
hostIP = job.Getenv("HostIP")
|
||||
hostPort = job.GetenvInt("HostPort")
|
||||
containerPort = job.GetenvInt("ContainerPort")
|
||||
proto = job.Getenv("Proto")
|
||||
network = currentInterfaces.Get(id)
|
||||
)
|
||||
|
||||
if hostIP != "" {
|
||||
ip = net.ParseIP(hostIP)
|
||||
if ip == nil {
|
||||
return job.Errorf("Bad parameter: invalid host ip %s", hostIP)
|
||||
}
|
||||
}
|
||||
|
||||
// host ip, proto, and host port
|
||||
var container net.Addr
|
||||
switch proto {
|
||||
case "tcp":
|
||||
container = &net.TCPAddr{IP: network.IP, Port: containerPort}
|
||||
case "udp":
|
||||
container = &net.UDPAddr{IP: network.IP, Port: containerPort}
|
||||
default:
|
||||
return job.Errorf("unsupported address type %s", proto)
|
||||
}
|
||||
|
||||
//
|
||||
// Try up to 10 times to get a port that's not already allocated.
|
||||
//
|
||||
// In the event of failure to bind, return the error that portmapper.Map
|
||||
// yields.
|
||||
//
|
||||
|
||||
var host net.Addr
|
||||
for i := 0; i < MaxAllocatedPortAttempts; i++ {
|
||||
if host, err = portmapper.Map(container, ip, hostPort); err == nil {
|
||||
break
|
||||
}
|
||||
// There is no point in immediately retrying to map an explicitly
|
||||
// chosen port.
|
||||
if hostPort != 0 {
|
||||
job.Logf("Failed to allocate and map port %d: %s", hostPort, err)
|
||||
break
|
||||
}
|
||||
job.Logf("Failed to allocate and map port: %s, retry: %d", err, i+1)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
network.PortMappings = append(network.PortMappings, host)
|
||||
|
||||
out := engine.Env{}
|
||||
switch netAddr := host.(type) {
|
||||
case *net.TCPAddr:
|
||||
out.Set("HostIP", netAddr.IP.String())
|
||||
out.SetInt("HostPort", netAddr.Port)
|
||||
case *net.UDPAddr:
|
||||
out.Set("HostIP", netAddr.IP.String())
|
||||
out.SetInt("HostPort", netAddr.Port)
|
||||
}
|
||||
if _, err := out.WriteTo(job.Stdout); err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
|
||||
return engine.StatusOK
|
||||
}
|
||||
|
||||
func LinkContainers(job *engine.Job) engine.Status {
|
||||
var (
|
||||
action = job.Args[0]
|
||||
nfAction iptables.Action
|
||||
childIP = job.Getenv("ChildIP")
|
||||
parentIP = job.Getenv("ParentIP")
|
||||
ignoreErrors = job.GetenvBool("IgnoreErrors")
|
||||
ports = job.GetenvList("Ports")
|
||||
)
|
||||
|
||||
switch action {
|
||||
case "-A":
|
||||
nfAction = iptables.Append
|
||||
case "-I":
|
||||
nfAction = iptables.Insert
|
||||
case "-D":
|
||||
nfAction = iptables.Delete
|
||||
default:
|
||||
return job.Errorf("Invalid action '%s' specified", action)
|
||||
}
|
||||
|
||||
ip1 := net.ParseIP(parentIP)
|
||||
if ip1 == nil {
|
||||
return job.Errorf("parent IP '%s' is invalid", parentIP)
|
||||
}
|
||||
ip2 := net.ParseIP(childIP)
|
||||
if ip2 == nil {
|
||||
return job.Errorf("child IP '%s' is invalid", childIP)
|
||||
}
|
||||
|
||||
chain := iptables.Chain{Name: "DOCKER", Bridge: bridgeIface}
|
||||
for _, p := range ports {
|
||||
port := nat.Port(p)
|
||||
if err := chain.Link(nfAction, ip1, ip2, port.Int(), port.Proto()); !ignoreErrors && err != nil {
|
||||
return job.Error(err)
|
||||
}
|
||||
}
|
||||
return engine.StatusOK
|
||||
}
|
161
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver_test.go
generated
vendored
Normal file
161
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/bridge/driver_test.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/daemon/networkdriver/portmapper"
|
||||
"github.com/docker/docker/engine"
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// reset the new proxy command for mocking out the userland proxy in tests
|
||||
portmapper.NewProxy = portmapper.NewMockProxyCommand
|
||||
}
|
||||
|
||||
func findFreePort(t *testing.T) int {
|
||||
l, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
t.Fatal("Failed to find a free port")
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
result, err := net.ResolveTCPAddr("tcp", l.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatal("Failed to resolve address to identify free port")
|
||||
}
|
||||
return result.Port
|
||||
}
|
||||
|
||||
func newPortAllocationJob(eng *engine.Engine, port int) (job *engine.Job) {
|
||||
strPort := strconv.Itoa(port)
|
||||
|
||||
job = eng.Job("allocate_port", "container_id")
|
||||
job.Setenv("HostIP", "127.0.0.1")
|
||||
job.Setenv("HostPort", strPort)
|
||||
job.Setenv("Proto", "tcp")
|
||||
job.Setenv("ContainerPort", strPort)
|
||||
return
|
||||
}
|
||||
|
||||
func newPortAllocationJobWithInvalidHostIP(eng *engine.Engine, port int) (job *engine.Job) {
|
||||
strPort := strconv.Itoa(port)
|
||||
|
||||
job = eng.Job("allocate_port", "container_id")
|
||||
job.Setenv("HostIP", "localhost")
|
||||
job.Setenv("HostPort", strPort)
|
||||
job.Setenv("Proto", "tcp")
|
||||
job.Setenv("ContainerPort", strPort)
|
||||
return
|
||||
}
|
||||
|
||||
func TestAllocatePortDetection(t *testing.T) {
|
||||
eng := engine.New()
|
||||
eng.Logging = false
|
||||
|
||||
freePort := findFreePort(t)
|
||||
|
||||
// Init driver
|
||||
job := eng.Job("initdriver")
|
||||
if res := InitDriver(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to initialize network driver")
|
||||
}
|
||||
|
||||
// Allocate interface
|
||||
job = eng.Job("allocate_interface", "container_id")
|
||||
if res := Allocate(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to allocate network interface")
|
||||
}
|
||||
|
||||
// Allocate same port twice, expect failure on second call
|
||||
job = newPortAllocationJob(eng, freePort)
|
||||
if res := AllocatePort(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to find a free port to allocate")
|
||||
}
|
||||
if res := AllocatePort(job); res == engine.StatusOK {
|
||||
t.Fatal("Duplicate port allocation granted by AllocatePort")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHostnameFormatChecking(t *testing.T) {
|
||||
eng := engine.New()
|
||||
eng.Logging = false
|
||||
|
||||
freePort := findFreePort(t)
|
||||
|
||||
// Init driver
|
||||
job := eng.Job("initdriver")
|
||||
if res := InitDriver(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to initialize network driver")
|
||||
}
|
||||
|
||||
// Allocate interface
|
||||
job = eng.Job("allocate_interface", "container_id")
|
||||
if res := Allocate(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to allocate network interface")
|
||||
}
|
||||
|
||||
// Allocate port with invalid HostIP, expect failure with Bad Request http status
|
||||
job = newPortAllocationJobWithInvalidHostIP(eng, freePort)
|
||||
if res := AllocatePort(job); res == engine.StatusOK {
|
||||
t.Fatal("Failed to check invalid HostIP")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMacAddrGeneration(t *testing.T) {
|
||||
ip := net.ParseIP("192.168.0.1")
|
||||
mac := generateMacAddr(ip).String()
|
||||
|
||||
// Should be consistent.
|
||||
if generateMacAddr(ip).String() != mac {
|
||||
t.Fatal("Inconsistent MAC address")
|
||||
}
|
||||
|
||||
// Should be unique.
|
||||
ip2 := net.ParseIP("192.168.0.2")
|
||||
if generateMacAddr(ip2).String() == mac {
|
||||
t.Fatal("Non-unique MAC address")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkContainers(t *testing.T) {
|
||||
eng := engine.New()
|
||||
eng.Logging = false
|
||||
|
||||
// Init driver
|
||||
job := eng.Job("initdriver")
|
||||
if res := InitDriver(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to initialize network driver")
|
||||
}
|
||||
|
||||
// Allocate interface
|
||||
job = eng.Job("allocate_interface", "container_id")
|
||||
if res := Allocate(job); res != engine.StatusOK {
|
||||
t.Fatal("Failed to allocate network interface")
|
||||
}
|
||||
|
||||
job.Args[0] = "-I"
|
||||
|
||||
job.Setenv("ChildIP", "172.17.0.2")
|
||||
job.Setenv("ParentIP", "172.17.0.1")
|
||||
job.SetenvBool("IgnoreErrors", false)
|
||||
job.SetenvList("Ports", []string{"1234"})
|
||||
|
||||
bridgeIface = "lo"
|
||||
_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if res := LinkContainers(job); res != engine.StatusOK {
|
||||
t.Fatalf("LinkContainers failed")
|
||||
}
|
||||
|
||||
// flush rules
|
||||
if _, err = iptables.Raw([]string{"-F", "DOCKER"}...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
160
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator.go
generated
vendored
Normal file
160
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator.go
generated
vendored
Normal file
|
@ -0,0 +1,160 @@
|
|||
package ipallocator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/networkdriver"
|
||||
)
|
||||
|
||||
// allocatedMap is thread-unsafe set of allocated IP
|
||||
type allocatedMap struct {
|
||||
p map[string]struct{}
|
||||
last *big.Int
|
||||
begin *big.Int
|
||||
end *big.Int
|
||||
}
|
||||
|
||||
func newAllocatedMap(network *net.IPNet) *allocatedMap {
|
||||
firstIP, lastIP := networkdriver.NetworkRange(network)
|
||||
begin := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
|
||||
end := big.NewInt(0).Sub(ipToBigInt(lastIP), big.NewInt(1))
|
||||
|
||||
return &allocatedMap{
|
||||
p: make(map[string]struct{}),
|
||||
begin: begin,
|
||||
end: end,
|
||||
last: big.NewInt(0).Sub(begin, big.NewInt(1)), // so first allocated will be begin
|
||||
}
|
||||
}
|
||||
|
||||
type networkSet map[string]*allocatedMap
|
||||
|
||||
var (
|
||||
ErrNoAvailableIPs = errors.New("no available ip addresses on network")
|
||||
ErrIPAlreadyAllocated = errors.New("ip already allocated")
|
||||
ErrIPOutOfRange = errors.New("requested ip is out of range")
|
||||
ErrNetworkAlreadyRegistered = errors.New("network already registered")
|
||||
ErrBadSubnet = errors.New("network does not contain specified subnet")
|
||||
)
|
||||
|
||||
var (
|
||||
lock = sync.Mutex{}
|
||||
allocatedIPs = networkSet{}
|
||||
)
|
||||
|
||||
// RegisterSubnet registers network in global allocator with bounds
|
||||
// defined by subnet. If you want to use network range you must call
|
||||
// this method before first RequestIP, otherwise full network range will be used
|
||||
func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
key := network.String()
|
||||
if _, ok := allocatedIPs[key]; ok {
|
||||
return ErrNetworkAlreadyRegistered
|
||||
}
|
||||
n := newAllocatedMap(network)
|
||||
beginIP, endIP := networkdriver.NetworkRange(subnet)
|
||||
begin := big.NewInt(0).Add(ipToBigInt(beginIP), big.NewInt(1))
|
||||
end := big.NewInt(0).Sub(ipToBigInt(endIP), big.NewInt(1))
|
||||
|
||||
// Check that subnet is within network
|
||||
if !(begin.Cmp(n.begin) >= 0 && end.Cmp(n.end) <= 0 && begin.Cmp(end) == -1) {
|
||||
return ErrBadSubnet
|
||||
}
|
||||
n.begin.Set(begin)
|
||||
n.end.Set(end)
|
||||
n.last.Sub(begin, big.NewInt(1))
|
||||
allocatedIPs[key] = n
|
||||
return nil
|
||||
}
|
||||
|
||||
// RequestIP requests an available ip from the given network. It
|
||||
// will return the next available ip if the ip provided is nil. If the
|
||||
// ip provided is not nil it will validate that the provided ip is available
|
||||
// for use or return an error
|
||||
func RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
key := network.String()
|
||||
allocated, ok := allocatedIPs[key]
|
||||
if !ok {
|
||||
allocated = newAllocatedMap(network)
|
||||
allocatedIPs[key] = allocated
|
||||
}
|
||||
|
||||
if ip == nil {
|
||||
return allocated.getNextIP()
|
||||
}
|
||||
return allocated.checkIP(ip)
|
||||
}
|
||||
|
||||
// ReleaseIP adds the provided ip back into the pool of
|
||||
// available ips to be returned for use.
|
||||
func ReleaseIP(network *net.IPNet, ip net.IP) error {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
if allocated, exists := allocatedIPs[network.String()]; exists {
|
||||
delete(allocated.p, ip.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
|
||||
if _, ok := allocated.p[ip.String()]; ok {
|
||||
return nil, ErrIPAlreadyAllocated
|
||||
}
|
||||
|
||||
pos := ipToBigInt(ip)
|
||||
// Verify that the IP address is within our network range.
|
||||
if pos.Cmp(allocated.begin) == -1 || pos.Cmp(allocated.end) == 1 {
|
||||
return nil, ErrIPOutOfRange
|
||||
}
|
||||
|
||||
// Register the IP.
|
||||
allocated.p[ip.String()] = struct{}{}
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
// return an available ip if one is currently available. If not,
|
||||
// return the next available ip for the nextwork
|
||||
func (allocated *allocatedMap) getNextIP() (net.IP, error) {
|
||||
pos := big.NewInt(0).Set(allocated.last)
|
||||
allRange := big.NewInt(0).Sub(allocated.end, allocated.begin)
|
||||
for i := big.NewInt(0); i.Cmp(allRange) <= 0; i.Add(i, big.NewInt(1)) {
|
||||
pos.Add(pos, big.NewInt(1))
|
||||
if pos.Cmp(allocated.end) == 1 {
|
||||
pos.Set(allocated.begin)
|
||||
}
|
||||
if _, ok := allocated.p[bigIntToIP(pos).String()]; ok {
|
||||
continue
|
||||
}
|
||||
allocated.p[bigIntToIP(pos).String()] = struct{}{}
|
||||
allocated.last.Set(pos)
|
||||
return bigIntToIP(pos), nil
|
||||
}
|
||||
return nil, ErrNoAvailableIPs
|
||||
}
|
||||
|
||||
// Converts a 4 bytes IP into a 128 bit integer
|
||||
func ipToBigInt(ip net.IP) *big.Int {
|
||||
x := big.NewInt(0)
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
return x.SetBytes(ip4)
|
||||
}
|
||||
if ip6 := ip.To16(); ip6 != nil {
|
||||
return x.SetBytes(ip6)
|
||||
}
|
||||
|
||||
log.Errorf("ipToBigInt: Wrong IP length! %s", ip)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Converts 128 bit integer into a 4 bytes IP address
|
||||
func bigIntToIP(v *big.Int) net.IP {
|
||||
return net.IP(v.Bytes())
|
||||
}
|
681
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator_test.go
generated
vendored
Normal file
681
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/ipallocator/allocator_test.go
generated
vendored
Normal file
|
@ -0,0 +1,681 @@
|
|||
package ipallocator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func reset() {
|
||||
allocatedIPs = networkSet{}
|
||||
}
|
||||
|
||||
func TestConversion(t *testing.T) {
|
||||
ip := net.ParseIP("127.0.0.1")
|
||||
i := ipToBigInt(ip)
|
||||
if i.Cmp(big.NewInt(0x7f000001)) != 0 {
|
||||
t.Fatal("incorrect conversion")
|
||||
}
|
||||
conv := bigIntToIP(i)
|
||||
if !ip.Equal(conv) {
|
||||
t.Error(conv.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestConversionIPv6(t *testing.T) {
|
||||
ip := net.ParseIP("2a00:1450::1")
|
||||
ip2 := net.ParseIP("2a00:1450::2")
|
||||
ip3 := net.ParseIP("2a00:1450::1:1")
|
||||
i := ipToBigInt(ip)
|
||||
val, success := big.NewInt(0).SetString("2a001450000000000000000000000001", 16)
|
||||
if !success {
|
||||
t.Fatal("Hex-String to BigInt conversion failed.")
|
||||
}
|
||||
if i.Cmp(val) != 0 {
|
||||
t.Fatal("incorrent conversion")
|
||||
}
|
||||
|
||||
conv := bigIntToIP(i)
|
||||
conv2 := bigIntToIP(big.NewInt(0).Add(i, big.NewInt(1)))
|
||||
conv3 := bigIntToIP(big.NewInt(0).Add(i, big.NewInt(0x10000)))
|
||||
|
||||
if !ip.Equal(conv) {
|
||||
t.Error("2a00:1450::1 should be equal to " + conv.String())
|
||||
}
|
||||
if !ip2.Equal(conv2) {
|
||||
t.Error("2a00:1450::2 should be equal to " + conv2.String())
|
||||
}
|
||||
if !ip3.Equal(conv3) {
|
||||
t.Error("2a00:1450::1:1 should be equal to " + conv3.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestNewIps(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
var ip net.IP
|
||||
var err error
|
||||
|
||||
for i := 1; i < 10; i++ {
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := fmt.Sprintf("192.168.0.%d", i); ip.String() != expected {
|
||||
t.Fatalf("Expected ip %s got %s", expected, ip.String())
|
||||
}
|
||||
}
|
||||
value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip.String() != value {
|
||||
t.Fatalf("Expected to receive the next ip %s got %s", value, ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestNewIpV6(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
|
||||
var ip net.IP
|
||||
var err error
|
||||
for i := 1; i < 10; i++ {
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := fmt.Sprintf("2a00:1450::%d", i); ip.String() != expected {
|
||||
t.Fatalf("Expected ip %s got %s", expected, ip.String())
|
||||
}
|
||||
}
|
||||
value := bigIntToIP(big.NewInt(0).Add(ipToBigInt(ip), big.NewInt(1))).String()
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ip.String() != value {
|
||||
t.Fatalf("Expected to receive the next ip %s got %s", value, ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseIp(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseIpV6(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetReleasedIp(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
value := ip.String()
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 253; i++ {
|
||||
_, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ReleaseIP(network, ip)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ip.String() != value {
|
||||
t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetReleasedIpV6(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0},
|
||||
}
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
value := ip.String()
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := 0; i < 253; i++ {
|
||||
_, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ReleaseIP(network, ip)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
ip, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if ip.String() != value {
|
||||
t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestSpecificIp(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 224},
|
||||
}
|
||||
|
||||
ip := net.ParseIP("192.168.0.5")
|
||||
|
||||
// Request a "good" IP.
|
||||
if _, err := RequestIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Request the same IP again.
|
||||
if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated {
|
||||
t.Fatalf("Got the same IP twice: %#v", err)
|
||||
}
|
||||
|
||||
// Request an out of range IP.
|
||||
if _, err := RequestIP(network, net.ParseIP("192.168.0.42")); err != ErrIPOutOfRange {
|
||||
t.Fatalf("Got an out of range IP: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestSpecificIpV6(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
|
||||
ip := net.ParseIP("2a00:1450::5")
|
||||
|
||||
// Request a "good" IP.
|
||||
if _, err := RequestIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Request the same IP again.
|
||||
if _, err := RequestIP(network, ip); err != ErrIPAlreadyAllocated {
|
||||
t.Fatalf("Got the same IP twice: %#v", err)
|
||||
}
|
||||
|
||||
// Request an out of range IP.
|
||||
if _, err := RequestIP(network, net.ParseIP("2a00:1500::1")); err != ErrIPOutOfRange {
|
||||
t.Fatalf("Got an out of range IP: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPAllocator(t *testing.T) {
|
||||
expectedIPs := []net.IP{
|
||||
0: net.IPv4(127, 0, 0, 1),
|
||||
1: net.IPv4(127, 0, 0, 2),
|
||||
2: net.IPv4(127, 0, 0, 3),
|
||||
3: net.IPv4(127, 0, 0, 4),
|
||||
4: net.IPv4(127, 0, 0, 5),
|
||||
5: net.IPv4(127, 0, 0, 6),
|
||||
}
|
||||
|
||||
gwIP, n, _ := net.ParseCIDR("127.0.0.1/29")
|
||||
|
||||
network := &net.IPNet{IP: gwIP, Mask: n.Mask}
|
||||
// Pool after initialisation (f = free, u = used)
|
||||
// 1(f) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// Check that we get 6 IPs, from 127.0.0.1–127.0.0.6, in that
|
||||
// order.
|
||||
for i := 0; i < 6; i++ {
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, expectedIPs[i], ip)
|
||||
}
|
||||
// Before loop begin
|
||||
// 1(f) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 0
|
||||
// 1(u) - 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 1
|
||||
// 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 2
|
||||
// 1(u) - 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 3
|
||||
// 1(u) - 2(u) - 3(u) - 4(u) - 5(f) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 4
|
||||
// 1(u) - 2(u) - 3(u) - 4(u) - 5(u) - 6(f)
|
||||
// ↑
|
||||
|
||||
// After i = 5
|
||||
// 1(u) - 2(u) - 3(u) - 4(u) - 5(u) - 6(u)
|
||||
// ↑
|
||||
|
||||
// Check that there are no more IPs
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err == nil {
|
||||
t.Fatalf("There shouldn't be any IP addresses at this point, got %s\n", ip)
|
||||
}
|
||||
|
||||
// Release some IPs in non-sequential order
|
||||
if err := ReleaseIP(network, expectedIPs[3]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 1(u) - 2(u) - 3(u) - 4(f) - 5(u) - 6(u)
|
||||
// ↑
|
||||
|
||||
if err := ReleaseIP(network, expectedIPs[2]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 1(u) - 2(u) - 3(f) - 4(f) - 5(u) - 6(u)
|
||||
// ↑
|
||||
|
||||
if err := ReleaseIP(network, expectedIPs[4]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// 1(u) - 2(u) - 3(f) - 4(f) - 5(f) - 6(u)
|
||||
// ↑
|
||||
|
||||
// Make sure that IPs are reused in sequential order, starting
|
||||
// with the first released IP
|
||||
newIPs := make([]net.IP, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
newIPs[i] = ip
|
||||
}
|
||||
assertIPEquals(t, expectedIPs[2], newIPs[0])
|
||||
assertIPEquals(t, expectedIPs[3], newIPs[1])
|
||||
assertIPEquals(t, expectedIPs[4], newIPs[2])
|
||||
|
||||
_, err = RequestIP(network, nil)
|
||||
if err == nil {
|
||||
t.Fatal("There shouldn't be any IP addresses at this point")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateFirstIP(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 0},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
firstIP := network.IP.To4().Mask(network.Mask)
|
||||
first := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
|
||||
|
||||
ip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
allocated := ipToBigInt(ip)
|
||||
|
||||
if allocated == first {
|
||||
t.Fatalf("allocated ip should not equal first ip: %d == %d", first, allocated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateAllIps(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
var (
|
||||
current, first net.IP
|
||||
err error
|
||||
isFirst = true
|
||||
)
|
||||
|
||||
for err == nil {
|
||||
current, err = RequestIP(network, nil)
|
||||
if isFirst {
|
||||
first = current
|
||||
isFirst = false
|
||||
}
|
||||
}
|
||||
|
||||
if err != ErrNoAvailableIPs {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ReleaseIP(network, first); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
again, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, first, again)
|
||||
|
||||
// ensure that alloc.last == alloc.begin won't result in dead loop
|
||||
if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test by making alloc.last the only free ip and ensure we get it back
|
||||
// #1. first of the range, (alloc.last == ipToInt(first) already)
|
||||
if err := ReleaseIP(network, first); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ret, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, first, ret)
|
||||
|
||||
// #2. last of the range, note that current is the last one
|
||||
last := net.IPv4(192, 168, 0, 254)
|
||||
setLastTo(t, network, last)
|
||||
|
||||
ret, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, last, ret)
|
||||
|
||||
// #3. middle of the range
|
||||
mid := net.IPv4(192, 168, 0, 7)
|
||||
setLastTo(t, network, mid)
|
||||
|
||||
ret, err = RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, mid, ret)
|
||||
}
|
||||
|
||||
// make sure the pool is full when calling setLastTo.
|
||||
// we don't cheat here
|
||||
func setLastTo(t *testing.T, network *net.IPNet, ip net.IP) {
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ret, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertIPEquals(t, ip, ret)
|
||||
|
||||
if err := ReleaseIP(network, ip); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateDifferentSubnets(t *testing.T) {
|
||||
defer reset()
|
||||
network1 := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
network2 := &net.IPNet{
|
||||
IP: []byte{127, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
network3 := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
network4 := &net.IPNet{
|
||||
IP: []byte{0x2a, 0x00, 0x16, 0x32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||
}
|
||||
expectedIPs := []net.IP{
|
||||
0: net.IPv4(192, 168, 0, 1),
|
||||
1: net.IPv4(192, 168, 0, 2),
|
||||
2: net.IPv4(127, 0, 0, 1),
|
||||
3: net.IPv4(127, 0, 0, 2),
|
||||
4: net.ParseIP("2a00:1450::1"),
|
||||
5: net.ParseIP("2a00:1450::2"),
|
||||
6: net.ParseIP("2a00:1450::3"),
|
||||
7: net.ParseIP("2a00:1632::1"),
|
||||
8: net.ParseIP("2a00:1632::2"),
|
||||
}
|
||||
|
||||
ip11, err := RequestIP(network1, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip12, err := RequestIP(network1, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip21, err := RequestIP(network2, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip22, err := RequestIP(network2, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip31, err := RequestIP(network3, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip32, err := RequestIP(network3, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip33, err := RequestIP(network3, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip41, err := RequestIP(network4, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ip42, err := RequestIP(network4, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertIPEquals(t, expectedIPs[0], ip11)
|
||||
assertIPEquals(t, expectedIPs[1], ip12)
|
||||
assertIPEquals(t, expectedIPs[2], ip21)
|
||||
assertIPEquals(t, expectedIPs[3], ip22)
|
||||
assertIPEquals(t, expectedIPs[4], ip31)
|
||||
assertIPEquals(t, expectedIPs[5], ip32)
|
||||
assertIPEquals(t, expectedIPs[6], ip33)
|
||||
assertIPEquals(t, expectedIPs[7], ip41)
|
||||
assertIPEquals(t, expectedIPs[8], ip42)
|
||||
}
|
||||
|
||||
func TestRegisterBadTwice(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
subnet := &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 8},
|
||||
Mask: []byte{255, 255, 255, 248},
|
||||
}
|
||||
|
||||
if err := RegisterSubnet(network, subnet); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
subnet = &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 16},
|
||||
Mask: []byte{255, 255, 255, 248},
|
||||
}
|
||||
if err := RegisterSubnet(network, subnet); err != ErrNetworkAlreadyRegistered {
|
||||
t.Fatalf("Expecteded ErrNetworkAlreadyRegistered error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterBadRange(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
subnet := &net.IPNet{
|
||||
IP: []byte{192, 168, 1, 1},
|
||||
Mask: []byte{255, 255, 0, 0},
|
||||
}
|
||||
if err := RegisterSubnet(network, subnet); err != ErrBadSubnet {
|
||||
t.Fatalf("Expected ErrBadSubnet error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateFromRange(t *testing.T) {
|
||||
defer reset()
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
// 192.168.1.9 - 192.168.1.14
|
||||
subnet := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 8},
|
||||
Mask: []byte{255, 255, 255, 248},
|
||||
}
|
||||
|
||||
if err := RegisterSubnet(network, subnet); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedIPs := []net.IP{
|
||||
0: net.IPv4(192, 168, 0, 9),
|
||||
1: net.IPv4(192, 168, 0, 10),
|
||||
2: net.IPv4(192, 168, 0, 11),
|
||||
3: net.IPv4(192, 168, 0, 12),
|
||||
4: net.IPv4(192, 168, 0, 13),
|
||||
5: net.IPv4(192, 168, 0, 14),
|
||||
}
|
||||
for _, ip := range expectedIPs {
|
||||
rip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertIPEquals(t, ip, rip)
|
||||
}
|
||||
|
||||
if _, err := RequestIP(network, nil); err != ErrNoAvailableIPs {
|
||||
t.Fatalf("Expected ErrNoAvailableIPs error, got %v", err)
|
||||
}
|
||||
for _, ip := range expectedIPs {
|
||||
ReleaseIP(network, ip)
|
||||
rip, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assertIPEquals(t, ip, rip)
|
||||
}
|
||||
}
|
||||
|
||||
func assertIPEquals(t *testing.T, ip1, ip2 net.IP) {
|
||||
if !ip1.Equal(ip2) {
|
||||
t.Fatalf("Expected IP %s, got %s", ip1, ip2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRequestIP(b *testing.B) {
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := 0; j < 253; j++ {
|
||||
_, err := RequestIP(network, nil)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
reset()
|
||||
}
|
||||
}
|
10
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network.go
generated
vendored
Normal file
10
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
package networkdriver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")
|
||||
ErrNetworkOverlaps = errors.New("requested network overlaps with existing network")
|
||||
)
|
175
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network_test.go
generated
vendored
Normal file
175
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/network_test.go
generated
vendored
Normal file
|
@ -0,0 +1,175 @@
|
|||
package networkdriver
|
||||
|
||||
import (
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNonOverlapingNameservers(t *testing.T) {
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
nameservers := []string{
|
||||
"127.0.0.1/32",
|
||||
}
|
||||
|
||||
if err := CheckNameserverOverlaps(nameservers, network); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverlapingNameservers(t *testing.T) {
|
||||
network := &net.IPNet{
|
||||
IP: []byte{192, 168, 0, 1},
|
||||
Mask: []byte{255, 255, 255, 0},
|
||||
}
|
||||
nameservers := []string{
|
||||
"192.168.0.1/32",
|
||||
}
|
||||
|
||||
if err := CheckNameserverOverlaps(nameservers, network); err == nil {
|
||||
t.Fatalf("Expected error %s got %s", ErrNetworkOverlapsWithNameservers, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckRouteOverlaps(t *testing.T) {
|
||||
orig := networkGetRoutesFct
|
||||
defer func() {
|
||||
networkGetRoutesFct = orig
|
||||
}()
|
||||
networkGetRoutesFct = func() ([]netlink.Route, error) {
|
||||
routesData := []string{"10.0.2.0/32", "10.0.3.0/24", "10.0.42.0/24", "172.16.42.0/24", "192.168.142.0/24"}
|
||||
|
||||
routes := []netlink.Route{}
|
||||
for _, addr := range routesData {
|
||||
_, netX, _ := net.ParseCIDR(addr)
|
||||
routes = append(routes, netlink.Route{IPNet: netX})
|
||||
}
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
_, netX, _ := net.ParseCIDR("172.16.0.1/24")
|
||||
if err := CheckRouteOverlaps(netX); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, netX, _ = net.ParseCIDR("10.0.2.0/24")
|
||||
if err := CheckRouteOverlaps(netX); err == nil {
|
||||
t.Fatalf("10.0.2.0/24 and 10.0.2.0 should overlap but it doesn't")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckNameserverOverlaps(t *testing.T) {
|
||||
nameservers := []string{"10.0.2.3/32", "192.168.102.1/32"}
|
||||
|
||||
_, netX, _ := net.ParseCIDR("10.0.2.3/32")
|
||||
|
||||
if err := CheckNameserverOverlaps(nameservers, netX); err == nil {
|
||||
t.Fatalf("%s should overlap 10.0.2.3/32 but doesn't", netX)
|
||||
}
|
||||
|
||||
_, netX, _ = net.ParseCIDR("192.168.102.2/32")
|
||||
|
||||
if err := CheckNameserverOverlaps(nameservers, netX); err != nil {
|
||||
t.Fatalf("%s should not overlap %v but it does", netX, nameservers)
|
||||
}
|
||||
}
|
||||
|
||||
func AssertOverlap(CIDRx string, CIDRy string, t *testing.T) {
|
||||
_, netX, _ := net.ParseCIDR(CIDRx)
|
||||
_, netY, _ := net.ParseCIDR(CIDRy)
|
||||
if !NetworkOverlaps(netX, netY) {
|
||||
t.Errorf("%v and %v should overlap", netX, netY)
|
||||
}
|
||||
}
|
||||
|
||||
func AssertNoOverlap(CIDRx string, CIDRy string, t *testing.T) {
|
||||
_, netX, _ := net.ParseCIDR(CIDRx)
|
||||
_, netY, _ := net.ParseCIDR(CIDRy)
|
||||
if NetworkOverlaps(netX, netY) {
|
||||
t.Errorf("%v and %v should not overlap", netX, netY)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkOverlaps(t *testing.T) {
|
||||
//netY starts at same IP and ends within netX
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.1/25", t)
|
||||
//netY starts within netX and ends at same IP
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.128/25", t)
|
||||
//netY starts and ends within netX
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.64/25", t)
|
||||
//netY starts at same IP and ends outside of netX
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.1/23", t)
|
||||
//netY starts before and ends at same IP of netX
|
||||
AssertOverlap("172.16.1.1/24", "172.16.0.1/23", t)
|
||||
//netY starts before and ends outside of netX
|
||||
AssertOverlap("172.16.1.1/24", "172.16.0.1/22", t)
|
||||
//netY starts and ends before netX
|
||||
AssertNoOverlap("172.16.1.1/25", "172.16.0.1/24", t)
|
||||
//netX starts and ends before netY
|
||||
AssertNoOverlap("172.16.1.1/25", "172.16.2.1/24", t)
|
||||
}
|
||||
|
||||
func TestNetworkRange(t *testing.T) {
|
||||
// Simple class C test
|
||||
_, network, _ := net.ParseCIDR("192.168.0.1/24")
|
||||
first, last := NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("192.168.0.0")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("192.168.0.255")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// Class A test
|
||||
_, network, _ = net.ParseCIDR("10.0.0.1/8")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.0.0.0")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.255.255.255")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// Class A, random IP address
|
||||
_, network, _ = net.ParseCIDR("10.1.2.3/8")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.0.0.0")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.255.255.255")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// 32bit mask
|
||||
_, network, _ = net.ParseCIDR("10.1.2.3/32")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.1.2.3")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.1.2.3")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// 31bit mask
|
||||
_, network, _ = net.ParseCIDR("10.1.2.3/31")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.1.2.2")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.1.2.3")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
|
||||
// 26bit mask
|
||||
_, network, _ = net.ParseCIDR("10.1.2.3/26")
|
||||
first, last = NetworkRange(network)
|
||||
if !first.Equal(net.ParseIP("10.1.2.0")) {
|
||||
t.Error(first.String())
|
||||
}
|
||||
if !last.Equal(net.ParseIP("10.1.2.63")) {
|
||||
t.Error(last.String())
|
||||
}
|
||||
}
|
153
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator.go
generated
vendored
Normal file
153
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator.go
generated
vendored
Normal file
|
@ -0,0 +1,153 @@
|
|||
package portallocator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type portMap struct {
|
||||
p map[int]struct{}
|
||||
last int
|
||||
}
|
||||
|
||||
func newPortMap() *portMap {
|
||||
return &portMap{
|
||||
p: map[int]struct{}{},
|
||||
last: EndPortRange,
|
||||
}
|
||||
}
|
||||
|
||||
type protoMap map[string]*portMap
|
||||
|
||||
func newProtoMap() protoMap {
|
||||
return protoMap{
|
||||
"tcp": newPortMap(),
|
||||
"udp": newPortMap(),
|
||||
}
|
||||
}
|
||||
|
||||
type ipMapping map[string]protoMap
|
||||
|
||||
const (
|
||||
BeginPortRange = 49153
|
||||
EndPortRange = 65535
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAllPortsAllocated = errors.New("all ports are allocated")
|
||||
ErrUnknownProtocol = errors.New("unknown protocol")
|
||||
)
|
||||
|
||||
var (
|
||||
mutex sync.Mutex
|
||||
|
||||
defaultIP = net.ParseIP("0.0.0.0")
|
||||
globalMap = ipMapping{}
|
||||
)
|
||||
|
||||
type ErrPortAlreadyAllocated struct {
|
||||
ip string
|
||||
port int
|
||||
}
|
||||
|
||||
func NewErrPortAlreadyAllocated(ip string, port int) ErrPortAlreadyAllocated {
|
||||
return ErrPortAlreadyAllocated{
|
||||
ip: ip,
|
||||
port: port,
|
||||
}
|
||||
}
|
||||
|
||||
func (e ErrPortAlreadyAllocated) IP() string {
|
||||
return e.ip
|
||||
}
|
||||
|
||||
func (e ErrPortAlreadyAllocated) Port() int {
|
||||
return e.port
|
||||
}
|
||||
|
||||
func (e ErrPortAlreadyAllocated) IPPort() string {
|
||||
return fmt.Sprintf("%s:%d", e.ip, e.port)
|
||||
}
|
||||
|
||||
func (e ErrPortAlreadyAllocated) Error() string {
|
||||
return fmt.Sprintf("Bind for %s:%d failed: port is already allocated", e.ip, e.port)
|
||||
}
|
||||
|
||||
// RequestPort requests new port from global ports pool for specified ip and proto.
|
||||
// If port is 0 it returns first free port. Otherwise it cheks port availability
|
||||
// in pool and return that port or error if port is already busy.
|
||||
func RequestPort(ip net.IP, proto string, port int) (int, error) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if proto != "tcp" && proto != "udp" {
|
||||
return 0, ErrUnknownProtocol
|
||||
}
|
||||
|
||||
if ip == nil {
|
||||
ip = defaultIP
|
||||
}
|
||||
ipstr := ip.String()
|
||||
protomap, ok := globalMap[ipstr]
|
||||
if !ok {
|
||||
protomap = newProtoMap()
|
||||
globalMap[ipstr] = protomap
|
||||
}
|
||||
mapping := protomap[proto]
|
||||
if port > 0 {
|
||||
if _, ok := mapping.p[port]; !ok {
|
||||
mapping.p[port] = struct{}{}
|
||||
return port, nil
|
||||
}
|
||||
return 0, NewErrPortAlreadyAllocated(ipstr, port)
|
||||
}
|
||||
|
||||
port, err := mapping.findPort()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return port, nil
|
||||
}
|
||||
|
||||
// ReleasePort releases port from global ports pool for specified ip and proto.
|
||||
func ReleasePort(ip net.IP, proto string, port int) error {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if ip == nil {
|
||||
ip = defaultIP
|
||||
}
|
||||
protomap, ok := globalMap[ip.String()]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
delete(protomap[proto].p, port)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReleaseAll releases all ports for all ips.
|
||||
func ReleaseAll() error {
|
||||
mutex.Lock()
|
||||
globalMap = ipMapping{}
|
||||
mutex.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pm *portMap) findPort() (int, error) {
|
||||
port := pm.last
|
||||
for i := 0; i <= EndPortRange-BeginPortRange; i++ {
|
||||
port++
|
||||
if port > EndPortRange {
|
||||
port = BeginPortRange
|
||||
}
|
||||
|
||||
if _, ok := pm.p[port]; !ok {
|
||||
pm.p[port] = struct{}{}
|
||||
pm.last = port
|
||||
return port, nil
|
||||
}
|
||||
}
|
||||
return 0, ErrAllPortsAllocated
|
||||
}
|
245
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator_test.go
generated
vendored
Normal file
245
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portallocator/portallocator_test.go
generated
vendored
Normal file
|
@ -0,0 +1,245 @@
|
|||
package portallocator
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func reset() {
|
||||
ReleaseAll()
|
||||
}
|
||||
|
||||
func TestRequestNewPort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := BeginPortRange; port != expected {
|
||||
t.Fatalf("Expected port %d got %d", expected, port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequestSpecificPort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port != 5000 {
|
||||
t.Fatalf("Expected port 5000 got %d", port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleasePort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port != 5000 {
|
||||
t.Fatalf("Expected port 5000 got %d", port)
|
||||
}
|
||||
|
||||
if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReuseReleasedPort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port != 5000 {
|
||||
t.Fatalf("Expected port 5000 got %d", port)
|
||||
}
|
||||
|
||||
if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
port, err = RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseUnreadledPort(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
port, err := RequestPort(defaultIP, "tcp", 5000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port != 5000 {
|
||||
t.Fatalf("Expected port 5000 got %d", port)
|
||||
}
|
||||
|
||||
port, err = RequestPort(defaultIP, "tcp", 5000)
|
||||
|
||||
switch err.(type) {
|
||||
case ErrPortAlreadyAllocated:
|
||||
default:
|
||||
t.Fatalf("Expected port allocation error got %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknowProtocol(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
if _, err := RequestPort(defaultIP, "tcpp", 0); err != ErrUnknownProtocol {
|
||||
t.Fatalf("Expected error %s got %s", ErrUnknownProtocol, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateAllPorts(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
for i := 0; i <= EndPortRange-BeginPortRange; i++ {
|
||||
port, err := RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := BeginPortRange + i; port != expected {
|
||||
t.Fatalf("Expected port %d got %d", expected, port)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := RequestPort(defaultIP, "tcp", 0); err != ErrAllPortsAllocated {
|
||||
t.Fatalf("Expected error %s got %s", ErrAllPortsAllocated, err)
|
||||
}
|
||||
|
||||
_, err := RequestPort(defaultIP, "udp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// release a port in the middle and ensure we get another tcp port
|
||||
port := BeginPortRange + 5
|
||||
if err := ReleasePort(defaultIP, "tcp", port); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
newPort, err := RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if newPort != port {
|
||||
t.Fatalf("Expected port %d got %d", port, newPort)
|
||||
}
|
||||
|
||||
// now pm.last == newPort, release it so that it's the only free port of
|
||||
// the range, and ensure we get it back
|
||||
if err := ReleasePort(defaultIP, "tcp", newPort); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port, err = RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if newPort != port {
|
||||
t.Fatalf("Expected port %d got %d", newPort, port)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAllocatePorts(b *testing.B) {
|
||||
defer reset()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for i := 0; i <= EndPortRange-BeginPortRange; i++ {
|
||||
port, err := RequestPort(defaultIP, "tcp", 0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := BeginPortRange + i; port != expected {
|
||||
b.Fatalf("Expected port %d got %d", expected, port)
|
||||
}
|
||||
}
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestPortAllocation(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
ip := net.ParseIP("192.168.0.1")
|
||||
ip2 := net.ParseIP("192.168.0.2")
|
||||
if port, err := RequestPort(ip, "tcp", 80); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if port != 80 {
|
||||
t.Fatalf("Acquire(80) should return 80, not %d", port)
|
||||
}
|
||||
port, err := RequestPort(ip, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port <= 0 {
|
||||
t.Fatalf("Acquire(0) should return a non-zero port")
|
||||
}
|
||||
|
||||
if _, err := RequestPort(ip, "tcp", port); err == nil {
|
||||
t.Fatalf("Acquiring a port already in use should return an error")
|
||||
}
|
||||
|
||||
if newPort, err := RequestPort(ip, "tcp", 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if newPort == port {
|
||||
t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
|
||||
}
|
||||
|
||||
if _, err := RequestPort(ip, "tcp", 80); err == nil {
|
||||
t.Fatalf("Acquiring a port already in use should return an error")
|
||||
}
|
||||
if _, err := RequestPort(ip2, "tcp", 80); err != nil {
|
||||
t.Fatalf("It should be possible to allocate the same port on a different interface")
|
||||
}
|
||||
if _, err := RequestPort(ip2, "tcp", 80); err == nil {
|
||||
t.Fatalf("Acquiring a port already in use should return an error")
|
||||
}
|
||||
if err := ReleasePort(ip, "tcp", 80); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := RequestPort(ip, "tcp", 80); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
port, err = RequestPort(ip, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port2, err := RequestPort(ip, "tcp", port+1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port3, err := RequestPort(ip, "tcp", 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if port3 == port2 {
|
||||
t.Fatal("Requesting a dynamic port should never allocate a used port")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoDuplicateBPR(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
if port, err := RequestPort(defaultIP, "tcp", BeginPortRange); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if port != BeginPortRange {
|
||||
t.Fatalf("Expected port %d got %d", BeginPortRange, port)
|
||||
}
|
||||
|
||||
if port, err := RequestPort(defaultIP, "tcp", 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if port == BeginPortRange {
|
||||
t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
|
||||
}
|
||||
}
|
176
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper.go
generated
vendored
Normal file
176
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper.go
generated
vendored
Normal file
|
@ -0,0 +1,176 @@
|
|||
package portmapper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/networkdriver/portallocator"
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
)
|
||||
|
||||
type mapping struct {
|
||||
proto string
|
||||
userlandProxy UserlandProxy
|
||||
host net.Addr
|
||||
container net.Addr
|
||||
}
|
||||
|
||||
var (
|
||||
chain *iptables.Chain
|
||||
lock sync.Mutex
|
||||
|
||||
// udp:ip:port
|
||||
currentMappings = make(map[string]*mapping)
|
||||
|
||||
NewProxy = NewProxyCommand
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnknownBackendAddressType = errors.New("unknown container address type not supported")
|
||||
ErrPortMappedForIP = errors.New("port is already mapped to ip")
|
||||
ErrPortNotMapped = errors.New("port is not mapped")
|
||||
)
|
||||
|
||||
func SetIptablesChain(c *iptables.Chain) {
|
||||
chain = c
|
||||
}
|
||||
|
||||
func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err error) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
var (
|
||||
m *mapping
|
||||
proto string
|
||||
allocatedHostPort int
|
||||
proxy UserlandProxy
|
||||
)
|
||||
|
||||
switch container.(type) {
|
||||
case *net.TCPAddr:
|
||||
proto = "tcp"
|
||||
if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m = &mapping{
|
||||
proto: proto,
|
||||
host: &net.TCPAddr{IP: hostIP, Port: allocatedHostPort},
|
||||
container: container,
|
||||
}
|
||||
|
||||
proxy = NewProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
|
||||
case *net.UDPAddr:
|
||||
proto = "udp"
|
||||
if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m = &mapping{
|
||||
proto: proto,
|
||||
host: &net.UDPAddr{IP: hostIP, Port: allocatedHostPort},
|
||||
container: container,
|
||||
}
|
||||
|
||||
proxy = NewProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port)
|
||||
default:
|
||||
return nil, ErrUnknownBackendAddressType
|
||||
}
|
||||
|
||||
// release the allocated port on any further error during return.
|
||||
defer func() {
|
||||
if err != nil {
|
||||
portallocator.ReleasePort(hostIP, proto, allocatedHostPort)
|
||||
}
|
||||
}()
|
||||
|
||||
key := getKey(m.host)
|
||||
if _, exists := currentMappings[key]; exists {
|
||||
return nil, ErrPortMappedForIP
|
||||
}
|
||||
|
||||
containerIP, containerPort := getIPAndPort(m.container)
|
||||
if err := forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cleanup := func() error {
|
||||
// need to undo the iptables rules before we return
|
||||
proxy.Stop()
|
||||
forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
|
||||
if err := portallocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := proxy.Start(); err != nil {
|
||||
if err := cleanup(); err != nil {
|
||||
return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
m.userlandProxy = proxy
|
||||
currentMappings[key] = m
|
||||
return m.host, nil
|
||||
}
|
||||
|
||||
func Unmap(host net.Addr) error {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
key := getKey(host)
|
||||
data, exists := currentMappings[key]
|
||||
if !exists {
|
||||
return ErrPortNotMapped
|
||||
}
|
||||
|
||||
data.userlandProxy.Stop()
|
||||
|
||||
delete(currentMappings, key)
|
||||
|
||||
containerIP, containerPort := getIPAndPort(data.container)
|
||||
hostIP, hostPort := getIPAndPort(data.host)
|
||||
if err := forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
|
||||
log.Errorf("Error on iptables delete: %s", err)
|
||||
}
|
||||
|
||||
switch a := host.(type) {
|
||||
case *net.TCPAddr:
|
||||
return portallocator.ReleasePort(a.IP, "tcp", a.Port)
|
||||
case *net.UDPAddr:
|
||||
return portallocator.ReleasePort(a.IP, "udp", a.Port)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getKey(a net.Addr) string {
|
||||
switch t := a.(type) {
|
||||
case *net.TCPAddr:
|
||||
return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "tcp")
|
||||
case *net.UDPAddr:
|
||||
return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getIPAndPort(a net.Addr) (net.IP, int) {
|
||||
switch t := a.(type) {
|
||||
case *net.TCPAddr:
|
||||
return t.IP, t.Port
|
||||
case *net.UDPAddr:
|
||||
return t.IP, t.Port
|
||||
}
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
func forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
|
||||
if chain == nil {
|
||||
return nil
|
||||
}
|
||||
return chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort)
|
||||
}
|
152
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper_test.go
generated
vendored
Normal file
152
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mapper_test.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
package portmapper
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/daemon/networkdriver/portallocator"
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// override this func to mock out the proxy server
|
||||
NewProxy = NewMockProxyCommand
|
||||
}
|
||||
|
||||
func reset() {
|
||||
chain = nil
|
||||
currentMappings = make(map[string]*mapping)
|
||||
}
|
||||
|
||||
func TestSetIptablesChain(t *testing.T) {
|
||||
defer reset()
|
||||
|
||||
c := &iptables.Chain{
|
||||
Name: "TEST",
|
||||
Bridge: "192.168.1.1",
|
||||
}
|
||||
|
||||
if chain != nil {
|
||||
t.Fatal("chain should be nil at init")
|
||||
}
|
||||
|
||||
SetIptablesChain(c)
|
||||
if chain == nil {
|
||||
t.Fatal("chain should not be nil after set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapPorts(t *testing.T) {
|
||||
dstIp1 := net.ParseIP("192.168.0.1")
|
||||
dstIp2 := net.ParseIP("192.168.0.2")
|
||||
dstAddr1 := &net.TCPAddr{IP: dstIp1, Port: 80}
|
||||
dstAddr2 := &net.TCPAddr{IP: dstIp2, Port: 80}
|
||||
|
||||
srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
|
||||
srcAddr2 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.2")}
|
||||
|
||||
addrEqual := func(addr1, addr2 net.Addr) bool {
|
||||
return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
|
||||
}
|
||||
|
||||
if host, err := Map(srcAddr1, dstIp1, 80); err != nil {
|
||||
t.Fatalf("Failed to allocate port: %s", err)
|
||||
} else if !addrEqual(dstAddr1, host) {
|
||||
t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
|
||||
dstAddr1.String(), dstAddr1.Network(), host.String(), host.Network())
|
||||
}
|
||||
|
||||
if _, err := Map(srcAddr1, dstIp1, 80); err == nil {
|
||||
t.Fatalf("Port is in use - mapping should have failed")
|
||||
}
|
||||
|
||||
if _, err := Map(srcAddr2, dstIp1, 80); err == nil {
|
||||
t.Fatalf("Port is in use - mapping should have failed")
|
||||
}
|
||||
|
||||
if _, err := Map(srcAddr2, dstIp2, 80); err != nil {
|
||||
t.Fatalf("Failed to allocate port: %s", err)
|
||||
}
|
||||
|
||||
if Unmap(dstAddr1) != nil {
|
||||
t.Fatalf("Failed to release port")
|
||||
}
|
||||
|
||||
if Unmap(dstAddr2) != nil {
|
||||
t.Fatalf("Failed to release port")
|
||||
}
|
||||
|
||||
if Unmap(dstAddr2) == nil {
|
||||
t.Fatalf("Port already released, but no error reported")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUDPKey(t *testing.T) {
|
||||
addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
|
||||
|
||||
key := getKey(addr)
|
||||
|
||||
if expected := "192.168.1.5:53/udp"; key != expected {
|
||||
t.Fatalf("expected key %s got %s", expected, key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTCPKey(t *testing.T) {
|
||||
addr := &net.TCPAddr{IP: net.ParseIP("192.168.1.5"), Port: 80}
|
||||
|
||||
key := getKey(addr)
|
||||
|
||||
if expected := "192.168.1.5:80/tcp"; key != expected {
|
||||
t.Fatalf("expected key %s got %s", expected, key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUDPIPAndPort(t *testing.T) {
|
||||
addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
|
||||
|
||||
ip, port := getIPAndPort(addr)
|
||||
if expected := "192.168.1.5"; ip.String() != expected {
|
||||
t.Fatalf("expected ip %s got %s", expected, ip)
|
||||
}
|
||||
|
||||
if ep := 53; port != ep {
|
||||
t.Fatalf("expected port %d got %d", ep, port)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapAllPortsSingleInterface(t *testing.T) {
|
||||
dstIp1 := net.ParseIP("0.0.0.0")
|
||||
srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
|
||||
|
||||
hosts := []net.Addr{}
|
||||
var host net.Addr
|
||||
var err error
|
||||
|
||||
defer func() {
|
||||
for _, val := range hosts {
|
||||
Unmap(val)
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
for i := portallocator.BeginPortRange; i < portallocator.EndPortRange; i++ {
|
||||
if host, err = Map(srcAddr1, dstIp1, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
|
||||
if _, err := Map(srcAddr1, dstIp1, portallocator.BeginPortRange); err == nil {
|
||||
t.Fatalf("Port %d should be bound but is not", portallocator.BeginPortRange)
|
||||
}
|
||||
|
||||
for _, val := range hosts {
|
||||
if err := Unmap(val); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
hosts = []net.Addr{}
|
||||
}
|
||||
}
|
18
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mock_proxy.go
generated
vendored
Normal file
18
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/mock_proxy.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
package portmapper
|
||||
|
||||
import "net"
|
||||
|
||||
func NewMockProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) UserlandProxy {
|
||||
return &mockProxyCommand{}
|
||||
}
|
||||
|
||||
type mockProxyCommand struct {
|
||||
}
|
||||
|
||||
func (p *mockProxyCommand) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *mockProxyCommand) Stop() error {
|
||||
return nil
|
||||
}
|
161
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/proxy.go
generated
vendored
Normal file
161
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/portmapper/proxy.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
package portmapper
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/proxy"
|
||||
"github.com/docker/docker/pkg/reexec"
|
||||
)
|
||||
|
||||
const userlandProxyCommandName = "docker-proxy"
|
||||
|
||||
func init() {
|
||||
reexec.Register(userlandProxyCommandName, execProxy)
|
||||
}
|
||||
|
||||
type UserlandProxy interface {
|
||||
Start() error
|
||||
Stop() error
|
||||
}
|
||||
|
||||
// proxyCommand wraps an exec.Cmd to run the userland TCP and UDP
|
||||
// proxies as separate processes.
|
||||
type proxyCommand struct {
|
||||
cmd *exec.Cmd
|
||||
}
|
||||
|
||||
// execProxy is the reexec function that is registered to start the userland proxies
|
||||
func execProxy() {
|
||||
f := os.NewFile(3, "signal-parent")
|
||||
host, container := parseHostContainerAddrs()
|
||||
|
||||
p, err := proxy.NewProxy(host, container)
|
||||
if err != nil {
|
||||
fmt.Fprintf(f, "1\n%s", err)
|
||||
f.Close()
|
||||
os.Exit(1)
|
||||
}
|
||||
go handleStopSignals(p)
|
||||
fmt.Fprint(f, "0\n")
|
||||
f.Close()
|
||||
|
||||
// Run will block until the proxy stops
|
||||
p.Run()
|
||||
}
|
||||
|
||||
// parseHostContainerAddrs parses the flags passed on reexec to create the TCP or UDP
|
||||
// net.Addrs to map the host and container ports
|
||||
func parseHostContainerAddrs() (host net.Addr, container net.Addr) {
|
||||
var (
|
||||
proto = flag.String("proto", "tcp", "proxy protocol")
|
||||
hostIP = flag.String("host-ip", "", "host ip")
|
||||
hostPort = flag.Int("host-port", -1, "host port")
|
||||
containerIP = flag.String("container-ip", "", "container ip")
|
||||
containerPort = flag.Int("container-port", -1, "container port")
|
||||
)
|
||||
|
||||
flag.Parse()
|
||||
|
||||
switch *proto {
|
||||
case "tcp":
|
||||
host = &net.TCPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
|
||||
container = &net.TCPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
|
||||
case "udp":
|
||||
host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
|
||||
container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
|
||||
default:
|
||||
log.Fatalf("unsupported protocol %s", *proto)
|
||||
}
|
||||
|
||||
return host, container
|
||||
}
|
||||
|
||||
func handleStopSignals(p proxy.Proxy) {
|
||||
s := make(chan os.Signal, 10)
|
||||
signal.Notify(s, os.Interrupt, syscall.SIGTERM, syscall.SIGSTOP)
|
||||
|
||||
for _ = range s {
|
||||
p.Close()
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
func NewProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int) UserlandProxy {
|
||||
args := []string{
|
||||
userlandProxyCommandName,
|
||||
"-proto", proto,
|
||||
"-host-ip", hostIP.String(),
|
||||
"-host-port", strconv.Itoa(hostPort),
|
||||
"-container-ip", containerIP.String(),
|
||||
"-container-port", strconv.Itoa(containerPort),
|
||||
}
|
||||
|
||||
return &proxyCommand{
|
||||
cmd: &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: args,
|
||||
SysProcAttr: &syscall.SysProcAttr{
|
||||
Pdeathsig: syscall.SIGTERM, // send a sigterm to the proxy if the daemon process dies
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *proxyCommand) Start() error {
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
return fmt.Errorf("proxy unable to open os.Pipe %s", err)
|
||||
}
|
||||
defer r.Close()
|
||||
p.cmd.ExtraFiles = []*os.File{w}
|
||||
if err := p.cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Close()
|
||||
|
||||
errchan := make(chan error, 1)
|
||||
go func() {
|
||||
buf := make([]byte, 2)
|
||||
r.Read(buf)
|
||||
|
||||
if string(buf) != "0\n" {
|
||||
errStr, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
errchan <- fmt.Errorf("Error reading exit status from userland proxy: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
errchan <- fmt.Errorf("Error starting userland proxy: %s", errStr)
|
||||
return
|
||||
}
|
||||
errchan <- nil
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errchan:
|
||||
return err
|
||||
case <-time.After(16 * time.Second):
|
||||
return fmt.Errorf("Timed out proxy starting the userland proxy")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *proxyCommand) Stop() error {
|
||||
if p.cmd.Process != nil {
|
||||
if err := p.cmd.Process.Signal(os.Interrupt); err != nil {
|
||||
return err
|
||||
}
|
||||
return p.cmd.Wait()
|
||||
}
|
||||
return nil
|
||||
}
|
118
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/utils.go
generated
vendored
Normal file
118
libnetwork/Godeps/_workspace/src/github.com/docker/docker/daemon/networkdriver/utils.go
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
package networkdriver
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libcontainer/netlink"
|
||||
)
|
||||
|
||||
var (
|
||||
networkGetRoutesFct = netlink.NetworkGetRoutes
|
||||
ErrNoDefaultRoute = errors.New("no default route")
|
||||
)
|
||||
|
||||
func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
|
||||
if len(nameservers) > 0 {
|
||||
for _, ns := range nameservers {
|
||||
_, nsNetwork, err := net.ParseCIDR(ns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if NetworkOverlaps(toCheck, nsNetwork) {
|
||||
return ErrNetworkOverlapsWithNameservers
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CheckRouteOverlaps(toCheck *net.IPNet) error {
|
||||
networks, err := networkGetRoutesFct()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, network := range networks {
|
||||
if network.IPNet != nil && NetworkOverlaps(toCheck, network.IPNet) {
|
||||
return ErrNetworkOverlaps
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Detects overlap between one IPNet and another
|
||||
func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
|
||||
if len(netX.IP) == len(netY.IP) {
|
||||
if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
|
||||
return true
|
||||
}
|
||||
if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Calculates the first and last IP addresses in an IPNet
|
||||
func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
|
||||
var netIP net.IP
|
||||
if network.IP.To4() != nil {
|
||||
netIP = network.IP.To4()
|
||||
} else if network.IP.To16() != nil {
|
||||
netIP = network.IP.To16()
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
lastIP := make([]byte, len(netIP), len(netIP))
|
||||
|
||||
for i := 0; i < len(netIP); i++ {
|
||||
lastIP[i] = netIP[i] | ^network.Mask[i]
|
||||
}
|
||||
return netIP.Mask(network.Mask), net.IP(lastIP)
|
||||
}
|
||||
|
||||
// Return the first IPv4 address and slice of IPv6 addresses for the specified network interface
|
||||
func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var addrs4 []net.Addr
|
||||
var addrs6 []net.Addr
|
||||
for _, addr := range addrs {
|
||||
ip := (addr.(*net.IPNet)).IP
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
addrs4 = append(addrs4, addr)
|
||||
} else if ip6 := ip.To16(); len(ip6) == net.IPv6len {
|
||||
addrs6 = append(addrs6, addr)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case len(addrs4) == 0:
|
||||
return nil, nil, fmt.Errorf("Interface %v has no IPv4 addresses", name)
|
||||
case len(addrs4) > 1:
|
||||
fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
|
||||
name, (addrs4[0].(*net.IPNet)).IP)
|
||||
}
|
||||
return addrs4[0], addrs6, nil
|
||||
}
|
||||
|
||||
func GetDefaultRouteIface() (*net.Interface, error) {
|
||||
rs, err := networkGetRoutesFct()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get routes: %v", err)
|
||||
}
|
||||
for _, r := range rs {
|
||||
if r.Default {
|
||||
return r.Iface, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrNoDefaultRoute
|
||||
}
|
93
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go
generated
vendored
Normal file
93
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel.go
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
package kernel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type KernelVersionInfo struct {
|
||||
Kernel int
|
||||
Major int
|
||||
Minor int
|
||||
Flavor string
|
||||
}
|
||||
|
||||
func (k *KernelVersionInfo) String() string {
|
||||
return fmt.Sprintf("%d.%d.%d%s", k.Kernel, k.Major, k.Minor, k.Flavor)
|
||||
}
|
||||
|
||||
// Compare two KernelVersionInfo struct.
|
||||
// Returns -1 if a < b, 0 if a == b, 1 it a > b
|
||||
func CompareKernelVersion(a, b *KernelVersionInfo) int {
|
||||
if a.Kernel < b.Kernel {
|
||||
return -1
|
||||
} else if a.Kernel > b.Kernel {
|
||||
return 1
|
||||
}
|
||||
|
||||
if a.Major < b.Major {
|
||||
return -1
|
||||
} else if a.Major > b.Major {
|
||||
return 1
|
||||
}
|
||||
|
||||
if a.Minor < b.Minor {
|
||||
return -1
|
||||
} else if a.Minor > b.Minor {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func GetKernelVersion() (*KernelVersionInfo, error) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
|
||||
uts, err := uname()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
release := make([]byte, len(uts.Release))
|
||||
|
||||
i := 0
|
||||
for _, c := range uts.Release {
|
||||
release[i] = byte(c)
|
||||
i++
|
||||
}
|
||||
|
||||
// Remove the \x00 from the release for Atoi to parse correctly
|
||||
release = release[:bytes.IndexByte(release, 0)]
|
||||
|
||||
return ParseRelease(string(release))
|
||||
}
|
||||
|
||||
func ParseRelease(release string) (*KernelVersionInfo, error) {
|
||||
var (
|
||||
kernel, major, minor, parsed int
|
||||
flavor, partial string
|
||||
)
|
||||
|
||||
// Ignore error from Sscanf to allow an empty flavor. Instead, just
|
||||
// make sure we got all the version numbers.
|
||||
parsed, _ = fmt.Sscanf(release, "%d.%d%s", &kernel, &major, &partial)
|
||||
if parsed < 2 {
|
||||
return nil, errors.New("Can't parse kernel version " + release)
|
||||
}
|
||||
|
||||
// sometimes we have 3.12.25-gentoo, but sometimes we just have 3.12-1-amd64
|
||||
parsed, _ = fmt.Sscanf(partial, ".%d%s", &minor, &flavor)
|
||||
if parsed < 1 {
|
||||
flavor = partial
|
||||
}
|
||||
|
||||
return &KernelVersionInfo{
|
||||
Kernel: kernel,
|
||||
Major: major,
|
||||
Minor: minor,
|
||||
Flavor: flavor,
|
||||
}, nil
|
||||
}
|
61
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_test.go
generated
vendored
Normal file
61
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/kernel_test.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
package kernel
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertParseRelease(t *testing.T, release string, b *KernelVersionInfo, result int) {
|
||||
var (
|
||||
a *KernelVersionInfo
|
||||
)
|
||||
a, _ = ParseRelease(release)
|
||||
|
||||
if r := CompareKernelVersion(a, b); r != result {
|
||||
t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
|
||||
}
|
||||
if a.Flavor != b.Flavor {
|
||||
t.Fatalf("Unexpected parsed kernel flavor. Found %s, expected %s", a.Flavor, b.Flavor)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRelease(t *testing.T) {
|
||||
assertParseRelease(t, "3.8.0", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &KernelVersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.8.0-19-generic", &KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "-19-generic"}, 0)
|
||||
assertParseRelease(t, "3.12.8tag", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 8, Flavor: "tag"}, 0)
|
||||
assertParseRelease(t, "3.12-1-amd64", &KernelVersionInfo{Kernel: 3, Major: 12, Minor: 0, Flavor: "-1-amd64"}, 0)
|
||||
}
|
||||
|
||||
func assertKernelVersion(t *testing.T, a, b *KernelVersionInfo, result int) {
|
||||
if r := CompareKernelVersion(a, b); r != result {
|
||||
t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompareKernelVersion(t *testing.T) {
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
0)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
0)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 5},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
&KernelVersionInfo{Kernel: 3, Major: 0, Minor: 20},
|
||||
&KernelVersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
}
|
16
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_linux.go
generated
vendored
Normal file
16
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
package kernel
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type Utsname syscall.Utsname
|
||||
|
||||
func uname() (*syscall.Utsname, error) {
|
||||
uts := &syscall.Utsname{}
|
||||
|
||||
if err := syscall.Uname(uts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uts, nil
|
||||
}
|
15
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go
generated
vendored
Normal file
15
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/parsers/kernel/uname_unsupported.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
// +build !linux
|
||||
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Utsname struct {
|
||||
Release [65]byte
|
||||
}
|
||||
|
||||
func uname() (*Utsname, error) {
|
||||
return nil, errors.New("Kernel version detection is available only on linux")
|
||||
}
|
2
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS
generated
vendored
Normal file
2
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
|
||||
Guillaume J. Charmes <guillaume@docker.com> (@creack)
|
31
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go
generated
vendored
Normal file
31
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Packet netlink provide access to low level Netlink sockets and messages.
|
||||
//
|
||||
// Actual implementations are in:
|
||||
// netlink_linux.go
|
||||
// netlink_darwin.go
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrWrongSockType = errors.New("Wrong socket type")
|
||||
ErrShortResponse = errors.New("Got short response from netlink")
|
||||
ErrInterfaceExists = errors.New("Network interface already exists")
|
||||
)
|
||||
|
||||
// A Route is a subnet associated with the interface to reach it.
|
||||
type Route struct {
|
||||
*net.IPNet
|
||||
Iface *net.Interface
|
||||
Default bool
|
||||
}
|
||||
|
||||
// An IfAddr defines IP network settings for a given network interface
|
||||
type IfAddr struct {
|
||||
Iface *net.Interface
|
||||
IP net.IP
|
||||
IPNet *net.IPNet
|
||||
}
|
1307
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go
generated
vendored
Normal file
1307
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
5
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go
generated
vendored
Normal file
5
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
package netlink
|
||||
|
||||
func ifrDataByte(b byte) uint8 {
|
||||
return uint8(b)
|
||||
}
|
7
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go
generated
vendored
Normal file
7
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
// +build !arm
|
||||
|
||||
package netlink
|
||||
|
||||
func ifrDataByte(b byte) int8 {
|
||||
return int8(b)
|
||||
}
|
408
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
generated
vendored
Normal file
408
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,408 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testLink struct {
|
||||
name string
|
||||
linkType string
|
||||
}
|
||||
|
||||
func addLink(t *testing.T, name string, linkType string) {
|
||||
if err := NetworkLinkAdd(name, linkType); err != nil {
|
||||
t.Fatalf("Unable to create %s link: %s", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func readLink(t *testing.T, name string) *net.Interface {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not find %s interface: %s", name, err)
|
||||
}
|
||||
|
||||
return iface
|
||||
}
|
||||
|
||||
func deleteLink(t *testing.T, name string) {
|
||||
if err := NetworkLinkDel(name); err != nil {
|
||||
t.Fatalf("Unable to delete %s link: %s", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
func upLink(t *testing.T, name string) {
|
||||
iface := readLink(t, name)
|
||||
if err := NetworkLinkUp(iface); err != nil {
|
||||
t.Fatalf("Could not bring UP %#v interface: %s", iface, err)
|
||||
}
|
||||
}
|
||||
|
||||
func downLink(t *testing.T, name string) {
|
||||
iface := readLink(t, name)
|
||||
if err := NetworkLinkDown(iface); err != nil {
|
||||
t.Fatalf("Could not bring DOWN %#v interface: %s", iface, err)
|
||||
}
|
||||
}
|
||||
|
||||
func ipAssigned(iface *net.Interface, ip net.IP) bool {
|
||||
addrs, _ := iface.Addrs()
|
||||
|
||||
for _, addr := range addrs {
|
||||
args := strings.SplitN(addr.String(), "/", 2)
|
||||
if args[0] == ip.String() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func TestNetworkLinkAddDel(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
testLinks := []testLink{
|
||||
{"tstEth", "dummy"},
|
||||
{"tstBr", "bridge"},
|
||||
}
|
||||
|
||||
for _, tl := range testLinks {
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
readLink(t, tl.name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkLinkUpDown(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
|
||||
upLink(t, tl.name)
|
||||
ifcAfterUp := readLink(t, tl.name)
|
||||
|
||||
if (ifcAfterUp.Flags & syscall.IFF_UP) != syscall.IFF_UP {
|
||||
t.Fatalf("Could not bring UP %#v initerface", tl)
|
||||
}
|
||||
|
||||
downLink(t, tl.name)
|
||||
ifcAfterDown := readLink(t, tl.name)
|
||||
|
||||
if (ifcAfterDown.Flags & syscall.IFF_UP) == syscall.IFF_UP {
|
||||
t.Fatalf("Could not bring DOWN %#v initerface", tl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkSetMacAddress(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||
macaddr := "22:ce:e0:99:63:6f"
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
|
||||
ifcBeforeSet := readLink(t, tl.name)
|
||||
|
||||
if err := NetworkSetMacAddress(ifcBeforeSet, macaddr); err != nil {
|
||||
t.Fatalf("Could not set %s MAC address on %#v interface: %s", macaddr, tl, err)
|
||||
}
|
||||
|
||||
ifcAfterSet := readLink(t, tl.name)
|
||||
|
||||
if ifcAfterSet.HardwareAddr.String() != macaddr {
|
||||
t.Fatalf("Could not set %s MAC address on %#v interface", macaddr, tl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkSetMTU(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||
mtu := 1400
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
|
||||
ifcBeforeSet := readLink(t, tl.name)
|
||||
|
||||
if err := NetworkSetMTU(ifcBeforeSet, mtu); err != nil {
|
||||
t.Fatalf("Could not set %d MTU on %#v interface: %s", mtu, tl, err)
|
||||
}
|
||||
|
||||
ifcAfterSet := readLink(t, tl.name)
|
||||
|
||||
if ifcAfterSet.MTU != mtu {
|
||||
t.Fatalf("Could not set %d MTU on %#v interface", mtu, tl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkSetMasterNoMaster(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
master := testLink{"tstBr", "bridge"}
|
||||
slave := testLink{"tstEth", "dummy"}
|
||||
testLinks := []testLink{master, slave}
|
||||
|
||||
for _, tl := range testLinks {
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
upLink(t, tl.name)
|
||||
}
|
||||
|
||||
masterIfc := readLink(t, master.name)
|
||||
slaveIfc := readLink(t, slave.name)
|
||||
if err := NetworkSetMaster(slaveIfc, masterIfc); err != nil {
|
||||
t.Fatalf("Could not set %#v to be the master of %#v: %s", master, slave, err)
|
||||
}
|
||||
|
||||
// Trying to figure out a way to test which will not break on RHEL6.
|
||||
// We could check for existence of /sys/class/net/tstEth/upper_tstBr
|
||||
// which should point to the ../tstBr which is the UPPER device i.e. network bridge
|
||||
|
||||
if err := NetworkSetNoMaster(slaveIfc); err != nil {
|
||||
t.Fatalf("Could not UNset %#v master of %#v: %s", master, slave, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkChangeName(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := testLink{"tstEth", "dummy"}
|
||||
newName := "newTst"
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
|
||||
linkIfc := readLink(t, tl.name)
|
||||
if err := NetworkChangeName(linkIfc, newName); err != nil {
|
||||
deleteLink(t, tl.name)
|
||||
t.Fatalf("Could not change %#v interface name to %s: %s", tl, newName, err)
|
||||
}
|
||||
|
||||
readLink(t, newName)
|
||||
deleteLink(t, newName)
|
||||
}
|
||||
|
||||
func TestNetworkLinkAddVlan(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := struct {
|
||||
name string
|
||||
id uint16
|
||||
}{
|
||||
name: "tstVlan",
|
||||
id: 32,
|
||||
}
|
||||
masterLink := testLink{"tstEth", "dummy"}
|
||||
|
||||
addLink(t, masterLink.name, masterLink.linkType)
|
||||
defer deleteLink(t, masterLink.name)
|
||||
|
||||
if err := NetworkLinkAddVlan(masterLink.name, tl.name, tl.id); err != nil {
|
||||
t.Fatalf("Unable to create %#v VLAN interface: %s", tl, err)
|
||||
}
|
||||
|
||||
readLink(t, tl.name)
|
||||
}
|
||||
|
||||
func TestNetworkLinkAddMacVlan(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := struct {
|
||||
name string
|
||||
mode string
|
||||
}{
|
||||
name: "tstVlan",
|
||||
mode: "private",
|
||||
}
|
||||
masterLink := testLink{"tstEth", "dummy"}
|
||||
|
||||
addLink(t, masterLink.name, masterLink.linkType)
|
||||
defer deleteLink(t, masterLink.name)
|
||||
|
||||
if err := NetworkLinkAddMacVlan(masterLink.name, tl.name, tl.mode); err != nil {
|
||||
t.Fatalf("Unable to create %#v MAC VLAN interface: %s", tl, err)
|
||||
}
|
||||
|
||||
readLink(t, tl.name)
|
||||
}
|
||||
|
||||
func TestNetworkLinkAddMacVtap(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
tl := struct {
|
||||
name string
|
||||
mode string
|
||||
}{
|
||||
name: "tstVtap",
|
||||
mode: "private",
|
||||
}
|
||||
masterLink := testLink{"tstEth", "dummy"}
|
||||
|
||||
addLink(t, masterLink.name, masterLink.linkType)
|
||||
defer deleteLink(t, masterLink.name)
|
||||
|
||||
if err := NetworkLinkAddMacVtap(masterLink.name, tl.name, tl.mode); err != nil {
|
||||
t.Fatalf("Unable to create %#v MAC VTAP interface: %s", tl, err)
|
||||
}
|
||||
|
||||
readLink(t, tl.name)
|
||||
}
|
||||
|
||||
func TestAddDelNetworkIp(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
ifaceName := "lo"
|
||||
ip := net.ParseIP("127.0.1.1")
|
||||
mask := net.IPv4Mask(255, 255, 255, 255)
|
||||
ipNet := &net.IPNet{IP: ip, Mask: mask}
|
||||
|
||||
iface, err := net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
t.Skip("No 'lo' interface; skipping tests")
|
||||
}
|
||||
|
||||
if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
|
||||
t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err)
|
||||
}
|
||||
|
||||
if !ipAssigned(iface, ip) {
|
||||
t.Fatalf("Could not locate address '%s' in lo address list.", ip.String())
|
||||
}
|
||||
|
||||
if err := NetworkLinkDelIp(iface, ip, ipNet); err != nil {
|
||||
t.Fatalf("Could not delete IP address %s from interface %#v: %s", ip.String(), iface, err)
|
||||
}
|
||||
|
||||
if ipAssigned(iface, ip) {
|
||||
t.Fatalf("Located address '%s' in lo address list after removal.", ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddRouteSourceSelection(t *testing.T) {
|
||||
tstIp := "127.1.1.1"
|
||||
tl := testLink{name: "tstEth", linkType: "dummy"}
|
||||
|
||||
addLink(t, tl.name, tl.linkType)
|
||||
defer deleteLink(t, tl.name)
|
||||
|
||||
ip := net.ParseIP(tstIp)
|
||||
mask := net.IPv4Mask(255, 255, 255, 255)
|
||||
ipNet := &net.IPNet{IP: ip, Mask: mask}
|
||||
|
||||
iface, err := net.InterfaceByName(tl.name)
|
||||
if err != nil {
|
||||
t.Fatalf("Lost created link %#v", tl)
|
||||
}
|
||||
|
||||
if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
|
||||
t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err)
|
||||
}
|
||||
|
||||
upLink(t, tl.name)
|
||||
defer downLink(t, tl.name)
|
||||
|
||||
if err := AddRoute("127.0.0.0/8", tstIp, "", tl.name); err != nil {
|
||||
t.Fatalf("Failed to add route with source address")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateVethPair(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
name1 = "veth1"
|
||||
name2 = "veth2"
|
||||
)
|
||||
|
||||
if err := NetworkCreateVethPair(name1, name2, 0); err != nil {
|
||||
t.Fatalf("Could not create veth pair %s %s: %s", name1, name2, err)
|
||||
}
|
||||
defer NetworkLinkDel(name1)
|
||||
|
||||
readLink(t, name1)
|
||||
readLink(t, name2)
|
||||
}
|
||||
|
||||
//
|
||||
// netlink package tests which do not use RTNETLINK
|
||||
//
|
||||
func TestCreateBridgeWithMac(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
name := "testbridge"
|
||||
|
||||
if err := CreateBridge(name, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := net.InterfaceByName(name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// cleanup and tests
|
||||
|
||||
if err := DeleteBridge(name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := net.InterfaceByName(name); err == nil {
|
||||
t.Fatalf("expected error getting interface because %s bridge was deleted", name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMacAddress(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
name := "testmac"
|
||||
mac := randMacAddr()
|
||||
|
||||
if err := NetworkLinkAdd(name, "bridge"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer NetworkLinkDel(name)
|
||||
|
||||
if err := SetMacAddress(name, mac); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if iface.HardwareAddr.String() != mac {
|
||||
t.Fatalf("mac address %q does not match %q", iface.HardwareAddr, mac)
|
||||
}
|
||||
}
|
88
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
generated
vendored
Normal file
88
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
// +build !linux
|
||||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
)
|
||||
|
||||
func NetworkGetRoutes() ([]Route, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkAdd(name string, linkType string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkDel(name string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkUp(iface *net.Interface) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddRoute(destination, source, gateway, device string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddDefaultGw(ip, device string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetMTU(iface *net.Interface, mtu int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetTxQueueLen(iface *net.Interface, txQueueLen int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkCreateVethPair(name1, name2 string, txQueueLen int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkChangeName(iface *net.Interface, newName string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkSetMaster(iface, master *net.Interface) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func NetworkLinkDown(iface *net.Interface) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func CreateBridge(name string, setMacAddr bool) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func DeleteBridge(name string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func AddToBridge(iface, master *net.Interface) error {
|
||||
return ErrNotImplemented
|
||||
}
|
|
@ -1,14 +1,20 @@
|
|||
machine:
|
||||
# sudo -E doesn't preserve $PATH, so go isn't found anymore.
|
||||
environment:
|
||||
GO_BIN: $(which go)
|
||||
GO_PATH: /home/ubuntu/.go_workspace/bin/
|
||||
BASE_DIR: src/github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
|
||||
CHECKOUT: /home/ubuntu/$CIRCLE_PROJECT_REPONAME
|
||||
pre:
|
||||
# sudo -E doesn't preserve $PATH, so go isn't found anymore.
|
||||
- sudo ln -s $(which go) /usr/local/bin
|
||||
|
||||
checkout:
|
||||
post:
|
||||
# We need docker/libnetwork itself in the GOPATH for imports to work.
|
||||
- ln -s $CHECKOUT $(echo $GOPATH | cut -d":" -f1)/$BASE_DIR
|
||||
|
||||
dependencies:
|
||||
override:
|
||||
- go get github.com/tools/godep
|
||||
post:
|
||||
- go get github.com/axw/gocov/gocov
|
||||
- go get github.com/golang/lint/golint
|
||||
- go get golang.org/x/tools/cmd/goimports
|
||||
|
||||
|
@ -17,5 +23,5 @@ test:
|
|||
- test -z "$(goimports -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
|
||||
- go vet ./...
|
||||
- test -z "$(golint ./... | tee /dev/stderr)"
|
||||
- sudo -E $GO_BIN test -test.v ./...
|
||||
- sudo -E $(which godep) go test -test.v ./...
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue