sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/internal/cidr/cidr.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cidr 18 19 import ( 20 "encoding/binary" 21 "fmt" 22 "math" 23 "net" 24 25 "github.com/pkg/errors" 26 ) 27 28 // SplitIntoSubnetsIPv4 splits a IPv4 CIDR into a specified number of subnets. 29 // If the number of required subnets isn't a power of 2 then then CIDR will be split 30 // into the the next highest power of 2 and you will end up with unused ranges. 31 // NOTE: this code is adapted from kops https://github.com/kubernetes/kops/blob/c323819e6480d71bad8d21184516e3162eaeca8f/pkg/util/subnet/subnet.go#L46 32 func SplitIntoSubnetsIPv4(cidrBlock string, numSubnets int) ([]*net.IPNet, error) { 33 _, parent, err := net.ParseCIDR(cidrBlock) 34 if err != nil { 35 return nil, errors.Wrap(err, "failed to parse CIDR") 36 } 37 38 subnetBits := math.Ceil(math.Log2(float64(numSubnets))) 39 40 networkLen, addrLen := parent.Mask.Size() 41 modifiedNetworkLen := networkLen + int(subnetBits) 42 43 if modifiedNetworkLen > addrLen { 44 return nil, errors.Errorf("cidr %s cannot accommodate %d subnets", cidrBlock, numSubnets) 45 } 46 47 var subnets []*net.IPNet 48 for i := 0; i < numSubnets; i++ { 49 ip4 := parent.IP.To4() 50 if ip4 == nil { 51 return nil, errors.Errorf("unexpected IP address type: %s", parent) 52 } 53 54 n := binary.BigEndian.Uint32(ip4) 55 n += uint32(i) << uint(32-modifiedNetworkLen) 56 subnetIP := make(net.IP, len(ip4)) 57 binary.BigEndian.PutUint32(subnetIP, n) 58 59 subnets = append(subnets, &net.IPNet{ 60 IP: subnetIP, 61 Mask: net.CIDRMask(modifiedNetworkLen, 32), 62 }) 63 } 64 65 return subnets, nil 66 } 67 68 // GetIPv4Cidrs gets the IPv4 CIDRs from a string slice. 69 func GetIPv4Cidrs(cidrs []string) ([]string, error) { 70 found := []string{} 71 72 for i := range cidrs { 73 cidr := cidrs[i] 74 75 ip, _, err := net.ParseCIDR(cidr) 76 if err != nil { 77 return found, fmt.Errorf("parsing %s as cidr: %w", cidr, err) 78 } 79 80 ipv4 := ip.To4() 81 if ipv4 != nil { 82 found = append(found, cidr) 83 } 84 } 85 86 return found, nil 87 } 88 89 // GetIPv6Cidrs gets the IPv6 CIDRs from a string slice. 90 func GetIPv6Cidrs(cidrs []string) ([]string, error) { 91 found := []string{} 92 93 for i := range cidrs { 94 cidr := cidrs[i] 95 96 ip, _, err := net.ParseCIDR(cidr) 97 if err != nil { 98 return found, fmt.Errorf("parsing %s as cidr: %w", cidr, err) 99 } 100 101 ipv4 := ip.To4() 102 if ipv4 == nil { 103 found = append(found, cidr) 104 } 105 } 106 107 return found, nil 108 }