Browse Source

[master] Merge branch 'trac3328'

Adds sender_ip,sender_port,max_queue_size to D2 client config
Thomas Markwalder 11 years ago
parent
commit
8d8d0b5eed

+ 151 - 86
doc/guide/bind10-guide.xml

@@ -2125,6 +2125,9 @@ Dhcp4/subnet4/	list
 Dhcp4/dhcp-ddns/enable-updates	true	boolean
 Dhcp4/dhcp-ddns/server-ip	"127.0.0.1"	string
 Dhcp4/dhcp-ddns/server-port	53001	integer
+Dhcp4/dhcp-ddns/sender-ip	""	string
+Dhcp4/dhcp-ddns/sender-port	0	integer
+Dhcp4/dhcp-ddns/max-queue-size	1024	integer
 Dhcp4/dhcp-ddns/ncr-protocol	"UDP"	string
 Dhcp4/dhcp-ddns/ncr-format	"JSON"	string
 Dhcp4/dhcp-ddns/override-no-update	false	boolean
@@ -3010,7 +3013,7 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
     <section id="dhcp4-ddns-config">
       <title>Configuring DHCPv4 for DDNS</title>
       <para>
-      As mentioned earlier, DHCPv4 can be configured to generate requests to the
+      As mentioned earlier, b10-dhcp4 can be configured to generate requests to the
       DHCP-DDNS server to update DNS entries.  These requests are known as
       NameChangeRequests or NCRs.  Each NCR contains the following information:
       <orderedlist>
@@ -3026,13 +3029,16 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
       </para></listitem>
       </orderedlist>
       The parameters for controlling the generation of NCRs for submission to D2
-      are contained in the "dhcp-ddns" section of the DHCPv4 server
+      are contained in the "dhcp-ddns" section of the b10-dhcp4 server
       configuration. The default values for this section appears as follows:
 <screen>
 &gt; <userinput>config show Dhcp4/dhcp-ddns</userinput>
 Dhcp4/dhcp-ddns/enable-updates	true	boolean
 Dhcp4/dhcp-ddns/server-ip	"127.0.0.1"	string
 Dhcp4/dhcp-ddns/server-port	53001	integer
+Dhcp4/dhcp-ddns/sender-ip	""	string
+Dhcp4/dhcp-ddns/sender-port	0	integer
+Dhcp4/dhcp-ddns/max-queue-size	1024	integer
 Dhcp4/dhcp-ddns/ncr-protocol	"UDP"	string
 Dhcp4/dhcp-ddns/ncr-format	"JSON"	string
 Dhcp4/dhcp-ddns/override-no-update	false	boolean
@@ -3043,7 +3049,7 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
 </screen>
       </para>
       <para>
-      The "enable-updates" parameter determines whether or not DHCPv4 will
+      The "enable-updates" parameter determines whether or not b10-dhcp4 will
       generate NCRs.  By default, this value is false hence DDNS updates are
       disabled.  To enable DDNS updates set this value to true:
       </para>
@@ -3054,47 +3060,74 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
       <section id="dhcpv4-d2-io-config">
       <title>DHCP-DDNS Server Connectivity</title>
       <para>
-      In order for NCRs to reach the D2 server, DHCPv4 must be able
-      to communicate with it and so the relevant parameters must be set
-      appropriately.  The parameters, "server-ip" and "server-port", specify
-      the address of the D2 server.  By default, D2 is assumed to running
-      on the same machine as DHCPv4, and the default values for these two
-      parameters should be sufficient. However, if D2 has been configured
-      to listen on a different address or port, these values must altered
-      accordingly.  For example, if D2 has been configured to listen on
-      198.162.1.10 port 900, the following commands would be required:
+      In order for NCRs to reach the D2 server, b10-dhcp4 must be able
+      to communicate with it.  b10-dhcp4 uses the following configuration
+      parameters to control how it communications with D2:
+      <orderedlist>
+      <listitem><para>
+      server-ip - IP address on which D2 listens for requests. The default is
+      the local loopback interface at address 127.0.0.1. You may specify
+      either an IPv4 or IPv6 address.
+      </para></listitem>
+      <listitem><para>
+      server-port - port on which D2 listens for requests.  The default value
+      is 53001.
+      </para></listitem>
+      <listitem><para>
+      sender-ip - IP address which b10-dhcp4 should use to send requests to D2.
+      The default value is blank which instructs b10-dhcp4 to select a suitable
+      address.
+      </para></listitem>
+      <listitem><para>
+      sender-port - port which b10-dhcp4 should use to send requests to D2. The
+      default value of 0 instructs b10-dhcp4 to select suitable port.
+      </para></listitem>
+      <listitem><para>
+      ncr-format - Socket protocol use when sending requests to D2.  Currently
+      only UDP is supported.  TCP may be available in an upcoming release.
+      </para></listitem>
+      <listitem><para>
+      ncr-protocol - Packet format to use when sending requests to D2.
+      Currently only JSON format is supported.  Other formats may be available
+      in future releases.
+      </para></listitem>
+      <listitem><para>
+      max-queue-size - maximum number of requests allowed to queue waiting to
+      be sent to D2. This value guards against requests accumulating
+      uncontrollably if they are being generated faster than they can be
+      delivered.  If the number of requests queued for transmission reaches
+      this value, DDNS updating will be turned off until the queue backlog has
+      been sufficiently reduced.  The intent is allow the b10-dhcp4 server to
+      continue lease operations.  The default value is 1024.
+      </para></listitem>
+      </orderedlist>
+      By default, D2 is assumed to running on the same machine as b10-dhcp4, and
+      all of the default values mentioned above should be sufficient.
+      If, however, D2 has been configured to listen on a different address or
+      port, these values must altered accordingly. For example, if D2 has been
+      configured to listen on 198.162.1.10 port 900, the following commands
+      would be required:
 <screen>
 &gt; <userinput>config set Dhcp4/dhcp-ddns/server-ip "198.162.1.10"</userinput>
 &gt; <userinput>config set Dhcp4/dhcp-ddns/server-port 900</userinput>
 &gt; <userinput>config commit</userinput>
 </screen>
