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  }