github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/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 FirstIPInSubnet(cidr) 58 } 59 hostStart := ones / 8 60 // Handle the first host byte 61 cidr.IP[hostStart] |= 0xff & cidr.Mask[hostStart] 62 // Fill the rest with ones 63 for i := hostStart; i < len(cidr.IP); i++ { 64 cidr.IP[i] = 0xff 65 } 66 return cidr.IP, nil 67 } 68 69 // FirstIPInSubnet gets the first IP in a subnet 70 func FirstIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer 71 // re-parse to ensure clean network address 72 _, cidr, err := net.ParseCIDR(addr.String()) 73 if err != nil { 74 return nil, err 75 } 76 cidr.IP[len(cidr.IP)-1]++ 77 return cidr.IP, nil 78 }