-      D2 can be configured to listen over IPv4 or IPv6, therefore server-ip
-      may be either an IPv4 or IPv6 address.
-      </para>
-      <para>
-      The socket protocol that DHCPv4 should use to communicate with D2 is
-      specified with the "ncr-protocol" parameter.  Currently only UDP is
-      supported.
-      </para>
-      <para>
-      The internal format for DDNS update requests sent by DHCPv4 is specified
-      with the "ncr-format" parameter. Currently only JSON is supported.
       </para>
       </section>
       <section id="dhcpv4-d2-rules-config">
-      <title>When does the DHCPv4 server generate DDNS requests?</title>
-      DHCPv4 follows the behavior prescribed for DHCP servers in RFC 4702.
-      It is important to keep in mind that DHCPv4 provides the initial decision
+      <title>When does the b10-dhcp4 server generate DDNS requests?</title>
+      b10-dhcp4 follows the behavior prescribed for DHCP servers in RFC 4702.
+      It is important to keep in mind that b10-dhcp4 provides the initial decision
       making of when and what to update and forwards that information to D2 in
       the form of NCRs. Carrying out the actual DNS updates and dealing with
       such things as conflict resolution are the purview of D2 (<xref linkend="dhcp-ddns-server"/>).
       <para>
-      This section describes when DHCPv4 will generate NCRs and the
+      This section describes when b10-dhcp4 will generate NCRs and the
       configuration parameters that can be used to influence this decision.
       It assumes that the "enable-updates" parameter is true.
       </para>
       <para>
-      In general, DHCPv4 will generate DDNS update requests when:
+      In general, b10-dhcp4 will generate DDNS update requests when:
       <orderedlist>
       <listitem><para>
       A new lease is granted in response to a DHCP REQUEST
@@ -3115,10 +3148,10 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
       involved and is discussed next.
       </para>
       <para>
-      When a new lease is granted, the DHCPv4 server will generate a DDNS
+      When a new lease is granted, b10-dhcp4 will generate a DDNS
       update request if the DHCP REQUEST contains either the FQDN option
       (code 81) or the Host Name option (code 12). If both are present,
-      the server will use the FQDN option. By default the DHCPv4 server
+      the server will use the FQDN option. By default b10-dhcp4
       will respect the FQDN N and S flags specified by the client as shown
       in the following table:
       </para>
@@ -3164,11 +3197,11 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
       <para>
       The first row in the table above represents "client delegation". Here
       the DHCP client states that it intends to do the forward DNS updates and
-      the server should do the reverse updates.  By default, DHCPv4 will honor
+      the server should do the reverse updates.  By default, b10-dhcp4 will honor
       the client's wishes and generate a DDNS request to D2 to update only
       reverse DNS data.  The parameter, "override-client-update", can be used
       to instruct the server to override client delegation requests.  When
-      this parameter is true, DHCPv4 will disregard requests for client
+      this parameter is true, b10-dhcp4 will disregard requests for client
       delegation and generate a DDNS request to update both forward and
       reverse DNS data.  In this case, the N-S-O flags in the server's
       response to the client will be 0-1-1 respectively.
@@ -3176,7 +3209,7 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
       <para>
       (Note that the flag combination N=1, S=1 is prohibited according to
       RFC 4702. If such a combination is received from the client, the packet
-      will be dropped by the DHCPv4 server.)
+      will be dropped by the b10-dhcp4.)
       </para>
       <para>
       To override client delegation, issue the following commands:
@@ -3189,7 +3222,7 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
       The third row in the table above describes the case in which the client
       requests that no DNS updates be done. The parameter, "override-no-update",
       can be used to instruct the server to disregard the client's wishes. When
-      this parameter is true, DHCPv4 will generate DDNS update request to D2
+      this parameter is true, b10-dhcp4 will generate DDNS update request to D2
       even if the client requests no updates be done.  The N-S-O flags in the
       server's response to the client will be 0-1-1.
       </para>
@@ -3201,7 +3234,7 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
 &gt; <userinput>config commit</userinput>
 </screen>
       <para>
-      DHCPv4 will always generate DDNS update requests if the client request
+      b10-dhcp4 will always generate DDNS update requests if the client request
       only contains the Host Name option. In addition it will include an FQDN
       option in the response to the client with the FQDN N-S-O flags set to
       0-1-0 respectively. The domain name portion of the FQDN option will be
@@ -3209,9 +3242,9 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
       </para>
       </section>
       <section id="dhcpv4-fqdn-name-generation">
-      <title>DHCPv4 name generation for DDNS update requests</title>
+      <title>b10-dhcp4 name generation for DDNS update requests</title>
       Each NameChangeRequest must of course include the fully qualified domain
-      name whose DNS entries are to be affected.  DHCPv4 can be configured to
+      name whose DNS entries are to be affected.  b10-dhcp4 can be configured to
       supply a portion or all of that name based upon what it receives from
       the client in the DHCP REQUEST.
       <para>
@@ -3240,7 +3273,7 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
       </orderedlist>
       </para></listitem>
       </orderedlist>
-      To instruct DHCPv4 to always generate the FQDN for a client, set the
+      To instruct b10-dhcp4 to always generate the FQDN for a client, set the
       parameter "replace-client-name" to true as follows:
       </para>
 <screen>
