From: Francis Dupont Date: Sat, 7 Apr 2018 16:32:01 +0000 (+0200) Subject: [5374] Checkpoint: HA tests X-Git-Tag: trac5458a_base~14^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2de90c470587804b61924a46b21ef4439905ef71;p=thirdparty%2Fkea.git [5374] Checkpoint: HA tests --- diff --git a/src/bin/dhcp4/tests/classify_unittest.cc b/src/bin/dhcp4/tests/classify_unittest.cc index 7e9e2d8f32..227abd7fa5 100644 --- a/src/bin/dhcp4/tests/classify_unittest.cc +++ b/src/bin/dhcp4/tests/classify_unittest.cc @@ -64,6 +64,17 @@ namespace { /// option[93].hex == 0x0007, set server-hostname to deneb /// option[93].hex == 0x0006, set boot-file-name to pxelinux.0 /// option[93].hex == 0x0001, set boot-file-name to ipxe.efi +/// +/// - Configuration 4: +/// - Used for complex membership (example taken from HA) +/// - 1 subnet: 10.0.0.0/24 +/// - 4 pools: 10.0.0.10-10.0.0.49, 10.0.0.60-10.0.0.99, +/// 10.0.0.110-10.0.0.149, 10.0.0.1.60-10.0.0.199 +/// - 4 classes to compose: +/// server1 and server2 for each HA server +/// option[93].hex == 0x0009 aka telephones +/// option[93].hex == 0x0007 aka computers +/// const char* CONFIGS[] = { // Configuration 0 "{ \"interfaces-config\": {" @@ -211,7 +222,58 @@ const char* CONFIGS[] = { " \"pools\": [ { \"pool\": \"10.0.0.10-10.0.0.100\" } ]," " \"require-client-classes\": [ \"pxe2\" ]" " } ]" - "}" + "}", + + // Configuration 4 + "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"valid-lifetime\": 600," + "\"client-classes\": [" + "{" + " \"name\": \"server1\"" + "}," + "{" + " \"name\": \"server2\"" + "}," + "{" + " \"name\": \"telephones\"," + " \"test\": \"option[93].hex == 0x0009\"" + "}," + "{" + " \"name\": \"computers\"," + " \"test\": \"option[93].hex == 0x0007\"" + "}," + "{" + " \"name\": \"server1_and_telephones\"," + " \"test\": \"member('server1') and member('telephones')\"" + "}," + "{" + " \"name\": \"server1_and_computers\"," + " \"test\": \"member('server1') and member('computers')\"" + "}," + "{" + " \"name\": \"server2_and_telephones\"," + " \"test\": \"member('server2') and member('telephones')\"" + "}," + "{" + " \"name\": \"server2_and_computers\"," + " \"test\": \"member('server2') and member('computers')\"" + "} ]," + "\"subnet4\": [ { " + " \"subnet\": \"10.0.0.0/24\", " + " \"id\": 1," + " \"pools\": [ " + " { \"pool\": \"10.0.0.10-10.0.0.49\"," + " \"client-class\": \"server1_and_telephones\" }," + " { \"pool\": \"10.0.0.60-10.0.0.99\"," + " \"client-class\": \"server1_and_computers\" }," + " { \"pool\": \"10.0.0.110-10.0.0.149\"," + " \"client-class\": \"server2_and_telephones\" }," + " { \"pool\": \"10.0.0.160-10.0.0.199\"," + " \"client-class\": \"server2_and_computers\" } ]" + " } ]" + "}", }; @@ -633,6 +695,106 @@ TEST_F(ClassifyTest, fixedFieldsInformFile32) { testFixedFields(CONFIGS[3], DHCPINFORM, pxe, "0.0.0.0", "", "ipxe.efi"); } +// This test checks the complex membership from HA with server1 telephone. +TEST_F(ClassifyTest, server1Telephone) { + Dhcp4Client client(Dhcp4Client::SELECTING); + + // Configure DHCP server. + configure(CONFIGS[4], *client.getServer()); + + // Add option. + OptionPtr pxe(new OptionInt(Option::V4, 93, 0x0009)); + client.addExtraOption(pxe); + + // Add server1 + client.addClass("server1"); + + // Get an address + client.doDORA(); + + // Check response. + Pkt4Ptr resp = client.getContext().response_; + ASSERT_TRUE(resp); + + // The address is from the first pool. + EXPECT_EQ("10.0.0.10", resp->getYiaddr().toText()); +} + +// This test checks the complex membership from HA with server1 computer. +TEST_F(ClassifyTest, server1computer) { + Dhcp4Client client(Dhcp4Client::SELECTING); + + // Configure DHCP server. + configure(CONFIGS[4], *client.getServer()); + + // Add option. + OptionPtr pxe(new OptionInt(Option::V4, 93, 0x0007)); + client.addExtraOption(pxe); + + // Add server1 + client.addClass("server1"); + + // Get an address + client.doDORA(); + + // Check response. + Pkt4Ptr resp = client.getContext().response_; + ASSERT_TRUE(resp); + + // The address is from the second pool. + EXPECT_EQ("10.0.0.60", resp->getYiaddr().toText()); +} + +// This test checks the complex membership from HA with server2 telephone. +TEST_F(ClassifyTest, server2Telephone) { + Dhcp4Client client(Dhcp4Client::SELECTING); + + // Configure DHCP server. + configure(CONFIGS[4], *client.getServer()); + + // Add option. + OptionPtr pxe(new OptionInt(Option::V4, 93, 0x0009)); + client.addExtraOption(pxe); + + // Add server2 + client.addClass("server2"); + + // Get an address + client.doDORA(); + + // Check response. + Pkt4Ptr resp = client.getContext().response_; + ASSERT_TRUE(resp); + + // The address is from the third pool. + EXPECT_EQ("10.0.0.110", resp->getYiaddr().toText()); +} + +// This test checks the complex membership from HA with server2 computer. +TEST_F(ClassifyTest, server2computer) { + Dhcp4Client client(Dhcp4Client::SELECTING); + + // Configure DHCP server. + configure(CONFIGS[4], *client.getServer()); + + // Add option. + OptionPtr pxe(new OptionInt(Option::V4, 93, 0x0007)); + client.addExtraOption(pxe); + + // Add server2 + client.addClass("server2"); + + // Get an address + client.doDORA(); + + // Check response. + Pkt4Ptr resp = client.getContext().response_; + ASSERT_TRUE(resp); + + // The address is from the forth pool. + EXPECT_EQ("10.0.0.160", resp->getYiaddr().toText()); +} + // This test checks the precedence order in required evaluation. // This order is: shared-network > subnet > pools TEST_F(ClassifyTest, precedenceNone) { diff --git a/src/bin/dhcp4/tests/dhcp4_client.cc b/src/bin/dhcp4/tests/dhcp4_client.cc index c117ba4320..8475989105 100644 --- a/src/bin/dhcp4/tests/dhcp4_client.cc +++ b/src/bin/dhcp4/tests/dhcp4_client.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2018 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 @@ -238,6 +238,14 @@ Dhcp4Client::appendExtraOptions() { } } +void +Dhcp4Client::appendClasses() { + for (ClientClasses::const_iterator cclass = classes_.cbegin(); + cclass != classes_.cend(); ++cclass) { + context_.query_->addClass(*cclass); + } +} + void Dhcp4Client::doDiscover(const boost::shared_ptr& requested_addr) { context_.query_ = createMsg(DHCPDISCOVER); @@ -255,6 +263,7 @@ Dhcp4Client::doDiscover(const boost::shared_ptr& requested_addr) { context_.query_->setCiaddr(ciaddr_.get()); } appendExtraOptions(); + appendClasses(); // Send the message to the server. sendMsg(context_.query_); @@ -277,6 +286,8 @@ Dhcp4Client::doInform(const bool set_ciaddr) { appendPRL(); // Any other options to be sent by a client. appendExtraOptions(); + // Add classes. + appendClasses(); // The client sending a DHCPINFORM message has an IP address obtained // by some other means, e.g. static configuration. The lease which we // are using here is most likely set by the createLease method. @@ -396,6 +407,8 @@ Dhcp4Client::doRequest() { appendClientId(); // Any other options to be sent by a client. appendExtraOptions(); + // Add classes. + appendClasses(); // Send the message to the server. sendMsg(context_.query_); // Expect response. @@ -518,6 +531,12 @@ Dhcp4Client::sendMsg(const Pkt4Ptr& msg) { msg_copy->setRemoteAddr(msg->getLocalAddr()); msg_copy->setLocalAddr(dest_addr_); msg_copy->setIface(iface_name_); + // Copy classes + const ClientClasses& classes = msg->getClasses(); + for (ClientClasses::const_iterator cclass = classes.cbegin(); + cclass != classes.cend(); ++cclass) { + msg_copy->addClass(*cclass); + } srv_->fakeReceive(msg_copy); srv_->run(); } @@ -536,6 +555,13 @@ Dhcp4Client::addExtraOption(const OptionPtr& opt) { extra_options_.insert(std::make_pair(opt->getType(), opt)); } +void +Dhcp4Client::addClass(const ClientClass& client_class) { + if (!classes_.contains(client_class)) { + classes_.insert(client_class); + } +} + } // end of namespace isc::dhcp::test } // end of namespace isc::dhcp } // end of namespace isc diff --git a/src/bin/dhcp4/tests/dhcp4_client.h b/src/bin/dhcp4/tests/dhcp4_client.h index a30b7d821f..887ddd98b1 100644 --- a/src/bin/dhcp4/tests/dhcp4_client.h +++ b/src/bin/dhcp4/tests/dhcp4_client.h @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2018 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 @@ -369,12 +369,22 @@ public: /// @param opt additional option to be sent void addExtraOption(const OptionPtr& opt); + /// @brief Add a client class. + /// + /// @param client_class name of the class to be added. + void addClass(const ClientClass& client_class); + private: /// @brief Appends extra options, previously added with addExtraOption() /// /// @brief Copies options from extra_options_ into outgoing message void appendExtraOptions(); + /// @brief Appends extra classes, previously added with addClass() + /// + /// @brief Add client classes from classes_ to incoming message + void appendClasses(); + /// @brief Creates and adds Requested IP Address option to the client's /// query. /// @@ -491,6 +501,9 @@ private: /// @brief Extra options the client will send. OptionCollection extra_options_; + + /// @brief Extra classes to add to the query. + ClientClasses classes_; }; } // end of namespace isc::dhcp::test diff --git a/src/bin/dhcp6/tests/classify_unittests.cc b/src/bin/dhcp6/tests/classify_unittests.cc index 99611da61e..6ca129a4bb 100644 --- a/src/bin/dhcp6/tests/classify_unittests.cc +++ b/src/bin/dhcp6/tests/classify_unittests.cc @@ -46,6 +46,27 @@ namespace { /// the 'foo' value. /// - There is one subnet specified 2001:db8:1::/48 with pool of /// IPv6 addresses. +/// +/// - Configuration 1: +/// - Used for complex membership (example taken from HA) +/// - 1 subnet: 2001:db8:1::/48 +/// - 4 pools: 2001:db8:1:1::/64, 2001:db8:1:2::/64, +/// 2001:db8:1:3::/64 and 2001:db8:1:4::/64 +/// - 4 classes to compose: +/// server1 and server2 for each HA server +/// option 1234 'foo' aka telephones +/// option 1234 'bar' aka computers +/// +/// - Configuration 2: +/// - Used for complex membership (example taken from HA) and pd-pools +/// - 1 subnet: 2001:db8::/32 +/// - 4 pd-pools: 2001:db8:1::/48, 2001:db8:2::/48, +/// 2001:db8:3::/48 and 2001:db8:4::/48 +/// - 4 classes to compose: +/// server1 and server2 for each HA server +/// option 1234 'foo' aka telephones +/// option 1234 'bar' aka computers +/// const char* CONFIGS[] = { // Configuration 0 "{ \"interfaces-config\": {" @@ -104,7 +125,128 @@ const char* CONFIGS[] = { " \"client-classes\": [ \"reserved-class1\", \"reserved-class2\" ]" " } ]" " } ]," + "\"valid-lifetime\": 4000 }", + + // Configuration 1 + "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"option-def\": [ " + "{" + " \"name\": \"host-name\"," + " \"code\": 1234," + " \"type\": \"string\"" + "} ]," + "\"client-classes\": [" + "{" + " \"name\": \"server1\"" + "}," + "{" + " \"name\": \"server2\"" + "}," + "{" + " \"name\": \"telephones\"," + " \"test\": \"option[host-name].text == 'foo'\"" + "}," + "{" + " \"name\": \"computers\"," + " \"test\": \"option[host-name].text == 'bar'\"" + "}," + "{" + " \"name\": \"server1_and_telephones\"," + " \"test\": \"member('server1') and member('telephones')\"" + "}," + "{" + " \"name\": \"server1_and_computers\"," + " \"test\": \"member('server1') and member('computers')\"" + "}," + "{" + " \"name\": \"server2_and_telephones\"," + " \"test\": \"member('server2') and member('telephones')\"" + "}," + "{" + " \"name\": \"server2_and_computers\"," + " \"test\": \"member('server2') and member('computers')\"" + "}" + "]," + "\"subnet6\": [ " + "{ \"subnet\": \"2001:db8:1::/48\", " + " \"interface\": \"eth1\"," + " \"pools\": [ " + " { \"pool\": \"2001:db8:1:1::/64\"," + " \"client-class\": \"server1_and_telephones\" }," + " { \"pool\": \"2001:db8:1:2::/64\"," + " \"client-class\": \"server1_and_computers\" }," + " { \"pool\": \"2001:db8:1:3::/64\"," + " \"client-class\": \"server2_and_telephones\" }," + " { \"pool\": \"2001:db8:1:4::/64\"," + " \"client-class\": \"server2_and_computers\" } ]" + " } ]," + "\"valid-lifetime\": 4000 }", + + // Configuration 2 + "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + "\"option-def\": [ " + "{" + " \"name\": \"host-name\"," + " \"code\": 1234," + " \"type\": \"string\"" + "} ]," + "\"client-classes\": [" + "{" + " \"name\": \"server1\"" + "}," + "{" + " \"name\": \"server2\"" + "}," + "{" + " \"name\": \"telephones\"," + " \"test\": \"option[host-name].text == 'foo'\"" + "}," + "{" + " \"name\": \"computers\"," + " \"test\": \"option[host-name].text == 'bar'\"" + "}," + "{" + " \"name\": \"server1_and_telephones\"," + " \"test\": \"member('server1') and member('telephones')\"" + "}," + "{" + " \"name\": \"server1_and_computers\"," + " \"test\": \"member('server1') and member('computers')\"" + "}," + "{" + " \"name\": \"server2_and_telephones\"," + " \"test\": \"member('server2') and member('telephones')\"" + "}," + "{" + " \"name\": \"server2_and_computers\"," + " \"test\": \"member('server2') and member('computers')\"" + "}" + "]," + "\"subnet6\": [ " + "{ \"subnet\": \"2001:db8::/32\", " + " \"interface\": \"eth1\"," + " \"pools\": [ " + " { \"pool\": \"2001:db8:1::/48\"," + " \"client-class\": \"server1_and_telephones\" }," + " { \"pool\": \"2001:db8:2::/48\"," + " \"client-class\": \"server1_and_computers\" }," + " { \"pool\": \"2001:db8:3::/48\"," + " \"client-class\": \"server2_and_telephones\" }," + " { \"pool\": \"2001:db8:4::/48\"," + " \"client-class\": \"server2_and_computers\" } ]" + " } ]," "\"valid-lifetime\": 4000 }" + }; /// @brief Test fixture class for testing client classification by the @@ -1551,4 +1693,32 @@ TEST_F(ClassifyTest, precedenceNetwork) { EXPECT_EQ("2001:db8:1::3", addrs[0].toText()); } +// This test checks the complex membership from HA with server1 telephone. +TEST_F(ClassifyTest, server1Telephone) { + // Create a client. + Dhcp6Client client; + client.setInterface("eth1"); + ASSERT_NO_THROW(client.requestAddress(0xabca0)); + + // Add option. + OptionStringPtr hostname(new OptionString(Option::V6, 1234, "foo")); + client.addExtraOption(hostname); + + // Add server1 + client.addClass("server1"); + + // Load the config and perform a SARR + configure(CONFIGS[1], *client.getServer()); + ASSERT_NO_THROW(client.doSARR()); + + // Check response + Pkt6Ptr resp = client.getContext().response_; + ASSERT_TRUE(resp); + + // The address is from the first pool. + ASSERT_EQ(1, client.getLeaseNum()); + Lease6 lease_client = client.getLease(0); + EXPECT_EQ("2001:db8:1:1::", lease_client.addr_.toText()); +} + } // end of anonymous namespace diff --git a/src/bin/dhcp6/tests/dhcp6_client.cc b/src/bin/dhcp6/tests/dhcp6_client.cc index f32189d294..8ab931cd6c 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.cc +++ b/src/bin/dhcp6/tests/dhcp6_client.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2018 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 @@ -423,6 +423,12 @@ Dhcp6Client::createMsg(const uint8_t msg_type) { } } + // Add classes. + for (ClientClasses::const_iterator cclass = classes_.cbegin(); + cclass != classes_.cend(); ++cclass) { + msg->addClass(*cclass); + } + return (msg); } @@ -930,6 +936,13 @@ Dhcp6Client::sendMsg(const Pkt6Ptr& msg) { msg_copy->setLocalAddr(dest_addr_); msg_copy->setIface(iface_name_); + // Copy classes + const ClientClasses& classes = msg->getClasses(); + for (ClientClasses::const_iterator cclass = classes.cbegin(); + cclass != classes.cend(); ++cclass) { + msg_copy->addClass(*cclass); + } + srv_->fakeReceive(msg_copy); srv_->run(); } @@ -969,6 +982,18 @@ Dhcp6Client::clearExtraOptions() { extra_options_.clear(); } +void +Dhcp6Client::addClass(const ClientClass& client_class) { + if (!classes_.contains(client_class)) { + classes_.insert(client_class); + } +} + +void +Dhcp6Client::clearClasses() { + classes_.clear(); +} + void Dhcp6Client::printConfiguration() const { diff --git a/src/bin/dhcp6/tests/dhcp6_client.h b/src/bin/dhcp6/tests/dhcp6_client.h index 3402bc6c26..80ff2c37c1 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.h +++ b/src/bin/dhcp6/tests/dhcp6_client.h @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2018 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 @@ -753,6 +753,14 @@ public: /// @brief Configures the client to not send any extra options. void clearExtraOptions(); + /// @brief Add a client class. + /// + /// @param client_class name of the class to be added. + void addClass(const ClientClass& client_class); + + /// @brief Configures the client to not add client classes. + void clearClasses(); + /// @brief Debugging method the prints currently held configuration /// /// @todo: This is mostly useful when debugging tests. This method @@ -927,6 +935,9 @@ private: /// @brief Interface id. OptionPtr interface_id_; + + /// @brief Extra classes to add to the query. + ClientClasses classes_; }; } // end of namespace isc::dhcp::test