Browse Source

[3328] Added new configurable values to dhcpsrv::D2ClientConfig

Adding new members to D2ClientConfig
- sender_ip
- sender_port
- max_queue_size

Modified D2ClientConfigParser to parse the new values
Modified D2ClientMgr to make use of the new values
Updated the appropriate unittests
Thomas Markwalder 11 years ago
parent
commit
90f20fdef2

+ 19 - 0
src/lib/dhcpsrv/d2_client_cfg.cc

@@ -25,6 +25,10 @@ namespace dhcp {
 
 const char *D2ClientConfig::DFT_SERVER_IP = "127.0.0.1";
 const size_t D2ClientConfig::DFT_SERVER_PORT = 53001;
+const char *D2ClientConfig::DFT_V4_SENDER_IP = "0.0.0.0";
+const char *D2ClientConfig::DFT_V6_SENDER_IP = "::";
+const size_t D2ClientConfig::DFT_SENDER_PORT = 0;
+const size_t D2ClientConfig::DFT_MAX_QUEUE_SIZE = 1024;
 const char *D2ClientConfig::DFT_NCR_PROTOCOL = "UDP";
 const char *D2ClientConfig::DFT_NCR_FORMAT = "JSON";
 const bool D2ClientConfig::DFT_ALWAYS_INCLUDE_FQDN = false;
@@ -37,6 +41,9 @@ const char *D2ClientConfig::DFT_QUALIFYING_SUFFIX = "example.com";
 D2ClientConfig::D2ClientConfig(const  bool enable_updates,
                                const isc::asiolink::IOAddress& server_ip,
                                const size_t server_port,
+                               const isc::asiolink::IOAddress& sender_ip,
+                               const size_t sender_port,
+                               const size_t max_queue_size,
                                const dhcp_ddns::
                                      NameChangeProtocol& ncr_protocol,
                                const dhcp_ddns::
@@ -50,6 +57,9 @@ D2ClientConfig::D2ClientConfig(const  bool enable_updates,
     : enable_updates_(enable_updates),
     server_ip_(server_ip),
     server_port_(server_port),
+    sender_ip_(sender_ip),
+    sender_port_(sender_port),
+    max_queue_size_(max_queue_size),
     ncr_protocol_(ncr_protocol),
     ncr_format_(ncr_format),
     always_include_fqdn_(always_include_fqdn),
@@ -65,6 +75,9 @@ D2ClientConfig::D2ClientConfig()
     : enable_updates_(false),
       server_ip_(isc::asiolink::IOAddress("0.0.0.0")),
       server_port_(0),
+      sender_ip_(isc::asiolink::IOAddress("0.0.0.0")),
+      sender_port_(0),
+      max_queue_size_(0),
       ncr_protocol_(dhcp_ddns::NCR_UDP),
       ncr_format_(dhcp_ddns::FMT_JSON),
       always_include_fqdn_(false),
@@ -106,6 +119,9 @@ D2ClientConfig::operator == (const D2ClientConfig& other) const {
     return ((enable_updates_ == other.enable_updates_) &&
             (server_ip_ == other.server_ip_) &&
             (server_port_ == other.server_port_) &&
+            (sender_ip_ == other.sender_ip_) &&
+            (sender_port_ == other.sender_port_) &&
+            (max_queue_size_ == other.max_queue_size_) &&
             (ncr_protocol_ == other.ncr_protocol_) &&
             (ncr_format_ == other.ncr_format_) &&
             (always_include_fqdn_ == other.always_include_fqdn_) &&
@@ -129,6 +145,9 @@ D2ClientConfig::toText() const {
     if (enable_updates_) {
         stream << ", server_ip: " << server_ip_.toText()
                << ", server_port: " << server_port_
+               << ", sender_ip: " << sender_ip_.toText()
+               << ", sender_port: " << sender_port_
+               << ", max_queue_size: " << max_queue_size_
                << ", ncr_protocol: " << ncr_protocol_
                << ", ncr_format: " << ncr_format_
                << ", always_include_fqdn: " << (always_include_fqdn_ ?

+ 34 - 0
src/lib/dhcpsrv/d2_client_cfg.h

@@ -62,6 +62,10 @@ public:
     /// readily provide them (see Trac #3358).
     static const char *DFT_SERVER_IP;
     static const size_t DFT_SERVER_PORT;
+    static const char *DFT_V4_SENDER_IP;
+    static const char *DFT_V6_SENDER_IP;
+    static const size_t DFT_SENDER_PORT;
+    static const size_t DFT_MAX_QUEUE_SIZE;
     static const char *DFT_NCR_PROTOCOL;
     static const char *DFT_NCR_FORMAT;
     static const bool DFT_ALWAYS_INCLUDE_FQDN;
@@ -76,6 +80,9 @@ public:
     /// @param enable_updates Enables DHCP-DDNS updates
     /// @param server_ip IP address of the b10-dhcp-ddns server (IPv4 or IPv6)
     /// @param server_port IP port of the b10-dhcp-ddns server
+    /// @param sender_ip IP address of the b10-dhcp-ddns server (IPv4 or IPv6)
+    /// @param sender_port IP port of the b10-dhcp-ddns server
+    /// @param max_queue_size  maximum NCRs allowed in sender's queue
     /// @param ncr_protocol Socket protocol to use with b10-dhcp-ddns
     /// Currently only UDP is supported.
     /// @param ncr_format Format of the b10-dhcp-ddns requests.
@@ -95,6 +102,9 @@ public:
     D2ClientConfig(const bool enable_updates,
                    const isc::asiolink::IOAddress& server_ip,
                    const size_t server_port,
+                   const isc::asiolink::IOAddress& sender_ip,
+                   const size_t sender_port,
+                   const size_t max_queue_size,
                    const dhcp_ddns::NameChangeProtocol& ncr_protocol,
                    const dhcp_ddns::NameChangeFormat& ncr_format,
                    const bool always_include_fqdn,
@@ -126,6 +136,21 @@ public:
         return(server_port_);
     }
 
+    /// @brief Return the IP address client should use to send
+    const isc::asiolink::IOAddress& getSenderIp() const {
+        return(sender_ip_);
+    }
+
+    /// @brief Return the IP port client should use to send
+    size_t getSenderPort() const {
+        return(sender_port_);
+    }
+
+    /// @brief Return Maximun sender queue size
+    size_t getMaxQueueSize() const {
+        return(max_queue_size_);
+    }
+
     /// @brief Return the socket protocol to use with b10-dhcp-ddns.
     const dhcp_ddns::NameChangeProtocol& getNcrProtocol() const {
          return(ncr_protocol_);
@@ -202,6 +227,15 @@ private:
     /// @brief IP port of the b10-dhcp-ddns server.
     size_t server_port_;
 
+    /// @brief IP address on which the client should send
+    isc::asiolink::IOAddress sender_ip_;
+
+    /// @brief IP port on which the client should send
+    size_t sender_port_;
+
+    /// @brief Maxium number of NCRs allowed to queue waiting to send
+    size_t max_queue_size_;
+
     /// @brief The socket protocol to use with b10-dhcp-ddns.
     /// Currently only UDP is supported.
     dhcp_ddns::NameChangeProtocol ncr_protocol_;

+ 4 - 10
src/lib/dhcpsrv/d2_client_mgr.cc

@@ -68,21 +68,15 @@ D2ClientMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
             dhcp_ddns::NameChangeSenderPtr new_sender;
             switch (new_config->getNcrProtocol()) {
             case dhcp_ddns::NCR_UDP: {
-                /// @todo Should we be able to configure a sender's client
-                /// side ip and port?  We should certainly be able to
-                /// configure a maximum queue size.  These were overlooked
-                /// but are covered in Trac# 3328.
-                isc::asiolink::IOAddress any_addr("0.0.0.0");
-                uint32_t any_port = 0;
-                uint32_t queue_max = 1024;
-
                 // Instantiate a new sender.
                 new_sender.reset(new dhcp_ddns::NameChangeUDPSender(
-                                                any_addr, any_port,
+                                                new_config->getSenderIp(),
+                                                new_config->getSenderPort(),
                                                 new_config->getServerIp(),
                                                 new_config->getServerPort(),
                                                 new_config->getNcrFormat(),
-                                                *this, queue_max));
+                                                *this,
+                                                new_config->getMaxQueueSize()));
                 break;
                 }
             default:

+ 30 - 5
src/lib/dhcpsrv/dhcp_parsers.cc

@@ -1281,6 +1281,23 @@ D2ClientConfigParser::build(isc::data::ConstElementPtr client_config) {
     uint32_t server_port = uint32_values_->getOptionalParam("server-port",
                                                              D2ClientConfig::
                                                              DFT_SERVER_PORT);
+
+    // The default sender IP depends on the server IP family
+    asiolink::IOAddress
+        sender_ip(string_values_->
+                  getOptionalParam("sender-ip",
+                                   (server_ip.isV4() ?
+                                    D2ClientConfig::DFT_V4_SENDER_IP :
+                                    D2ClientConfig::DFT_V6_SENDER_IP)));
+
+    uint32_t sender_port = uint32_values_->getOptionalParam("sender-port",
+                                                             D2ClientConfig::
+                                                             DFT_SENDER_PORT);
+    uint32_t max_queue_size
+        = uint32_values_->getOptionalParam("max-queue-size",
+                                            D2ClientConfig::
+                                            DFT_MAX_QUEUE_SIZE);
+
     dhcp_ddns::NameChangeProtocol ncr_protocol
         = dhcp_ddns::stringToNcrProtocol(string_values_->
                                          getOptionalParam("ncr-protocol",
@@ -1302,8 +1319,8 @@ D2ClientConfigParser::build(isc::data::ConstElementPtr client_config) {
 
     bool always_include_fqdn = boolean_values_->
                                getOptionalParam("always-include-fqdn",
-                                               D2ClientConfig::
-                                               DFT_ALWAYS_INCLUDE_FQDN);
+                                                D2ClientConfig::
+                                                DFT_ALWAYS_INCLUDE_FQDN);
 
     bool override_no_update = boolean_values_->
                               getOptionalParam("override-no-update",
@@ -1320,8 +1337,13 @@ D2ClientConfigParser::build(isc::data::ConstElementPtr client_config) {
                                                 DFT_REPLACE_CLIENT_NAME);
 
     // Attempt to create the new client config.
-    local_client_config_.reset(new D2ClientConfig(enable_updates, server_ip,
-                                                  server_port, ncr_protocol,
+    local_client_config_.reset(new D2ClientConfig(enable_updates,
+                                                  server_ip,
+                                                  server_port,
+                                                  sender_ip,
+                                                  sender_port,
+                                                  max_queue_size,
+                                                  ncr_protocol,
                                                   ncr_format,
                                                   always_include_fqdn,
                                                   override_no_update,
@@ -1334,12 +1356,15 @@ D2ClientConfigParser::build(isc::data::ConstElementPtr client_config) {
 isc::dhcp::ParserPtr
 D2ClientConfigParser::createConfigParser(const std::string& config_id) {
     DhcpConfigParser* parser = NULL;
-    if (config_id.compare("server-port") == 0) {
+    if ((config_id.compare("server-port") == 0) ||
+        (config_id.compare("sender-port") == 0) ||
+        (config_id.compare("max-queue-size") == 0)) {
         parser = new Uint32Parser(config_id, uint32_values_);
     } else if ((config_id.compare("server-ip") == 0) ||
         (config_id.compare("ncr-protocol") == 0) ||
         (config_id.compare("ncr-format") == 0) ||
         (config_id.compare("generated-prefix") == 0) ||
+        (config_id.compare("sender-ip") == 0) ||
         (config_id.compare("qualifying-suffix") == 0)) {
         parser = new StringParser(config_id, string_values_);
     } else if ((config_id.compare("enable-updates") == 0) ||

+ 2 - 0
src/lib/dhcpsrv/tests/cfgmgr_unittest.cc

@@ -991,6 +991,8 @@ TEST_F(CfgMgrTest, d2ClientConfig) {
     // Create a new, enabled configuration.
     ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   true, true, true, true,
                                   "pre-fix", "suf-fix")));

+ 81 - 11
src/lib/dhcpsrv/tests/d2_client_unittest.cc

@@ -47,6 +47,9 @@ TEST(D2ClientConfigTest, constructorsAndAccessors) {
     bool enable_updates = true;
     isc::asiolink::IOAddress server_ip("127.0.0.1");
     size_t server_port = 477;
+    isc::asiolink::IOAddress sender_ip("127.0.0.1");
+    size_t sender_port = 478;
+    size_t max_queue_size = 2048;
     dhcp_ddns::NameChangeProtocol ncr_protocol = dhcp_ddns::NCR_UDP;
     dhcp_ddns::NameChangeFormat ncr_format = dhcp_ddns::FMT_JSON;
     bool always_include_fqdn = true;
@@ -61,6 +64,9 @@ TEST(D2ClientConfigTest, constructorsAndAccessors) {
                                            D2ClientConfig(enable_updates,
                                                           server_ip,
                                                           server_port,
+                                                          sender_ip,
+                                                          sender_port,
+                                                          max_queue_size,
                                                           ncr_protocol,
                                                           ncr_format,
                                                           always_include_fqdn,
@@ -77,6 +83,9 @@ TEST(D2ClientConfigTest, constructorsAndAccessors) {
 
     EXPECT_EQ(d2_client_config->getServerIp(), server_ip);
     EXPECT_EQ(d2_client_config->getServerPort(), server_port);
+    EXPECT_EQ(d2_client_config->getSenderIp(), sender_ip);
+    EXPECT_EQ(d2_client_config->getSenderPort(), sender_port);
+    EXPECT_EQ(d2_client_config->getMaxQueueSize(), max_queue_size);
     EXPECT_EQ(d2_client_config->getNcrProtocol(), ncr_protocol);
     EXPECT_EQ(d2_client_config->getNcrFormat(), ncr_format);
     EXPECT_EQ(d2_client_config->getAlwaysIncludeFqdn(), always_include_fqdn);
@@ -97,6 +106,9 @@ TEST(D2ClientConfigTest, constructorsAndAccessors) {
                                         D2ClientConfig(enable_updates,
                                                        server_ip,
                                                        server_port,
+                                                       sender_ip,
+                                                       sender_port,
+                                                       max_queue_size,
                                                        dhcp_ddns::NCR_TCP,
                                                        ncr_format,
                                                        always_include_fqdn,
@@ -121,7 +133,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Create an instance to use as a reference.
     ASSERT_NO_THROW(ref_config.reset(new D2ClientConfig(true,
-                    ref_address, 477,
+                    ref_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, true, true, true,
                     "pre-fix", "suf-fix")));
@@ -129,7 +141,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that is identical to reference configuration.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
-                    ref_address, 477,
+                    ref_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, true, true, true,
                     "pre-fix", "suf-fix")));
@@ -139,7 +151,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that differs only by enable flag.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(false,
-                    ref_address, 477,
+                    ref_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, true, true, true,
                     "pre-fix", "suf-fix")));
@@ -149,7 +161,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that differs only by server ip.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
-                    test_address, 477,
+                    test_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, true, true, true,
                     "pre-fix", "suf-fix")));
@@ -159,7 +171,37 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that differs only by server port.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
-                    ref_address, 333,
+                    ref_address, 333, ref_address, 478, 1024,
+                    dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+                    true, true, true, true,
+                    "pre-fix", "suf-fix")));
+    ASSERT_TRUE(test_config);
+    EXPECT_FALSE(*ref_config == *test_config);
+    EXPECT_TRUE(*ref_config != *test_config);
+
+    // Check a configuration that differs only by sender ip.
+    ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+                    ref_address, 477, test_address, 478, 1024,
+                    dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+                    true, true, true, true,
+                    "pre-fix", "suf-fix")));
+    ASSERT_TRUE(test_config);
+    EXPECT_FALSE(*ref_config == *test_config);
+    EXPECT_TRUE(*ref_config != *test_config);
+
+    // Check a configuration that differs only by sender port.
+    ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+                    ref_address, 477, ref_address, 333, 1024,
+                    dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
+                    true, true, true, true,
+                    "pre-fix", "suf-fix")));
+    ASSERT_TRUE(test_config);
+    EXPECT_FALSE(*ref_config == *test_config);
+    EXPECT_TRUE(*ref_config != *test_config);
+
+    // Check a configuration that differs only by max queue size.
+    ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
+                    ref_address, 477, ref_address, 478, 2048,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, true, true, true,
                     "pre-fix", "suf-fix")));
@@ -169,7 +211,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that differs only by always_include_fqdn.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
-                    ref_address, 477,
+                    ref_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     false, true, true, true,
                     "pre-fix", "suf-fix")));
@@ -179,7 +221,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that differs only by override_no_update.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
-                    ref_address, 477,
+                    ref_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, false, true, true,
                     "pre-fix", "suf-fix")));