@@ -3268,7 +3301,7 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
 </screen>
       </section>
       <para>
-      When generating a name, DHCPv4 will construct name of the format:
+      When generating a name, b10-dhcp4 will construct name of the format:
       </para>
       <para>
         [generated-prefix]-[address-text].[qualifying-suffix].
@@ -3284,7 +3317,7 @@ Dhcp4/dhcp-ddns/qualifying-suffix	"example.com"	string
       </para>
     </section>
 
-  </section> <!-- end of configuring DHCPv4 server section with many subsections -->
+  </section> <!-- end of configuring b10-dhcp4 server section with many subsections -->
 
     <section id="dhcp4-serverid">
       <title>Server Identifier in DHCPv4</title>
@@ -3629,6 +3662,9 @@ Dhcp6/subnet6/  list
 Dhcp6/dhcp-ddns/enable-updates  true    boolean
 Dhcp6/dhcp-ddns/server-ip   "127.0.0.1" string
 Dhcp6/dhcp-ddns/server-port 53001   integer
+Dhcp6/dhcp-ddns/sender-ip	""	string
+Dhcp6/dhcp-ddns/sender-port	0	integer
+Dhcp6/dhcp-ddns/max-queue-size	1024  integer
 Dhcp6/dhcp-ddns/ncr-protocol    "UDP"   string
 Dhcp6/dhcp-ddns/ncr-format  "JSON"  string
 Dhcp6/dhcp-ddns/always-include-fqdn false   boolean
@@ -4562,7 +4598,7 @@ should include options from the isc option space:
     <section id="dhcp6-ddns-config">
       <title>Configuring DHCPv6 for DDNS</title>
       <para>
-      As mentioned earlier, DHCPv6 can be configured to generate requests to
+      As mentioned earlier, b10-dhcp6 can be configured to generate requests to
       the DHCP-DDNS server (referred to here as the "D2" server) to update
       DNS entries.  These requests are known as NameChangeRequests or NCRs.
       Each NCR contains the following information:
@@ -4579,13 +4615,16 @@ should include options from the isc option space:
       </para></listitem>
       </orderedlist>
       The parameters controlling the generation of NCRs for submission to D2
-      are contained in the "dhcp-ddns" section of the DHCPv6 server
+      are contained in the "dhcp-ddns" section of b10-dhcp6
       configuration. The default values for this section appears as follows:
 <screen>
 &gt; <userinput>config show Dhcp6/dhcp-ddns</userinput>
 Dhcp6/dhcp-ddns/enable-updates	true	boolean
 Dhcp6/dhcp-ddns/server-ip	"127.0.0.1"	string
 Dhcp6/dhcp-ddns/server-port	53001	integer
+Dhcp6/dhcp-ddns/sender-ip	""	string
+Dhcp6/dhcp-ddns/sender-port	0	integer
+Dhcp6/dhcp-ddns/max-queue-size	1024 integer
 Dhcp6/dhcp-ddns/ncr-protocol	"UDP"	string
 Dhcp6/dhcp-ddns/ncr-format	"JSON"	string
 Dhcp6/dhcp-ddns/override-no-update	false	boolean
@@ -4596,7 +4635,7 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
 </screen>
       </para>
       <para>
-      The "enable-updates" parameter determines whether or not DHCPv6 will
+      The "enable-updates" parameter determines whether or not b10-dhcp6 will
       generate NCRs.  By default, this value is false hence DDNS updates are
       disabled.  To enable DDNS updates set this value to true as follows:
       </para>
@@ -4606,58 +4645,84 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
 </screen>
       <section id="dhcpv6-d2-io-config">
       <title>DHCP-DDNS Server Connectivity</title>
-      In order for NCRs to reach D2, DHCPv6 must be able to communicate with it.
-      The following parameters are used to establish connectivty between DHCPv6
-      and D2.
-      <para>
-      The parameters, "server-ip" and "server-port", specify the address of the
-      D2 server.  By default, D2 is assumed to running on the same machine as
-      DHCPv6, and the default values for these two parameters should be
-      sufficient. However, if D2 has been configured to listen on a different
-      address or port, these values must altered accordingly.  For example, if
-      D2 has been configured to listen on 198.162.1.10 port 900, the following
-      commands would be required:
-      </para>
+      <para>
+      In order for NCRs to reach the D2 server, b10-dhcp6 must be able
+      to communicate with it.  b10-dhcp6 uses the following configuration
+      parameters to control how it communications with D2:
+      <orderedlist>
+      <listitem><para>
+      server-ip - IP address on which D2 listens for requests. The default is
+      the local loopback interface at address 127.0.0.1. You may specify
+      either an IPv4 or IPv6 address.
+      </para></listitem>
+      <listitem><para>
+      server-port - port on which D2 listens for requests.  The default value
+      is 53001.
+      </para></listitem>
+      <listitem><para>
+      sender-ip - IP address which b10-dhcp6 should use to send requests to D2.
+      The default value is blank which instructs b10-dhcp6 to select a suitable
+      address.
+      </para></listitem>
+      <listitem><para>
+      sender-port - port which b10-dhcp6 should use to send requests to D2. The
+      default value of 0 instructs b10-dhcp6 to select suitable port.
+      </para></listitem>
+      <listitem><para>
+      ncr-format - Socket protocol use when sending requests to D2.  Currently
+      only UDP is supported.  TCP may be available in an upcoming release.
+      </para></listitem>
+      <listitem><para>
+      ncr-protocol - Packet format to use when sending requests to D2.
+      Currently only JSON format is supported.  Other formats may be available
+      in future releases.
+      </para></listitem>
+      <listitem><para>
+      max-queue-size - maximum number of requests allowed to queue waiting to
+      be sent to D2. This value guards against requests accumulating
+      uncontrollably if they are being generated faster than they can be
+      delivered.  If the number of requests queued for transmission reaches
+      this value, DDNS updating will be turned off until the queue backlog has
+      been sufficiently reduced.  The intent is allow b10-dhcp6 to
+      continue lease operations.  The default value is 1024.
+      </para></listitem>
+      </orderedlist>
+      By default, D2 is assumed to running on the same machine as b10-dhcp6, and
+      all of the default values mentioned above should be sufficient.
+      If, however, D2 has been configured to listen on a different address or
+      port, these values must altered accordingly. For example, if D2 has been
+      configured to listen on 3001::5 port 900, the following commands
+      would be required:
 <screen>
