@@ -0,0 +1,54 @@
|
|||||||
|
package rings
|
||||||
|
|
||||||
|
import "net/netip"
|
||||||
|
|
||||||
|
func PrefixToRange(subnet netip.Prefix) (from, to netip.Addr) {
|
||||||
|
if u, ok := addrToU32(subnet.Addr()); ok {
|
||||||
|
shift := 32 - subnet.Bits()
|
||||||
|
|
||||||
|
m1 := uint32((1 << shift) - 1)
|
||||||
|
m0 := uint32(0xffffffff) & ^m1
|
||||||
|
|
||||||
|
u0 := u & m0
|
||||||
|
u1 := u0 + m1
|
||||||
|
|
||||||
|
from = u32ToAddr(u0)
|
||||||
|
to = u32ToAddr(u1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return from, to
|
||||||
|
}
|
||||||
|
|
||||||
|
func u32ToAddr(v uint32) netip.Addr {
|
||||||
|
return addrFrom4(
|
||||||
|
uint(v>>24)&0xff,
|
||||||
|
uint(v>>16)&0xff,
|
||||||
|
uint(v>>8)&0xff,
|
||||||
|
uint(v)&0xff,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addrToU32(addr netip.Addr) (uint32, bool) {
|
||||||
|
switch {
|
||||||
|
case !addr.IsValid():
|
||||||
|
return 0, false
|
||||||
|
case addr.Is4(), addr.Is4In6():
|
||||||
|
a4 := addr.As4()
|
||||||
|
v := uint32(a4[0])<<24 +
|
||||||
|
uint32(a4[1])<<16 +
|
||||||
|
uint32(a4[2])<<8 +
|
||||||
|
uint32(a4[3])
|
||||||
|
return v, true
|
||||||
|
default:
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addrFrom4(a, b, c, d uint) netip.Addr {
|
||||||
|
return netip.AddrFrom4([4]byte{
|
||||||
|
byte(a),
|
||||||
|
byte(b),
|
||||||
|
byte(c),
|
||||||
|
byte(d),
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package rings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"darvaza.org/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ErrOutOfRange[T ~int](value T, field string) error {
|
||||||
|
return core.Wrap(syscall.EINVAL, "%v: %s out of range", value, field)
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
// Package rings implements ...
|
||||||
|
package rings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RegionBits = 4
|
||||||
|
ZoneBits = 4
|
||||||
|
NodeBits = 12
|
||||||
|
NodeZeroBits = 8
|
||||||
|
|
||||||
|
RegionMax = (1 << RegionBits) - 1
|
||||||
|
ZoneMax = (1 << ZoneBits) - 1
|
||||||
|
NodeMax = (1 << NodeBits) - 1
|
||||||
|
NodeZeroMax = (1 << NodeZeroBits) - 1
|
||||||
|
|
||||||
|
RingZeroBits = 20
|
||||||
|
RingOneBits = 20
|
||||||
|
RingTwoBits = 20
|
||||||
|
RingThreeBits = 12
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
RegionID int
|
||||||
|
ZoneID int
|
||||||
|
NodeID int
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n RegionID) Valid() bool { return n > 0 && n <= RegionMax }
|
||||||
|
func (n ZoneID) Valid() bool { return n > 0 && n <= ZoneMax }
|
||||||
|
func (n NodeID) Valid() bool { return n > 0 && n <= NodeMax }
|
||||||
|
func (n NodeID) ValidZero() bool { return n > 0 && n <= NodeZeroMax }
|
||||||
|
|
||||||
|
// 10.0.(region_id << 4 + zone_id).(node_id)/20 for ring 0
|
||||||
|
func RingZeroAddress(region RegionID, zone ZoneID, node NodeID) (addr netip.Addr, err error) {
|
||||||
|
switch {
|
||||||
|
case !region.Valid():
|
||||||
|
err = ErrOutOfRange(region, "region")
|
||||||
|
case !zone.Valid():
|
||||||
|
err = ErrOutOfRange(zone, "zone")
|
||||||
|
case !node.ValidZero():
|
||||||
|
err = ErrOutOfRange(node, "node")
|
||||||
|
default:
|
||||||
|
addr = addrFrom4(10, 0, uint(region)<<4+uint(zone), uint(node))
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func RingZeroPrefix(region RegionID, zone ZoneID) (cidr netip.Prefix, err error) {
|
||||||
|
switch {
|
||||||
|
case !region.Valid():
|
||||||
|
err = ErrOutOfRange(region, "region")
|
||||||
|
case !zone.Valid():
|
||||||
|
err = ErrOutOfRange(zone, "zone")
|
||||||
|
default:
|
||||||
|
addr := addrFrom4(10, 0, uint(region)<<4+uint(zone), 0)
|
||||||
|
cidr = netip.PrefixFrom(addr, RingZeroBits)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cidr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10.(region_id).(zone_id << 4).(node_id)/20 for ring 1
|
||||||
|
func RingOneAddress(region RegionID, zone ZoneID, node NodeID) (addr netip.Addr, err error) {
|
||||||
|
switch {
|
||||||
|
case !region.Valid():
|
||||||
|
err = ErrOutOfRange(region, "region")
|
||||||
|
case !zone.Valid():
|
||||||
|
err = ErrOutOfRange(zone, "zone")
|
||||||
|
case !node.Valid():
|
||||||
|
err = ErrOutOfRange(node, "node")
|
||||||
|
default:
|
||||||
|
n1 := uint(node) / 8
|
||||||
|
n2 := uint(node) % 8
|
||||||
|
addr = addrFrom4(10, uint(region), uint(zone)<<4+n1, n2)
|
||||||
|
}
|
||||||
|
return addr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func RingOnePrefix(region RegionID, zone ZoneID) (cidr netip.Prefix, err error) {
|
||||||
|
switch {
|
||||||
|
case !region.Valid():
|
||||||
|
err = ErrOutOfRange(region, "region")
|
||||||
|
case !zone.Valid():
|
||||||
|
err = ErrOutOfRange(zone, "zone")
|
||||||
|
default:
|
||||||
|
addr := addrFrom4(10, uint(region), uint(zone)<<4, 0)
|
||||||
|
cidr = netip.PrefixFrom(addr, RingOneBits)
|
||||||
|
}
|
||||||
|
return cidr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10.(region_id).0.0/20 for ring 2
|
||||||
|
func RingTwoPrefix(region RegionID) (cidr netip.Prefix, err error) {
|
||||||
|
switch {
|
||||||
|
case !region.Valid():
|
||||||
|
err = ErrOutOfRange(region, "region")
|
||||||
|
default:
|
||||||
|
addr := addrFrom4(10, uint(region), 0, 0)
|
||||||
|
cidr = netip.PrefixFrom(addr, RingTwoBits)
|
||||||
|
}
|
||||||
|
return cidr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10.(region_id << 4).0.0/12 for ring 3
|
||||||
|
func RingThreePrefix(region RegionID) (cidr netip.Prefix, err error) {
|
||||||
|
switch {
|
||||||
|
case !region.Valid():
|
||||||
|
err = ErrOutOfRange(region, "region")
|
||||||
|
default:
|
||||||
|
addr := addrFrom4(10, uint(region)<<4, 0, 0)
|
||||||
|
cidr = netip.PrefixFrom(addr, RingThreeBits)
|
||||||
|
}
|
||||||
|
return cidr, err
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user