go_subnetter/netsplit/funcs_cidrsplitter.go
brent saner 860ad5842b
v0.2.5
ADDED:
* num-addrs subcommand, to get the number of hosts/addresses in a given
  prefix length
* get-net subcommand, to more easily get a single subnet from either the
  beginning or the end of a prefix. (MUCH FASTER than CIDR-splitting!)
2025-04-13 18:25:32 -04:00

72 lines
1.7 KiB
Go

package netsplit
import (
"net/netip"
"go4.org/netipx"
)
/*
Split splits the network defined in a CIDRSplitter alongside its configuration and performs the subnetting.
This strategy attempts to split a network into subnets of a single uniform explicit size.
*/
func (c *CIDRSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, err error) {
var ok bool
var base netip.Prefix
var sub netip.Prefix
var subPtr *netip.Prefix
var ipsb *netipx.IPSetBuilder = new(netipx.IPSetBuilder)
if c == nil || c.PrefixLength == 0 || c.BaseSplitter == nil || c.network == nil {
return
}
if err = validate.Struct(c); err != nil {
return
}
if base, ok = netipx.FromStdIPNet(c.network); !ok {
err = ErrBadBoundary
return
}
if !base.IsValid() {
err = ErrBadBoundary
return
}
if c.PrefixLength < uint8(base.Bits()) {
err = ErrBigPrefix
return
}
ipsb.AddPrefix(base)
if remaining, err = ipsb.IPSet(); err != nil {
return
}
/*
TODO: This is *super* slow for tiny subnets in a large net.
For future optimzation, first off benchmark to make sure it makes a difference, but
chunk out the network (how to find appropriate length?) of n < x < y, where n is the network pfx len,
and goroutine each split into a channel.
Because this splits *on CIDR boundaries* and we aren't VLSM-ing, remaining never has to be considered-
it'll always be clean splitting.
See CIDRSplitter.LenSwitch.
*/
for {
if sub, remaining, ok = remaining.RemoveFreePrefix(c.PrefixLength); !ok {
if !sub.IsValid() {
// No error; it's literally impossible since we network on boundaries.
// We just hit the end of the prefix.
break
}
}
subPtr = new(netip.Prefix)
*subPtr = sub
nets = append(nets, subPtr)
}
return
}