go_subnetter/netsplit/funcs_vlsmsplitter.go
2025-01-31 17:18:35 -05:00

98 lines
2.2 KiB
Go

package netsplit
import (
"go4.org/netipx"
"net/netip"
"sort"
)
// Split splits the network defined in a VLSMSplitter alongside its configuration and performs the subnetting.
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 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
}
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
}