aboutsummaryrefslogtreecommitdiff
path: root/libpod/network/subnet.go
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2020-10-06 12:24:21 -0500
committerbaude <bbaude@redhat.com>2020-10-07 10:03:21 -0500
commitfe3faa517e1bbc3b2e82afaae32d8712c844fdae (patch)
tree3b4a74edc98a2861d2e1b6bb1d9769e078b9ba3c /libpod/network/subnet.go
parentdefb754945b3f99c1d786dac95d9b17b24f55e59 (diff)
downloadpodman-fe3faa517e1bbc3b2e82afaae32d8712c844fdae.tar.gz
podman-fe3faa517e1bbc3b2e82afaae32d8712c844fdae.tar.bz2
podman-fe3faa517e1bbc3b2e82afaae32d8712c844fdae.zip
prevent unpredictable results with network create|remove
due to a lack of "locking" on cni operations, we could get ourselves in trouble when doing rapid creation or removal of networks. added a simple file lock to deal with the collision and because it is not considered a performent path, use of the file lock should be ok. if proven otherwise in the future, some generic shared memory lock should be implemented for libpod and also used here. moved pkog/network to libpod/network because libpod is now being pulled into the package and it has therefore lost its generic nature. this will make it easier to absorb into libpod as we try to make the network closer to core operations. Fixes: #7807 Signed-off-by: baude <bbaude@redhat.com>
Diffstat (limited to 'libpod/network/subnet.go')
-rw-r--r--libpod/network/subnet.go78
1 files changed, 78 insertions, 0 deletions
diff --git a/libpod/network/subnet.go b/libpod/network/subnet.go
new file mode 100644
index 000000000..90f0cdfce
--- /dev/null
+++ b/libpod/network/subnet.go
@@ -0,0 +1,78 @@
+package network
+
+/*
+ The code in this was kindly contributed by Dan Williams(dcbw@redhat.com). Many thanks
+ for his contributions.
+*/
+
+import (
+ "fmt"
+ "net"
+)
+
+func incByte(subnet *net.IPNet, idx int, shift uint) error {
+ if idx < 0 {
+ return fmt.Errorf("no more subnets left")
+ }
+ if subnet.IP[idx] == 255 {
+ subnet.IP[idx] = 0
+ return incByte(subnet, idx-1, 0)
+ }
+ subnet.IP[idx] += 1 << shift
+ return nil
+}
+
+// NextSubnet returns subnet incremented by 1
+func NextSubnet(subnet *net.IPNet) (*net.IPNet, error) {
+ newSubnet := &net.IPNet{
+ IP: subnet.IP,
+ Mask: subnet.Mask,
+ }
+ ones, bits := newSubnet.Mask.Size()
+ if ones == 0 {
+ return nil, fmt.Errorf("%s has only one subnet", subnet.String())
+ }
+ zeroes := uint(bits - ones)
+ shift := zeroes % 8
+ idx := ones/8 - 1
+ if idx < 0 {
+ idx = 0
+ }
+ if err := incByte(newSubnet, idx, shift); err != nil {
+ return nil, err
+ }
+ return newSubnet, nil
+}
+
+// LastIPInSubnet gets the last IP in a subnet
+func LastIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
+ // re-parse to ensure clean network address
+ _, cidr, err := net.ParseCIDR(addr.String())
+ if err != nil {
+ return nil, err
+ }
+
+ ones, bits := cidr.Mask.Size()
+ if ones == bits {
+ return FirstIPInSubnet(cidr)
+ }
+ hostStart := ones / 8
+ // Handle the first host byte
+ cidr.IP[hostStart] |= 0xff & cidr.Mask[hostStart]
+ // Fill the rest with ones
+ for i := hostStart; i < len(cidr.IP); i++ {
+ cidr.IP[i] = 0xff
+ }
+ return cidr.IP, nil
+}
+
+// FirstIPInSubnet gets the first IP in a subnet
+func FirstIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
+ // re-parse to ensure clean network address
+ _, cidr, err := net.ParseCIDR(addr.String())
+ if err != nil {
+ return nil, err
+ }
+ cidr.IP[len(cidr.IP)-1]++
+ return cidr.IP, nil
+}