mirror of https://github.com/docker/docs.git
Merge pull request #6101 from LK4D4/ip_range_#4986
Implement allocating IPs from CIDR within bridge network
This commit is contained in:
commit
9fb34ae571
|
@ -30,6 +30,7 @@ type Config struct {
|
||||||
DefaultIp net.IP
|
DefaultIp net.IP
|
||||||
BridgeIface string
|
BridgeIface string
|
||||||
BridgeIP string
|
BridgeIP string
|
||||||
|
FixedCIDR string
|
||||||
InterContainerCommunication bool
|
InterContainerCommunication bool
|
||||||
GraphDriver string
|
GraphDriver string
|
||||||
GraphOptions []string
|
GraphOptions []string
|
||||||
|
@ -53,6 +54,7 @@ func (config *Config) InstallFlags() {
|
||||||
flag.BoolVar(&config.EnableIpMasq, []string{"-ip-masq"}, true, "Enable IP masquerading for bridge's IP range")
|
flag.BoolVar(&config.EnableIpMasq, []string{"-ip-masq"}, true, "Enable IP masquerading for bridge's IP range")
|
||||||
flag.StringVar(&config.BridgeIP, []string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b")
|
flag.StringVar(&config.BridgeIP, []string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b")
|
||||||
flag.StringVar(&config.BridgeIface, []string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking")
|
flag.StringVar(&config.BridgeIface, []string{"b", "-bridge"}, "", "Attach containers to a pre-existing network bridge\nuse 'none' to disable container networking")
|
||||||
|
flag.StringVar(&config.FixedCIDR, []string{"-fixed-cidr"}, "", "IPv4 subnet for fixed IPs (ex: 10.20.0.0/16)\nthis subnet must be nested in the bridge subnet (which is defined by -b or --bip)")
|
||||||
flag.BoolVar(&config.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
|
flag.BoolVar(&config.InterContainerCommunication, []string{"#icc", "-icc"}, true, "Enable inter-container communication")
|
||||||
flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Force the Docker runtime to use a specific storage driver")
|
flag.StringVar(&config.GraphDriver, []string{"s", "-storage-driver"}, "", "Force the Docker runtime to use a specific storage driver")
|
||||||
flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, "native", "Force the Docker runtime to use a specific exec driver")
|
flag.StringVar(&config.ExecDriver, []string{"e", "-exec-driver"}, "native", "Force the Docker runtime to use a specific exec driver")
|
||||||
|
|
|
@ -821,6 +821,7 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error)
|
||||||
job.SetenvBool("EnableIpMasq", config.EnableIpMasq)
|
job.SetenvBool("EnableIpMasq", config.EnableIpMasq)
|
||||||
job.Setenv("BridgeIface", config.BridgeIface)
|
job.Setenv("BridgeIface", config.BridgeIface)
|
||||||
job.Setenv("BridgeIP", config.BridgeIP)
|
job.Setenv("BridgeIP", config.BridgeIP)
|
||||||
|
job.Setenv("FixedCIDR", config.FixedCIDR)
|
||||||
job.Setenv("DefaultBindingIP", config.DefaultIp.String())
|
job.Setenv("DefaultBindingIP", config.DefaultIp.String())
|
||||||
|
|
||||||
if err := job.Run(); err != nil {
|
if err := job.Run(); err != nil {
|
||||||
|
|
|
@ -84,6 +84,7 @@ func InitDriver(job *engine.Job) engine.Status {
|
||||||
ipMasq = job.GetenvBool("EnableIpMasq")
|
ipMasq = job.GetenvBool("EnableIpMasq")
|
||||||
ipForward = job.GetenvBool("EnableIpForward")
|
ipForward = job.GetenvBool("EnableIpForward")
|
||||||
bridgeIP = job.Getenv("BridgeIP")
|
bridgeIP = job.Getenv("BridgeIP")
|
||||||
|
fixedCIDR = job.Getenv("FixedCIDR")
|
||||||
)
|
)
|
||||||
|
|
||||||
if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
|
if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
|
||||||
|
@ -155,6 +156,16 @@ func InitDriver(job *engine.Job) engine.Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
bridgeNetwork = network
|
bridgeNetwork = network
|
||||||
|
if fixedCIDR != "" {
|
||||||
|
_, subnet, err := net.ParseCIDR(fixedCIDR)
|
||||||
|
if err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
log.Debugf("Subnet: %v", subnet)
|
||||||
|
if err := ipallocator.RegisterSubnet(bridgeNetwork, subnet); err != nil {
|
||||||
|
return job.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://github.com/docker/docker/issues/2768
|
// https://github.com/docker/docker/issues/2768
|
||||||
job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeNetwork.IP)
|
job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeNetwork.IP)
|
||||||
|
@ -318,14 +329,14 @@ func createBridgeIface(name string) error {
|
||||||
// Allocate a network interface
|
// Allocate a network interface
|
||||||
func Allocate(job *engine.Job) engine.Status {
|
func Allocate(job *engine.Job) engine.Status {
|
||||||
var (
|
var (
|
||||||
ip *net.IP
|
ip net.IP
|
||||||
err error
|
err error
|
||||||
id = job.Args[0]
|
id = job.Args[0]
|
||||||
requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
|
requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
|
||||||
)
|
)
|
||||||
|
|
||||||
if requestedIP != nil {
|
if requestedIP != nil {
|
||||||
ip, err = ipallocator.RequestIP(bridgeNetwork, &requestedIP)
|
ip, err = ipallocator.RequestIP(bridgeNetwork, requestedIP)
|
||||||
} else {
|
} else {
|
||||||
ip, err = ipallocator.RequestIP(bridgeNetwork, nil)
|
ip, err = ipallocator.RequestIP(bridgeNetwork, nil)
|
||||||
}
|
}
|
||||||
|
@ -343,7 +354,7 @@ func Allocate(job *engine.Job) engine.Status {
|
||||||
out.SetInt("IPPrefixLen", size)
|
out.SetInt("IPPrefixLen", size)
|
||||||
|
|
||||||
currentInterfaces.Set(id, &networkInterface{
|
currentInterfaces.Set(id, &networkInterface{
|
||||||
IP: *ip,
|
IP: ip,
|
||||||
})
|
})
|
||||||
|
|
||||||
out.WriteTo(job.Stdout)
|
out.WriteTo(job.Stdout)
|
||||||
|
@ -368,7 +379,7 @@ func Release(job *engine.Job) engine.Status {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ipallocator.ReleaseIP(bridgeNetwork, &containerInterface.IP); err != nil {
|
if err := ipallocator.ReleaseIP(bridgeNetwork, containerInterface.IP); err != nil {
|
||||||
log.Infof("Unable to release ip %s", err)
|
log.Infof("Unable to release ip %s", err)
|
||||||
}
|
}
|
||||||
return engine.StatusOK
|
return engine.StatusOK
|
||||||
|
|
|
@ -3,26 +3,39 @@ package ipallocator
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/docker/docker/daemon/networkdriver"
|
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/docker/docker/daemon/networkdriver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// allocatedMap is thread-unsafe set of allocated IP
|
// allocatedMap is thread-unsafe set of allocated IP
|
||||||
type allocatedMap struct {
|
type allocatedMap struct {
|
||||||
p map[int32]struct{}
|
p map[uint32]struct{}
|
||||||
last int32
|
last uint32
|
||||||
|
begin uint32
|
||||||
|
end uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAllocatedMap() *allocatedMap {
|
func newAllocatedMap(network *net.IPNet) *allocatedMap {
|
||||||
return &allocatedMap{p: make(map[int32]struct{})}
|
firstIP, lastIP := networkdriver.NetworkRange(network)
|
||||||
|
begin := ipToInt(firstIP) + 2
|
||||||
|
end := ipToInt(lastIP) - 1
|
||||||
|
return &allocatedMap{
|
||||||
|
p: make(map[uint32]struct{}),
|
||||||
|
begin: begin,
|
||||||
|
end: end,
|
||||||
|
last: begin - 1, // so first allocated will be begin
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type networkSet map[string]*allocatedMap
|
type networkSet map[string]*allocatedMap
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrNoAvailableIPs = errors.New("no available ip addresses on network")
|
ErrNoAvailableIPs = errors.New("no available ip addresses on network")
|
||||||
ErrIPAlreadyAllocated = errors.New("ip already allocated")
|
ErrIPAlreadyAllocated = errors.New("ip already allocated")
|
||||||
|
ErrNetworkAlreadyRegistered = errors.New("network already registered")
|
||||||
|
ErrBadSubnet = errors.New("network not contains specified subnet")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -30,47 +43,63 @@ var (
|
||||||
allocatedIPs = networkSet{}
|
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, end := ipToInt(beginIP)+1, ipToInt(endIP)-1
|
||||||
|
if !(begin >= n.begin && end <= n.end && begin < end) {
|
||||||
|
return ErrBadSubnet
|
||||||
|
}
|
||||||
|
n.begin = begin
|
||||||
|
n.end = end
|
||||||
|
n.last = begin - 1
|
||||||
|
allocatedIPs[key] = n
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// RequestIP requests an available ip from the given network. It
|
// RequestIP requests an available ip from the given network. It
|
||||||
// will return the next available ip if the ip provided is nil. If the
|
// 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
|
// ip provided is not nil it will validate that the provided ip is available
|
||||||
// for use or return an error
|
// for use or return an error
|
||||||
func RequestIP(network *net.IPNet, ip *net.IP) (*net.IP, error) {
|
func RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
key := network.String()
|
key := network.String()
|
||||||
allocated, ok := allocatedIPs[key]
|
allocated, ok := allocatedIPs[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
allocated = newAllocatedMap()
|
allocated = newAllocatedMap(network)
|
||||||
allocatedIPs[key] = allocated
|
allocatedIPs[key] = allocated
|
||||||
}
|
}
|
||||||
|
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
return allocated.getNextIP(network)
|
return allocated.getNextIP()
|
||||||
}
|
}
|
||||||
return allocated.checkIP(network, ip)
|
return allocated.checkIP(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReleaseIP adds the provided ip back into the pool of
|
// ReleaseIP adds the provided ip back into the pool of
|
||||||
// available ips to be returned for use.
|
// available ips to be returned for use.
|
||||||
func ReleaseIP(network *net.IPNet, ip *net.IP) error {
|
func ReleaseIP(network *net.IPNet, ip net.IP) error {
|
||||||
lock.Lock()
|
lock.Lock()
|
||||||
defer lock.Unlock()
|
defer lock.Unlock()
|
||||||
if allocated, exists := allocatedIPs[network.String()]; exists {
|
if allocated, exists := allocatedIPs[network.String()]; exists {
|
||||||
pos := getPosition(network, ip)
|
pos := ipToInt(ip)
|
||||||
delete(allocated.p, pos)
|
delete(allocated.p, pos)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert the ip into the position in the subnet. Only
|
func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
|
||||||
// position are saved in the set
|
pos := ipToInt(ip)
|
||||||
func getPosition(network *net.IPNet, ip *net.IP) int32 {
|
|
||||||
first, _ := networkdriver.NetworkRange(network)
|
|
||||||
return ipToInt(ip) - ipToInt(&first)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (allocated *allocatedMap) checkIP(network *net.IPNet, ip *net.IP) (*net.IP, error) {
|
|
||||||
pos := getPosition(network, ip)
|
|
||||||
if _, ok := allocated.p[pos]; ok {
|
if _, ok := allocated.p[pos]; ok {
|
||||||
return nil, ErrIPAlreadyAllocated
|
return nil, ErrIPAlreadyAllocated
|
||||||
}
|
}
|
||||||
|
@ -81,47 +110,30 @@ func (allocated *allocatedMap) checkIP(network *net.IPNet, ip *net.IP) (*net.IP,
|
||||||
|
|
||||||
// return an available ip if one is currently available. If not,
|
// return an available ip if one is currently available. If not,
|
||||||
// return the next available ip for the nextwork
|
// return the next available ip for the nextwork
|
||||||
func (allocated *allocatedMap) getNextIP(network *net.IPNet) (*net.IP, error) {
|
func (allocated *allocatedMap) getNextIP() (net.IP, error) {
|
||||||
var (
|
for pos := allocated.last + 1; pos != allocated.last; pos++ {
|
||||||
ownIP = ipToInt(&network.IP)
|
if pos > allocated.end {
|
||||||
first, _ = networkdriver.NetworkRange(network)
|
pos = allocated.begin
|
||||||
base = ipToInt(&first)
|
|
||||||
size = int(networkdriver.NetworkSize(network.Mask))
|
|
||||||
max = int32(size - 2) // size -1 for the broadcast network, -1 for the gateway network
|
|
||||||
pos = allocated.last
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
firstNetIP = network.IP.To4().Mask(network.Mask)
|
|
||||||
firstAsInt = ipToInt(&firstNetIP) + 1
|
|
||||||
)
|
|
||||||
|
|
||||||
for i := int32(0); i < max; i++ {
|
|
||||||
pos = pos%max + 1
|
|
||||||
next := int32(base + pos)
|
|
||||||
|
|
||||||
if next == ownIP || next == firstAsInt {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if _, ok := allocated.p[pos]; ok {
|
if _, ok := allocated.p[pos]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
allocated.p[pos] = struct{}{}
|
allocated.p[pos] = struct{}{}
|
||||||
allocated.last = pos
|
allocated.last = pos
|
||||||
return intToIP(next), nil
|
return intToIP(pos), nil
|
||||||
}
|
}
|
||||||
return nil, ErrNoAvailableIPs
|
return nil, ErrNoAvailableIPs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts a 4 bytes IP into a 32 bit integer
|
// Converts a 4 bytes IP into a 32 bit integer
|
||||||
func ipToInt(ip *net.IP) int32 {
|
func ipToInt(ip net.IP) uint32 {
|
||||||
return int32(binary.BigEndian.Uint32(ip.To4()))
|
return binary.BigEndian.Uint32(ip.To4())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts 32 bit integer into a 4 bytes IP address
|
// Converts 32 bit integer into a 4 bytes IP address
|
||||||
func intToIP(n int32) *net.IP {
|
func intToIP(n uint32) net.IP {
|
||||||
b := make([]byte, 4)
|
b := make([]byte, 4)
|
||||||
binary.BigEndian.PutUint32(b, uint32(n))
|
binary.BigEndian.PutUint32(b, n)
|
||||||
ip := net.IP(b)
|
ip := net.IP(b)
|
||||||
return &ip
|
return ip
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ func TestRequestNewIps(t *testing.T) {
|
||||||
Mask: []byte{255, 255, 255, 0},
|
Mask: []byte{255, 255, 255, 0},
|
||||||
}
|
}
|
||||||
|
|
||||||
var ip *net.IP
|
var ip net.IP
|
||||||
var err error
|
var err error
|
||||||
for i := 2; i < 10; i++ {
|
for i := 2; i < 10; i++ {
|
||||||
ip, err = RequestIP(network, nil)
|
ip, err = RequestIP(network, nil)
|
||||||
|
@ -106,19 +106,19 @@ func TestRequesetSpecificIp(t *testing.T) {
|
||||||
|
|
||||||
ip := net.ParseIP("192.168.1.5")
|
ip := net.ParseIP("192.168.1.5")
|
||||||
|
|
||||||
if _, err := RequestIP(network, &ip); err != nil {
|
if _, err := RequestIP(network, ip); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConversion(t *testing.T) {
|
func TestConversion(t *testing.T) {
|
||||||
ip := net.ParseIP("127.0.0.1")
|
ip := net.ParseIP("127.0.0.1")
|
||||||
i := ipToInt(&ip)
|
i := ipToInt(ip)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
t.Fatal("converted to zero")
|
t.Fatal("converted to zero")
|
||||||
}
|
}
|
||||||
conv := intToIP(i)
|
conv := intToIP(i)
|
||||||
if !ip.Equal(*conv) {
|
if !ip.Equal(conv) {
|
||||||
t.Error(conv.String())
|
t.Error(conv.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ func TestIPAllocator(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assertIPEquals(t, &expectedIPs[i], ip)
|
assertIPEquals(t, expectedIPs[i], ip)
|
||||||
}
|
}
|
||||||
// Before loop begin
|
// Before loop begin
|
||||||
// 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
// 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||||
|
@ -179,19 +179,19 @@ func TestIPAllocator(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release some IPs in non-sequential order
|
// Release some IPs in non-sequential order
|
||||||
if err := ReleaseIP(network, &expectedIPs[3]); err != nil {
|
if err := ReleaseIP(network, expectedIPs[3]); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// 2(u) - 3(u) - 4(u) - 5(f) - 6(u)
|
// 2(u) - 3(u) - 4(u) - 5(f) - 6(u)
|
||||||
// ↑
|
// ↑
|
||||||
|
|
||||||
if err := ReleaseIP(network, &expectedIPs[2]); err != nil {
|
if err := ReleaseIP(network, expectedIPs[2]); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// 2(u) - 3(u) - 4(f) - 5(f) - 6(u)
|
// 2(u) - 3(u) - 4(f) - 5(f) - 6(u)
|
||||||
// ↑
|
// ↑
|
||||||
|
|
||||||
if err := ReleaseIP(network, &expectedIPs[4]); err != nil {
|
if err := ReleaseIP(network, expectedIPs[4]); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
|
// 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
|
||||||
|
@ -199,7 +199,7 @@ func TestIPAllocator(t *testing.T) {
|
||||||
|
|
||||||
// Make sure that IPs are reused in sequential order, starting
|
// Make sure that IPs are reused in sequential order, starting
|
||||||
// with the first released IP
|
// with the first released IP
|
||||||
newIPs := make([]*net.IP, 3)
|
newIPs := make([]net.IP, 3)
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
ip, err := RequestIP(network, nil)
|
ip, err := RequestIP(network, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -208,9 +208,9 @@ func TestIPAllocator(t *testing.T) {
|
||||||
|
|
||||||
newIPs[i] = ip
|
newIPs[i] = ip
|
||||||
}
|
}
|
||||||
assertIPEquals(t, &expectedIPs[2], newIPs[0])
|
assertIPEquals(t, expectedIPs[2], newIPs[0])
|
||||||
assertIPEquals(t, &expectedIPs[3], newIPs[1])
|
assertIPEquals(t, expectedIPs[3], newIPs[1])
|
||||||
assertIPEquals(t, &expectedIPs[4], newIPs[2])
|
assertIPEquals(t, expectedIPs[4], newIPs[2])
|
||||||
|
|
||||||
_, err = RequestIP(network, nil)
|
_, err = RequestIP(network, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -226,7 +226,7 @@ func TestAllocateFirstIP(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstIP := network.IP.To4().Mask(network.Mask)
|
firstIP := network.IP.To4().Mask(network.Mask)
|
||||||
first := ipToInt(&firstIP) + 1
|
first := ipToInt(firstIP) + 1
|
||||||
|
|
||||||
ip, err := RequestIP(network, nil)
|
ip, err := RequestIP(network, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -247,7 +247,7 @@ func TestAllocateAllIps(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
current, first *net.IP
|
current, first net.IP
|
||||||
err error
|
err error
|
||||||
isFirst = true
|
isFirst = true
|
||||||
)
|
)
|
||||||
|
@ -313,14 +313,94 @@ func TestAllocateDifferentSubnets(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
assertIPEquals(t, &expectedIPs[0], ip11)
|
assertIPEquals(t, expectedIPs[0], ip11)
|
||||||
assertIPEquals(t, &expectedIPs[1], ip12)
|
assertIPEquals(t, expectedIPs[1], ip12)
|
||||||
assertIPEquals(t, &expectedIPs[2], ip21)
|
assertIPEquals(t, expectedIPs[2], ip21)
|
||||||
assertIPEquals(t, &expectedIPs[3], ip22)
|
assertIPEquals(t, expectedIPs[3], ip22)
|
||||||
|
}
|
||||||
|
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 assertIPEquals(t *testing.T, ip1, ip2 *net.IP) {
|
func TestRegisterBadRange(t *testing.T) {
|
||||||
if !ip1.Equal(*ip2) {
|
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)
|
t.Fatalf("Expected IP %s, got %s", ip1, ip2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,10 @@ unix://[/path/to/socket] to use.
|
||||||
**-g**=""
|
**-g**=""
|
||||||
Path to use as the root of the Docker runtime. Default is `/var/lib/docker`.
|
Path to use as the root of the Docker runtime. Default is `/var/lib/docker`.
|
||||||
|
|
||||||
|
|
||||||
|
**--fixed-cidr**=""
|
||||||
|
IPv4 subnet for fixed IPs (ex: 10.20.0.0/16); this subnet must be nested in the bridge subnet (which is defined by \-b or \-\-bip)
|
||||||
|
|
||||||
**--icc**=*true*|*false*
|
**--icc**=*true*|*false*
|
||||||
Enable inter\-container communication. Default is true.
|
Enable inter\-container communication. Default is true.
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,9 @@ server when it starts up, and cannot be changed once it is running:
|
||||||
* `--bip=CIDR` — see
|
* `--bip=CIDR` — see
|
||||||
[Customizing docker0](#docker0)
|
[Customizing docker0](#docker0)
|
||||||
|
|
||||||
|
* `--fixed-cidr` — see
|
||||||
|
[Customizing docker0](#docker0)
|
||||||
|
|
||||||
* `-H SOCKET...` or `--host=SOCKET...` —
|
* `-H SOCKET...` or `--host=SOCKET...` —
|
||||||
This might sound like it would affect container networking,
|
This might sound like it would affect container networking,
|
||||||
but it actually faces in the other direction:
|
but it actually faces in the other direction:
|
||||||
|
@ -365,17 +368,25 @@ By default, the Docker server creates and configures the host system's
|
||||||
can pass packets back and forth between other physical or virtual
|
can pass packets back and forth between other physical or virtual
|
||||||
network interfaces so that they behave as a single Ethernet network.
|
network interfaces so that they behave as a single Ethernet network.
|
||||||
|
|
||||||
Docker configures `docker0` with an IP address and netmask so the host
|
Docker configures `docker0` with an IP address, netmask and IP
|
||||||
machine can both receive and send packets to containers connected to the
|
allocation range. The host machine can both receive and send packets to
|
||||||
bridge, and gives it an MTU — the *maximum transmission unit* or largest
|
containers connected to the bridge, and gives it an MTU — the *maximum
|
||||||
packet length that the interface will allow — of either 1,500 bytes or
|
transmission unit* or largest packet length that the interface will
|
||||||
else a more specific value copied from the Docker host's interface that
|
allow — of either 1,500 bytes or else a more specific value copied from
|
||||||
supports its default route. Both are configurable at server startup:
|
the Docker host's interface that supports its default route. These
|
||||||
|
options are configurable at server startup:
|
||||||
|
|
||||||
* `--bip=CIDR` — supply a specific IP address and netmask for the
|
* `--bip=CIDR` — supply a specific IP address and netmask for the
|
||||||
`docker0` bridge, using standard CIDR notation like
|
`docker0` bridge, using standard CIDR notation like
|
||||||
`192.168.1.5/24`.
|
`192.168.1.5/24`.
|
||||||
|
|
||||||
|
* `--fixed-cidr=CIDR` — restrict the IP range from the `docker0` subnet,
|
||||||
|
using the standard CIDR notation like `172.167.1.0/28`. This range must
|
||||||
|
be and IPv4 range for fixed IPs (ex: 10.20.0.0/16) and must be a subset
|
||||||
|
of the bridge IP range (`docker0` or set using `--bridge`). For example
|
||||||
|
with `--fixed-cidr=192.168.1.0/25`, IPs for your containers will be chosen
|
||||||
|
from the first half of `192.168.1.0/24` subnet.
|
||||||
|
|
||||||
* `--mtu=BYTES` — override the maximum packet length on `docker0`.
|
* `--mtu=BYTES` — override the maximum packet length on `docker0`.
|
||||||
|
|
||||||
On Ubuntu you would add these to the `DOCKER_OPTS` setting in
|
On Ubuntu you would add these to the `DOCKER_OPTS` setting in
|
||||||
|
|
|
@ -54,6 +54,8 @@ expect an integer, and they can only be specified once.
|
||||||
-b, --bridge="" Attach containers to a pre-existing network bridge
|
-b, --bridge="" Attach containers to a pre-existing network bridge
|
||||||
use 'none' to disable container networking
|
use 'none' to disable container networking
|
||||||
--bip="" Use this CIDR notation address for the network bridge's IP, not compatible with -b
|
--bip="" Use this CIDR notation address for the network bridge's IP, not compatible with -b
|
||||||
|
--fixed-cidr="" IPv4 subnet for fixed IPs (ex: 10.20.0.0/16)
|
||||||
|
this subnet must be nested in the bridge subnet (which is defined by -b or --bip)
|
||||||
-D, --debug=false Enable debug mode
|
-D, --debug=false Enable debug mode
|
||||||
-d, --daemon=false Enable daemon mode
|
-d, --daemon=false Enable daemon mode
|
||||||
--dns=[] Force Docker to use specific DNS servers
|
--dns=[] Force Docker to use specific DNS servers
|
||||||
|
|
Loading…
Reference in New Issue