github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/network/subnet.go (about)

     1  package network
     2  
     3  /*
     4  	The code in this was kindly contributed by Dan Williams(dcbw@redhat.com).  Many thanks
     5  	for his contributions.
     6  */
     7  
     8  import (
     9  	"fmt"
    10  	"net"
    11  )
    12  
    13  func incByte(subnet *net.IPNet, idx int, shift uint) error {
    14  	if idx < 0 {
    15  		return fmt.Errorf("no more subnets left")
    16  	}
    17  	if subnet.IP[idx] == 255 {
    18  		subnet.IP[idx] = 0
    19  		return incByte(subnet, idx-1, 0)
    20  	}
    21  	subnet.IP[idx] += 1 << shift
    22  	return nil
    23  }
    24  
    25  // NextSubnet returns subnet incremented by 1
    26  func NextSubnet(subnet *net.IPNet) (*net.IPNet, error) {
    27  	newSubnet := &net.IPNet{
    28  		IP:   subnet.IP,
    29  		Mask: subnet.Mask,
    30  	}
    31  	ones, bits := newSubnet.Mask.Size()
    32  	if ones == 0 {
    33  		return nil, fmt.Errorf("%s has only one subnet", subnet.String())
    34  	}
    35  	zeroes := uint(bits - ones)
    36  	shift := zeroes % 8
    37  	idx := ones/8 - 1
    38  	if idx < 0 {
    39  		idx = 0
    40  	}
    41  	if err := incByte(newSubnet, idx, shift); err != nil {
    42  		return nil, err
    43  	}
    44  	return newSubnet, nil
    45  }
    46  
    47  // LastIPInSubnet gets the last IP in a subnet
    48  func LastIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
    49  	// re-parse to ensure clean network address
    50  	_, cidr, err := net.ParseCIDR(addr.String())
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	ones, bits := cidr.Mask.Size()
    56  	if ones == bits {
    57  		return cidr.IP, nil
    58  	}
    59  	for i := range cidr.IP {
    60  		cidr.IP[i] = cidr.IP[i] | ^cidr.Mask[i]
    61  	}
    62  	return cidr.IP, nil
    63  }
    64  
    65  // FirstIPInSubnet gets the first IP in a subnet
    66  func FirstIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
    67  	// re-parse to ensure clean network address
    68  	_, cidr, err := net.ParseCIDR(addr.String())
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	ones, bits := cidr.Mask.Size()
    73  	if ones == bits {
    74  		return cidr.IP, nil
    75  	}
    76  	cidr.IP[len(cidr.IP)-1]++
    77  	return cidr.IP, nil
    78  }