// This test verifies that externally configured shared-networks are
// merged correctly into staging configuration.
// @todo enable test when SrvConfig can merge shared networks.
-TEST_F(Dhcp4CBTest, DISABLED_mergeSharedNetworks) {
+TEST_F(Dhcp4CBTest, mergeSharedNetworks) {
string base_config =
"{ \n"
" \"interfaces-config\": { \n"
ASSERT_TRUE(staged_network);
// Subnet3, which is in db2 should not have been merged, since it is
- // first found, first used?
+ // backend data is first found, first used.
staged_network = networks->getByName("three");
ASSERT_FALSE(staged_network);
}
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2019 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
return (network_it != index.cend());
}
+void
+CfgSharedNetworks4::merge(const CfgSharedNetworks4& other) {
+ auto& index = networks_.get<SharedNetworkNameIndexTag>();
+
+ // Iterate over the subnets to be merged. They will replace the existing
+ // subnets with the same id. All new subnets will be inserted into the
+ // configuration into which we're merging.
+ auto other_networks = other.getAll();
+ for (auto other_network = other_networks->begin();
+ other_network != other_networks->end(); ++other_network) {
+
+ // In theory we should drop subnet assignments from "other". The
+ // idea being those that come from the CB should not have subnets_
+ // populated. We will quietly throw them away, just in case.
+ (*other_network)->delAll();
+
+ // Check if the other network exists in this config.
+ auto existing_network = index.find((*other_network)->getName());
+ if (existing_network != index.end()) {
+
+ // Somehow the same instance is in both, skip it.
+ if (*existing_network == *other_network) {
+ continue;
+ }
+
+ // Network exists, which means we're updating it.
+ // First we need to move its subnets to the new
+ // version of the network.
+ const Subnet4Collection* subnets = (*existing_network)->getAllSubnets();
+
+ Subnet4Collection copy_subnets(*subnets);
+ for (auto subnet = copy_subnets.cbegin(); subnet != copy_subnets.cend(); ++subnet) {
+ (*existing_network)->del((*subnet)->getID());
+ (*other_network)->add(*subnet);
+ }
+
+ // Now we discard the existing copy of the network.
+ index.erase(existing_network);
+ }
+
+ // Add the new/updated nework.
+ networks_.push_back(*other_network);
+ }
+
+}
} // end of namespace isc::dhcp
} // end of namespace isc
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2019 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
/// @return true if there is a network with a specified server identifier.
bool hasNetworkWithServerId(const asiolink::IOAddress& server_id) const;
-
+ /// @brief Merges specified shared network configuration into this configuration.
+ ///
+ /// This method merges networks from the @c other configuration into this
+ /// configuration. The general rule is that existing networks are replaced
+ /// by the networks from @c other.
+ ///
+ /// For each network in @c other, do the following:
+ ///
+ /// - Any associated subnets are removed. Shared networks retreived from
+ /// config backends, do not carry their associated subnets (if any) with them.
+ /// Subnet assignments are maintained by subnet merges.
+ /// - If a shared network of the same name, already exists in this
+ /// configuration:
+ /// - All of its associated subnets are movde to the "other" network
+ /// - The existing network is removed from this configuration
+ /// - The "other" network is added
+ ///
+ /// @warning The merge operation may affect the @c other configuration.
+ /// Therefore, the caller must not rely on the data held in the @c other
+ /// object after the call to @c merge. Also, the data held in @c other must
+ /// not be modified after the call to @c merge because it may affect the
+ /// merged configuration.
+ ///
+ /// @param other the shared network configuration to be merged into this
+ /// configuration.
+ void merge(const CfgSharedNetworks4& other);
};
/// @brief Pointer to the configuration of IPv4 shared networks.
}
void
-CfgSubnets4::merge(const CfgSubnets4& other) {
+CfgSubnets4::merge(CfgSharedNetworks4Ptr networks,
+ const CfgSubnets4& other) {
auto& index = subnets_.get<SubnetSubnetIdIndexTag>();
// Iterate over the subnets to be merged. They will replace the existing
// subnets with the same id. All new subnets will be inserted into the
// configuration into which we're merging.
auto other_subnets = other.getAll();
- for (auto other_subnet = other_subnets->begin();
- other_subnet != other_subnets->end();
+ for (auto other_subnet = other_subnets->begin(); other_subnet != other_subnets->end();
++other_subnet) {
// Check if there is a subnet with the same ID.
if (subnet_it != index.end()) {
// Subnet found.
- auto subnet = *subnet_it;
+ auto existing_subnet = *subnet_it;
- // Continue if the merged and existing subnets are the same instance.
- if (subnet == *other_subnet) {
+ // Continue if the existing subnet and other subnet
+ // are the same instance skip it.
+ if (existing_subnet == *other_subnet) {
continue;
}
- // If the merged subnet belongs to a shared network we need to
- // discard this shared network so as it is merged into the existing
- // shared network or left not unassigned if the existing subnet
- // is unassigned.
- SharedNetwork4Ptr other_network;
- (*other_subnet)->getSharedNetwork(other_network);
- if (other_network) {
- other_network->del((*other_subnet)->getID());
- }
-
- // Check if the subnet belongs to a shared network.
+ // We're going to replace the existing subnet with the other
+ // version. If it belongs to a shared network, we need
+ // remove it from that network.
SharedNetwork4Ptr network;
- subnet->getSharedNetwork(network);
+ existing_subnet->getSharedNetwork(network);
if (network) {
- // The subnet belongs to a shared network. The shared network
- // instance holds a pointer to the subnet so we need to remove
- // the existing subnet from the shared network it belongs to.
- network->del(subnet->getID());
-
- // The new subnet instance must be added to the existing shared
- // network.
- network->add(*other_subnet);
+ network->del(existing_subnet->getID());
}
- // The existing subnet may now be removed.
+ // Now we remove the existing subnet.
index.erase(subnet_it);
}
- }
- // Make another pass over the merged subnets to add them. Any existing
- // instances with the same IDs have been removed.
- for (auto other_subnet = other_subnets->begin();
- other_subnet != other_subnets->end();
- ++other_subnet) {
+ // Add the "other" subnet to the our collection of subnets.
+ subnets_.push_back(*other_subnet);
- // Continue if the merged and existing subnets are the same instance.
- auto subnet_it = index.find((*other_subnet)->getID());
- if ((subnet_it != index.end()) && ((*subnet_it) == (*other_subnet))) {
- continue;
+ // If it belongs to a shared network, find the network and
+ // add the subnet to it
+ std::string network_name = (*other_subnet)->getSharedNetworkName();
+ if (!network_name.empty()) {
+ SharedNetwork4Ptr network = networks->getByName(network_name);
+ if (network) {
+ network->add(*other_subnet);
+ } else {
+ // This implies the shared-network collection we were given
+ // is out of sync with the subnets we were given.
+ isc_throw(InvalidOperation, "Cannot assign subnet ID of '"
+ << (*other_subnet)->getID()
+ << " to shared network: " << network_name
+ << ", network does not exist");
+ }
}
-
- subnets_.push_back(*other_subnet);
}
}
#include <asiolink/io_address.h>
#include <cc/cfg_to_element.h>
#include <dhcp/pkt4.h>
+#include <dhcpsrv/cfg_shared_networks.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/subnet_id.h>
#include <dhcpsrv/subnet_selector.h>
/// this configuration the subnet from @c other configuration is inserted.
///
/// The complexity of the merge process stems from the associations between
- /// the subnets and shared networks. Although, the subnets in this
- /// configuration are replaced by the subnets from @c other, the existing
- /// shared networks should not be affected. The new subnets must be
- /// inserted into the exsiting shared networks. The @c CfgSharedNetworks4
- /// is responsible for merging the shared networks and this merge must
- /// be triggered before the merge of the subnets. Therefore, this method
- /// assumes that existing shared networks have been already merged.
- ///
- /// These are the rules concerning the shared network associations that
- /// this method follows:
- /// - If there is a subnet in this configuration and it is associated with
- /// a shared network, the shared network is preserved and the new subnet
- /// instance (replacing existing one) is associated with it. The old
- /// subnet instance is removed from the shared network.
- /// - If there is a subnet in this configuration and it is not associated
- /// with any shared network, the new subnet instance replaces the existing
- /// subnet instance and its association with a shared network is discarded.
- /// As a result, the configuration will contain new subnet instance but
- /// not associated with any shared network.
- /// - If there is no subnet with the given ID, the new subnet instance is
- /// inserted into the configuration and the association with a shared
- /// network (if present) will be preserved. As a result, the configuration
- /// will hold the instance of the new subnet with the shared network
- /// it originally belonged to.
+ /// the subnets and shared networks. It is assumed that subnets in @c other
+ /// are the authority on their shared network assignments. It is also
+ /// assumed that @ networks is the list of shared networks that should be
+ /// used in making assignments. The general concept is that the overarching
+ /// merge process will first merge shared networks and then pass that list of
+ /// networks into this method. Subnets from @c other are then merged into this
+ /// configuration as follows:
+ ///
+ /// For each subnet in @c other:
+ ///
+ /// - If a subnet of the same ID already exists in this configuration:
+ /// -# If it belongs to a shared network, remove it from that network
+ /// -# Remove the subnet from this configuration and discard it
+ ///
+ /// - Add the subnet from other to this configuration.
+ /// - If that subnet is associated to shared network, find that network
+ /// in @ networks and add that subnet to it.
///
/// @warning The merge operation affects the @c other configuration.
/// Therefore, the caller must not rely on the data held in the @c other
/// not be modified after the call to @c merge because it may affect the
/// merged configuration.
///
+ /// @param networks collection of shared networks that to which assignments
+ /// should be added. In other words, the list of shared networks that belong
+ /// to the same SrvConfig instance we are merging into.
/// @param other the subnet configuration to be merged into this
/// configuration.
- void merge(const CfgSubnets4& other);
+ void merge(CfgSharedNetworks4Ptr networks, const CfgSubnets4& other);
/// @brief Returns pointer to the collection of all IPv4 subnets.
///
Impl::add(subnets_, subnet);
// Associate the subnet with this network.
setSharedNetwork(subnet);
+ subnet->setSharedNetworkName(name_);
}
void
SharedNetwork4::del(const SubnetID& subnet_id) {
Subnet4Ptr subnet = Impl::del<Subnet4Ptr>(subnets_, subnet_id);
clearSharedNetwork(subnet);
+ subnet->setSharedNetworkName("");
}
void
SharedNetwork4::delAll() {
for (auto subnet = subnets_.cbegin(); subnet != subnets_.cend(); ++subnet) {
clearSharedNetwork(*subnet);
+ (*subnet)->setSharedNetworkName("");
}
subnets_.clear();
}
decline_timer_(0), echo_v4_client_id_(true), dhcp4o6_port_(0),
d2_client_config_(new D2ClientConfig()),
configured_globals_(Element::createMap()),
- cfg_consist_(new CfgConsistency()),
+ cfg_consist_(new CfgConsistency()),
server_tag_("") {
}
ConfigBase::merge(other);
try {
- /// @todo merge other parts of the configuration here.
-
const SrvConfig& other_srv_config = dynamic_cast<const SrvConfig&>(other);
- cfg_subnets4_->merge(*other_srv_config.getCfgSubnets4());
+
+ /// We merge objects in order of dependency (real or theoretical).
+ /// @todo merge globals
+ /// @todo merge option defs
+ /// @todo merge options
+
+ // Merge shared networks.
+ cfg_shared_networks4_->merge(*(other_srv_config.getCfgSharedNetworks4()));
+
+ /// Merge subnets.
+ cfg_subnets4_->merge(getCfgSharedNetworks4(), *(other_srv_config.getCfgSubnets4()));
/// @todo merge other parts of the configuration here.
namespace {
+void checkMergedNetwork(const CfgSharedNetworks4& networks, const std::string& name,
+ const Triplet<uint32_t>& exp_valid,
+ const std::vector<SubnetID>& exp_subnets) {
+ auto network = networks.getByName(name);
+ ASSERT_TRUE(network) << "expected network: " << name << " not found";
+ ASSERT_EQ(exp_valid, network->getValid()) << " network valid lifetime wrong";
+ const Subnet4Collection* subnets = network->getAllSubnets();
+ ASSERT_EQ(exp_subnets.size(), subnets->size()) << " wrong number of subnets";
+ for (auto exp_id : exp_subnets) {
+ ASSERT_TRUE(network->getSubnet(exp_id))
+ << " did not find expected subnet: " << exp_id;
+ }
+}
+
// This test verifies that shared networks can be added to the configruation
// and retrieved by name.
TEST(CfgSharedNetworks4Test, getByName) {
test::runToElementTest<CfgSharedNetworks4>(expected, cfg);
}
+// This test verifies that shared-network configurations are properly merged.
+TEST(CfgSharedNetworks4Test, mergeNetworks) {
+ Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.1.0"),
+ 26, 1, 2, 100, SubnetID(1)));
+ Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.0"),
+ 26, 1, 2, 100, SubnetID(2)));
+ Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.3.0"),
+ 26, 1, 2, 100, SubnetID(3)));
+ Subnet4Ptr subnet4(new Subnet4(IOAddress("192.0.4.0"),
+ 26, 1, 2, 100, SubnetID(4)));
+
+ // Create network1 and add two subnets to it
+ SharedNetwork4Ptr network1(new SharedNetwork4("network1"));
+ network1->setValid(Triplet<uint32_t>(100));
+ ASSERT_NO_THROW(network1->add(subnet1));
+ ASSERT_NO_THROW(network1->add(subnet2));
+
+ // Create network2 with no subnets.
+ SharedNetwork4Ptr network2(new SharedNetwork4("network2"));
+ network2->setValid(Triplet<uint32_t>(200));
+
+ // Create network3 with one subnets.
+ SharedNetwork4Ptr network3(new SharedNetwork4("network3"));
+ network3->setValid(Triplet<uint32_t>(300));
+ ASSERT_NO_THROW(network3->add(subnet3));
+
+ // Create our "existing" configured networks.
+ // Add all three networks to the existing config.
+ CfgSharedNetworks4 cfg_to;
+ ASSERT_NO_THROW(cfg_to.add(network1));
+ ASSERT_NO_THROW(cfg_to.add(network2));
+ ASSERT_NO_THROW(cfg_to.add(network3));
+
+ // Merge in an "empty" config. Should have the original config, still intact.
+ CfgSharedNetworks4 cfg_from;
+ ASSERT_NO_THROW(cfg_to.merge(cfg_from));
+
+ ASSERT_EQ(3, cfg_to.getAll()->size());
+ ASSERT_NO_FATAL_FAILURE(checkMergedNetwork(cfg_to, "network1", Triplet<uint32_t>(100),
+ std::vector<SubnetID>{SubnetID(1), SubnetID(2)}));
+
+ ASSERT_NO_FATAL_FAILURE(checkMergedNetwork(cfg_to, "network2", Triplet<uint32_t>(200),
+ std::vector<SubnetID>()));
+
+ ASSERT_NO_FATAL_FAILURE(checkMergedNetwork(cfg_to, "network3", Triplet<uint32_t>(300),
+ std::vector<SubnetID>{SubnetID(3)}));
+
+ // Create network1b, this is an "update" of network1
+ // We'll double the valid time and add subnet4 to it
+ SharedNetwork4Ptr network1b(new SharedNetwork4("network1"));
+ network1b->setValid(Triplet<uint32_t>(200));
+ ASSERT_NO_THROW(network1b->add(subnet4));
+
+ // Network2 we will not touch.
+
+ // Create network3b, this is an "update" of network3.
+ // We'll double it's valid time, but leave off the subnet.
+ SharedNetwork4Ptr network3b(new SharedNetwork4("network3"));
+ network3b->setValid(Triplet<uint32_t>(600));
+
+ // Create our "existing" configured networks.
+ ASSERT_NO_THROW(cfg_from.add(network1b));
+ ASSERT_NO_THROW(cfg_from.add(network3b));
+
+ ASSERT_NO_THROW(cfg_to.merge(cfg_from));
+
+ // Should still have 3 networks.
+
+ // Network1 should have doubled its valid life time but still only have
+ // the orignal two subnets. Merge should discard assocations on CB
+ // subnets and preserve the associations from existing config.
+ ASSERT_EQ(3, cfg_to.getAll()->size());
+ ASSERT_NO_FATAL_FAILURE(checkMergedNetwork(cfg_to, "network1", Triplet<uint32_t>(200),
+ std::vector<SubnetID>{SubnetID(1), SubnetID(2)}));
+
+ // No changes to network2.
+ ASSERT_NO_FATAL_FAILURE(checkMergedNetwork(cfg_to, "network2", Triplet<uint32_t>(200),
+ std::vector<SubnetID>()));
+
+ // Network1 should have doubled its valid life time and still subnet3.
+ ASSERT_NO_FATAL_FAILURE(checkMergedNetwork(cfg_to, "network3", Triplet<uint32_t>(600),
+ std::vector<SubnetID>{SubnetID(3)}));
+}
+
} // end of anonymous namespace
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcpsrv/parsers/dhcp_parsers.h>
#include <dhcpsrv/shared_network.h>
+#include <dhcpsrv/cfg_shared_networks.h>
#include <dhcpsrv/cfg_subnets4.h>
#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
namespace {
+void checkMergedSubnet(CfgSubnets4& cfg_subnets,
+ const SubnetID exp_subnet_id,
+ const std::string& prefix,
+ int exp_valid,
+ SharedNetwork4Ptr exp_network) {
+
+ // The subnet1 should be replaced by subnet4 but the shared network
+ // should not be affected.
+ auto subnet = cfg_subnets.getByPrefix(prefix);
+ ASSERT_TRUE(subnet) << "subnet: " << prefix << " not found";
+ ASSERT_EQ(exp_subnet_id, subnet->getID()) << "subnet ID is wrong";
+ ASSERT_EQ(exp_valid, subnet->getValid()) << "subnet valid time is wrong";
+
+ SharedNetwork4Ptr shared_network;
+ subnet->getSharedNetwork(shared_network);
+ if (exp_network) {
+ ASSERT_TRUE(shared_network)
+ << " expected network: " << exp_network->getName() << " not found";
+ ASSERT_TRUE(shared_network == exp_network) << " networks do no match";
+ } else {
+ ASSERT_FALSE(shared_network) << " unexpected network assignment: "
+ << shared_network->getName();
+ }
+}
+
// This test verifies that specific subnet can be retrieved by specifying
// subnet identifier or subnet prefix.
TEST(CfgSubnets4Test, getSpecificSubnet) {
EXPECT_FALSE(cfg.getByPrefix("192.0.3.0/26"));
}
-// This test verifies that the subnets configuration is properly merged.
+// This test verifies that subnets configuration is properly merged.
TEST(CfgSubnets4Test, mergeSubnets) {
+ Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.1.0"),
+ 26, 1, 2, 100, SubnetID(1)));
+ Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.0"),
+ 26, 1, 2, 100, SubnetID(2)));
+ Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.3.0"),
+ 26, 1, 2, 100, SubnetID(3)));
+ Subnet4Ptr subnet4(new Subnet4(IOAddress("192.0.4.0"),
+ 26, 1, 2, 100, SubnetID(4)));
+
+
+ // Create the "existing" list of shared networks
+ CfgSharedNetworks4Ptr networks(new CfgSharedNetworks4());
+ SharedNetwork4Ptr shared_network1(new SharedNetwork4("shared-network1"));
+ networks->add(shared_network1);
+ SharedNetwork4Ptr shared_network2(new SharedNetwork4("shared-network2"));
+ networks->add(shared_network2);
+
+ // Empty network pointer.
+ SharedNetwork4Ptr no_network;
+
+ // Add Subnets1,2, and 4 to shared networks.
+ ASSERT_NO_THROW(shared_network1->add(subnet1));
+ ASSERT_NO_THROW(shared_network2->add(subnet2));
+ ASSERT_NO_THROW(shared_network2->add(subnet4));
+
+ // Create our "existing" configured subnets.
CfgSubnets4 cfg_to;
- Subnet4Ptr subnet1(new Subnet4(IOAddress("192.0.2.0"),
- 26, 1, 2, 3, SubnetID(5)));
- Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.3.0"),
- 26, 1, 2, 3, SubnetID(8)));
- Subnet4Ptr subnet3(new Subnet4(IOAddress("192.0.4.0"),
- 26, 1, 2, 3, SubnetID(10)));
ASSERT_NO_THROW(cfg_to.add(subnet1));
ASSERT_NO_THROW(cfg_to.add(subnet2));
ASSERT_NO_THROW(cfg_to.add(subnet3));
+ ASSERT_NO_THROW(cfg_to.add(subnet4));
- SharedNetwork4Ptr shared_network1(new SharedNetwork4("shared-network1"));
- ASSERT_NO_THROW(shared_network1->add(subnet1));
-
- SharedNetwork4Ptr shared_network2(new SharedNetwork4("shared-network2"));
- ASSERT_NO_THROW(shared_network2->add(subnet2));
+ // Merge in an "empty" config. Should have the original config,
+ // still intact.
CfgSubnets4 cfg_from;
+ ASSERT_NO_THROW(cfg_to.merge(networks, cfg_from));
- ASSERT_NO_THROW(cfg_to.merge(cfg_from));
- ASSERT_EQ(3, cfg_to.getAll()->size());
-
- SharedNetwork4Ptr returned_network;
-
- // The subnet1 should not be modified and should still belong
- // to the same shared network.
- auto returned_subnet1 = cfg_to.getByPrefix("192.0.2.0/26");
- ASSERT_TRUE(returned_subnet1);
- returned_subnet1->getSharedNetwork(returned_network);
- EXPECT_TRUE(shared_network1 == returned_network);
+ // We should have all four subnets, with no changes.
+ ASSERT_EQ(4, cfg_to.getAll()->size());
- // The subnet2 should not be modified and should still belong
- // to the same shared network.
- auto returned_subnet2 = cfg_to.getByPrefix("192.0.3.0/26");
- ASSERT_TRUE(returned_subnet2);
- returned_subnet2->getSharedNetwork(returned_network);
- EXPECT_TRUE(shared_network2 == returned_network);
- // The subnet3 should not be modified.
- auto returned_subnet3 = cfg_to.getByPrefix("192.0.4.0/26");
- ASSERT_TRUE(returned_subnet3);
- returned_subnet3->getSharedNetwork(returned_network);
- EXPECT_FALSE(returned_network);
+ // Should be no changes to the configuration.
+ ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, SubnetID(1),
+ "192.0.1.0/26", 100, shared_network1));
+ ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, SubnetID(2),
+ "192.0.2.0/26", 100, shared_network2));
+ ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, SubnetID(3),
+ "192.0.3.0/26", 100, no_network));
+ ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, SubnetID(4),
+ "192.0.4.0/26", 100, shared_network2));
// Fill cfg_from configuration with subnets.
- Subnet4Ptr subnet4(new Subnet4(IOAddress("192.0.2.0"),
- 26, 2, 3, 4, SubnetID(5)));
- Subnet4Ptr subnet5(new Subnet4(IOAddress("192.0.6.0"),
- 26, 1, 2, 3, SubnetID(32)));
- Subnet4Ptr subnet6(new Subnet4(IOAddress("192.0.4.0"),
- 26, 3, 4, 5, SubnetID(10)));
- ASSERT_NO_THROW(cfg_from.add(subnet4));
+ // subnet 1b updates subnet 1 but leaves it in network 1
+ Subnet4Ptr subnet1b(new Subnet4(IOAddress("192.0.1.0"),
+ 26, 2, 3, 400, SubnetID(1)));
+ subnet1b->setSharedNetworkName("shared-network1");
+
+ // subnet 3b updates subnet 3 and removes it from network 2
+ Subnet4Ptr subnet3b(new Subnet4(IOAddress("192.0.3.0"),
+ 26, 3, 4, 500, SubnetID(3)));
+
+ // subnet 4b updates subnet 4 and moves it from network2 to network 1
+ Subnet4Ptr subnet4b(new Subnet4(IOAddress("192.0.4.0"),
+ 26, 3, 4, 500, SubnetID(4)));
+ subnet4b->setSharedNetworkName("shared-network1");
+
+ // subnet 5 is new and belongs to network 2
+ Subnet4Ptr subnet5(new Subnet4(IOAddress("192.0.5.0"),
+ 26, 1, 2, 300, SubnetID(5)));
+ subnet5->setSharedNetworkName("shared-network2");
+
+ // Add subnets to the merge from config.
+ ASSERT_NO_THROW(cfg_from.add(subnet1b));
+ ASSERT_NO_THROW(cfg_from.add(subnet3b));
+ ASSERT_NO_THROW(cfg_from.add(subnet4b));
ASSERT_NO_THROW(cfg_from.add(subnet5));
- ASSERT_NO_THROW(cfg_from.add(subnet6));
- // First two subnets belong to shared networks.
- SharedNetwork4Ptr shared_network3(new SharedNetwork4("shared-network3"));
- ASSERT_NO_THROW(shared_network3->add(subnet4));
+ // Merge again.
+ ASSERT_NO_THROW(cfg_to.merge(networks, cfg_from));
+ ASSERT_EQ(5, cfg_to.getAll()->size());
- SharedNetwork4Ptr shared_network4(new SharedNetwork4("shared-network4"));
- ASSERT_NO_THROW(shared_network4->add(subnet5));
+ // The subnet1 should be replaced by subnet1b.
+ ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, SubnetID(1),
+ "192.0.1.0/26", 400, shared_network1));
- SharedNetwork4Ptr shared_network5(new SharedNetwork4("shared-network5"));
- ASSERT_NO_THROW(shared_network5->add(subnet6));
+ // The subnet2 should not be affected because it was not present.
+ ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, SubnetID(2),
+ "192.0.2.0/26", 100, shared_network2));
- // Merge again. The subnet4 and subnet6 should replace the subnet1 and
- // subnet3.
- ASSERT_NO_THROW(cfg_to.merge(cfg_from));
- ASSERT_EQ(4, cfg_to.getAll()->size());
+ // subnet3 should be replaced by subnet3b and no longer assigned to a network.
+ ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, SubnetID(3),
+ "192.0.3.0/26", 500, no_network));
- returned_subnet1 = cfg_to.getByPrefix("192.0.2.0/26");
- ASSERT_TRUE(returned_subnet1);
- EXPECT_EQ(4, returned_subnet1->getValid());
- // The subnet1 should be replaced by subnet4 but the shared network
- // should not be affected.
- returned_subnet1->getSharedNetwork(returned_network);
- EXPECT_TRUE(shared_network1 == returned_network);
-
- // The subnet2 should not be affected because it was not present
- // in the cfg_from.
- returned_subnet2 = cfg_to.getByPrefix("192.0.3.0/26");
- ASSERT_TRUE(returned_subnet2);
- EXPECT_EQ(3, returned_subnet2->getValid());
- returned_subnet2->getSharedNetwork(returned_network);
- EXPECT_TRUE(shared_network2 == returned_network);
-
- returned_subnet3 = cfg_to.getByPrefix("192.0.4.0/26");
- ASSERT_TRUE(returned_subnet3);
- EXPECT_EQ(5, returned_subnet3->getValid());
- // subnet3 should be replaced by subnet6 but the shared network
- // should not be assigned (regardless if the subnet6 belongs to
- // a shared network or not).
- returned_subnet3->getSharedNetwork(returned_network);
- EXPECT_FALSE(returned_network);
-
- // subnet5 should be merged to the configuration.
- auto returned_subnet5 = cfg_to.getByPrefix("192.0.6.0/26");
- ASSERT_TRUE(returned_subnet5);
- EXPECT_EQ(3, returned_subnet5->getValid());
- // subnet5 shared network should be preserved.
- returned_subnet5->getSharedNetwork(returned_network);
- EXPECT_TRUE(shared_network4 == returned_network);
+ // subnet4 should be replaced by subnet4b and moved to network1.
+ ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, SubnetID(4),
+ "192.0.4.0/26", 500, shared_network1));
+
+ // subnet5 should have been added to configuration.
+ ASSERT_NO_FATAL_FAILURE(checkMergedSubnet(cfg_to, SubnetID(5),
+ "192.0.5.0/26", 300, shared_network2));
}
// This test verifies that it is possible to retrieve a subnet using an