</para>
</section>
+ <section id="dhcp6-rapid-commit">
+ <title>Rapid Commit</title>
+ <para>The Rapid Commit option, described in
+ <ulink url="http://tools.ietf.org/html/rfc3315">RFC 3315</ulink>, is supported
+ by the Kea DHCPv6 server. However, support is disabled by default for
+ all subnets. It can be enabled for a particular subnet using the
+ <command>rapid-commit</command> parameter as shown below:
+<screen>
+"Dhcp6": {
+ "subnet6": [
+ {
+ "subnet": "2001:db8:beef::/48",
+ <userinput>"rapid-commit": true</userinput>,
+ "pools": [
+ {
+ "pool": "2001:db8:beef::1-2001:db8:beef::10"
+ }
+ ],
+ }
+ ],
+ ...
+}
+</screen>
+ </para>
+ <para>
+ This setting only affects the subnet for which the
+ <command>rapid-commit</command> is set to <command>true</command>.
+ For clients connected to other subnets, the server will ignore the
+ Rapid Commit option sent by the client and will follow the 4-way
+ exchange procedure, i.e. respond with the Advertise for the Solicit
+ containing Rapid Commit option.
+ </para>
+ </section>
+
<section id="dhcp6-relays">
<title>DHCPv6 Relays</title>
<para>
"item_default": ""
},
+ { "item_name": "rapid-commit",
+ "item_type": "boolean",
+ "item_optional": false,
+ "item_default": false
+ },
+
{ "item_name": "renew-timer",
"item_type": "integer",
"item_optional": false,
% DHCP6_QUERY_DATA received packet length %1, data length %2, data is %3
A debug message listing the data received from the client or relay.
+% DHCP6_RAPID_COMMIT %1: Rapid Commit option received, following 2-way exchange
+This debug message is issued when the server found a Rapid Commit option
+in the client's message and 2-way exchanges are supported by the
+server for the subnet on which the client is connected. The argument
+specifies the client and transaction identification information.
+
% DHCP6_RELEASE_MISSING_CLIENTID client (address=%1) sent RELEASE message without mandatory client-id
This warning message indicates that client sent RELEASE message without
mandatory client-id option. This is most likely caused by a buggy client
break;
}
case D6O_IA_PD: {
- OptionPtr answer_opt = assignIA_PD(question, ctx,
+ OptionPtr answer_opt = assignIA_PD(question, answer, ctx,
boost::dynamic_pointer_cast<
Option6IA>(opt->second));
if (answer_opt) {
const Subnet6Ptr& subnet = orig_ctx.subnet_;
const DuidPtr& duid = orig_ctx.duid_;
- // If there is no subnet selected for handling this IA_NA, the only thing to do left is
+ // If there is no subnet selected for handling this IA_NA, the only thing left to do is
// to say that we are sorry, but the user won't get an address. As a convenience, we
// use a different status text to indicate that (compare to the same status code,
// but different wording below)
.arg(duid ? duid->toText() : "(no-duid)").arg(ia->getIAID())
.arg(hint_opt ? hint.toText() : "(no hint)");
- // "Fake" allocation is processing of SOLICIT message. We pretend to do an
- // allocation, but we do not put the lease in the database. That is ok,
- // because we do not guarantee that the user will get that exact lease. If
- // the user selects this server to do actual allocation (i.e. sends REQUEST)
- // it should include this hint. That will help us during the actual lease
- // allocation.
- bool fake_allocation = false;
- if (query->getType() == DHCPV6_SOLICIT) {
- /// @todo: Check if we support rapid commit
- fake_allocation = true;
- }
+ // "Fake" allocation is the case when the server is processing the Solicit
+ // message without the Rapid Commit option and advertises a lease to
+ // the client, but doesn't commit this lease to the lease database. If
+ // the Solicit contains the Rapid Commit option and the server is
+ // configured to honor the Rapid Commit option, or the client has sent
+ // the Request message, the lease will be committed to the lease
+ // database. The type of the server's response may be used to determine
+ // if this is the fake allocation case or not. When the server sends
+ // Reply message it means that it is committing leases. Other message
+ // type (Advertise) means that server is not committing leases (fake
+ // allocation).
+ bool fake_allocation = (answer->getType() != DHCPV6_REPLY);
// Get DDNS update direction flags
bool do_fwd = false;
}
OptionPtr
-Dhcpv6Srv::assignIA_PD(const Pkt6Ptr& query,
+Dhcpv6Srv::assignIA_PD(const Pkt6Ptr& query, const Pkt6Ptr& answer,
AllocEngine::ClientContext6& orig_ctx,
boost::shared_ptr<Option6IA> ia) {
// as we can initialize IAID using a constructor.
boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_PD, ia->getIAID()));
- // If there is no subnet selected for handling this IA_PD, the only thing to
- // do left is to say that we are sorry, but the user won't get an address.
+ // If there is no subnet selected for handling this IA_PD, the only thing
+ // left to do is to say that we are sorry, but the user won't get an address.
// As a convenience, we use a different status text to indicate that
// (compare to the same status code, but different wording below)
if (!subnet) {
.arg(duid ? duid->toText() : "(no-duid)").arg(ia->getIAID())
.arg(hint_opt ? hint.toText() : "(no hint)");
- // "Fake" allocation is processing of SOLICIT message. We pretend to do an
- // allocation, but we do not put the lease in the database. That is ok,
- // because we do not guarantee that the user will get that exact lease. If
- // the user selects this server to do actual allocation (i.e. sends REQUEST)
- // it should include this hint. That will help us during the actual lease
- // allocation.
- bool fake_allocation = (query->getType() == DHCPV6_SOLICIT);
+ // "Fake" allocation is the case when the server is processing the Solicit
+ // message without the Rapid Commit option and advertises a lease to
+ // the client, but doesn't commit this lease to the lease database. If
+ // the Solicit contains the Rapid Commit option and the server is
+ // configured to honor the Rapid Commit option, or the client has sent
+ // the Request message, the lease will be committed to the lease
+ // database. The type of the server's response may be used to determine
+ // if this is the fake allocation case or not. When the server sends
+ // Reply message it means that it is committing leases. Other message
+ // type (Advertise) means that server is not committing leases (fake
+ // allocation).
+ bool fake_allocation = (answer->getType() != DHCPV6_REPLY);
// Use allocation engine to pick a lease for this client. Allocation engine
// will try to honour the hint, but it is just a hint - some other address
// Let's create a simplified client context here.
AllocEngine::ClientContext6 ctx = createContext(solicit);
- Pkt6Ptr advertise(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
-
- copyClientOptions(solicit, advertise);
- appendDefaultOptions(solicit, advertise);
+ Pkt6Ptr response(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
- if (!validateSeDhcpOptions(solicit, advertise, ctx)) {
- return (advertise);
+ // Handle Rapid Commit option, if present.
+ if (ctx.subnet_ && ctx.subnet_->getRapidCommit()) {
+ OptionPtr opt_rapid_commit = solicit->getOption(D6O_RAPID_COMMIT);
+ if (opt_rapid_commit) {
+
+ /// @todo uncomment when #3807 is merged!
+/* LOG_DEBUG(options_logger, DBG_DHCP6_DETAIL, DHCP6_RAPID_COMMIT)
+ .arg(solicit->getLabel()); */
+
+ // If Rapid Commit has been sent by the client, change the
+ // response type to Reply and include Rapid Commit option.
+ response->setType(DHCPV6_REPLY);
+ response->addOption(opt_rapid_commit);
+ }
}
- appendRequestedOptions(solicit, advertise, ctx);
- appendRequestedVendorOptions(solicit, advertise, ctx);
+
+ copyClientOptions(solicit, response);
+ appendDefaultOptions(solicit, response);
- processClientFqdn(solicit, advertise, ctx);
- assignLeases(solicit, advertise, ctx);
- // Note, that we don't create NameChangeRequests here because we don't
- // perform DNS Updates for Solicit. Client must send Request to update
- // DNS.
+ if (!validateSeDhcpOptions(solicit, response, ctx)) {
+ return (response);
+ }
+ appendRequestedOptions(solicit, response, ctx);
+ appendRequestedVendorOptions(solicit, response, ctx);
- generateFqdn(advertise);
+ processClientFqdn(solicit, response, ctx);
+ assignLeases(solicit, response, ctx);
- return (advertise);
+ // Only generate name change requests if sending a Reply as a result
+ // of receiving Rapid Commit option.
+ if (response->getType() == DHCPV6_REPLY) {
+ createNameChangeRequests(response);
+ }
+
+ return (response);
}
Pkt6Ptr
/// allocation failure.
///
/// @param query client's message (typically SOLICIT or REQUEST)
+ /// @param answer server's response to the client's message.
/// @param orig_ctx client context (contains subnet, duid and other parameters)
/// @param ia pointer to client's IA_PD option (client's request)
/// @return IA_PD option (server's response)
OptionPtr assignIA_PD(const Pkt6Ptr& query,
+ const isc::dhcp::Pkt6Ptr& answer,
AllocEngine::ClientContext6& orig_ctx,
boost::shared_ptr<Option6IA> ia);
parser = new PdPoolListParser(config_id, pools_);
} else if (config_id.compare("option-data") == 0) {
parser = new OptionDataListParser(config_id, options_, AF_INET6);
+ } else if (config_id.compare("rapid-commit") == 0) {
+ parser = new BooleanParser(config_id, boolean_values_);
} else {
isc_throw(NotImplemented, "unsupported parameter: " << config_id);
}
}
}
- stringstream tmp;
- tmp << addr << "/" << static_cast<int>(len)
- << " with params t1=" << t1 << ", t2=" << t2 << ", pref="
- << pref << ", valid=" << valid;
+ bool rapid_commit = boolean_values_->getOptionalParam("rapid-commit", false);
- LOG_INFO(dhcp6_logger, DHCP6_CONFIG_NEW_SUBNET).arg(tmp.str());
+ std::ostringstream output;
+ output << addr << "/" << static_cast<int>(len)
+ << " with params t1=" << t1 << ", t2="
+ << t2 << ", preferred-lifetime=" << pref
+ << ", valid-lifetime=" << valid
+ << ", rapid-commit is " << (rapid_commit ? "enabled" : "disabled");
+
+ LOG_INFO(dhcp6_logger, DHCP6_CONFIG_NEW_SUBNET).arg(output.str());
// Create a new subnet.
Subnet6* subnet6 = new Subnet6(addr, len, t1, t2, pref, valid,
subnet6->setInterfaceId(opt);
}
+ // Enable or disable Rapid Commit option support for the subnet.
+ subnet6->setRapidCommit(rapid_commit);
+
// Try setting up client class (if specified)
try {
string client_class = string_values_->getParam("client-class");
CfgMgr::instance().clear();
}
+ /// @brief Tests the Rapid Commit configuration for a subnet.
+ ///
+ /// This test configures the server with a given configuration and
+ /// verifies if the Rapid Commit has been configured successfully
+ /// for a subnet.
+ ///
+ /// @param config Server configuration, possibly including the
+ /// 'rapid-commit' parameter.
+ /// @param exp_rapid_commit Expected value of the Rapid Commit flag
+ /// within a subnet.
+ void testRapidCommit(const std::string& config,
+ const bool exp_rapid_commit) {
+ // Clear any existing configuration.
+ CfgMgr::instance().clear();
+
+ // Configure the server.
+ ElementPtr json = Element::fromJSON(config);
+
+ // Make sure that the configuration was successful.
+ ConstElementPtr status;
+ EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+ checkResult(status, 0);
+
+ // Get the subnet.
+ Subnet6Ptr subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->
+ selectSubnet(IOAddress("2001:db8:1::5"), classify_);
+ ASSERT_TRUE(subnet);
+
+ // Check the Rapid Commit flag for the subnet.
+ EXPECT_EQ(exp_rapid_commit, subnet->getRapidCommit());
+
+ // Clear any existing configuration.
+ CfgMgr::instance().clear();
+ }
+
int rcode_; ///< Return code (see @ref isc::config::parseAnswer)
Dhcpv6Srv srv_; ///< Instance of the Dhcp6Srv used during tests
ConstElementPtr comment_; ///< Comment (see @ref isc::config::parseAnswer)
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
}
+// This test checks the configuration of the Rapid Commit option
+// support for the subnet.
+TEST_F(Dhcp6ParserTest, subnetRapidCommit) {
+ {
+ // rapid-commit implicitly set to false.
+ SCOPED_TRACE("Default Rapid Commit setting");
+ testRapidCommit("{ \"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::1 - "
+ "2001:db8:1::ffff\" } ],"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }",
+ false);
+ }
+
+ {
+ // rapid-commit explicitly set to true.
+ SCOPED_TRACE("Enable Rapid Commit");
+ testRapidCommit("{ \"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::1 - "
+ "2001:db8:1::ffff\" } ],"
+ " \"rapid-commit\": True,"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }",
+ true);
+ }
+
+ {
+ // rapid-commit explicitly set to false.
+ SCOPED_TRACE("Disable Rapid Commit");
+ testRapidCommit("{ \"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::1 - "
+ "2001:db8:1::ffff\" } ],"
+ " \"rapid-commit\": False,"
+ " \"subnet\": \"2001:db8:1::/64\" } ],"
+ "\"valid-lifetime\": 4000 }",
+ false);
+ }
+}
+
// This test checks that multiple pools can be defined and handled properly.
// The test defines 2 subnets, each with 2 pools.
TEST_F(Dhcp6ParserTest, multiplePools) {
const bool Dhcp6SrvD2Test::SHOULD_FAIL;
Dhcp6SrvD2Test::Dhcp6SrvD2Test() : rcode_(-1) {
+ reset();
}
Dhcp6SrvD2Test::~Dhcp6SrvD2Test() {
dest_addr_(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
duid_(generateDUID(DUID::DUID_LLT)),
link_local_("fe80::3a60:77ff:fed5:cdef"),
+ iface_name_("eth0"),
srv_(boost::shared_ptr<NakedDhcpv6Srv>(new NakedDhcpv6Srv(0))),
use_na_(false),
use_pd_(false),
use_relay_(false),
use_oro_(false),
use_client_id_(true),
- prefix_hint_() {
+ use_rapid_commit_(false),
+ prefix_hint_(),
+ fqdn_() {
}
Dhcp6Client::Dhcp6Client(boost::shared_ptr<NakedDhcpv6Srv>& srv) :
dest_addr_(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
duid_(generateDUID(DUID::DUID_LLT)),
link_local_("fe80::3a60:77ff:fed5:cdef"),
+ iface_name_("eth0"),
srv_(srv),
use_na_(false),
use_pd_(false),
use_relay_(false),
use_oro_(false),
use_client_id_(true),
- prefix_hint_() {
+ use_rapid_commit_(false),
+ prefix_hint_(),
+ fqdn_() {
}
void
config_.leases_.push_back(lease_info);
}
+void
+Dhcp6Client::appendFQDN() {
+ if (fqdn_) {
+ context_.query_->addOption(fqdn_);
+ }
+}
+
void
Dhcp6Client::copyIAs(const Pkt6Ptr& source, const Pkt6Ptr& dest) {
typedef OptionCollection Opts;
}
context_.query_->addOption(ia);
}
+ if (use_rapid_commit_) {
+ context_.query_->addOption(OptionPtr(new Option(Option::V6,
+ D6O_RAPID_COMMIT)));
+ }
+ // Add Client FQDN if configured.
+ appendFQDN();
+
sendMsg(context_.query_);
context_.response_ = receiveOneMsg();
- /// @todo Sanity check here
+ // If using Rapid Commit and the server has responded with Reply,
+ // let's apply received configuration.
+ if (use_rapid_commit_ && context_.response_ &&
+ context_.response_->getType() == DHCPV6_REPLY) {
+ applyRcvdConfiguration(context_.response_);
+ }
}
void
Pkt6Ptr query = createMsg(DHCPV6_REQUEST);
query->addOption(context_.response_->getOption(D6O_SERVERID));
copyIAs(context_.response_, query);
+
+ // Add Client FQDN if configured.
+ appendFQDN();
+
context_.query_ = query;
sendMsg(context_.query_);
context_.response_ = receiveOneMsg();
Pkt6Ptr query = createMsg(DHCPV6_RENEW);
query->addOption(context_.response_->getOption(D6O_SERVERID));
copyIAsFromLeases(query);
+
+ // Add Client FQDN if configured.
+ appendFQDN();
+
context_.query_ = query;
sendMsg(context_.query_);
context_.response_ = receiveOneMsg();
Dhcp6Client::doRebind() {
Pkt6Ptr query = createMsg(DHCPV6_REBIND);
copyIAsFromLeases(query);
+
+ // Add Client FQDN if configured.
+ appendFQDN();
+
context_.query_ = query;
sendMsg(context_.query_);
context_.response_ = receiveOneMsg();
msg->getBuffer().getLength()));
msg_copy->setRemoteAddr(link_local_);
msg_copy->setLocalAddr(dest_addr_);
- msg_copy->setIface("eth0");
+ msg_copy->setIface(iface_name_);
srv_->fakeReceive(msg_copy);
srv_->run();
}
len, pref_lft, valid_lft));
}
+void
+Dhcp6Client::useFQDN(const uint8_t flags, const std::string& fqdn_name,
+ Option6ClientFqdn::DomainNameType fqdn_type) {
+ fqdn_.reset(new Option6ClientFqdn(flags, fqdn_name, fqdn_type));
+}
+
+
} // end of namespace isc::dhcp::test
} // end of namespace isc::dhcp
#include <asiolink/io_address.h>
#include <dhcp/duid.h>
#include <dhcp/option.h>
+#include <dhcp/option6_client_fqdn.h>
#include <dhcp6/tests/dhcp6_test_utils.h>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
dest_addr_ = dest_addr;
}
+ /// @brief Sets the interface to be used by the client.
+ ///
+ /// @param iface_name Interface name.
+ void setInterface(const std::string& iface_name) {
+ iface_name_ = iface_name;
+ }
+
/// @brief Sets a prefix hint to be sent to a server.
///
/// @param pref_lft Preferred lifetime.
/// @brief Controls whether the client should send a client-id or not
/// @param send should the client-id be sent?
- void useClientId(bool send) {
+ void useClientId(const bool send) {
use_client_id_ = send;
}
+ /// @brief Specifies if the Rapid Commit option should be included in
+ /// the Solicit message.
+ ///
+ /// @param rapid_commit Boolean parameter controlling if the Rapid Commit
+ /// option must be included in the Solicit (if true), or not (if false).
+ void useRapidCommit(const bool rapid_commit) {
+ use_rapid_commit_ = rapid_commit;
+ }
+
+ /// @brief Creates an instance of the Client FQDN option to be included
+ /// in the client's message.
+ ///
+ /// @param flags Flags.
+ /// @param fqdn_name Name in the textual format.
+ /// @param fqdn_type Type of the name (fully qualified or partial).
+ void useFQDN(const uint8_t flags, const std::string& fqdn_name,
+ Option6ClientFqdn::DomainNameType fqdn_type);
+
/// @brief Lease configuration obtained by the client.
Configuration config_;
/// @param lease_info Structure holding new lease information.
void applyLease(const LeaseInfo& lease_info);
+ /// @brief Includes CLient FQDN in the client's message.
+ ///
+ /// This method checks if @c fqdn_ is specified and includes it in
+ /// the client's message.
+ void appendFQDN();
+
/// @brief Copy IA options from one message to another.
///
/// This method copies IA_NA and IA_PD options from one message to another.
/// @biref Current transaction id (altered on each send).
uint32_t curr_transid_;
- /// @brief Currently use destination address.
+ /// @brief Currently used destination address.
asiolink::IOAddress dest_addr_;
/// @brief Currently used DUID.
/// @brief Currently used link local address.
asiolink::IOAddress link_local_;
+ /// @brief Currently used interface.
+ std::string iface_name_;
+
/// @brief Pointer to the server that the client is communicating with.
boost::shared_ptr<isc::test::NakedDhcpv6Srv> srv_;
bool use_oro_; ///< Conth
bool use_client_id_;
+ bool use_rapid_commit_;
/// @brief Pointer to the option holding a prefix hint.
Option6IAPrefixPtr prefix_hint_;
/// Content of this vector will be sent as ORO if use_oro_ is set
/// to true. See @ref sendORO for details.
std::vector<uint16_t> oro_;
+
+ /// @brief FQDN requested by the client.
+ Option6ClientFqdnPtr fqdn_;
};
} // end of namespace isc::dhcp::test
#include <config.h>
#include <dhcp/tests/iface_mgr_test_config.h>
+#include <dhcp/option6_client_fqdn.h>
#include <dhcp6/tests/dhcp6_test_utils.h>
#include <dhcp6/tests/dhcp6_client.h>
+#include <dhcpsrv/cfgmgr.h>
+#include <dhcpsrv/d2_client_mgr.h>
using namespace isc;
using namespace isc::dhcp;
/// - the delegated prefix was intentionally selected to not match the
/// subnet prefix, to test that the delegated prefix doesn't need to
/// match the subnet prefix
+///
+/// - Configuration 1:
+/// - two subnets 2001:db8:1::/48 and 2001:db8:2::/48
+/// - first subnet assigned to interface eth0, another one assigned to eth1
+/// - one pool for subnet in a range of 2001:db8:X::1 - 2001:db8:X::10,
+/// where X is 1 or 2
+/// - enables Rapid Commit for the first subnet and disables for the second
+/// one
+/// - DNS updates enabled
+///
const char* CONFIGS[] = {
// Configuration 0
"{ \"interfaces-config\": {"
" \"interface-id\": \"\","
" \"interface\": \"eth0\""
" } ],"
- "\"valid-lifetime\": 4000 }"
+ "\"valid-lifetime\": 4000 }",
+
+// Configuration 1
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::10\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface\": \"eth0\","
+ " \"rapid-commit\": True"
+ " },"
+ " {"
+ " \"pools\": [ { \"pool\": \"2001:db8:2::1 - 2001:db8:2::10\" } ],"
+ " \"subnet\": \"2001:db8:2::/48\", "
+ " \"interface\": \"eth1\","
+ " \"rapid-commit\": False"
+ " } ],"
+ "\"valid-lifetime\": 4000,"
+ " \"dhcp-ddns\" : {"
+ " \"enable-updates\" : True, "
+ " \"qualifying-suffix\" : \"example.com\" }"
+ "}"
};
/// @brief Test fixture class for testing 4-way exchange: Solicit-Advertise,
-/// Request-Reply.
+/// Request-Reply and 2-way exchange: Solicit-Reply.
class SARRTest : public Dhcpv6SrvTest {
public:
/// @brief Constructor.
iface_mgr_test_config_(true) {
}
+ /// @brief Destructor.
+ ///
+ /// Clear the DHCP-DDNS configuration.
+ virtual ~SARRTest() {
+ D2ClientConfigPtr cfg(new D2ClientConfig());
+ CfgMgr::instance().setD2ClientConfig(cfg);
+ }
+
/// @brief Interface Manager's fake configuration control.
IfaceMgrTestConfig iface_mgr_test_config_;
};
ASSERT_TRUE(lease_server);
}
+// Check that when the client includes the Rapid Commit option in its
+// Solicit, the server responds with Reply and commits the lease.
+TEST_F(SARRTest, rapidCommitEnable) {
+ Dhcp6Client client;
+ // Configure client to request IA_NA
+ client.useNA();
+ configure(CONFIGS[1], *client.getServer());
+ ASSERT_NO_THROW(client.getServer()->startD2());
+ // Make sure we ended-up having expected number of subnets configured.
+ const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
+ getCfgSubnets6()->getAll();
+ ASSERT_EQ(2, subnets->size());
+ // Perform 2-way exchange.
+ client.useRapidCommit(true);
+ // Include FQDN to trigger generation of name change requests.
+ ASSERT_NO_THROW(client.useFQDN(Option6ClientFqdn::FLAG_S,
+ "client-name.example.org",
+ Option6ClientFqdn::FULL));
+
+ ASSERT_NO_THROW(client.doSolicit());
+ // Server should have committed a lease.
+ ASSERT_EQ(1, client.getLeaseNum());
+ Lease6 lease_client = client.getLease(0);
+ // Make sure that the address belongs to the subnet configured.
+ ASSERT_TRUE(CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->
+ selectSubnet(lease_client.addr_, ClientClasses()));
+ // Make sure that the server responded with Reply.
+ ASSERT_TRUE(client.getContext().response_);
+ EXPECT_EQ(DHCPV6_REPLY, client.getContext().response_->getType());
+ // Rapid Commit option should be included.
+ EXPECT_TRUE(client.getContext().response_->getOption(D6O_RAPID_COMMIT));
+ // Check that the lease has been committed.
+ Lease6Ptr lease_server = checkLease(lease_client);
+ EXPECT_TRUE(lease_server);
+ // There should be one name change request generated.
+ EXPECT_EQ(1, CfgMgr::instance().getD2ClientMgr().getQueueSize());
+}
+
+// Check that the server responds with Advertise if the client hasn't
+// included the Rapid Commit option in the Solicit.
+TEST_F(SARRTest, rapidCommitNoOption) {
+ Dhcp6Client client;
+ // Configure client to request IA_NA
+ client.useNA();
+ configure(CONFIGS[1], *client.getServer());
+ ASSERT_NO_THROW(client.getServer()->startD2());
+ // Make sure we ended-up having expected number of subnets configured.
+ const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
+ getCfgSubnets6()->getAll();
+ ASSERT_EQ(2, subnets->size());
+ // Include FQDN to test that the server will not create name change
+ // requests when it sends Advertise (Rapid Commit disabled).
+ ASSERT_NO_THROW(client.useFQDN(Option6ClientFqdn::FLAG_S,
+ "client-name.example.org",
+ Option6ClientFqdn::FULL));
+ ASSERT_NO_THROW(client.doSolicit());
+ // There should be no lease because the server should have responded
+ // with Advertise.
+ ASSERT_EQ(0, client.getLeaseNum());
+ // Make sure that the server responded.
+ ASSERT_TRUE(client.getContext().response_);
+ EXPECT_EQ(DHCPV6_ADVERTISE, client.getContext().response_->getType());
+ // Make sure that the Rapid Commit option is not included.
+ EXPECT_FALSE(client.getContext().response_->getOption(D6O_RAPID_COMMIT));
+ // There should be no name change request generated.
+ EXPECT_EQ(0, CfgMgr::instance().getD2ClientMgr().getQueueSize());
+}
+
+// Check that when the Rapid Commit support is disabled for the subnet
+// the server replies with an Advertise and ignores the Rapid Commit
+// option sent by the client.
+TEST_F(SARRTest, rapidCommitDisable) {
+ Dhcp6Client client;
+ // The subnet assigned to eth1 has Rapid Commit disabled.
+ client.setInterface("eth1");
+ // Configure client to request IA_NA
+ client.useNA();
+ configure(CONFIGS[1], *client.getServer());
+ ASSERT_NO_THROW(client.getServer()->startD2());
+ // Make sure we ended-up having expected number of subnets configured.
+ const Subnet6Collection* subnets = CfgMgr::instance().getCurrentCfg()->
+ getCfgSubnets6()->getAll();
+ ASSERT_EQ(2, subnets->size());
+ // Send Rapid Commit option to the server.
+ client.useRapidCommit(true);
+ // Include FQDN to test that the server will not create name change
+ // requests when it sends Advertise (Rapid Commit disabled).
+ ASSERT_NO_THROW(client.useFQDN(Option6ClientFqdn::FLAG_S,
+ "client-name.example.org",
+ Option6ClientFqdn::FULL));
+ ASSERT_NO_THROW(client.doSolicit());
+ // There should be no lease because the server should have responded
+ // with Advertise.
+ ASSERT_EQ(0, client.getLeaseNum());
+ // Make sure that the server responded.
+ ASSERT_TRUE(client.getContext().response_);
+ EXPECT_EQ(DHCPV6_ADVERTISE, client.getContext().response_->getType());
+ // Make sure that the Rapid Commit option is not included.
+ EXPECT_FALSE(client.getContext().response_->getOption(D6O_RAPID_COMMIT));
+ // There should be no name change request generated.
+ EXPECT_EQ(0, CfgMgr::instance().getD2ClientMgr().getQueueSize());
+}
+
+
} // end of anonymous namespace
: uint32_values_(new Uint32Storage()),
string_values_(new StringStorage()),
boolean_values_(new BooleanStorage()),
- pools_(new PoolStorage()), global_context_(global_context),
+ pools_(new PoolStorage()),
+ global_context_(global_context),
relay_info_(new isc::dhcp::Subnet::RelayInfo(default_addr)),
options_(new CfgOption()) {
// The first parameter should always be "subnet", but we don't check
const Triplet<uint32_t>& preferred_lifetime,
const Triplet<uint32_t>& valid_lifetime,
const SubnetID id)
-:Subnet(prefix, length, t1, t2, valid_lifetime, RelayInfo(IOAddress("::")), id),
- preferred_(preferred_lifetime) {
+ :Subnet(prefix, length, t1, t2, valid_lifetime, RelayInfo(IOAddress("::")), id),
+ preferred_(preferred_lifetime), rapid_commit_(false) {
if (!prefix.isV6()) {
isc_throw(BadValue, "Non IPv6 prefix " << prefix
<< " specified in subnet6");
return interface_id_;
}
-protected:
+ /// @brief Enables or disables Rapid Commit option support for the subnet.
+ ///
+ /// @param rapid_commit A boolean value indicating that the Rapid Commit
+ /// option support is enabled (if true), or disabled (if false).
+ void setRapidCommit(const bool rapid_commit) {
+ rapid_commit_ = rapid_commit;
+ };
+
+ /// @brief Returns boolean value indicating that the Rapid Commit option
+ /// is supported or unsupported for the subnet.
+ ///
+ /// @return true if the Rapid Commit option is supported, false otherwise.
+ bool getRapidCommit() const {
+ return (rapid_commit_);
+ }
+
+private:
/// @brief Returns default address for pool selection
/// @return ANY IPv6 address
/// @brief a triplet with preferred lifetime (in seconds)
Triplet<uint32_t> preferred_;
+
+ /// @brief A flag indicating if Rapid Commit option is supported
+ /// for this subnet.
+ ///
+ /// It's default value is false, which indicates that the Rapid
+ /// Commit is disabled for the subnet.
+ bool rapid_commit_;
};
/// @brief A pointer to a Subnet6 object
}
+// This test checks that the Rapid Commit support can be enabled or
+// disabled for a subnet. It also checks that the Rapid Commit
+// support is disabled by default.
+TEST(Subnet6Test, rapidCommit) {
+ Subnet6 subnet(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4);
+
+ // By default, the RC should be disabled.
+ EXPECT_FALSE(subnet.getRapidCommit());
+
+ // Enable Rapid Commit.
+ subnet.setRapidCommit(true);
+ EXPECT_TRUE(subnet.getRapidCommit());
+
+ // Disable again.
+ subnet.setRapidCommit(false);
+ EXPECT_FALSE(subnet.getRapidCommit());
+}
+
// Checks if last allocated address/prefix is stored/retrieved properly
TEST(Subnet6Test, lastAllocated) {
IOAddress ia("2001:db8:1::1");