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 }