go_subnetter/netsplit/funcs_vlsmsplitter.go
brent saner 0c8577f149
v0.1.0
ADDED:
* Explicit subnet ordering option for VLSM
2025-04-03 18:35:35 -04:00

106 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 = new(netipx.IPSetBuilder)
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 == nil || v.PrefixLengths == nil || len(v.PrefixLengths) == 0 || v.BaseSplitter == nil || v.network == nil {
return
}
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
}