@@ -189,7 +231,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that differs only by override_client_update.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
-                    ref_address, 477,
+                    ref_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, true, false, true,
                     "pre-fix", "suf-fix")));
@@ -199,7 +241,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that differs only by replace_client_name.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
-                    ref_address, 477,
+                    ref_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, true, true, false,
                     "pre-fix", "suf-fix")));
@@ -209,7 +251,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that differs only by generated_prefix.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
-                    ref_address, 477,
+                    ref_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, true, true, true,
                     "bogus", "suf-fix")));
@@ -219,7 +261,7 @@ TEST(D2ClientConfigTest, equalityOperator) {
 
     // Check a configuration that differs only by qualifying_suffix.
     ASSERT_NO_THROW(test_config.reset(new D2ClientConfig(true,
-                    ref_address, 477,
+                    ref_address, 477, ref_address, 478, 1024,
                     dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                     true, true, true, true,
                     "pre-fix", "bogus")));
@@ -263,6 +305,8 @@ TEST(D2ClientMgr, validConfig) {
     // Create a new, enabled config.
     ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   true, true, true, true,
                                   "pre-fix", "suf-fix")));
@@ -305,6 +349,8 @@ TEST(D2ClientMgr, analyzeFqdnInvalidCombination) {
     // Create enabled configuration with all controls off (no overrides).
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, false, false,
                                   "pre-fix", "suf-fix")));
