From: Francis Dupont Date: Fri, 1 Jul 2016 13:42:40 +0000 (+0200) Subject: [4523] Added DOCSIS vendor ORO unit tests for renew and rebind X-Git-Tag: trac4551_base~26^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cfe22c8dd7e14649b8878c3e83ec4ef4ccc1c46d;p=thirdparty%2Fkea.git [4523] Added DOCSIS vendor ORO unit tests for renew and rebind --- diff --git a/src/bin/dhcp6/tests/dhcp6_client.cc b/src/bin/dhcp6/tests/dhcp6_client.cc index 3842ba7ecd..bbe109e5a5 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.cc +++ b/src/bin/dhcp6/tests/dhcp6_client.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2014-2016 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 @@ -6,11 +6,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -53,7 +55,7 @@ struct getLeasesByPropertyFun { for (typename std::vector::const_iterator lease = config.leases_.begin(); lease != config.leases_.end(); ++lease) { - // Check if fulfils the condition. + // Check if fulfills the condition. if ((equals && ((*lease).*MemberPointer) == property) || (!equals && ((*lease).*MemberPointer) != property)) { // Found the matching lease. @@ -81,6 +83,7 @@ Dhcp6Client::Dhcp6Client() : use_pd_(false), use_relay_(false), use_oro_(false), + use_docsis_oro_(false), use_client_id_(true), use_rapid_commit_(false), address_hint_(), @@ -103,6 +106,7 @@ Dhcp6Client::Dhcp6Client(boost::shared_ptr& srv) : use_pd_(false), use_relay_(false), use_oro_(false), + use_docsis_oro_(false), use_client_id_(true), use_rapid_commit_(false), address_hint_(), @@ -369,6 +373,15 @@ Dhcp6Client::createMsg(const uint8_t msg_type) { msg->addOption(oro); }; + if (use_docsis_oro_) { + OptionUint16ArrayPtr vendor_oro(new OptionUint16Array(Option::V6, + DOCSIS3_V6_ORO)); + vendor_oro->setValues(docsis_oro_); + OptionPtr vendor(new OptionVendor(Option::V6, 4491)); + vendor->addOption(vendor_oro); + msg->addOption(vendor); + } + // If there are any custom options specified, add them all to the message. if (!extra_options_.empty()) { for (OptionCollection::iterator opt = extra_options_.begin(); diff --git a/src/bin/dhcp6/tests/dhcp6_client.h b/src/bin/dhcp6/tests/dhcp6_client.h index 3bf97d8389..916a4a8255 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.h +++ b/src/bin/dhcp6/tests/dhcp6_client.h @@ -24,7 +24,7 @@ namespace test { /// @brief DHCPv6 client used for unit testing. /// /// This class implements a DHCPv6 "client" which interoperates with the -/// @c NakedDhcpv6Srv class. It calls @c NakedDhcpv6Srv::fakeRecive to +/// @c NakedDhcpv6Srv class. It calls @c NakedDhcpv6Srv::fakeReceive to /// deliver client messages to the server for processing. The server places /// the response in the @c NakedDhcpv6Srv::fake_sent_ container. The client /// pops messages from this container which simulates reception of the @@ -499,7 +499,7 @@ public: use_client_id_ = send; } - /// @brief Controls whether the client should send an addres in IA_NA + /// @brief Controls whether the client should send an address in IA_NA /// /// @todo: For now, this flag is only used in Decline /// @param send should the address be included? @@ -566,6 +566,25 @@ public: oro_.push_back(option_code); } + /// @brief Controls whether the client will send DOCSIS vendor ORO + /// + /// The actual content of the ORO is specified in docsis_oro_. + /// It is useful to split the actual content and the ORO sending + /// decision, so we could test cases of sending empty ORO. + /// @param send controls whether ORO will be sent or not. + void useDocsisORO(bool send) { + use_docsis_oro_ = send; + } + + /// @brief Instructs client to request specified option in DOCSIS + /// vendor ORO + /// + /// @param option_code client will request this option code + void requestDocsisOption(uint16_t option_code) { + use_docsis_oro_ = true; + docsis_oro_.push_back(option_code); + } + /// @brief returns client-id /// @return client-id DuidPtr getDuid() const { @@ -738,6 +757,7 @@ private: bool use_relay_; ///< Enable relaying messages to the server. bool use_oro_; ///< Conth + bool use_docsis_oro_; bool use_client_id_; bool use_rapid_commit_; @@ -753,6 +773,12 @@ private: /// to true. See @ref sendORO for details. std::vector oro_; + /// @brief List of DOCSIS vendor options to be requested + /// + /// Content of this vector will be sent as DOCSIS vendor ORO if + /// use_docsis_oro_ is set to true. See @ref sendDocsisORO for details. + std::vector docsis_oro_; + /// @brief forced (Overridden) value of the server-id option (may be NULL) OptionPtr forced_server_id_; diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index cf81f9569e..2406258880 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -240,7 +240,7 @@ TEST_F(Dhcpv6SrvTest, basic) { }); srv.reset(); ASSERT_NO_THROW({ - // open an unpriviledged port + // open an unprivileged port srv.reset(new NakedDhcpv6Srv(DHCP6_SERVER_PORT + 10000)); }); } @@ -1631,7 +1631,7 @@ TEST_F(Dhcpv6SrvTest, vendorOptionsORO) { // check if we get response at all ASSERT_TRUE(adv); - // We did not include any vendor opts in SOLCIT, so there should be none + // We did not include any vendor opts in SOLICIT, so there should be none // in ADVERTISE. ASSERT_FALSE(adv->getOption(D6O_VENDOR_OPTS)); @@ -2449,8 +2449,8 @@ TEST_F(Dhcpv6SrvTest, rsoo2relays) { opt = createRSOO(rsoo2, 2); // use 0x2 as payload relay2.options_.insert(make_pair(opt->getType(), opt)); - // The relays ecapsulate packet in this order: relay1, relay2, but the server - // decapsulates the packet in reverse order. + // The relays encapsulate packet in this order: relay1, relay2, + // but the server decapsulates the packet in reverse order. client.relay_info_.push_back(relay2); client.relay_info_.push_back(relay1); @@ -2639,7 +2639,7 @@ TEST_F(Dhcpv6SrvTest, receiveParseFailedStat) { // fakeReceive() srv.run(); - // All expected statstics must be present. + // All expected statistics must be present. pkt6_rcvd = mgr.getObservation("pkt6-received"); parse_fail = mgr.getObservation("pkt6-parse-failed"); recv_drop = mgr.getObservation("pkt6-receive-drop"); diff --git a/src/bin/dhcp6/tests/rebind_unittest.cc b/src/bin/dhcp6/tests/rebind_unittest.cc index ff61204a31..a7d68ac6bf 100644 --- a/src/bin/dhcp6/tests/rebind_unittest.cc +++ b/src/bin/dhcp6/tests/rebind_unittest.cc @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -60,6 +63,12 @@ namespace { /// - address pool: 2001:db8:1::/64 /// - prefix pool: 3000::/72 /// +/// - Configuration 7: +/// - only addresses (no prefixes) +/// - 2 subnets with 2001:db8:1::/64 and 2001:db8:2::/64 +/// - 1 subnet for eth0 and 1 subnet for eth1 +/// - DOCSIS vendor config file sub-option +/// const char* REBIND_CONFIGS[] = { // Configuration 0 "{ \"interfaces-config\": {" @@ -221,6 +230,38 @@ const char* REBIND_CONFIGS[] = { " \"interface-id\": \"\"," " \"interface\": \"eth0\"" " } ]," + "\"valid-lifetime\": 4000 }", + +// Configuration 0 + "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + " \"option-def\": [ {" + " \"name\": \"config-file\"," + " \"code\": 33," + " \"type\": \"string\"," + " \"space\": \"vendor-4491\"" + " } ]," + " \"option-data\": [ {" + " \"name\": \"config-file\"," + " \"space\": \"vendor-4491\"," + " \"data\": \"normal_erouter_v6.cm\"" + " }]," + "\"subnet6\": [ { " + " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," + " \"subnet\": \"2001:db8:1::/48\", " + " \"interface-id\": \"\"," + " \"interface\": \"eth0\"" + " }," + " {" + " \"pools\": [ { \"pool\": \"2001:db8:2::/64\" } ]," + " \"subnet\": \"2001:db8:2::/48\", " + " \"interface-id\": \"\"," + " \"interface\": \"eth1\"" + " } ]," "\"valid-lifetime\": 4000 }" }; @@ -892,5 +933,78 @@ TEST_F(RebindTest, requestAddressInRebind) { EXPECT_EQ(STATUS_Success, client.getStatusCode(1234)); } +// This test verifies that the client can request the DOCSIS sub-options. +TEST_F(RebindTest, docsisORO) { + Dhcp6Client client; + // Configure client to request IA_NA. + client.useNA(); + // Configure the DOCSIS vendor ORO for 32, 33, 34, 37 and 38. + client.requestDocsisOption(DOCSIS3_V6_TFTP_SERVERS); + client.requestDocsisOption(DOCSIS3_V6_CONFIG_FILE); + client.requestDocsisOption(DOCSIS3_V6_SYSLOG_SERVERS); + client.requestDocsisOption(DOCSIS3_V6_TIME_SERVERS); + client.requestDocsisOption(DOCSIS3_V6_TIME_OFFSET); + // Don't add it for now. + client.useDocsisORO(false); + // Make 4-way exchange to get the lease. + ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[7], 2, client)); + // Keep the client's lease for future reference. + Lease6 lease_client = client.getLease(0); + + // Send Rebind message to the server. + ASSERT_NO_THROW(client.doRebind()); + // The client should still have one lease which belong to one of the + // subnets. + ASSERT_EQ(1, client.getLeaseNum()); + Lease6 lease_client2 = client.getLease(0); + ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()-> + selectSubnet(lease_client2.addr_, ClientClasses())); + // The client's lease should have been extended. The client will + // update the cltt to current time when the lease gets extended. + ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000); + // Make sure, that the client's lease matches the lease held by the + // server. + Lease6Ptr lease_server2 = checkLease(lease_client2); + EXPECT_TRUE(lease_server2); + // No vendor option was included in the renew so there should be none + // in the received configuration. + OptionPtr opt = client.config_.findOption(D6O_VENDOR_OPTS); + ASSERT_FALSE(opt); + + // Add a DOCSIS ORO. + client.useDocsisORO(true); + // Send Rebind message to the server. + ASSERT_NO_THROW(client.doRebind()); + // The client should still have one lease which belong to one of the + // subnets. + ASSERT_EQ(1, client.getLeaseNum()); + lease_client2 = client.getLease(0); + ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()-> + selectSubnet(lease_client2.addr_, ClientClasses())); + // The client's lease should have been extended. The client will + // update the cltt to current time when the lease gets extended. + ASSERT_GE(lease_client2.cltt_ - lease_client.cltt_, 1000); + // Make sure, that the client's lease matches the lease held by the + // server. + lease_server2 = checkLease(lease_client2); + EXPECT_TRUE(lease_server2); + + // Verify whether there is a vendor option. + opt = client.config_.findOption(D6O_VENDOR_OPTS); + ASSERT_TRUE(opt); + // The vendor option must be a OptionVentor object. + boost::shared_ptr vendor = + boost::dynamic_pointer_cast(opt); + ASSERT_TRUE(vendor); + // The vendor-id should be DOCSIS. + EXPECT_EQ(VENDOR_ID_CABLE_LABS, vendor->getVendorId()); + // There must be a config file sub-option. + opt = vendor->getOption(DOCSIS3_V6_CONFIG_FILE); + // With the expected content. + OptionStringPtr config_file = + boost::dynamic_pointer_cast(opt); + ASSERT_TRUE(opt); + EXPECT_EQ("normal_erouter_v6.cm", config_file->getValue()); +} } // end of anonymous namespace diff --git a/src/bin/dhcp6/tests/renew_unittest.cc b/src/bin/dhcp6/tests/renew_unittest.cc index da42bfe283..c4fbfe050b 100644 --- a/src/bin/dhcp6/tests/renew_unittest.cc +++ b/src/bin/dhcp6/tests/renew_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2015-2016 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 @@ -7,9 +7,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include using namespace isc; using namespace isc::asiolink; @@ -35,6 +39,11 @@ namespace { /// - address pool: 2001:db8:1::/64 /// - prefix pool: 3000::/72 /// +/// - Configuration 3: +/// - only addresses (no prefixes) +/// - 1 subnet with 2001:db8:1::/64 pool +/// - DOCSIS vendor config file sub-option +/// const char* RENEW_CONFIGS[] = { // Configuration 0 "{ \"interfaces-config\": {" @@ -88,7 +97,34 @@ const char* RENEW_CONFIGS[] = { " \"interface-id\": \"\"," " \"interface\": \"eth0\"" " } ]," + "\"valid-lifetime\": 4000 }", + +// Configuration 3 + "{ \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + "}," + "\"preferred-lifetime\": 3000," + "\"rebind-timer\": 2000, " + "\"renew-timer\": 1000, " + " \"option-def\": [ {" + " \"name\": \"config-file\"," + " \"code\": 33," + " \"type\": \"string\"," + " \"space\": \"vendor-4491\"" + " } ]," + " \"option-data\": [ {" + " \"name\": \"config-file\"," + " \"space\": \"vendor-4491\"," + " \"data\": \"normal_erouter_v6.cm\"" + " }]," + "\"subnet6\": [ { " + " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ]," + " \"subnet\": \"2001:db8:1::/48\", " + " \"interface-id\": \"\"," + " \"interface\": \"eth0\"" + " } ]," "\"valid-lifetime\": 4000 }" + }; /// @brief Test fixture class for testing Renew. @@ -370,5 +406,79 @@ TEST_F(RenewTest, requestAddressInRenewHint) { EXPECT_EQ(STATUS_Success, client.getStatusCode(na_iaid_)); } +// This test verifies that the client can request the DOCSIS sub-options. +TEST_F(RenewTest, requestDocsisORORenew) { + Dhcp6Client client; + + // Configure client to request IA_NA. + client.useNA(na_iaid_); + + // Configure the DOCSIS vendor ORO for 32, 33, 34, 37 and 38. + client.requestDocsisOption(DOCSIS3_V6_TFTP_SERVERS); + client.requestDocsisOption(DOCSIS3_V6_CONFIG_FILE); + client.requestDocsisOption(DOCSIS3_V6_SYSLOG_SERVERS); + client.requestDocsisOption(DOCSIS3_V6_TIME_SERVERS); + client.requestDocsisOption(DOCSIS3_V6_TIME_OFFSET); + // Don't add it for now. + client.useDocsisORO(false); + + // Configure the server with NA pools and DOCSIS config file. + ASSERT_NO_THROW(configure(RENEW_CONFIGS[3], *client.getServer())); + + // Perform 4-way exchange. + ASSERT_NO_THROW(client.doSARR()); + + // Simulate aging of leases. + client.fastFwdTime(1000); + + // Make sure that the client has acquired NA lease. + std::vector leases_client_na = client.getLeasesByType(Lease::TYPE_NA); + ASSERT_EQ(1, leases_client_na.size()); + EXPECT_EQ(STATUS_Success, client.getStatusCode(na_iaid_)); + + // Send Renew message to the server. + ASSERT_NO_THROW(client.doRenew()); + + std::vector leases_client_na_renewed = + client.getLeasesByType(Lease::TYPE_NA); + ASSERT_EQ(1, leases_client_na_renewed.size()); + EXPECT_EQ(STATUS_Success, client.getStatusCode(na_iaid_)); + + // No vendor option was included in the renew so there should be none + // in the received configuration. + OptionPtr opt = client.config_.findOption(D6O_VENDOR_OPTS); + ASSERT_FALSE(opt); + + // Add a DOCSIS ORO. + client.useDocsisORO(true); + + // Send Renew message to the server. + ASSERT_NO_THROW(client.doRenew()); + + leases_client_na_renewed = client.getLeasesByType(Lease::TYPE_NA); + ASSERT_EQ(1, leases_client_na_renewed.size()); + EXPECT_EQ(STATUS_Success, client.getStatusCode(na_iaid_)); + + // Verify whether there is a vendor option. + opt = client.config_.findOption(D6O_VENDOR_OPTS); + ASSERT_TRUE(opt); + + // The vendor option must be a OptionVentor object. + boost::shared_ptr vendor = + boost::dynamic_pointer_cast(opt); + ASSERT_TRUE(vendor); + + // The vendor-id should be DOCSIS. + EXPECT_EQ(VENDOR_ID_CABLE_LABS, vendor->getVendorId()); + + // There must be a config file sub-option. + opt = vendor->getOption(DOCSIS3_V6_CONFIG_FILE); + + // With the expected content. + OptionStringPtr config_file = + boost::dynamic_pointer_cast(opt); + ASSERT_TRUE(opt); + EXPECT_EQ("normal_erouter_v6.cm", config_file->getValue()); +} } // end of anonymous namespace