go_subnetter/netsplit/funcs_vlsmsplitter.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

110 lines
2.4 KiB
Go

package netsplit
import (
"net/netip"
`sort`
"go4.org/netipx"
)
/*
Split splits the network defined in a VLSMSplitter alongside its configuration and performs the subnetting.
This strategy allows for multiple subnets of differing sizes to be specified.
remaining may or may not be nil depending on if all desired subnet sizes fit cleanly into the network boundaries.
*/
func (v *VLSMSplitter) Split() (nets []*netip.Prefix, remaining *netipx.IPSet, err error) {
var ok bool
var pfxLen int
var pfxLen8 uint8
var base netip.Prefix
var sub netip.Prefix
var subPtr *netip.Prefix
var ipsb *netipx.IPSetBuilder = new(netipx.IPSetBuilder)
if v == nil || v.PrefixLengths == nil || len(v.PrefixLengths) == 0 || v.BaseSplitter == nil || v.network == nil {
return
}
if err = validate.Struct(v); err != nil {
return
}
if err = ValidateSizes(v.network, v.PrefixLengths...); err != nil {
return
}
/*
I thought about using the following:
* https://pkg.go.dev/net/netip
* https://pkg.go.dev/github.com/sacloud/packages-go/cidr
* https://pkg.go.dev/github.com/projectdiscovery/mapcidr
* https://pkg.go.dev/github.com/EvilSuperstars/go-cidrman
But, as I expected, netipx ftw again.
*/
if !v.Explicit {
sort.SliceStable(
v.PrefixLengths,
func(i, j int) (isBefore bool) { // We use a reverse sorting by default so we get larger prefixes at the beginning.
if v.Ascending {
isBefore = v.PrefixLengths[i] > v.PrefixLengths[j]
} else {
isBefore = v.PrefixLengths[i] < v.PrefixLengths[j]
}
return
},
)
}
pfxLen, _ = v.network.Mask.Size()
pfxLen8 = uint8(pfxLen)
if base, ok = netipx.FromStdIPNet(v.network); !ok {
err = ErrBadBoundary
return
}
if !base.IsValid() {
err = ErrBadBoundary
return
}
ipsb.AddPrefix(base)
if remaining, err = ipsb.IPSet(); err != nil {
return
}
for _, size := range v.PrefixLengths {
if size < pfxLen8 {
err = &SplitErr{
Wrapped: ErrBigPrefix,
Nets: nets,
Remaining: remaining,
LastSubnet: &sub,
RequestedPrefixLen: size,
}
return
}
if sub, remaining, ok = remaining.RemoveFreePrefix(size); !ok {
err = &SplitErr{
Wrapped: ErrNoNetSpace,
Nets: nets,
Remaining: remaining,
LastSubnet: &sub,
RequestedPrefixLen: size,
}
return
}
subPtr = new(netip.Prefix)
*subPtr = sub
nets = append(nets, subPtr)
}
return
}