浏览代码

Merge pull request #42626 from mfeit-internet2/small-ipv4-networks

Support small ipv4 networks
Sebastiaan van Stijn 3 年之前
父节点
当前提交
9959eceb9a
共有 2 个文件被更改,包括 74 次插入5 次删除
  1. 8 5
      libnetwork/ipam/allocator.go
  2. 66 0
      libnetwork/ipam/allocator_test.go

+ 8 - 5
libnetwork/ipam/allocator.go

@@ -348,12 +348,15 @@ func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
 		return err
 	}
 
-	// Do not let network identifier address be reserved
-	// Do the same for IPv6 so that bridge ip starts with XXXX...::1
-	h.Set(0)
+	// Pre-reserve the network address on IPv4 networks large
+	// enough to have one (i.e., anything bigger than a /31.
+	if !(ipVer == v4 && numAddresses <= 2) {
+		h.Set(0)
+	}
 
-	// Do not let broadcast address be reserved
-	if ipVer == v4 {
+	// Pre-reserve the broadcast address on IPv4 networks large
+	// enough to have one (i.e., anything bigger than a /31).
+	if ipVer == v4 && numAddresses > 2 {
 		h.Set(numAddresses - 1)
 	}
 

+ 66 - 0
libnetwork/ipam/allocator_test.go

@@ -1055,6 +1055,72 @@ func TestOverlappingRequests(t *testing.T) {
 	}
 }
 
+func TestUnusualSubnets(t *testing.T) {
+
+	subnet := "192.168.0.2/31"
+
+	outsideTheRangeAddresses := []struct {
+		address string
+	}{
+		{"192.168.0.1"},
+		{"192.168.0.4"},
+		{"192.168.0.100"},
+	}
+
+	expectedAddresses := []struct {
+		address string
+	}{
+		{"192.168.0.2"},
+		{"192.168.0.3"},
+	}
+
+	for _, store := range []bool{false, true} {
+
+		allocator, err := getAllocator(store)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		//
+		// IPv4 /31 blocks.  See RFC 3021.
+		//
+
+		pool, _, _, err := allocator.RequestPool(localAddressSpace, subnet, "", nil, false)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		// Outside-the-range
+
+		for _, outside := range outsideTheRangeAddresses {
+			_, _, errx := allocator.RequestAddress(pool, net.ParseIP(outside.address), nil)
+			if errx != ipamapi.ErrIPOutOfRange {
+				t.Fatalf("Address %s failed to throw expected error: %s", outside.address, errx.Error())
+			}
+		}
+
+		// Should get just these two IPs followed by exhaustion on the next request
+
+		for _, expected := range expectedAddresses {
+			got, _, errx := allocator.RequestAddress(pool, nil, nil)
+			if errx != nil {
+				t.Fatalf("Failed to obtain the address: %s", errx.Error())
+			}
+			expectedIP := net.ParseIP(expected.address)
+			gotIP := got.IP
+			if !gotIP.Equal(expectedIP) {
+				t.Fatalf("Failed to obtain sequentialaddress. Expected: %s, Got: %s", expectedIP, gotIP)
+			}
+		}
+
+		_, _, err = allocator.RequestAddress(pool, nil, nil)
+		if err != ipamapi.ErrNoAvailableIPs {
+			t.Fatal("Did not get expected error when pool is exhausted.")
+		}
+
+	}
+}
+
 func TestRelease(t *testing.T) {
 	var (
 		subnet = "192.168.0.0/23"