mirror of
https://github.com/clearlinux/libnetwork.git
synced 2026-10-04 07:48:30 +00:00
Fix preferred ip allocation in ipam
- also provided a new utility to compute the host part ip address which is resilient to input passed in different representations. Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
@@ -197,6 +197,59 @@ func CompareIPNet(a, b *net.IPNet) bool {
|
||||
return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
|
||||
}
|
||||
|
||||
// GetMinimalIP returns the address in its shortest form
|
||||
func GetMinimalIP(ip net.IP) net.IP {
|
||||
if ip != nil && ip.To4() != nil {
|
||||
return ip.To4()
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
// GetMinimalIPNet returns a copy of the passed IP Network with congruent ip and mask notation
|
||||
func GetMinimalIPNet(nw *net.IPNet) *net.IPNet {
|
||||
if nw == nil {
|
||||
return nil
|
||||
}
|
||||
if len(nw.IP) == 16 && nw.IP.To4() != nil {
|
||||
m := nw.Mask
|
||||
if len(m) == 16 {
|
||||
m = m[12:16]
|
||||
}
|
||||
return &net.IPNet{IP: nw.IP.To4(), Mask: m}
|
||||
}
|
||||
return nw
|
||||
}
|
||||
|
||||
var v4inV6MaskPrefix = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||
|
||||
// GetHostPartIP returns the host portion of the ip address identified by the mask.
|
||||
// IP address representation is not modified. If address and mask are not compatible
|
||||
// an error is returned.
|
||||
func GetHostPartIP(ip net.IP, mask net.IPMask) (net.IP, error) {
|
||||
// Find the effective starting of address and mask
|
||||
is := 0
|
||||
ms := 0
|
||||
if len(ip) == net.IPv6len && ip.To4() != nil {
|
||||
is = 12
|
||||
}
|
||||
if len(ip[is:]) == net.IPv4len && len(mask) == net.IPv6len && bytes.Equal(mask[:12], v4inV6MaskPrefix) {
|
||||
ms = 12
|
||||
}
|
||||
|
||||
// Check if address and mask are semantically compatible
|
||||
if len(ip[is:]) != len(mask[ms:]) {
|
||||
return nil, fmt.Errorf("cannot compute host portion ip address as ip and mask are not compatible: (%#v, %#v)", ip, mask)
|
||||
}
|
||||
|
||||
// Compute host portion
|
||||
out := GetIPCopy(ip)
|
||||
for i := 0; i < len(mask[ms:]); i++ {
|
||||
out[is+i] &= ^mask[ms+i]
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
const (
|
||||
// NEXTHOP indicates a StaticRoute with an IP next hop.
|
||||
NEXTHOP = iota
|
||||
|
||||
@@ -2,6 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -109,3 +110,61 @@ func TestErrorConstructors(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUtilGetHostPortionIP(t *testing.T) {
|
||||
input := []struct {
|
||||
ip net.IP
|
||||
mask net.IPMask
|
||||
host net.IP
|
||||
err error
|
||||
}{
|
||||
{ // ip in v4Inv6 representation, mask in v4 representation
|
||||
ip: net.IPv4(172, 28, 30, 1),
|
||||
mask: []byte{0xff, 0xff, 0xff, 0},
|
||||
host: net.IPv4(0, 0, 0, 1),
|
||||
},
|
||||
{ // ip and mask in v4Inv6 representation
|
||||
ip: net.IPv4(172, 28, 30, 2),
|
||||
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0},
|
||||
host: net.IPv4(0, 0, 0, 2),
|
||||
},
|
||||
{ // ip in v4 representation, mask in v4Inv6 representation
|
||||
ip: net.IPv4(172, 28, 30, 3)[12:],
|
||||
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0},
|
||||
host: net.IPv4(0, 0, 0, 3)[12:],
|
||||
},
|
||||
{ // ip and mask in v4 representation
|
||||
ip: net.IPv4(172, 28, 30, 4)[12:],
|
||||
mask: []byte{0xff, 0xff, 0xff, 0},
|
||||
host: net.IPv4(0, 0, 0, 4)[12:],
|
||||
},
|
||||
{ // ip and mask as v6
|
||||
ip: net.ParseIP("2005:2004:2002:2001:FFFF:ABCD:EEAB:00CD"),
|
||||
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0},
|
||||
host: net.ParseIP("0::AB:00CD"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, i := range input {
|
||||
h, err := GetHostPartIP(i.ip, i.mask)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !i.host.Equal(h) {
|
||||
t.Fatalf("Failed to return expected host ip. Expected: %s. Got: %s", i.host, h)
|
||||
}
|
||||
}
|
||||
|
||||
// ip as v6 and mask as v4 are not compatible
|
||||
if _, err := GetHostPartIP(net.ParseIP("2005:2004:2002:2001:FFFF:ABCD:EEAB:00CD"), []byte{0xff, 0xff, 0xff, 0}); err == nil {
|
||||
t.Fatalf("Unexpected success")
|
||||
}
|
||||
// ip as v4 and non conventional mask
|
||||
if _, err := GetHostPartIP(net.ParseIP("173.32.4.5"), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0}); err == nil {
|
||||
t.Fatalf("Unexpected success")
|
||||
}
|
||||
// ip as v4 and non conventional mask
|
||||
if _, err := GetHostPartIP(net.ParseIP("173.32.4.5"), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0}); err == nil {
|
||||
t.Fatalf("Unexpected success")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user