-&gt; <userinput>config set Dhcp6/dhcp-ddns/server-ip "198.162.1.10"</userinput>
+&gt; <userinput>config set Dhcp6/dhcp-ddns/server-ip "3001::5"</userinput>
 &gt; <userinput>config set Dhcp6/dhcp-ddns/server-port 900</userinput>
 &gt; <userinput>config commit</userinput>
 </screen>
-      D2 can be configured to listen over IPv4 or IPv6, therefore server-ip
-      may be either an IPv4 or IPv6 address.
-      <para>
-      The socket protocol that DHCPv6 should use to communicate with D2 is
-      specified with the "ncr-protocol" parameter.  Currently only UDP is
-      supported.
-      </para>
-      <para>
-      The internal format for DDNS update requests sent by DHCPv6 is specified
-      with the "ncr-format" parameter. Currently only JSON is supported.
       </para>
       </section>
       <section id="dhcpv6-d2-rules-config">
-      <title>When does DHCPv6 generate DDNS request</title>
-      DHCPv6 follows the behavior prescribed for DHCP servers in RFC 4704.
-      It is important to keep in mind that DHCPv6 provides the initial decision
+      <title>When does b10-dhcp6 generate DDNS request</title>
+      b10-dhcp6 follows the behavior prescribed for DHCP servers in RFC 4704.
+      It is important to keep in mind that b10-dhcp6 provides the initial decision
       making of when and what to update and forwards that information to D2 in
       the form of NCRs. Carrying out the actual DNS updates and dealing with
       such things as conflict resolution are the purview of D2 (<xref linkend="dhcp-ddns-server"/>).
       <para>
-      This section describes when DHCPv6 will generate NCRs and the
+      This section describes when b10-dhcp6 will generate NCRs and the
       configuration parameters that can be used to influence this decision.
       It assumes that the "enable-updates" parameter is true.
       </para>
       <note>
         <para>
-        Currently the interface between DHCPv6 and D2 only supports requests
+        Currently the interface between b10-dhcp6 and D2 only supports requests
         which update DNS entries for a single IP address.  If a lease grants
-        more than one address, DHCPv6 will create the DDNS update request for
+        more than one address, b10-dhcp6 will create the DDNS update request for
         only the first of these addresses.  Support for multiple address
         mappings may be provided in a future release.
         </para>
       </note>
       <para>
-      In general, DHCPv6 will generate DDNS update requests when:
+      In general, b10-dhcp6 will generate DDNS update requests when:
       <orderedlist>
       <listitem><para>
       A new lease is granted in response to a DHCP REQUEST
@@ -4678,8 +4743,8 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
       discussed next.
       </para>
       <para>
-      DHCPv6 will generate a DDNS update request only if the DHCP REQUEST
-      contains the FQDN option (code 39). By default the DHCPv6 server will
+      b10-dhcp6 will generate a DDNS update request only if the DHCP REQUEST
+      contains the FQDN option (code 39). By default b10-dhcp6 will
       respect the FQDN N and S flags specified by the client as shown in the
       following table:
       </para>
@@ -4725,11 +4790,11 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
       <para>
       The first row in the table above represents "client delegation". Here
       the DHCP client states that it intends to do the forward DNS updates and
-      the server should do the reverse updates.  By default, DHCPv6 will honor
+      the server should do the reverse updates.  By default, b10-dhcp6 will honor
       the client's wishes and generate a DDNS request to D2 to update only
       reverse DNS data.  The parameter, "override-client-update", can be used
       to instruct the server to override client delegation requests.  When
-      this parameter is true, DHCPv6 will disregard requests for client
+      this parameter is true, b10-dhcp6 will disregard requests for client
       delegation and generate a DDNS request to update both forward and
       reverse DNS data.  In this case, the N-S-O flags in the server's
       response to the client will be 0-1-1 respectively.
@@ -4737,7 +4802,7 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
       <para>
       (Note that the flag combination N=1, S=1 is prohibited according to
       RFC 4702. If such a combination is received from the client, the packet
-      will be dropped by the DHCPv6 server.)
+      will be dropped by b10-dhcp6.)
       </para>
       <para>
       To override client delegation, issue the following commands:
@@ -4750,7 +4815,7 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
       The third row in the table above describes the case in which the client
       requests that no DNS updates be done. The parameter, "override-no-update",
       can be used to instruct the server to disregard the client's wishes. When
-      this parameter is true, DHCPv6 will generate DDNS update request to D2
+      this parameter is true, b10-dhcp6 will generate DDNS update request to D2
       even if the client requests no updates be done.  The N-S-O flags in the
       server's response to the client will be 0-1-1.
       </para>
@@ -4763,9 +4828,9 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
 </screen>
       </section>
       <section id="dhcpv6-fqdn-name-generation">