@@ -327,6 +373,8 @@ TEST(D2ClientMgr, analyzeFqdnEnabledNoOverrides) {
     D2ClientConfigPtr cfg;
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, false, false,
                                   "pre-fix", "suf-fix")));
@@ -369,6 +417,8 @@ TEST(D2ClientMgr, analyzeFqdnEnabledOverrideNoUpdate) {
     D2ClientConfigPtr cfg;
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, true, false, false,
                                   "pre-fix", "suf-fix")));
@@ -410,6 +460,8 @@ TEST(D2ClientMgr, analyzeFqdnEnabledOverrideClientUpdate) {
     D2ClientConfigPtr cfg;
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, true, false,
                                   "pre-fix", "suf-fix")));
@@ -452,6 +504,8 @@ TEST(D2ClientMgr, adjustFqdnFlagsV4) {
     D2ClientConfigPtr cfg;
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, true, false, false,
                                   "pre-fix", "suf-fix")));
@@ -549,6 +603,8 @@ TEST(D2ClientMgr, qualifyName) {
     D2ClientConfigPtr cfg;
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, true, false,
                                   "prefix", "suffix.com")));
@@ -561,6 +617,8 @@ TEST(D2ClientMgr, qualifyName) {
 
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, true, false,
                                   "prefix", "hasdot.com.")));
