mirror of https://github.com/docker/docs.git
Merge pull request #8319 from MalteJ/ipv6-ipallocator
Implementing IPv6 functionality for ipallocator
This commit is contained in:
commit
fd19e473fc
|
@ -1,31 +1,38 @@
|
||||||
package ipallocator
|
package ipallocator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
"errors"
|
||||||
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/docker/daemon/networkdriver"
|
"github.com/docker/docker/daemon/networkdriver"
|
||||||
|
"github.com/docker/docker/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// allocatedMap is thread-unsafe set of allocated IP
|
// allocatedMap is thread-unsafe set of allocated IP
|
||||||
type allocatedMap struct {
|
type allocatedMap struct {
|
||||||
p map[uint32]struct{}
|
p map[string]struct{}
|
||||||
last uint32
|
last *big.Int
|
||||||
begin uint32
|
begin *big.Int
|
||||||
end uint32
|
end *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAllocatedMap(network *net.IPNet) *allocatedMap {
|
func newAllocatedMap(network *net.IPNet) *allocatedMap {
|
||||||
firstIP, lastIP := networkdriver.NetworkRange(network)
|
firstIP, lastIP := networkdriver.NetworkRange(network)
|
||||||
begin := ipToInt(firstIP) + 2
|
begin := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
|
||||||
end := ipToInt(lastIP) - 1
|
end := big.NewInt(0).Sub(ipToBigInt(lastIP), big.NewInt(1))
|
||||||
|
|
||||||
|
// if IPv4 network, then allocation range starts at begin + 1 because begin is bridge IP
|
||||||
|
if len(firstIP) == 4 {
|
||||||
|
begin = begin.Add(begin, big.NewInt(1))
|
||||||
|
}
|
||||||
|
|
||||||
return &allocatedMap{
|
return &allocatedMap{
|
||||||
p: make(map[uint32]struct{}),
|
p: make(map[string]struct{}),
|
||||||
begin: begin,
|
begin: begin,
|
||||||
end: end,
|
end: end,
|
||||||
last: begin - 1, // so first allocated will be begin
|
last: big.NewInt(0).Sub(begin, big.NewInt(1)), // so first allocated will be begin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,13 +63,16 @@ func RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
|
||||||
}
|
}
|
||||||
n := newAllocatedMap(network)
|
n := newAllocatedMap(network)
|
||||||
beginIP, endIP := networkdriver.NetworkRange(subnet)
|
beginIP, endIP := networkdriver.NetworkRange(subnet)
|
||||||
begin, end := ipToInt(beginIP)+1, ipToInt(endIP)-1
|
begin := big.NewInt(0).Add(ipToBigInt(beginIP), big.NewInt(1))
|
||||||
if !(begin >= n.begin && end <= n.end && begin < end) {
|
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
|
return ErrBadSubnet
|
||||||
}
|
}
|
||||||
n.begin = begin
|
n.begin.Set(begin)
|
||||||
n.end = end
|
n.end.Set(end)
|
||||||
n.last = begin - 1
|
n.last.Sub(begin, big.NewInt(1))
|
||||||
allocatedIPs[key] = n
|
allocatedIPs[key] = n
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -93,28 +103,25 @@ 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 := ipToInt(ip)
|
delete(allocated.p, ip.String())
|
||||||
delete(allocated.p, pos)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
|
func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
|
||||||
pos := ipToInt(ip)
|
if _, ok := allocated.p[ip.String()]; ok {
|
||||||
|
|
||||||
// Verify that the IP address has not been already allocated.
|
|
||||||
if _, ok := allocated.p[pos]; ok {
|
|
||||||
return nil, ErrIPAlreadyAllocated
|
return nil, ErrIPAlreadyAllocated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pos := ipToBigInt(ip)
|
||||||
// Verify that the IP address is within our network range.
|
// Verify that the IP address is within our network range.
|
||||||
if pos < allocated.begin || pos > allocated.end {
|
if pos.Cmp(allocated.begin) == -1 || pos.Cmp(allocated.end) == 1 {
|
||||||
return nil, ErrIPOutOfRange
|
return nil, ErrIPOutOfRange
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the IP.
|
// Register the IP.
|
||||||
allocated.p[pos] = struct{}{}
|
allocated.p[ip.String()] = struct{}{}
|
||||||
allocated.last = pos
|
allocated.last.Set(pos)
|
||||||
|
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
@ -122,29 +129,35 @@ func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
|
||||||
// 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() (net.IP, error) {
|
func (allocated *allocatedMap) getNextIP() (net.IP, error) {
|
||||||
for pos := allocated.last + 1; pos != allocated.last; pos++ {
|
for pos := big.NewInt(0).Add(allocated.last, big.NewInt(1)); pos.Cmp(allocated.last) != 0; pos.Add(pos, big.NewInt(1)) {
|
||||||
if pos > allocated.end {
|
if pos.Cmp(allocated.end) == 1 {
|
||||||
pos = allocated.begin
|
pos.Set(allocated.begin)
|
||||||
}
|
}
|
||||||
if _, ok := allocated.p[pos]; ok {
|
if _, ok := allocated.p[bigIntToIP(pos).String()]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
allocated.p[pos] = struct{}{}
|
allocated.p[bigIntToIP(pos).String()] = struct{}{}
|
||||||
allocated.last = pos
|
allocated.last.Set(pos)
|
||||||
return intToIP(pos), nil
|
return bigIntToIP(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 128 bit integer
|
||||||
func ipToInt(ip net.IP) uint32 {
|
func ipToBigInt(ip net.IP) *big.Int {
|
||||||
return binary.BigEndian.Uint32(ip.To4())
|
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 32 bit integer into a 4 bytes IP address
|
// Converts 128 bit integer into a 4 bytes IP address
|
||||||
func intToIP(n uint32) net.IP {
|
func bigIntToIP(v *big.Int) net.IP {
|
||||||
b := make([]byte, 4)
|
return net.IP(v.Bytes())
|
||||||
binary.BigEndian.PutUint32(b, n)
|
|
||||||
ip := net.IP(b)
|
|
||||||
return ip
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ipallocator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -10,6 +11,46 @@ func reset() {
|
||||||
allocatedIPs = networkSet{}
|
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) {
|
func TestRequestNewIps(t *testing.T) {
|
||||||
defer reset()
|
defer reset()
|
||||||
network := &net.IPNet{
|
network := &net.IPNet{
|
||||||
|
@ -19,6 +60,7 @@ func TestRequestNewIps(t *testing.T) {
|
||||||
|
|
||||||
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)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -29,7 +71,39 @@ func TestRequestNewIps(t *testing.T) {
|
||||||
t.Fatalf("Expected ip %s got %s", expected, ip.String())
|
t.Fatalf("Expected ip %s got %s", expected, ip.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value := intToIP(ipToInt(ip) + 1).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 {
|
if err := ReleaseIP(network, ip); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -59,6 +133,23 @@ func TestReleaseIp(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func TestGetReleasedIp(t *testing.T) {
|
||||||
defer reset()
|
defer reset()
|
||||||
network := &net.IPNet{
|
network := &net.IPNet{
|
||||||
|
@ -97,6 +188,44 @@ func TestGetReleasedIp(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func TestRequestSpecificIp(t *testing.T) {
|
||||||
defer reset()
|
defer reset()
|
||||||
network := &net.IPNet{
|
network := &net.IPNet{
|
||||||
|
@ -122,15 +251,28 @@ func TestRequestSpecificIp(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConversion(t *testing.T) {
|
func TestRequestSpecificIpV6(t *testing.T) {
|
||||||
ip := net.ParseIP("127.0.0.1")
|
defer reset()
|
||||||
i := ipToInt(ip)
|
network := &net.IPNet{
|
||||||
if i == 0 {
|
IP: []byte{0x2a, 0x00, 0x14, 0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||||
t.Fatal("converted to zero")
|
Mask: []byte{255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0}, // /64 netmask
|
||||||
}
|
}
|
||||||
conv := intToIP(i)
|
|
||||||
if !ip.Equal(conv) {
|
ip := net.ParseIP("2a00:1450::5")
|
||||||
t.Error(conv.String())
|
|
||||||
|
// 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +286,7 @@ func TestIPAllocator(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
gwIP, n, _ := net.ParseCIDR("127.0.0.1/29")
|
gwIP, n, _ := net.ParseCIDR("127.0.0.1/29")
|
||||||
|
|
||||||
network := &net.IPNet{IP: gwIP, Mask: n.Mask}
|
network := &net.IPNet{IP: gwIP, Mask: n.Mask}
|
||||||
// Pool after initialisation (f = free, u = used)
|
// Pool after initialisation (f = free, u = used)
|
||||||
// 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
// 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
|
||||||
|
@ -237,13 +380,13 @@ func TestAllocateFirstIP(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
firstIP := network.IP.To4().Mask(network.Mask)
|
firstIP := network.IP.To4().Mask(network.Mask)
|
||||||
first := ipToInt(firstIP) + 1
|
first := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
|
||||||
|
|
||||||
ip, err := RequestIP(network, nil)
|
ip, err := RequestIP(network, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
allocated := ipToInt(ip)
|
allocated := ipToBigInt(ip)
|
||||||
|
|
||||||
if allocated == first {
|
if allocated == first {
|
||||||
t.Fatalf("allocated ip should not equal first ip: %d == %d", first, allocated)
|
t.Fatalf("allocated ip should not equal first ip: %d == %d", first, allocated)
|
||||||
|
@ -301,11 +444,24 @@ func TestAllocateDifferentSubnets(t *testing.T) {
|
||||||
IP: []byte{127, 0, 0, 1},
|
IP: []byte{127, 0, 0, 1},
|
||||||
Mask: []byte{255, 255, 255, 0},
|
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{
|
expectedIPs := []net.IP{
|
||||||
0: net.IPv4(192, 168, 0, 2),
|
0: net.IPv4(192, 168, 0, 2),
|
||||||
1: net.IPv4(192, 168, 0, 3),
|
1: net.IPv4(192, 168, 0, 3),
|
||||||
2: net.IPv4(127, 0, 0, 2),
|
2: net.IPv4(127, 0, 0, 2),
|
||||||
3: net.IPv4(127, 0, 0, 3),
|
3: net.IPv4(127, 0, 0, 3),
|
||||||
|
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)
|
ip11, err := RequestIP(network1, nil)
|
||||||
|
@ -324,11 +480,37 @@ func TestAllocateDifferentSubnets(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
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[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)
|
||||||
|
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) {
|
func TestRegisterBadTwice(t *testing.T) {
|
||||||
defer reset()
|
defer reset()
|
||||||
network := &net.IPNet{
|
network := &net.IPNet{
|
||||||
|
@ -378,6 +560,7 @@ func TestAllocateFromRange(t *testing.T) {
|
||||||
IP: []byte{192, 168, 0, 8},
|
IP: []byte{192, 168, 0, 8},
|
||||||
Mask: []byte{255, 255, 255, 248},
|
Mask: []byte{255, 255, 255, 248},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := RegisterSubnet(network, subnet); err != nil {
|
if err := RegisterSubnet(network, subnet); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,9 +122,6 @@ func TestNetworkRange(t *testing.T) {
|
||||||
if !last.Equal(net.ParseIP("192.168.0.255")) {
|
if !last.Equal(net.ParseIP("192.168.0.255")) {
|
||||||
t.Error(last.String())
|
t.Error(last.String())
|
||||||
}
|
}
|
||||||
if size := NetworkSize(network.Mask); size != 256 {
|
|
||||||
t.Error(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Class A test
|
// Class A test
|
||||||
_, network, _ = net.ParseCIDR("10.0.0.1/8")
|
_, network, _ = net.ParseCIDR("10.0.0.1/8")
|
||||||
|
@ -135,9 +132,6 @@ func TestNetworkRange(t *testing.T) {
|
||||||
if !last.Equal(net.ParseIP("10.255.255.255")) {
|
if !last.Equal(net.ParseIP("10.255.255.255")) {
|
||||||
t.Error(last.String())
|
t.Error(last.String())
|
||||||
}
|
}
|
||||||
if size := NetworkSize(network.Mask); size != 16777216 {
|
|
||||||
t.Error(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Class A, random IP address
|
// Class A, random IP address
|
||||||
_, network, _ = net.ParseCIDR("10.1.2.3/8")
|
_, network, _ = net.ParseCIDR("10.1.2.3/8")
|
||||||
|
@ -158,9 +152,6 @@ func TestNetworkRange(t *testing.T) {
|
||||||
if !last.Equal(net.ParseIP("10.1.2.3")) {
|
if !last.Equal(net.ParseIP("10.1.2.3")) {
|
||||||
t.Error(last.String())
|
t.Error(last.String())
|
||||||
}
|
}
|
||||||
if size := NetworkSize(network.Mask); size != 1 {
|
|
||||||
t.Error(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 31bit mask
|
// 31bit mask
|
||||||
_, network, _ = net.ParseCIDR("10.1.2.3/31")
|
_, network, _ = net.ParseCIDR("10.1.2.3/31")
|
||||||
|
@ -171,9 +162,6 @@ func TestNetworkRange(t *testing.T) {
|
||||||
if !last.Equal(net.ParseIP("10.1.2.3")) {
|
if !last.Equal(net.ParseIP("10.1.2.3")) {
|
||||||
t.Error(last.String())
|
t.Error(last.String())
|
||||||
}
|
}
|
||||||
if size := NetworkSize(network.Mask); size != 2 {
|
|
||||||
t.Error(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 26bit mask
|
// 26bit mask
|
||||||
_, network, _ = net.ParseCIDR("10.1.2.3/26")
|
_, network, _ = net.ParseCIDR("10.1.2.3/26")
|
||||||
|
@ -184,7 +172,4 @@ func TestNetworkRange(t *testing.T) {
|
||||||
if !last.Equal(net.ParseIP("10.1.2.63")) {
|
if !last.Equal(net.ParseIP("10.1.2.63")) {
|
||||||
t.Error(last.String())
|
t.Error(last.String())
|
||||||
}
|
}
|
||||||
if size := NetworkSize(network.Mask); size != 64 {
|
|
||||||
t.Error(size)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package networkdriver
|
package networkdriver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
@ -56,25 +55,21 @@ func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
|
||||||
|
|
||||||
// Calculates the first and last IP addresses in an IPNet
|
// Calculates the first and last IP addresses in an IPNet
|
||||||
func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
|
func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
|
||||||
var (
|
var netIP net.IP
|
||||||
netIP = network.IP.To4()
|
if network.IP.To4() != nil {
|
||||||
firstIP = netIP.Mask(network.Mask)
|
netIP = network.IP.To4()
|
||||||
lastIP = net.IPv4(0, 0, 0, 0).To4()
|
} else if network.IP.To16() != nil {
|
||||||
)
|
netIP = network.IP.To16()
|
||||||
|
} else {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < len(lastIP); i++ {
|
lastIP := make([]byte, len(netIP), len(netIP))
|
||||||
|
|
||||||
|
for i := 0; i < len(netIP); i++ {
|
||||||
lastIP[i] = netIP[i] | ^network.Mask[i]
|
lastIP[i] = netIP[i] | ^network.Mask[i]
|
||||||
}
|
}
|
||||||
return firstIP, lastIP
|
return netIP.Mask(network.Mask), net.IP(lastIP)
|
||||||
}
|
|
||||||
|
|
||||||
// Given a netmask, calculates the number of available hosts
|
|
||||||
func NetworkSize(mask net.IPMask) int32 {
|
|
||||||
m := net.IPv4Mask(0, 0, 0, 0)
|
|
||||||
for i := 0; i < net.IPv4len; i++ {
|
|
||||||
m[i] = ^mask[i]
|
|
||||||
}
|
|
||||||
return int32(binary.BigEndian.Uint32(m)) + 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the IPv4 address of a network interface
|
// Return the IPv4 address of a network interface
|
||||||
|
@ -90,7 +85,7 @@ func GetIfaceAddr(name string) (net.Addr, error) {
|
||||||
var addrs4 []net.Addr
|
var addrs4 []net.Addr
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
ip := (addr.(*net.IPNet)).IP
|
ip := (addr.(*net.IPNet)).IP
|
||||||
if ip4 := ip.To4(); len(ip4) == net.IPv4len {
|
if ip4 := ip.To4(); ip4 != nil {
|
||||||
addrs4 = append(addrs4, addr)
|
addrs4 = append(addrs4, addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue