-// 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
#include <config.h>
#include <dhcp/dhcp6.h>
+#include <dhcp/docsis3_option_defs.h>
#include <dhcp/option_custom.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_status_code.h>
#include <dhcp/option_int_array.h>
+#include <dhcp/option_vendor.h>
#include <dhcp/pkt6.h>
#include <dhcpsrv/lease.h>
#include <dhcp6/tests/dhcp6_client.h>
for (typename std::vector<Lease6>::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.
use_pd_(false),
use_relay_(false),
use_oro_(false),
+ use_docsis_oro_(false),
use_client_id_(true),
use_rapid_commit_(false),
address_hint_(),
use_pd_(false),
use_relay_(false),
use_oro_(false),
+ use_docsis_oro_(false),
use_client_id_(true),
use_rapid_commit_(false),
address_hint_(),
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();
/// @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
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?
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 {
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_;
/// to true. See @ref sendORO for details.
std::vector<uint16_t> 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<uint16_t> docsis_oro_;
+
/// @brief forced (Overridden) value of the server-id option (may be NULL)
OptionPtr forced_server_id_;
});
srv.reset();
ASSERT_NO_THROW({
- // open an unpriviledged port
+ // open an unprivileged port
srv.reset(new NakedDhcpv6Srv(DHCP6_SERVER_PORT + 10000));
});
}
// 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));
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);
// 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");
#include <config.h>
#include <asiolink/io_address.h>
#include <cc/data.h>
+#include <dhcp/docsis3_option_defs.h>
+#include <dhcp/option_string.h>
+#include <dhcp/option_vendor.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp6/json_config_parser.h>
#include <dhcp6/tests/dhcp6_message_test.h>
/// - 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\": {"
" \"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 }"
};
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<OptionVendor> vendor =
+ boost::dynamic_pointer_cast<OptionVendor>(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<OptionString>(opt);
+ ASSERT_TRUE(opt);
+ EXPECT_EQ("normal_erouter_v6.cm", config_file->getValue());
+}
} // end of anonymous namespace
-// 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
#include <config.h>
#include <asiolink/io_address.h>
#include <cc/data.h>
+#include <dhcp/docsis3_option_defs.h>
+#include <dhcp/option_string.h>
+#include <dhcp/option_vendor.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp6/json_config_parser.h>
#include <dhcp6/tests/dhcp6_message_test.h>
+#include <boost/pointer_cast.hpp>
using namespace isc;
using namespace isc::asiolink;
/// - 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\": {"
" \"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.
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<Lease6> 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<Lease6> 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<OptionVendor> vendor =
+ boost::dynamic_pointer_cast<OptionVendor>(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<OptionString>(opt);
+ ASSERT_TRUE(opt);
+ EXPECT_EQ("normal_erouter_v6.cm", config_file->getValue());
+}
} // end of anonymous namespace