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 }