-      <title>DHCPv6 name generation for DDNS update requests</title>
+      <title>b10-dhcp6 name generation for DDNS update requests</title>
       Each NameChangeRequest must of course include the fully qualified domain
-      name whose DNS entries are to be affected.  DHCPv6 can be configured to
+      name whose DNS entries are to be affected.  b10-dhcp6 can be configured to
       supply a portion or all of that name based upon what it receives from
       the client in the DHCP REQUEST.
       <para>
@@ -4793,7 +4858,7 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
       </orderedlist>
       </para></listitem>
       </orderedlist>
-      To instruct DHCPv6 to always generate a FQDN, set the parameter
+      To instruct b10-dhcp6 to always generate a FQDN, set the parameter
       "replace-client-name" to true:
       </para>
 <screen>
@@ -4821,7 +4886,7 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
 </screen>
       </section>
       <para>
-      When qualifying a partial name, DHCPv6 will construct a name with the
+      When qualifying a partial name, b10-dhcp6 will construct a name with the
       format:
       </para>
       <para>
@@ -4836,7 +4901,7 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
         some-computer.example.com.
       </para>
       <para>
-      When generating a the entire name, DHCPv6 will construct name of the
+      When generating a the entire name, b10-dhcp6 will construct name of the
       format:
       </para>
       <para>
@@ -5066,9 +5131,9 @@ Dhcp6/renew-timer	1000	integer	(default)
   <chapter id="dhcp-ddns-server">
     <title>The DHCP-DDNS Server</title>
     <para>
-    The DHCP-DDNS Server (known informally as D2) conducts the client side of
+    The DHCP-DDNS Server (b10-dhcp-ddns, known informally as D2) conducts the client side of
     the DDNS protocol (defined in RFC 2136) on behalf of the DHCPv4 and DHCPv6
-    servers. The DHCP servers construct
+    servers (b10-dhcp4 and b10-dhcp6 respectively). The DHCP servers construct
     DDNS update requests, known as NameChangeRequests (NCRs), based upon DHCP
     lease change events and then post these to D2. D2 attempts to match
     each such request to the appropriate DNS server(s) and carry out the

+ 21 - 0
src/bin/dhcp4/dhcp4.spec

@@ -356,6 +356,27 @@
                 "item_description" : "port number of b10-dhcp-ddns"
             },
             {
+                "item_name": "sender-ip",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": "",
+                "item_description" : "IP address from which to send to b10-dhcp-ddns (IPv4 or IPv6)"
+            },
+            {
+                "item_name": "sender-port",
+                "item_type": "integer",
+                "item_optional": true,
+                "item_default": 0,
+                "item_description" : "port number from which to send to b10-dhcp-ddns"
+            },
+            {
+                "item_name": "max-queue-size",
+                "item_type": "integer",
+                "item_optional": true,
+                "item_default": 1024,
+                "item_description" : "maximum number of requests allowed in the send queue"
+            },
+            {
                 "item_name": "ncr-protocol",
                 "item_type": "string",
                 "item_optional": true,

+ 6 - 0
src/bin/dhcp4/tests/config_parser_unittest.cc

@@ -2856,6 +2856,9 @@ TEST_F(Dhcp4ParserTest, d2ClientConfig) {
         "     \"enable-updates\" : true, "
         "     \"server-ip\" : \"192.168.2.1\", "
         "     \"server-port\" : 777, "
+        "     \"sender-ip\" : \"192.168.2.2\", "
+        "     \"sender-port\" : 778, "
+        "     \"max-queue-size\" : 2048, "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
@@ -2888,6 +2891,9 @@ TEST_F(Dhcp4ParserTest, d2ClientConfig) {
     EXPECT_TRUE(d2_client_config->getEnableUpdates());
     EXPECT_EQ("192.168.2.1", d2_client_config->getServerIp().toText());
     EXPECT_EQ(777, d2_client_config->getServerPort());
+    EXPECT_EQ("192.168.2.2", d2_client_config->getSenderIp().toText());
+    EXPECT_EQ(778, d2_client_config->getSenderPort());
+    EXPECT_EQ(2048, d2_client_config->getMaxQueueSize());
     EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_client_config->getNcrProtocol());
     EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_client_config->getNcrFormat());
     EXPECT_TRUE(d2_client_config->getAlwaysIncludeFqdn());

+ 17 - 8
src/bin/dhcp4/tests/d2_unittest.cc

@@ -88,8 +88,11 @@ Dhcp4SrvD2Test::reset() {
 
 void
 Dhcp4SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
-                            const std::string& ip_address,
-                            const uint32_t port) {
+                            const std::string& server_ip,
+                            const size_t port,
+                            const std::string& sender_ip,
+                            const size_t sender_port,
+                            const size_t max_queue_size) {
     std::ostringstream config;
     config <<
         "{ \"interfaces\": [ \"*\" ],"
@@ -100,8 +103,11 @@ Dhcp4SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
         "    \"subnet\": \"192.0.2.0/24\" } ],"
         " \"dhcp-ddns\" : {"
         "     \"enable-updates\" : " << (enable_d2 ? "true" : "false") <<  ", "
-        "     \"server-ip\" : \"" << ip_address << "\", "
+        "     \"server-ip\" : \"" << server_ip << "\", "
         "     \"server-port\" : " << port << ", "
+        "     \"sender-ip\" : \"" << sender_ip << "\", "
+        "     \"sender-port\" : " << sender_port << ", "
+        "     \"max-queue-size\" : " << max_queue_size << ", "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
@@ -165,10 +171,10 @@ TEST_F(Dhcp4SrvD2Test, enableDisable) {
     ASSERT_FALSE(mgr.amSending());
 }
 
-// Tests Dhcp4 server's ability to correctly handle a flawed dhcp-ddns configuration.
-// It does so by first enabling updates by submitting a valid configuration and then
-// ensuring they remain on after submitting a flawed configuration.
-// and then invoking its startD2() method.
+// Tests Dhcp4 server's ability to correctly handle a flawed dhcp-ddns
+// configuration.  It does so by first enabling updates by submitting a valid
+// configuration and then ensuring they remain on after submitting a flawed
+// configuration and then invoking its startD2() method.
 TEST_F(Dhcp4SrvD2Test, badConfig) {
     // Grab the manager and verify that be default ddns is off
     // and a sender was not started.
@@ -293,7 +299,10 @@ TEST_F(Dhcp4SrvD2Test, forceUDPSendFailure) {
 
     // Configure it enabled and start it.
     // Using server address of 0.0.0.0/0 should induce failure on send.
-    ASSERT_NO_FATAL_FAILURE(configureD2(true, SHOULD_PASS, "0.0.0.0", 0));
+    // Pass in a non-zero sender port to avoid validation error when
+    // server-ip/port are same as sender-ip/port
+    ASSERT_NO_FATAL_FAILURE(configureD2(true, SHOULD_PASS, "0.0.0.0", 0,
+                                        "0.0.0.0", 53001));
     ASSERT_TRUE(mgr.ddnsEnabled());
     ASSERT_NO_THROW(srv_.startD2());
     ASSERT_TRUE(mgr.amSending());

+ 9 - 3
src/bin/dhcp4/tests/d2_unittest.h

@@ -77,11 +77,17 @@ public:
     ///
     /// @param enable_updates value to assign to the enable-updates parameter
     /// @param exp_result indicates if configuration should pass or fail
-    /// @param ip_address IP address for the D2 server
+    /// @param server_ip IP address for the D2 server
     /// @param port  port for the D2 server
+    /// @param sender_ip NCR sender's IP address
+    /// @param sender_port NCR sender port
+    /// @param max_queue_size maximum number of NCRs allowed in sender's queue
     void configureD2(bool enable_updates, bool exp_result = SHOULD_PASS,
-                     const std::string& ip_address = "127.0.0.1",
-                     const uint32_t port = 53001);
+                     const std::string& server_ip = "127.0.0.1",
+                     const size_t port = 53001,
+                     const std::string& sender_ip = "0.0.0.0",
+                     const size_t sender_port = 0,
+                     const size_t max_queue_size = 1024);
 
     /// @brief Configures the server with the given configuration
     ///

+ 1 - 0
src/bin/dhcp4/tests/fqdn_unittest.cc

@@ -77,6 +77,7 @@ public:
 
         ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
                                   isc::asiolink::IOAddress("127.0.0.1"), 53001,
+                                  isc::asiolink::IOAddress("0.0.0.0"), 0, 1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   (mask & ALWAYS_INCLUDE_FQDN),
                                   (mask & OVERRIDE_NO_UPDATE),

+ 21 - 0
src/bin/dhcp6/dhcp6.spec

@@ -393,6 +393,27 @@
                 "item_description" : "port number of b10-dhcp-ddns"
             },
             {
+                "item_name": "sender-ip",
+                "item_type": "string",
+                "item_optional": true,
+                "item_default": "",
+                "item_description" : "IP address from which to send to b10-dhcp-ddns (IPv4 or IPv6)"
+            },
+            {
+                "item_name": "sender-port",
+                "item_type": "integer",
+                "item_optional": true,
+                "item_default": 0,
+                "item_description" : "port number from which to send to b10-dhcp-ddns"
+            },
+            {
+                "item_name": "max-queue-size",
+                "item_type": "integer",
+                "item_optional": true,
+                "item_default": 1024,
+                "item_description" : "maximum number of requests allowed in the send queue"
+            },
+            {
                 "item_name": "ncr-protocol",
                 "item_type": "string",
                 "item_optional": true,

+ 8 - 2
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -3213,8 +3213,11 @@ TEST_F(Dhcp6ParserTest, d2ClientConfig) {
         "    \"subnet\": \"2001:db8:1::/64\" } ], "
         " \"dhcp-ddns\" : {"
         "     \"enable-updates\" : true, "
-        "     \"server-ip\" : \"192.168.2.1\", "
+        "     \"server-ip\" : \"3001::1\", "
         "     \"server-port\" : 777, "
+        "     \"sender-ip\" : \"3001::2\", "
+        "     \"sender-port\" : 778, "
+        "     \"max-queue-size\" : 2048, "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
@@ -3245,8 +3248,11 @@ TEST_F(Dhcp6ParserTest, d2ClientConfig) {
 
     // Verify that the configuration values are correct.
     EXPECT_TRUE(d2_client_config->getEnableUpdates());
-    EXPECT_EQ("192.168.2.1", d2_client_config->getServerIp().toText());
+    EXPECT_EQ("3001::1", d2_client_config->getServerIp().toText());
     EXPECT_EQ(777, d2_client_config->getServerPort());
+    EXPECT_EQ("3001::2", d2_client_config->getSenderIp().toText());
+    EXPECT_EQ(778, d2_client_config->getSenderPort());
+    EXPECT_EQ(2048, d2_client_config->getMaxQueueSize());
     EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_client_config->getNcrProtocol());
     EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_client_config->getNcrFormat());
     EXPECT_TRUE(d2_client_config->getAlwaysIncludeFqdn());

+ 18 - 9
src/bin/dhcp6/tests/d2_unittest.cc

@@ -90,8 +90,11 @@ Dhcp6SrvD2Test::reset() {
 
 void
 Dhcp6SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
-                            const std::string& ip_address,
-                            const uint32_t port) {
+                            const std::string& server_ip,
+                            const size_t port,
+                            const std::string& sender_ip,
+                            const size_t sender_port,
+                            const size_t max_queue_size) {
     std::ostringstream config;
     config <<
         "{ \"interfaces\": [ \"*\" ],"
@@ -104,8 +107,11 @@ Dhcp6SrvD2Test::configureD2(bool enable_d2, const bool exp_result,
         "    \"subnet\": \"2001:db8:1::/64\" } ],"
         " \"dhcp-ddns\" : {"
         "     \"enable-updates\" : " << (enable_d2 ? "true" : "false") <<  ", "
-        "     \"server-ip\" : \"" << ip_address << "\", "
+        "     \"server-ip\" : \"" << server_ip << "\", "
         "     \"server-port\" : " << port << ", "
+        "     \"sender-ip\" : \"" << sender_ip << "\", "
+        "     \"sender-port\" : " << sender_port << ", "
+        "     \"max-queue-size\" : " << max_queue_size << ", "
         "     \"ncr-protocol\" : \"UDP\", "
         "     \"ncr-format\" : \"JSON\", "
         "     \"always-include-fqdn\" : true, "
@@ -169,10 +175,10 @@ TEST_F(Dhcp6SrvD2Test, enableDisable) {
     ASSERT_FALSE(mgr.amSending());
 }
 
-// Tests Dhcp6 server's ability to correctly handle a flawed dhcp-ddns configuration.
-// It does so by first enabling updates by submitting a valid configuration and then
-// ensuring they remain on after submitting a flawed configuration.
-// and then invoking its startD2() method.
+// Tests Dhcp6 server's ability to correctly handle a flawed dhcp-ddns
+// configuration.  It does so by first enabling updates by submitting a valid
+// configuration and then ensuring they remain on after submitting a flawed
+// configuration and then invoking its startD2() method.
 TEST_F(Dhcp6SrvD2Test, badConfig) {
     // Grab the manager and verify that be default ddns is off
     // and a sender was not started.
@@ -244,7 +250,7 @@ TEST_F(Dhcp6SrvD2Test, differentConfig) {
     ASSERT_TRUE(mgr.amSending());
 
     // Now enable it on a different port.
-    ASSERT_NO_FATAL_FAILURE(configureD2(true, SHOULD_PASS, "127.0.0.1", 54001));
+    ASSERT_NO_FATAL_FAILURE(configureD2(true, SHOULD_PASS, "::1", 54001));
 
     // Configuration was altered, so ddns should still enabled but not sending.
     ASSERT_TRUE(mgr.ddnsEnabled());
@@ -297,7 +303,10 @@ TEST_F(Dhcp6SrvD2Test, forceUDPSendFailure) {
 
     // Configure it enabled and start it.
     // Using server address of 0.0.0.0/0 should induce failure on send.
-    ASSERT_NO_FATAL_FAILURE(configureD2(true, SHOULD_PASS, "0.0.0.0", 0));
+    // Pass in a non-zero sender port to avoid validation error when
+    // server-ip/port are same as sender-ip/port
+    ASSERT_NO_FATAL_FAILURE(configureD2(true, SHOULD_PASS, "::", 0,
+                                        "::", 53001));
     ASSERT_TRUE(mgr.ddnsEnabled());
     ASSERT_NO_THROW(srv_.startD2());
     ASSERT_TRUE(mgr.amSending());

+ 9 - 4
src/bin/dhcp6/tests/d2_unittest.h

@@ -76,12 +76,17 @@ public:
     /// parameters given and passes it into the server's configuration handler.
     ///
     /// @param enable_updates value to assign to the enable-updates parameter
-    /// @param exp_result indicates if configuration should pass or fail
-    /// @param ip_address IP address for the D2 server
+    /// @param server_ip IP address for the D2 server
     /// @param port  port for the D2 server
+    /// @param sender_ip NCR sender's IP address
+    /// @param sender_port NCR sender port
+    /// @param max_queue_size maximum number of NCRs allowed in sender's queue
     void configureD2(bool enable_updates, bool exp_result = SHOULD_PASS,
-                     const std::string& ip_address = "127.0.0.1",
-                     const uint32_t port = 53001);
+                     const std::string& server_ip = "::1",
+                     const size_t port = 53001,
+                     const std::string& sender_ip = "::",
+                     const size_t sender_port = 0,
+                     const size_t max_queue_size = 1024);
 
     /// @brief Configures the server with the given configuration
     ///

+ 3 - 1
src/bin/dhcp6/tests/fqdn_unittest.cc

@@ -109,7 +109,9 @@ public:
         D2ClientConfigPtr cfg;
 
         ASSERT_NO_THROW(cfg.reset(new D2ClientConfig(true,
-                                  isc::asiolink::IOAddress("127.0.0.1"), 53001,
+                                  isc::asiolink::IOAddress("::1"), 53001,
+                                  isc::asiolink::IOAddress("::"), 0,
+                                  1024,
                                   dhcp_ddns::NCR_UDP, dhcp_ddns::FMT_JSON,
                                   (mask & ALWAYS_INCLUDE_FQDN),
                                   (mask & OVERRIDE_NO_UPDATE),

+ 55 - 22
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::
@@ -48,31 +55,37 @@ D2ClientConfig::D2ClientConfig(const  bool enable_updates,
                                const std::string& generated_prefix,
                                const std::string& qualifying_suffix)
     : enable_updates_(enable_updates),
-    server_ip_(server_ip),
-    server_port_(server_port),
-    ncr_protocol_(ncr_protocol),
-    ncr_format_(ncr_format),
-    always_include_fqdn_(always_include_fqdn),
-    override_no_update_(override_no_update),
-    override_client_update_(override_client_update),
-    replace_client_name_(replace_client_name),
-    generated_prefix_(generated_prefix),
-    qualifying_suffix_(qualifying_suffix) {
+      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),
+      override_no_update_(override_no_update),
+      override_client_update_(override_client_update),
+      replace_client_name_(replace_client_name),
+      generated_prefix_(generated_prefix),
+      qualifying_suffix_(qualifying_suffix) {
     validateContents();
 }
 
 D2ClientConfig::D2ClientConfig()
     : enable_updates_(false),
-      server_ip_(isc::asiolink::IOAddress("0.0.0.0")),
-      server_port_(0),
-      ncr_protocol_(dhcp_ddns::NCR_UDP),
-      ncr_format_(dhcp_ddns::FMT_JSON),
-      always_include_fqdn_(false),
-      override_no_update_(false),
-      override_client_update_(false),
-      replace_client_name_(false),
-      generated_prefix_("myhost"),
-      qualifying_suffix_("example.com") {
+      server_ip_(isc::asiolink::IOAddress(DFT_SERVER_IP)),
+      server_port_(DFT_SERVER_PORT),
+      sender_ip_(isc::asiolink::IOAddress(DFT_V4_SENDER_IP)),
+      sender_port_(DFT_SENDER_PORT),
+      max_queue_size_(DFT_MAX_QUEUE_SIZE),
+      ncr_protocol_(dhcp_ddns::stringToNcrProtocol(DFT_NCR_PROTOCOL)),
+      ncr_format_(dhcp_ddns::stringToNcrFormat(DFT_NCR_FORMAT)),
+      always_include_fqdn_(DFT_ALWAYS_INCLUDE_FQDN),
+      override_no_update_(DFT_OVERRIDE_NO_UPDATE),
+      override_client_update_(DFT_OVERRIDE_CLIENT_UPDATE),
+      replace_client_name_(DFT_REPLACE_CLIENT_NAME),
+      generated_prefix_(DFT_GENERATED_PREFIX),
+      qualifying_suffix_(DFT_QUALIFYING_SUFFIX) {
     validateContents();
 }
 
@@ -93,8 +106,22 @@ D2ClientConfig::validateContents() {
 
     if (ncr_protocol_ != dhcp_ddns::NCR_UDP) {
         isc_throw(D2ClientError, "D2ClientConfig: NCR Protocol:"
-                    << dhcp_ddns::ncrProtocolToString(ncr_protocol_)
-                    << " is not yet supported");
+                  << dhcp_ddns::ncrProtocolToString(ncr_protocol_)
+                  << " is not yet supported");
+    }
+
+    if (sender_ip_.getFamily() != server_ip_.getFamily()) {
+        isc_throw(D2ClientError, "D2ClientConfig: address family mismatch: "
+                  << "server-ip: " << server_ip_.toText()
+                  << " is: " << (server_ip_.isV4() ? "IPv4" : "IPv6")
+                  << " while sender-ip: "  << sender_ip_.toText()
+                  << " is: " << (sender_ip_.isV4() ? "IPv4" : "IPv6"));
+    }
+
+    if (server_ip_ == sender_ip_ && server_port_ == sender_port_) {
+        isc_throw(D2ClientError, "D2ClientConfig: server and sender cannot"
+                  " share the exact same IP address/port: "
+                  << server_ip_.toText() << "/" << server_port_);
     }
 
     /// @todo perhaps more validation we should do yet?
@@ -106,6 +133,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 +159,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) {

+ 44 - 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, "
@@ -956,6 +962,44 @@ TEST_F(ParseConfigTest, invalidD2Config) {
         "     \"qualifying-suffix\" : \"test.suffix.\" "
         "    }"
         "}",
+        // Mismatched server and sender IPs
+        "{ \"dhcp-ddns\" :"
+        "    {"
+        "     \"enable-updates\" : true, "
+        "     \"server-ip\" : \"192.0.2.0\", "
+        "     \"server-port\" : 3432, "
+        "     \"sender-ip\" : \"3001::5\", "
+        "     \"sender-port\" : 3433, "
+        "     \"max-queue-size\" : 2048, "
+        "     \"ncr-protocol\" : \"UDP\", "
+        "     \"ncr-format\" : \"JSON\", "
+        "     \"always-include-fqdn\" : true, "
+        "     \"override-no-update\" : true, "
+        "     \"override-client-update\" : true, "
+        "     \"replace-client-name\" : true, "
+        "     \"generated-prefix\" : \"test.prefix\", "
+        "     \"qualifying-suffix\" : \"test.suffix.\" "
+        "    }"
+        "}",
+        // Identical server and sender IP/port
+        "{ \"dhcp-ddns\" :"
+        "    {"
+        "     \"enable-updates\" : true, "
+        "     \"server-ip\" : \"3001::5\", "
+        "     \"server-port\" : 3433, "
+        "     \"sender-ip\" : \"3001::5\", "
+        "     \"sender-port\" : 3433, "
+        "     \"max-queue-size\" : 2048, "
+        "     \"ncr-protocol\" : \"UDP\", "
+        "     \"ncr-format\" : \"JSON\", "
+        "     \"always-include-fqdn\" : true, "
+        "     \"override-no-update\" : true, "
+        "     \"override-client-update\" : true, "
+        "     \"replace-client-name\" : true, "
+        "     \"generated-prefix\" : \"test.prefix\", "
+        "     \"qualifying-suffix\" : \"test.suffix.\" "
+        "    }"
+        "}",
         // stop
         ""
     };