@@ -580,6 +638,8 @@ TEST(D2ClientMgr, generateFqdn) {
     D2ClientConfigPtr cfg;
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, true, false,
                                   "prefix", "suffix.com")));
@@ -612,6 +672,8 @@ TEST(D2ClientMgr, adjustDomainNameV4) {
     D2ClientConfigPtr cfg;
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, false, false,
                                   "prefix", "suffix.com")));
@@ -653,6 +715,8 @@ TEST(D2ClientMgr, adjustDomainNameV4) {
     // Create enabled configuration.
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, false, true,
                                   "prefix", "suffix.com")));
@@ -701,6 +765,8 @@ TEST(D2ClientMgr, adjustDomainNameV6) {
     D2ClientConfigPtr cfg;
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, false, false,
                                   "prefix", "suffix.com")));
@@ -739,6 +805,8 @@ TEST(D2ClientMgr, adjustDomainNameV6) {
     // Create enabled configuration.
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, false, false, true,
                                   "prefix", "suffix.com")));
@@ -787,6 +855,8 @@ TEST(D2ClientMgr, adjustFqdnFlagsV6) {
     D2ClientConfigPtr cfg;
     ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 477,
+                                  isc::asiolink::IOAddress("127.0.0.1"), 478,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   false, true, false, false,
                                   "pre-fix", "suf-fix")));

