]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[465-add-subnet4-update-and-subnet6-update-commands-to-subnet-cmds-hook] Added replac...
authorFrancis Dupont <fdupont@isc.org>
Fri, 8 Mar 2019 01:29:29 +0000 (02:29 +0100)
committerTomek Mrugalski <tomek@isc.org>
Fri, 19 Apr 2019 10:39:47 +0000 (06:39 -0400)
src/lib/dhcpsrv/shared_network.cc
src/lib/dhcpsrv/tests/shared_network_unittest.cc

index 089fd2015f246a0803e6b2692b75fd16cf05a7fc..0e2b8e0961f4c1663b0d9ee0022d5693f1a4220b 100644 (file)
@@ -77,7 +77,6 @@ public:
     ///
     /// @tparam SubnetPtrType Type of a pointer to a subnet, i.e. Subnet4Ptr
     /// or @ref Subnet6Ptr.
-    
     /// @tparam SubnetCollectionType Type of a container holding subnets, i.e.
     /// @ref Subnet4Collection or @ref Subnet6Collection.
     ///
@@ -94,10 +93,13 @@ public:
     static bool replace(SubnetCollectionType& subnets,
                         const SubnetPtrType& subnet) {
 
-        // Subnet must be non-null.
-        if (!subnet) {
-            isc_throw(BadValue, "null pointer specified when adding a subnet"
-                      " to a shared network");
+        // Check if the subnet is already associated with some network.
+        NetworkPtr network;
+        subnet->getSharedNetwork(network);
+        if (network) {
+            isc_throw(InvalidOperation, "subnet " << subnet->getID()
+                      << " being replaced in a shared network"
+                      " already belongs to a shared network");
         }
 
         // Get the subnet with the same ID.
@@ -305,6 +307,11 @@ SharedNetwork4::add(const Subnet4Ptr& subnet) {
 
 bool
 SharedNetwork4::replace(const Subnet4Ptr& subnet) {
+    // Subnet must be non-null.
+    if (!subnet) {
+        isc_throw(BadValue, "null pointer specified when adding a subnet"
+                  " to a shared network");
+    }
     const Subnet4Ptr& old = getSubnet(subnet->getID());
     bool ret = Impl::replace(subnets_, subnet);
     if (ret) {
@@ -385,6 +392,11 @@ SharedNetwork6::add(const Subnet6Ptr& subnet) {
 
 bool
 SharedNetwork6::replace(const Subnet6Ptr& subnet) {
+    // Subnet must be non-null.
+    if (!subnet) {
+        isc_throw(BadValue, "null pointer specified when adding a subnet"
+                  " to a shared network");
+    }
     const Subnet6Ptr& old = getSubnet(subnet->getID());
     bool ret = Impl::replace(subnets_, subnet);
     if (ret) {
index 044692b6a5a73625040e24e65ac99577978f888a..3e7b9f16de388c93352b67704c1caff0e32bed01 100644 (file)
@@ -120,6 +120,105 @@ TEST(SharedNetwork4Test, addSubnet4) {
     ASSERT_THROW(network2->add(subnet), InvalidOperation);
 }
 
+// This test verifies that an IPv4 subnet can be replaced in a shared network.
+// It does the same tests than for addSubnet4 (at the exception of conflicts)
+// and check the random order is kept.
+TEST(SharedNetwork4Test, replaceSubnet4) {
+    // First, create a network.
+    SharedNetwork4Ptr network(new SharedNetwork4("frog"));
+
+    // Try to replace null pointer. It should throw.
+    Subnet4Ptr subnet;
+    ASSERT_THROW(network->replace(subnet), BadValue);
+
+    // Create some valid subnets. they should now be added successfully.
+    subnet.reset(new Subnet4(IOAddress("10.0.0.0"), 8, 10, 20, 30,
+                             SubnetID(15)));
+    ASSERT_NO_THROW(network->add(subnet));
+    subnet.reset(new Subnet4(IOAddress("192.168.0.0"), 24, 10, 20, 30,
+                             SubnetID(1)));
+    ASSERT_NO_THROW(network->add(subnet));
+    subnet.reset(new Subnet4(IOAddress("192.168.1.0"), 24, 10, 20, 30,
+                             SubnetID(10)));
+    ASSERT_NO_THROW(network->add(subnet));
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+
+    // Create another subnet with another ID. Replace should return false.
+    subnet.reset(new Subnet4(IOAddress("192.168.2.0"), 24, 10, 20, 30,
+                             SubnetID(2)));
+    EXPECT_FALSE(network->replace(subnet));
+
+    // Subnets did not changed.
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+    Subnet4Ptr returned_subnet = network->getAllSubnets()->at(0);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(15, returned_subnet->getID());
+    returned_subnet = network->getAllSubnets()->at(2);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(10, returned_subnet->getID());
+    // Finish by the second subnet.
+    returned_subnet = network->getAllSubnets()->at(1);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(1, returned_subnet->getID());
+
+    // Create another subnet with the same ID than the second subnet.
+    subnet.reset(new Subnet4(IOAddress("192.168.0.0"), 24, 100, 200, 300,
+                             SubnetID(1)));
+    EXPECT_TRUE(network->replace(subnet));
+
+    // Second subnet was updated.
+    EXPECT_EQ(10, returned_subnet->getT1());
+    EXPECT_EQ(20, returned_subnet->getT2());
+    EXPECT_EQ(30, returned_subnet->getValid());
+    SharedNetwork4Ptr network1;
+    returned_subnet->getSharedNetwork(network1);
+    EXPECT_FALSE(network1);
+
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+    returned_subnet = network->getAllSubnets()->at(1);
+    ASSERT_TRUE(returned_subnet);
+    ASSERT_EQ(1, returned_subnet->getID());
+    EXPECT_EQ(100, returned_subnet->getT1());
+    EXPECT_EQ(200, returned_subnet->getT2());
+    EXPECT_EQ(300, returned_subnet->getValid());
+    returned_subnet->getSharedNetwork(network1);
+    EXPECT_TRUE(network1);
+    EXPECT_TRUE(network == network1);
+
+    // Other subnets did not changed.
+    returned_subnet = network->getAllSubnets()->at(0);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(15, returned_subnet->getID());
+    returned_subnet = network->getAllSubnets()->at(2);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(10, returned_subnet->getID());
+
+    // Create another network and try to replace a subnet to it. It should fail
+    // because the subnet is already associated with the first network.
+    SharedNetwork4Ptr network2(new SharedNetwork4("dog"));
+    ASSERT_THROW(network2->replace(subnet), InvalidOperation);
+
+    // Try to change the prefix. Not recommended but should work.
+    subnet.reset(new Subnet4(IOAddress("192.168.10.0"), 24, 100, 200, 300,
+                             SubnetID(1)));
+    EXPECT_TRUE(network->replace(subnet));
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+    returned_subnet = network->getAllSubnets()->at(1);
+    ASSERT_TRUE(returned_subnet);
+    ASSERT_EQ(1, returned_subnet->getID());
+    EXPECT_EQ("192.168.10.0/24", returned_subnet->toText());
+
+    // but not if the prefix already exists for another subnet.
+    subnet.reset(new Subnet4(IOAddress("192.168.1.0"), 24, 100, 200, 300,
+                             SubnetID(1)));
+    EXPECT_FALSE(network->replace(subnet));
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+    returned_subnet = network->getAllSubnets()->at(1);
+    ASSERT_TRUE(returned_subnet);
+    ASSERT_EQ(1, returned_subnet->getID());
+    EXPECT_EQ("192.168.10.0/24", returned_subnet->toText());
+}
+
 // This test verifies that it is possible to remove a specified subnet.
 TEST(SharedNetwork4Test, delSubnet4) {
     // Create two subnets and add them to the shared network.
@@ -561,6 +660,107 @@ TEST(SharedNetwork6Test, addSubnet6) {
     ASSERT_THROW(network2->add(subnet), InvalidOperation);
 }
 
+// This test verifies that an IPv6 subnet can be replaced in a shared network.
+// It does the same tests than for addSubnet6 (at the exception of conflicts)
+// and check the random order is kept.
+TEST(SharedNetwork6Test, replaceSubnet6) {
+    // First, create a network.
+    SharedNetwork6Ptr network(new SharedNetwork6("frog"));
+
+    // Try to replace null pointer. It should throw.
+    Subnet6Ptr subnet;
+    ASSERT_THROW(network->replace(subnet), BadValue);
+
+    // Create some valid subnets. they should now be added successfully.
+    subnet.reset(new Subnet6(IOAddress("2001:db8:1::"), 48, 10, 20, 30, 40,
+                             SubnetID(15)));
+    ASSERT_NO_THROW(network->add(subnet));
+    subnet.reset(new Subnet6(IOAddress("2001:db8:2::"), 64, 10, 20, 30, 40,
+                             SubnetID(1)));
+    ASSERT_NO_THROW(network->add(subnet));
+    subnet.reset(new Subnet6(IOAddress("2001:db8:3::"), 64, 10, 20, 30, 40,
+                             SubnetID(10)));
+    ASSERT_NO_THROW(network->add(subnet));
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+
+    // Create another subnet with another ID. Replace should return false.
+    subnet.reset(new Subnet6(IOAddress("2001:db8:4::1"), 64, 10, 20, 30, 40,
+                             SubnetID(2)));
+    EXPECT_FALSE(network->replace(subnet));
+
+    // Subnets did not changed.
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+    Subnet6Ptr returned_subnet = network->getAllSubnets()->at(0);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(15, returned_subnet->getID());
+    returned_subnet = network->getAllSubnets()->at(2);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(10, returned_subnet->getID());
+    // Finish by the second subnet.
+    returned_subnet = network->getAllSubnets()->at(1);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(1, returned_subnet->getID());
+
+    // Create another subnet with the same ID than the second subnet.
+    subnet.reset(new Subnet6(IOAddress("2001:db8:2::"), 64, 100, 200, 300, 400,
+                             SubnetID(1)));
+    EXPECT_TRUE(network->replace(subnet));
+
+    // Second subnet was updated.
+    EXPECT_EQ(10, returned_subnet->getT1());
+    EXPECT_EQ(20, returned_subnet->getT2());
+    EXPECT_EQ(30, returned_subnet->getPreferred());
+    EXPECT_EQ(40, returned_subnet->getValid());
+    SharedNetwork6Ptr network1;
+    returned_subnet->getSharedNetwork(network1);
+    EXPECT_FALSE(network1);
+
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+    returned_subnet = network->getAllSubnets()->at(1);
+    ASSERT_TRUE(returned_subnet);
+    ASSERT_EQ(1, returned_subnet->getID());
+    EXPECT_EQ(100, returned_subnet->getT1());
+    EXPECT_EQ(200, returned_subnet->getT2());
+    EXPECT_EQ(300, returned_subnet->getPreferred());
+    EXPECT_EQ(400, returned_subnet->getValid());
+    returned_subnet->getSharedNetwork(network1);
+    EXPECT_TRUE(network1);
+    EXPECT_TRUE(network == network1);
+
+    // Other subnets did not changed.
+    returned_subnet = network->getAllSubnets()->at(0);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(15, returned_subnet->getID());
+    returned_subnet = network->getAllSubnets()->at(2);
+    ASSERT_TRUE(returned_subnet);
+    EXPECT_EQ(10, returned_subnet->getID());
+
+    // Create another network and try to replace a subnet to it. It should fail
+    // because the subnet is already associated with the first network.
+    SharedNetwork6Ptr network2(new SharedNetwork6("dog"));
+    ASSERT_THROW(network2->replace(subnet), InvalidOperation);
+
+    // Try to change the prefix. Not recommended but should work.
+    subnet.reset(new Subnet6(IOAddress("2001:db8:10::"), 64, 100, 200, 300,
+                             400, SubnetID(1)));
+    EXPECT_TRUE(network->replace(subnet));
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+    returned_subnet = network->getAllSubnets()->at(1);
+    ASSERT_TRUE(returned_subnet);
+    ASSERT_EQ(1, returned_subnet->getID());
+    EXPECT_EQ("2001:db8:10::/64", returned_subnet->toText());
+
+    // but not if the prefix already exists for another subnet.
+    subnet.reset(new Subnet6(IOAddress("2001:db8:3::"), 64, 100, 200, 300, 400,
+                             SubnetID(1)));
+    EXPECT_FALSE(network->replace(subnet));
+    ASSERT_EQ(3, network->getAllSubnets()->size());
+    returned_subnet = network->getAllSubnets()->at(1);
+    ASSERT_TRUE(returned_subnet);
+    ASSERT_EQ(1, returned_subnet->getID());
+    EXPECT_EQ("2001:db8:10::/64", returned_subnet->toText());
+}
+
 // This test verifies that it is possible to remove a specified subnet.
 TEST(SharedNetwork6Test, delSubnet6) {
     // Create two subnets and add them to the shared network.