* Module name changed to `github.com/rajch/weave` * Added environment variable `CHECKPOINT_DISABLE=1` to default manifests, to bypass weaveworks telemetry
222 lines
5.2 KiB
Go
222 lines
5.2 KiB
Go
package address
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/rajch/weave/common"
|
|
)
|
|
|
|
// Using 32-bit integer to represent IPv4 address
|
|
type Address uint32
|
|
type Offset uint32
|
|
type Count uint32
|
|
|
|
type Range struct {
|
|
Start, End Address // [Start, End); Start <= End
|
|
}
|
|
|
|
func NewRange(start Address, size Offset) Range {
|
|
return Range{Start: start, End: Add(start, size)}
|
|
}
|
|
func (r Range) Size() Count { return Length(r.End, r.Start) }
|
|
func (r Range) String() string { return fmt.Sprintf("%s-%s", r.Start, r.End-1) }
|
|
func (r Range) Overlaps(or Range) bool { return !(r.Start >= or.End || r.End <= or.Start) }
|
|
func (r Range) Contains(addr Address) bool { return addr >= r.Start && addr < r.End }
|
|
|
|
func (r Range) AsCIDRString() string {
|
|
prefixLen := 32
|
|
for size := r.Size(); size > 1; size = size / 2 {
|
|
if size%2 != 0 { // Size not a power of two; cannot be expressed as a CIDR.
|
|
return r.String()
|
|
}
|
|
prefixLen--
|
|
}
|
|
return CIDR{Addr: r.Start, PrefixLen: prefixLen}.String()
|
|
}
|
|
|
|
// return the highest bit set in v
|
|
// algorithm from http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
|
|
func msb(v Count) Count {
|
|
v |= v >> 1
|
|
v |= v >> 2
|
|
v |= v >> 4
|
|
v |= v >> 8
|
|
v |= v >> 16
|
|
// Cast to 64-bit to avoid overflow when original v >= 0x80000000
|
|
return Count((uint64(v) + 1) / 2)
|
|
}
|
|
|
|
func (r Range) BiggestCIDRRange() Range {
|
|
sizeMsb := Offset(msb(r.Size()))
|
|
maskedSize := Offset(r.Size()) & (sizeMsb - 1)
|
|
maskedStart := Offset(r.Start) & (sizeMsb - 1)
|
|
if maskedStart == 0 {
|
|
return NewRange(r.Start, sizeMsb)
|
|
}
|
|
if sizeMsb-maskedStart <= maskedSize {
|
|
return NewRange(Add(r.Start, sizeMsb-maskedStart), sizeMsb)
|
|
}
|
|
size := sizeMsb / 2
|
|
if size >= maskedStart {
|
|
return NewRange(Add(r.Start, size-maskedStart), size)
|
|
}
|
|
return NewRange(Add(r.Start, sizeMsb-maskedStart), size)
|
|
}
|
|
|
|
func MakeCIDR(subnet CIDR, addr Address) CIDR {
|
|
return CIDR{Addr: addr, PrefixLen: subnet.PrefixLen}
|
|
}
|
|
|
|
type CIDR struct {
|
|
Addr Address
|
|
PrefixLen int
|
|
}
|
|
|
|
// CIDRs returns a list of CIDR-aligned ranges which cover this range.
|
|
func (r Range) CIDRs() []CIDR {
|
|
const (
|
|
fullMask = ^Address(0)
|
|
cidrMaxPrefixLen = 32
|
|
)
|
|
var cidrs []CIDR
|
|
|
|
for start, end := r.Start, r.End-1; end >= start; {
|
|
mask, prefixLen := fullMask, cidrMaxPrefixLen
|
|
// Find the smallest mask which would cover some part of [start;end].
|
|
// Once we found such, apply it by OR'ing
|
|
for mask > 0 {
|
|
tmpMask := mask << 1
|
|
// Check whether mask neither too short nor too long
|
|
if (start&tmpMask) != start || (start|^tmpMask) > end {
|
|
break
|
|
}
|
|
mask = tmpMask
|
|
prefixLen--
|
|
}
|
|
cidrs = append(cidrs, CIDR{start, prefixLen})
|
|
// Apply mask
|
|
start |= ^mask
|
|
// Check for overflow
|
|
if start+1 < start {
|
|
break
|
|
}
|
|
start++
|
|
}
|
|
|
|
return cidrs
|
|
}
|
|
|
|
func ParseIP(s string) (Address, error) {
|
|
if ip := net.ParseIP(s); ip != nil {
|
|
return FromIP4(ip), nil
|
|
}
|
|
return 0, &net.ParseError{Type: "IP Address", Text: s}
|
|
}
|
|
|
|
func ParseCIDR(s string) (CIDR, error) {
|
|
if ip, ipnet, err := net.ParseCIDR(s); err != nil {
|
|
return CIDR{}, err
|
|
} else if ipnet.IP.To4() == nil {
|
|
return CIDR{}, &net.ParseError{Type: "Non-IPv4 address not supported", Text: s}
|
|
} else {
|
|
prefixLen, _ := ipnet.Mask.Size()
|
|
return CIDR{Addr: FromIP4(ip), PrefixLen: prefixLen}, nil
|
|
}
|
|
}
|
|
|
|
func NewCIDRs(ranges []Range) (cidrs []CIDR) {
|
|
for _, r := range ranges {
|
|
cidrs = append(cidrs, r.CIDRs()...)
|
|
}
|
|
return cidrs
|
|
}
|
|
|
|
func (cidr CIDR) Start() Address {
|
|
return cidr.Addr
|
|
}
|
|
|
|
// cidr = [Start; End)
|
|
func (cidr CIDR) End() Address {
|
|
return cidr.Range().End
|
|
}
|
|
|
|
func (cidr CIDR) IsSubnet() bool {
|
|
mask := cidr.Size() - 1
|
|
return Offset(cidr.Addr)&mask == 0
|
|
}
|
|
|
|
func (cidr CIDR) Size() Offset { return 1 << uint(32-cidr.PrefixLen) }
|
|
|
|
func (cidr CIDR) Range() Range {
|
|
return NewRange(cidr.Addr, cidr.Size())
|
|
}
|
|
func (cidr CIDR) HostRange() Range {
|
|
// Respect RFC1122 exclusions of first and last addresses
|
|
return NewRange(cidr.Addr+1, cidr.Size()-2)
|
|
}
|
|
|
|
func (cidr CIDR) String() string {
|
|
return fmt.Sprintf("%s/%d", cidr.Addr.String(), cidr.PrefixLen)
|
|
}
|
|
|
|
func (cidr CIDR) IPNet() (r *net.IPNet) {
|
|
mask := net.CIDRMask(cidr.PrefixLen, 8*net.IPv4len)
|
|
return &net.IPNet{IP: cidr.Addr.IP4(), Mask: mask}
|
|
}
|
|
|
|
// FromIP4 converts an ipv4 address to our integer address type
|
|
func FromIP4(ip4 net.IP) (r Address) {
|
|
for _, b := range ip4.To4() {
|
|
r <<= 8
|
|
r |= Address(b)
|
|
}
|
|
return
|
|
}
|
|
|
|
// IP4 converts our integer address type to an ipv4 address
|
|
func (addr Address) IP4() (r net.IP) {
|
|
r = make([]byte, net.IPv4len)
|
|
for i := 3; i >= 0; i-- {
|
|
r[i] = byte(addr)
|
|
addr >>= 8
|
|
}
|
|
return
|
|
}
|
|
|
|
func (addr Address) MarshalJSON() ([]byte, error) {
|
|
return []byte(fmt.Sprintf("%q", addr.String())), nil
|
|
}
|
|
|
|
func (addr Address) String() string {
|
|
return addr.IP4().String()
|
|
}
|
|
|
|
func Add(addr Address, i Offset) Address {
|
|
return addr + Address(i)
|
|
}
|
|
|
|
func Subtract(a, b Address) Offset {
|
|
common.Assert(a >= b)
|
|
return Offset(a - b)
|
|
}
|
|
|
|
func Length(a, b Address) Count {
|
|
common.Assert(a >= b)
|
|
return Count(a - b)
|
|
}
|
|
|
|
func Min(a, b Count) Count {
|
|
if a > b {
|
|
return b
|
|
}
|
|
return a
|
|
}
|
|
|
|
func (addr Address) Reverse() Address {
|
|
return ((addr >> 24) & 0xff) | // move byte 3 to byte 0
|
|
((addr << 8) & 0xff0000) | // move byte 1 to byte 2
|
|
((addr >> 8) & 0xff00) | // move byte 2 to byte 1
|
|
((addr << 24) & 0xff000000) // byte 0 to byte 3
|
|
}
|