diff --git a/api/ipam.go b/api/ipam.go index 8be57b27..7f1dcacc 100644 --- a/api/ipam.go +++ b/api/ipam.go @@ -18,6 +18,14 @@ func (client *Client) AllocateIP(ID string) (*net.IPNet, error) { return client.ipamOp(ID, "POST") } +func (client *Client) AllocateIPInSubnet(ID string, subnet *net.IPNet) (*net.IPNet, error) { + ip, err := client.httpVerb("POST", fmt.Sprintf("/ip/%s/%s", ID, subnet), nil) + if err != nil { + return nil, err + } + return parseIP(ip) +} + // returns an IP for the ID given, or nil if one has not been // allocated func (client *Client) LookupIP(ID string) (*net.IPNet, error) { diff --git a/plugin/ipam/driver.go b/plugin/ipam/driver.go index 766aa9a1..77cf99b4 100644 --- a/plugin/ipam/driver.go +++ b/plugin/ipam/driver.go @@ -1,7 +1,9 @@ package ipamplugin import ( + "fmt" "net" + "strings" "github.com/docker/libnetwork/ipamapi" "github.com/docker/libnetwork/netlabel" @@ -29,14 +31,29 @@ func (i *ipam) GetDefaultAddressSpaces() (string, string, error) { return "weavelocal", "weaveglobal", nil } -func (i *ipam) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) { +func (i *ipam) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (poolname string, subnet *net.IPNet, data map[string]string, err error) { Log.Debugln("RequestPool", addressSpace, pool, subPool, options) - cidr, err := i.weave.DefaultSubnet() - Log.Debugln("RequestPool returning ", cidr, err) + defer func() { Log.Debugln("RequestPool returning", poolname, subnet, data, err) }() + if pool == "" { + subnet, err = i.weave.DefaultSubnet() + } else { + _, subnet, err = net.ParseCIDR(pool) + } + if err != nil { + return + } + iprange := subnet + if subPool != "" { + if _, iprange, err = net.ParseCIDR(subPool); err != nil { + return + } + } + // Cunningly-constructed pool "name" which gives us what we need later + poolname = strings.Join([]string{"weave", subnet.String(), iprange.String()}, "-") // Pass back a fake "gateway address"; we don't actually use it, // so just give the network address. - data := map[string]string{netlabel.Gateway: cidr.String()} - return "weavepool", cidr, data, err + data = map[string]string{netlabel.Gateway: subnet.String()} + return } func (i *ipam) ReleasePool(poolID string) error { @@ -44,12 +61,32 @@ func (i *ipam) ReleasePool(poolID string) error { return nil } -func (i *ipam) RequestAddress(poolID string, address net.IP, options map[string]string) (*net.IPNet, map[string]string, error) { +func (i *ipam) RequestAddress(poolID string, address net.IP, options map[string]string) (ip *net.IPNet, _ map[string]string, err error) { Log.Debugln("RequestAddress", poolID, address, options) - // Pass magic string to weave IPAM, which then stores the address under its own string - ip, err := i.weave.AllocateIP("_") - Log.Debugln("allocateIP returned", ip, err) - return ip, nil, err + defer func() { Log.Debugln("allocateIP returned", ip, err) }() + // If we pass magic string "_" to weave IPAM it stores the address under its own string + if poolID == "weavepool" { // old-style + ip, err = i.weave.AllocateIP("_") + return + } + parts := strings.Split(poolID, "-") + if len(parts) != 3 || parts[0] != "weave" { + err = fmt.Errorf("Unrecognized pool ID: %s", poolID) + return + } + var subnet, iprange *net.IPNet + if _, subnet, err = net.ParseCIDR(parts[1]); err != nil { + return + } + if _, iprange, err = net.ParseCIDR(parts[2]); err != nil { + return + } + // We are lying slightly to IPAM here: the range is not a subnet + if ip, err = i.weave.AllocateIPInSubnet("_", iprange); err != nil { + return + } + ip.Mask = subnet.Mask // fix up the subnet we lied about + return } func (i *ipam) ReleaseAddress(poolID string, address net.IP) error { diff --git a/site/plugin.md b/site/plugin.md index bddddee0..7a3e86fc 100644 --- a/site/plugin.md +++ b/site/plugin.md @@ -33,32 +33,48 @@ The Weave plugin actually provides *two* network drivers to Docker one named `weave` that can only work with one (like Docker's overlay driver). +Docker supports creating multiple networks via the plugin, although +Weave Net provides only one network underneath. So long as the IP +addresses for each network are on different subnets, containers on one +network will not be able to communicate with those on a different network. + ### `weavemesh` driver * Weave handles all co-ordination between hosts (referred to by Docker as a "local scope" driver) -* Supports only a single network (we create one named `weave` for you automatically) * Uses Weave's partition tolerant IPAM +* User must pick different subnets if creating multiple networks. -If you do create additional networks using the `weavemesh` driver, -containers attached to them will be able to communicate with -containers attached to `weave`; there is no isolation between those -networks. +We create a network named `weave` for you automatically, using the +[default subnet](ipam.html#subnets) set for the `weave` router. + +To create additional networks using the `weavemesh` driver, pick a +different subnet and run this command on all hosts: + + $ docker network create --driver=weavemesh --ipam-driver=weavemesh --subnet= + +The subnets you pick must be within the range covered by Weave's [IP +Address Management](ipam.html#range) ### `weave` driver * This runs in what Docker call "global scope"; requires a cluster store -* Supports multiple networks (these must be created with `docker network create --driver weave ...`) * Used with Docker's cluster store based IPAM +* Docker can coordinate choosing different subnets for multiple networks. + +To create a network using this driver, once you have your cluster store set up: + + $ docker network create --driver=weave + +### Cluster store + +This is the term used by Docker for a distributed key-value store such +as Consul, Etcd or ZooKeeper. There's no specific documentation from Docker on using a cluster store, but the first part of [Getting Started with Docker Multi-host Networking](https://github.com/docker/docker/blob/master/docs/userguide/networking/get-started-overlay.md) should point the way. -Note that in the case of multiple networks using the `weave` driver, all containers are -on the same virtual network but Docker allocates their addresses on -different subnets so they cannot talk to each other directly. - ## Plugin command-line arguments If you want to give some arguments to the plugin independently, don't