+ 44 - 3
src/lib/dhcpsrv/tests/d2_udp_unittest.cc

@@ -81,12 +81,20 @@ public:
                     const dhcp_ddns::NameChangeProtocol protocol) {
         // Update the configuration with one that is enabled.
         D2ClientConfigPtr new_cfg;
+
+        isc::asiolink::IOAddress server_ip(server_address);
+        isc::asiolink::IOAddress sender_ip(server_ip.isV4() ?
+                                           D2ClientConfig::DFT_V4_SENDER_IP :
+                                           D2ClientConfig::DFT_V6_SENDER_IP);
+
         ASSERT_NO_THROW(new_cfg.reset(new D2ClientConfig(true,
-                                  isc::asiolink::IOAddress(server_address),
-                                  server_port,
+                                  server_ip, server_port,
+                                  sender_ip, D2ClientConfig::DFT_SENDER_PORT,
+                                  D2ClientConfig::DFT_MAX_QUEUE_SIZE,
                                   protocol, dhcp_ddns::FMT_JSON,
                                   true, true, true, true,
                                   "myhost", ".example.com.")));
+
         ASSERT_NO_THROW(setD2ClientConfig(new_cfg));
         ASSERT_TRUE(ddnsEnabled());
     }
@@ -300,7 +308,7 @@ TEST_F(D2ClientMgrTest, udpSend) {
 /// an external IOService.
 TEST_F(D2ClientMgrTest, udpSendExternalIOService) {
     // Enable DDNS with server at 127.0.0.1/prot 53001 via UDP.
-    enableDdns("127.0.0.1", 530001, dhcp_ddns::NCR_UDP);
+    enableDdns("127.0.0.1", 53001, dhcp_ddns::NCR_UDP);
 
     // Place sender in send mode using an external IO service.
     asiolink::IOService io_service;
@@ -328,6 +336,39 @@ TEST_F(D2ClientMgrTest, udpSendExternalIOService) {
     ASSERT_NO_THROW(stopSender());
 }
 
+/// @brief Checks that D2ClientMgr can send with a UDP sender and
+/// an external IOService.
+TEST_F(D2ClientMgrTest, udpSendExternalIOService6) {
+    // Enable DDNS with server at 127.0.0.1/prot 53001 via UDP.
+    enableDdns("::1", 53001, dhcp_ddns::NCR_UDP);
+
+    // Place sender in send mode using an external IO service.
+    asiolink::IOService io_service;
+    ASSERT_NO_THROW(startSender(getErrorHandler(), io_service));
+
+    // select_fd should evaluate to NOT ready to read.
+    selectCheck(false);
+
+    // Build a test request and send it.
+    dhcp_ddns::NameChangeRequestPtr ncr = buildTestNcr();
+    ASSERT_NO_THROW(sendRequest(ncr));
+
+    // select_fd should evaluate to ready to read.
+    selectCheck(true);
+
+    // Call service handler.
+    runReadyIO();
+
+    // select_fd should evaluate to not ready to read.
+    selectCheck(false);
+
+    // Explicitly stop the sender. This ensures the sender's
+    // ASIO socket is closed prior to the local io_service
+    // instance goes out of scope.
+    ASSERT_NO_THROW(stopSender());
+}
+
+
 /// @brief Checks that D2ClientMgr invokes the client error handler
 /// when send errors occur.
 TEST_F(D2ClientMgrTest, udpSendErrorHandler) {

+ 6 - 0
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc

@@ -718,6 +718,9 @@ TEST_F(ParseConfigTest, validD2Config) {
         "     \"enable-updates\" : true, "
         "     \"server-ip\" : \"192.0.2.0\", "
         "     \"server-port\" : 3432, "
+        "     \"sender-ip\" : \"192.0.2.1\", "
+        "     \"sender-port\" : 3433, "
+        "     \"max-queue-size\" : 2048, "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
@@ -761,6 +764,9 @@ TEST_F(ParseConfigTest, validD2Config) {
         "     \"enable-updates\" : false, "
         "     \"server-ip\" : \"2001:db8::\", "
         "     \"server-port\" : 43567, "
+        "     \"sender-ip\" : \"2001:db8::1\", "
+        "     \"sender-port\" : 3433, "
+        "     \"max-queue-size\" : 2048, "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : false, "